/*
 * Vis5D system for visualizing five dimensional gridded data sets.
 * Copyright (C) 1990 - 2000 Bill Hibbard, Johan Kellum, Brian Paul,
 * Dave Santek, and Andre Battaiola.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * As a special exception to the terms of the GNU General Public
 * License, you are permitted to link Vis5D with (and distribute the
 * resulting source and executables) the LUI library (copyright by
 * Stellar Computer Inc. and licensed for distribution with Vis5D),
 * the McIDAS library, and/or the NetCDF library, where those
 * libraries are governed by the terms of their own licenses.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "../config.h"

/* grid.c */


/*
 * Functions for manipulating grids and lists of grids.
 */



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "grid_i.h"
#include "memory.h"
#include "projlist_i.h"



/*
 * Allocate a grid_info struct and initialize it.
 */
struct grid_info *alloc_grid_info( void )
{
   struct grid_info *g;

   g = (struct grid_info *) calloc( 1, sizeof(struct grid_info) );
   if (g) {
      /* all fields will be 0 thanks to calloc but here's some special cases */
      g->TimeStep = g->VarNum = g->Position = -1;
      g->Proj = NULL;
      g->Vcs = NULL;
      g->SelectBits = ALL_BITS;
   }
   return g;
}



/*
 * Deallocate a grid_info struct.
 */
void free_grid_info( struct grid_info *info )
{
   if (info->FileName) {
      FREE( info->FileName, 1000 );
   }
   if (info->VarName) {
      FREE( info->VarName, 1001 );
   }
   if (info->Units) {
      FREE( info->Units, 1002 );
   }
   if (info->Data) {
      FREE( info->Data, 1003 );
   }
   /* "erase" data to help with debugging */
   /*memset( info, 0xff, sizeof(struct grid_info) );*/
   FREE( info, 1004 );
}



/*
 * Allocate a grid_list struct and initialize it.
 */
struct grid_db *alloc_grid_db()
{
   struct grid_db *gl;

   /* Allocate w/ every field initialized to zero */
   gl = (struct grid_db *) calloc( sizeof(struct grid_db), 1 );

   return gl;
}


/*
 * Deallocate a grid_db struct.
 */
void free_grid_db( struct grid_db *db )
{
   struct grid_info *g, *next;
   int i;

   /* free grid_info list */
   for (g=db->FirstGrid; g; g=next) {
      next = g->Next;
      free_grid_info( g );
   }

   /* free varname and units strings */
   for (i=0;i<db->NumVars;i++) {
      FREE( db->VarNames[i], 1005 );
      if (db->Units[i]) {
         FREE( db->Units[i], 1005 );
      }
   }

   /* free projections */
   for (i=0;i<db->NumProj;i++) {
      FREE( db->ProjList[i], 1006 );
   }

   /* free VCSs */
   for (i=0;i<db->NumVcs;i++) {
      FREE( db->VcsList[i]->Args, 1007 );
      FREE( db->VcsList[i], 1008 );
   }

   FREE( db, 1008 );
}



/*
 * Append a grid_info struct onto the tail of the list.
 */
void append_grid( struct grid_info *grid, struct grid_db *db )
{

   if (db->LastGrid) {
      db->LastGrid->Next = grid;
      db->LastGrid = grid;
   }
   else {
      db->FirstGrid = db->LastGrid = grid;
   }
   grid->Next = NULL;
   db->NumGrids++;
   db->Sorted = 0;
}



/*
 * Remove a grid_info struct from a list.
 * Return:  1 = success, 0 = error
 */
int remove_grid( struct grid_info *grid, struct grid_db *db )
{
   struct grid_info *pred;
   int found;

   /* Find predecessor to the grid */
   if (db->FirstGrid==grid) {
      /* grid to remove is first in list */
      db->FirstGrid = grid->Next;
      pred = NULL;
      found = 1;
   }
   else {
      for (pred=db->FirstGrid; pred; pred=pred->Next) {
         if (pred->Next==grid) {
            /* found predecessor! */
            pred->Next = grid->Next;
            found = 1;
            break;
         }
      }
   }
   if (db->LastGrid==grid) {
      db->LastGrid = pred;
   }
   
   db->NumGrids--;
   return found;
}



/*
 * Free all the grids and associated data in a grid_db.
 */
void free_all_grids( struct grid_db *db )
{
   struct grid_info *g, *nextg;
   int i, j;

   /* free grids */
   for (g=db->FirstGrid; g; g=nextg) {
      nextg = g->Next;
      free_grid_info( g );
   }
   db->FirstGrid = db->LastGrid = NULL;
   db->NumGrids = 0;

   /* Free map projections */
   for (i=0;i<db->NumProj;i++) {
      FREE( db->ProjList[i]->Args, 1100 );
      FREE( db->ProjList[i], 1101 );
      db->ProjList[i] = NULL;
   }
   db->NumProj = 0;

   /* Free VCSs */
   for (i=0;i<db->NumVcs;i++) {
      FREE( db->VcsList[i]->Args, 1102 );
      FREE( db->VcsList[i], 1103 );
      db->VcsList[i] = NULL;
   }
   db->NumVcs = 0;

   /* Clear pointers in grid matrix */
   for (i=0;i<db->NumTimes;i++) {
      for (j=0;j<db->NumVars;j++) {
         db->Matrix[i][j] = NULL;
      }
   }

   db->NumVars = 0;
   db->NumTimes = 0;

   db->Sorted = 0;
}



/*
 * Print a grid list to stdout.  Just used for debugging.
 */
void print_grid_list( struct grid_db *db )
{
   struct grid_info *g;
   int i = 1;

   printf("  Grid  Date  Time    Variable    Nr  Nc  Nl  Proj#  Vcs#  Filename\n");
   for (g=db->FirstGrid; g; g=g->Next) {
      int projnum = lookup_proj( db, g->Proj );
      int vcsnum = lookup_vcs( db, g->Vcs );
      printf("%c %4d  %05d %06d  %-10s %3d %3d %3d   %3d   %3d   %s\n",
              g->SelectBits==ALL_BITS ? '*': ' ',
              i, g->DateStamp, g->TimeStamp, g->VarName, g->Nr, g->Nc, g->Nl,
              projnum, vcsnum,
              g->FileName );
      i++;
   }

   printf("*=include grid in output file\n");
}




/*
 * "Print" the grid list to generate an array of strings.
 * Return null if no grids in list.
 */
char **sprint_grid_list( struct grid_db *db )
{
   struct grid_info *g;
   int i = 0;
   char **vector;

   if (db->NumGrids==0) {
      return NULL;
   }

   vector = (char **) MALLOC( db->NumGrids * sizeof(char *) );

   /* See gui.h for column headings */
   for (g=db->FirstGrid; g; g=g->Next) {
      int projnum = lookup_proj( db, g->Proj );
      int vcsnum = lookup_vcs( db, g->Vcs );
      vector[i] = (char *) MALLOC( 1000 );
      sprintf( vector[i],
              "%4d  %05d %06d  %-10s%3d %3d %3d   %2d    %2d   %s%c",
              i+1,
              g->DateStamp, g->TimeStamp,
              g->VarName,
              g->Nr, g->Nc, g->Nl,
              projnum, vcsnum,
              g->FileName,
              g->Sibling ? ',' : ' ' );
      i++;
   }

   return vector;
}



/*
 * Find the maximum number of grid levels of all grids in the list.
 * Input:  db - the grid data base
 * Return:  max number of grid levels in list or -1 if empty list
 */
int find_max_levels( struct grid_db *db )
{
   struct grid_info *g;
   int maxnl = -1;

   for (g=db->FirstGrid; g; g=g->Next) {
      if (g->Nl>maxnl) {
         maxnl = g->Nl;
      }
   }

   return maxnl;
}


syntax highlighted by Code2HTML, v. 0.9.1