/* output.c */

/*
 * 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"



/*
 * Make the output file.
 */


#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "analyze_i.h"
#include "file_i.h"
#include "grid_i.h"
#include "memory.h"
#include "misc_i.h"
#include "proj_i.h"
#include "projlist_i.h"
#include "resample_i.h"
#include "api.h"
#include "v5d.h"
#include "gui.h"

extern int Debug_i;



/*
 * Write a grid of missing values.
 * Input:  v5d - the v5d file handle
 *         time, var - which timestep and variable
 *         nr, nc, nl - size of 3-D grid
 */
static void write_missing_grid( v5dstruct *v5d, int time, int var, 
                                int nr, int nc, int nl )
{
   static float *missing = NULL;
   static int gridsize = 0;
   int i;

   if (nr*nc*nl > gridsize) {
      /* allocate and initialize a larger grid of missing values */
      if (missing)   FREE(missing, 1);
      gridsize = nr*nc*nl;
      missing = (float *) MALLOC( gridsize * sizeof(float) );
      for (i=0;i<gridsize;i++) {
         missing[i] = MISSING;
      }
   }
   v5dWriteGrid( v5d, time, var, missing );
}




/*
 * Combine a number of grid arrays by averaging.  Missing values are handled
 * gracefully.
 * Input:  numvalues - how many elements in each grid (usually Nr*Nc*Nl)
 *         numgrids - how many arrays to merge
 *         grids - array of pointers to grids
 * Output:  result - array of averaged values.
 */
void average_values( int numvalues, int numgrids,
                     float *grids[], float *result )
{
   int i, j;

   for (i=0;i<numvalues;i++) {
      float sum = 0.0;
      int count = 0;
      for (j=0;j<numgrids;j++) {
         float value = grids[j][i];
         if (!IS_MISSING(value)) {
            sum += value;
            count++;
         }
      }
      if (count>0) {
         result[i] = sum / (float) count;
      }
      else {
         result[i] = MISSING;
      }
   }
}



/*
 * Like above but don't average, use first non-MISSING value.
 */
void merge_values( int numvalues, int numgrids, float *grids[], float *result )
{
   int i, j;

   for (i=0;i<numvalues;i++) {
      for (j=0;j<numgrids;j++) {
         float value = grids[j][i];
         if (!IS_MISSING(value)) {
            result[i] = value;
            break;
         }
      }
      if (j==numgrids) {
         /* have to use missing */
         result[i] = MISSING;
      }
   }
}




#ifdef LEAVEOUT
/*
 * Sort an array of grids which have the same timestep and variable number.
 * When there is more than one input grid available for a particular time-
 * step and variable we need to determine which of those grid(s) to choose
 * for the output file.  This function attempts to sort these grids into
 * an order which places the most desirable grids near the front of the list.
 *
 * Input:  numgrids - how many grids in the array
 *         glist - an array of pointers to grid_info structs
 */
static void sort_similar_grids( int numgrids, struct grid_info *glist[] )
{
   int i, j;

   /* bubble sort is good enough */
   for (i=0;i<numgrids-1;i++) {
      for (j=i+1;j<numgrids;j++) {
         int swap = 0;
         /* compare projection pointers */
         if (glist[i]->Proj > glist[j]->Proj) {
            swap = 1;
         }
         else if (glist[i]->Proj == glist[j]->Proj) {
            /* compare Vcs pointers */
            if (glist[i]->Vcs > glist[j]->Vcs) {
               swap = 1;
            }
            else if (glist[i]->Vcs == glist[j]->Vcs) {
               /* compare grid rows */
               if (glist[i]->Nr < glist[j]->Nr) {
                  swap = 1;
               }
               else if (glist[i]->Nr == glist[j]->Nr) {
                  /* compare grid columns */
                  if (glist[i]->Nc < glist[j]->Nc) {
                     swap = 1;
                  }
               }
            }
         }
         if (swap) {
            struct grid_info *gtemp = glist[i];
            glist[i] = glist[j];
            glist[j] = gtemp;
         }
      }
   }
}
#endif



/*
 * Combine a number of 2-D grids with the same map projection to form a
 * 3-D grid.
 */
static float *combine_2d_grids( struct grid_db *db, int numgrids,
                                struct grid_info *glist[],
                                struct projection **proj,
                                struct vcs **vcs )
{
   float *height;
   int i, j, n, m;
   int nr, nc, nl;
   float *grid;
   int equally_spaced;

   assert( numgrids>1 );

   height = (float *) MALLOC( numgrids * sizeof(float) );

#ifdef LEAVEOUT
   /* Determine how many grids to combine */
   for (i=0; i<numgrids; i++) {
      if (glist[i]->Proj==glist[0]->Proj && glist[i]->Vcs->Nl==1) {
         height[i] = glist[i]->Vcs->Args[0];
      }
      else {
         break;
      }
   }
   n = i;
#else
   for (i=0; i<numgrids; i++) {
      assert( glist[i]->Vcs->Nl == 1 );
      height[i] = glist[i]->Vcs->Args[0];
   }
   n = numgrids;
#endif

   /* we now have an array of [n] height values for the 2-D grids to combine */

   /* sort 2-D grids by height coordinate */
   for (i=0;i<n-1;i++) {
      for (j=i+1;j<n;j++) {
         if (height[i]>height[j]) {
            /* swap */
            float htemp;
            struct grid_info *gtemp;
            htemp = height[i];
            height[i] = height[j];
            height[j] = htemp;
            gtemp = glist[i];
            glist[i] = glist[j];
            glist[j] = gtemp;
         }
      }
   }

   /* remove duplicate heights, which is possible */
   m = 0;
   for (i=0;i<n;i++) {
      if (m==0 || height[i]!=height[m-1]) {
         /* save this height */
         height[m] = height[i];
         glist[m] = glist[i];
         m++;
      }
   }
   n = m;


   /* check for equally-spaced levels */
   {
      float delta = height[1] - height[0];
      equally_spaced = 1;
      for (i=2;i<n;i++) {
         if (height[i]-height[i-1]!=delta) {
            equally_spaced = 0;
            break;
         }
      }
   }

   /* Make a new VCS for the stack of grids */
   if (equally_spaced) {
      float args[2];
      args[0] = height[0];
      args[1] = height[1] - height[0];
      if (glist[0]->Vcs->Kind==VERT_GENERIC) {
         *vcs = new_vcs( db, VERT_GENERIC, n, 0, args );
      }
      else {
         *vcs = new_vcs( db, VERT_EQUAL_KM, n, 0, args );
      }
   }
   else {
      *vcs = new_vcs( db, VERT_UNEQUAL_KM, n, 0, height );
   }
   *proj = glist[0]->Proj;

   assert(*vcs);
   assert(*proj);

   /* all done with array of grid heights */
   FREE(height, 2);

   /* Allocate storage for the 3-D grid */
   nr = glist[0]->Proj->Nr;
   nc = glist[0]->Proj->Nc;
   nl = n;
   grid = (float *) MALLOC( nr * nc * nl * sizeof(float) );
   if (!grid) {
      return NULL;
   }

   /* build the 3-D grid */
   for (i=0;i<n;i++) {
      float *layer;
      layer = get_file_data( glist[i] );
      assert(layer);
      memcpy( grid + nr*nc*i, layer, nr*nc*sizeof(float) );
      FREE( layer, 3 );
   }

   return grid;
}




#ifdef LEAVEOUT
/*
 * Get a 3-D grid of data for a particular timestep and variable.  The
 * data will not be resampled.  The grid may be the result of combining
 * "compatible" 1-level (2-D) grids together (such as McIDAS GRIDs).
 * Input:  db - the grid data base
 *         time, var - timestep and variable number
 * Output:  proj - the map projection of the grid
 *          vcs - the VCS of the grid
 * Return:  pointer to 3-D grid of data or NULL if no data available
 */
static float *get_grid_data( struct grid_db *db, int time, int var,
                             struct projection **proj,
                             struct vcs **vcs )
{
#define MAX_GRIDS 100
   struct grid_info *g, *glist[MAX_GRIDS];
   int numgrids;

   /* Count number of selected grids at this time and var */
   g = db->Matrix[time][var];
   numgrids = 0;
   while (g && numgrids<MAX_GRIDS) {
      if (g->SelectBits==ALL_BITS) {
         glist[numgrids] = g;
         numgrids++;
      }
      g = g->Sibling;
   }

   if (numgrids>=MAX_GRIDS) {

   }

   if (numgrids==0) {
      /* Either no data present or it's not selected for output */
      *proj = NULL;
      *vcs = NULL;
      return NULL;
   }
   else if (numgrids==1) {
      /* Common, simple case */
      *proj = glist[0]->Proj;
      *vcs  = glist[0]->Vcs;
      return get_file_data( glist[0] );
   }
   else {
      /* multiple grids! */
      sort_similar_grids( numgrids, glist );

      if (glist[0]->Vcs->Nl > 1) {
         /* just use the first 3-D grid in the list */
         *proj = glist[0]->Proj;
         *vcs  = glist[0]->Vcs;
         return get_file_data( glist[0] );
      }
      else {
         return combine_2d_grids( db, numgrids, glist, proj, vcs );
      }
   }
#undef MAX_GRIDS
}
#endif



#ifdef LEAVEOUT
/*
 * Return a pointer to the 3-D grid of data resampled to the output file's
 * map projection and VCS.
 * Input:  db - the grid data base
 *         time, vvar - which timestep and variable
 *         outproj - output projection
 *         outvcs - output VCS
 *         outnl - number of grid levels wanted
 * Return:  pointer to 3-D grid of values which may be free()'d or
 *          NULL if there's no grid data
 */
static float *get_resampled_data( struct grid_db *db, int time, int var,
                                  struct projection *outproj,
                                  struct vcs *outvcs,
                                  int outnl )
{
   float *outdata;
   struct projection *gridproj;
   struct vcs *gridvcs;
   struct resampler *resamp;

   assert( outnl <= outvcs->Nl );

   /* get grid data in its original size, projection and VCS */
   outdata = get_grid_data( db, time, var, &gridproj, &gridvcs );
   if (!outdata) {
      return NULL;
   }

   resamp = get_resampler( gridproj, gridvcs, outproj, outvcs, outnl );

   if (Debug_i) {
      printf("Input grid:          ");
      print_min_max( outdata, gridproj->Nr * gridproj->Nc * gridvcs->Nl );
   }

   /* do vertical resampling if needed */
   if (gridvcs!=outvcs) {
      float *indata = outdata;
      outdata = (float *)
            MALLOC( gridproj->Nr * gridproj->Nc * outnl * sizeof(float) );
      resample_vertical( resamp, indata, outdata );
      FREE( indata, 4 );
   }

   if (Debug_i) {
      printf("After vert resamp:   ");
      print_min_max( outdata, gridproj->Nr * gridproj->Nc * outnl );
   }

   /* do horizontal resampling if needed */
   if (gridproj!=outproj) {
      float *indata = outdata;
      outdata = (float *) MALLOC( outproj->Nr * outproj->Nc * outnl
                                  * sizeof(float) );
      resample_horizontal( resamp, indata, outdata );
      FREE( indata, 5 );
   }

   if (Debug_i) {
      printf("After horiz resamp:  ");
      print_min_max( outdata, outproj->Nr * outproj->Nc * outnl );
   }

   return outdata;
}
#endif




/*
 * Given a list of grids, combine all sets of 2-D grids with same map
 * projection into new 3-D grids.  Return the new list of grids.
 * Input:  db - the grid data base
 * In/Out:  numgrids - how many grids in the list
 *          glist - list of grids
 *
 * Example:  suppose we have a list of 6 input grids:
 *             1. 6 levels
 *             2. 1 level, map projection #4
 *             3. 1 level, map projection #4
 *             4. 1 level, map projection #5
 *             5. 6 levels
 *             6. 1 level, map projection #4
 *
 *  The list of output grids would be:
 *             1. 6 levels
 *             2. 3 levels, map projection #4  (1,2 and 6 stacked)
 *             3. 1 level, map projection #5
 *             4. 6 levels
 */
static void find_and_combine_2d_grids( struct grid_db *db, int *numgrids,
                                       struct grid_info *glist[] )
{
   struct grid_info *outlist[100];
   int numout;
   int i, j;

   numout = 0;

   for (i=0;i<*numgrids;i++) {
      if (glist[i]) {
         if (glist[i]->Vcs->Nl==1) {
            struct grid_info *gp[100];   /* grids with same projection */
            int ngp;                     /* how many in gp[] array */
            struct grid_info *newgrid;   /* the "stacked" gp[] grids */

            /* make a list of containing this 2-D grid and all others with */
            /* the same horizonal coordinate system */
            gp[0] = glist[i];
            ngp = 1;
            for (j=i+1;j<*numgrids;j++) {
               if (glist[j]
                   && glist[j]->Vcs->Nl==1 && glist[j]->Proj==glist[i]->Proj) {
                  gp[ngp++] = glist[j];
                  glist[j] = NULL;  /* remove */
               }
            }
            glist[i] = NULL;  /* remove */

            /* Construct a new grid_info from a stack of 2-D grids */
            newgrid = alloc_grid_info();
            newgrid->TimeStep=123;
            newgrid->Data = combine_2d_grids( db, ngp, gp,
                                              &newgrid->Proj, &newgrid->Vcs );
            assert(newgrid->TimeStep==123);
            assert(newgrid->Proj);
            assert(newgrid->Vcs);
            newgrid->Nr = newgrid->Proj->Nr;
            newgrid->Nc = newgrid->Proj->Nc;
            newgrid->Nl = newgrid->Vcs->Nl;

            /* add new grid to output list */
            outlist[numout++] = newgrid;
         }
         else {
            /* just add this grid to the output list */
            outlist[numout++] = glist[i];
         }
      }
   }

   /* Return output grid list */
   for (i=0;i<numout;i++) {
      glist[i] = outlist[i];
   }
   *numgrids = numout;
}




/*
 * Given a grid_info, load the 3-D data from its file and resample
 * it to the output projection.
 */
static float *get_resampled_3d_data( struct grid_db *db, struct grid_info *g,
                                     struct projection *outproj,
                                     struct vcs *outvcs,
                                     int outnl )
{
   struct resampler *resamp;
   float *outdata;

   if (outvcs->Nl!=outnl) {
      printf("**** outvcs->Nl != outnl in get_r_3_d\n");
   }
   assert( g );
   assert( g->Nl==g->Vcs->Nl );

   /* get grid data in its original size, projection and VCS */
   if (g->Data) {
      /* Return a copy of grid data unchanged */
      outdata = MALLOC( g->Nr * g->Nc * g->Nl * sizeof(float) );
      if (!outdata) {
         return NULL;
      }
      memcpy( outdata, g->Data, g->Nr * g->Nc * g->Nl * sizeof(float) );
   }
   else {
      outdata = get_file_data( g );
      if (!outdata) {
         return NULL;
      }
   }

   resamp = get_resampler( g->Proj, g->Vcs, outproj, outvcs, outnl );

   if (Debug_i) {
      printf("Input grid:          ");
      print_min_max( outdata, g->Proj->Nr * g->Proj->Nc * g->Vcs->Nl );
   }

   /* do vertical resampling if needed */
   if (g->Vcs!=outvcs) {
      float *indata = outdata;
      outdata = (float *)
            MALLOC( g->Proj->Nr * g->Proj->Nc * outnl * sizeof(float) );
      resample_vertical( resamp, indata, outdata );
      FREE( indata, 6 );
   }

   if (Debug_i) {
      printf("After vert resamp:   ");
      print_min_max( outdata, g->Proj->Nr * g->Proj->Nc * outnl );
   }

   /* do horizontal resampling if needed */
   if (g->Proj!=outproj) {
      float *indata = outdata;
      outdata = (float *) MALLOC( outproj->Nr * outproj->Nc * outnl
                                  * sizeof(float) );
      resample_horizontal( resamp, indata, outdata );
      FREE( indata, 7 );
   }

   if (Debug_i) {
      printf("After horiz resamp:  ");
      print_min_max( outdata, outproj->Nr * outproj->Nc * outnl );
   }

   return outdata;
}



/*
 * For all the grids that belong to timestep 'time' and variable 'var'
 * resample them to the output projection and VCS then merge them into
 * one final 3-D grid.
 */
static float *get_combined_resampled_data( struct grid_db *db,
                                           int time, int var,
                                           struct projection *outproj,
                                           struct vcs *outvcs,
                                           int outnl, int average )
{
#define MAX_GRIDS 100
   int numgrids;
   struct grid_info *g, *glist[MAX_GRIDS];
   float *gdata[MAX_GRIDS];
   int i, j, n;

   /* just a test */
   if (outvcs->Nl!=outnl) {
      printf("***** outvcs->nl != outnl in get_c_r_d\n");
   }

   /* Make a list of all selected grids for this timestep and variable */
   g = db->Matrix[time][var];
   numgrids = 0;
   while (g && numgrids<MAX_GRIDS) {
      if (g->SelectBits==ALL_BITS) {
         glist[numgrids] = g;
         numgrids++;
      }
      g = g->Sibling;
   }

   if (numgrids==0) {
      /* no grid data available for this timstep and variable */
      return NULL;
   }

   /* Merge/stack 2-D grids into 3-D grid(s) */
   if (numgrids>1) {
      find_and_combine_2d_grids( db, &numgrids, glist );
   }

   /* Resample all the grids to the output proj and VCS */
   n = numgrids;
   numgrids = 0;
   for (i=0;i<n;i++) {
      gdata[numgrids] = get_resampled_3d_data( db, glist[i],
                                               outproj, outvcs, outnl );
      if (gdata[numgrids]) {
         numgrids++;
      }
   }

   if (numgrids==0) {
      return NULL;
   }
   else if (numgrids==1) {
      /* Common case */
      if (glist[0]->Data) {
         free_grid_info( glist[0] );
      }
      return gdata[0];
   }
   else {
      /* Average together the 3-D grids */
      int nrncnl = outproj->Nr * outproj->Nc * outnl;
      float *gout = (float *) MALLOC( nrncnl * sizeof(float) );

      if (average) {
         average_values( nrncnl, numgrids, gdata, gout );
      }
      else {
         /* sort grids by order of decreasing resolution (high-res first) */
         for (i=0;i<numgrids-1;i++) {
            for (j=i+1;j<numgrids;j++) {
               float res1, res2;
               res1 = proj_resolution( glist[i]->Proj );
               res2 = proj_resolution( glist[j]->Proj );
               if (res2<res1) {
                  /* swap */
                  float *ftmp;
                  struct grid_info *gtmp;
                  ftmp = gdata[i];
                  gdata[i] = gdata[j];
                  gdata[j] = ftmp;
                  gtmp = glist[i];
                  glist[i] = glist[j];
                  glist[j] = gtmp;
               }
            }
         }
         /* use values from high-res grid */
         merge_values( nrncnl, numgrids, gdata, gout );
      }

      /* free temporary data grids */
      for (i=0;i<numgrids;i++) {
         FREE( gdata[i], 8 );
         if (glist[i]->Data) {
            free_grid_info( glist[i] );
         }
      }

      return gout;
   }
}





/*
 * Make a v5d file from the table of grids and parameters found in the
 * v5dstruct.
 *
 * Input:  db - the grid database struct describing the grid data layout
 *         v5d - contains parameters to describe output file:
 *                   Nr = number of rows
 *                   Nc = number of columns
 *                   Projection, ProjArgs - map projection
 *                   Vertical, VertArgs - vertical coord system
 *         filename - name of v5d output file.
 *         maxnl - maximum number of grid levels allowed.
 *         average - 0=use higher-res co-located data
 *                   1=average co-located data
 *         compressmode - bytes per datapoint in output file: 1, 2, or 4
 *
 * Notes:  Which variables and timesteps to output is determined by
 * examining the grid table.
 */
void make_output_file( struct grid_db *db, v5dstruct *v5d, char *filename,
                       int maxnl, int average, int compressmode )
{
   int time, var;
   int xlate_time[MAXTIMES], xlate_var[MAXVARS];
   int nl[IMAXVARS], lowlev[IMAXVARS];
   struct projection *output_proj;
   struct vcs *output_vcs, *var_vcs[MAXVARS];
   int numproj, numvcs;
   int i;


#if V5D_VERSION >= 42
   printf("Writing a 4.3 file!\n");
#endif

   /* Save current number of projections and VCSs */
   numproj = db->NumProj;
   numvcs = db->NumVcs;

   /*
    * Finish initializing the v5d struct
    */

   /* Output file's projection and VCS */
   output_proj = new_projection( db, v5d->Projection, v5d->Nr, v5d->Nc,
                                 v5d->ProjArgs );
   output_vcs = new_vcs( db, v5d->VerticalSystem, maxnl, 0, v5d->VertArgs );

   /* Grid levels */
   compute_grid_levels( db, output_vcs, lowlev, nl );
   for (i=0;i<db->NumVars;i++) {
      /* truncate number of levels to fit user specified limit */
      if (lowlev[i]+nl[i]>maxnl) {
         if (nl[i]>maxnl) {
            lowlev[i] = 0;
            nl[i] = maxnl;
         }
         else {
            lowlev[i] = maxnl - nl[i];
         }
      }
   }


   /* Setup variables */
   v5d->NumVars = 0;
   for (var=0;var<db->NumVars;var++) {
      if (db->VarSelected[var]) {
         if (v5d->NumVars<MAXVARS) {
            strncpy( v5d->VarName[v5d->NumVars], db->VarNames[var], 10 );
            if (db->Units[var]) {
               strncpy( v5d->Units[v5d->NumVars], db->Units[var], 19 );
               v5d->Units[v5d->NumVars][19] = 0;
            }
            xlate_var[v5d->NumVars] = var;

            v5d->Nl[v5d->NumVars] = nl[var];
#if V5D_VERSION >= 42
            v5d->LowLev[v5d->NumVars] = lowlev[var];
#else
            /* sanity check */
            assert( lowlev[var] == 0 );
#endif
            v5d->NumVars++;
         }
         else {
            printf("Warning: too many variables, %d is limit,", MAXVARS );
            printf(" ignoring %s\n", db->VarNames[var] );
         }
      }
   }

   /* Setup timesteps */
   v5d->NumTimes = 0;
   for (time=0;time<db->NumTimes;time++) {
      if (db->TimeSelected[time]) {
         if (v5d->NumTimes<MAXTIMES) {
            v5d->DateStamp[v5d->NumTimes] = db->DateStamp[time];
            v5d->TimeStamp[v5d->NumTimes] = db->TimeStamp[time];
            xlate_time[v5d->NumTimes] = time;
            v5d->NumTimes++;
         }
         else {
            printf("Warning: too many time steps, %d is limit,", MAXTIMES);
            printf(" ignoring %05d %06d\n", db->DateStamp[time],
                   db->TimeStamp[time] );
         }
      }
   }


   /* actually need a different VCS for each variable */
   for (var=0;var<v5d->NumVars;var++) {
      var_vcs[var] = new_vcs( db, v5d->VerticalSystem, v5d->Nl[var],
#if V5D_VERSION >= 42
                                 v5d->LowLev[var],
#else
                                 0,
#endif
                                 v5d->VertArgs );
   }

   v5d->CompressMode = compressmode;

   /*
    * Create the v5d file
    */
   if (!v5dCreateFile( filename, v5d )) {
      printf("Error in v5dCreateFile\n");
      return;
   }


   /*
    * Write grid data
    */
   for (time=0;time<v5d->NumTimes;time++) {
      for (var=0;var<v5d->NumVars;var++) {
         int table_time, table_var;
         float *data;

         /* Translate timestep and variable number from v5d struct indexes */
         /* into grid table indexes. */
         table_time = xlate_time[time];
         table_var = xlate_var[var];

         printf("Time: %d  Var: %s\n", time+1, v5d->VarName[var] );

         /* Get the resampled data for this timestep and variable */
         data = get_combined_resampled_data( db, table_time, table_var,
                                 output_proj, var_vcs[var], v5d->Nl[var],
                                 average );
         if (data) {
            v5dWriteGrid( v5d, time, var, data );
            FREE( data, 9 );
         }
         else {
            printf("WARNING: writing missing field for: time=%d var=%d\n", time, var );
            write_missing_grid( v5d, time, var, v5d->Nr, v5d->Nc,v5d->Nl[var]);
         }
      }
   }

   v5dCloseFile( v5d );

   free_resamplers();

   /* free new projection and VCSs made during resampling */
   for (i=db->NumProj-1; i>=numproj; i--) {
      free_projection( db, db->ProjList[i] );
   }
   for (i=db->NumVcs-1; i>=numvcs; i--) {
      free_vcs( db, db->VcsList[i] );
   }
}



/***************************************************************************/
/* New 5.0 stuff ***********************************************************/
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/





int make_output_ctx( struct grid_db *db, v5dstruct *v5d, char *filename, char *ctxname,
                       int maxnl, int average, int compressmode, int mbs, int mf, int mc )
{
   int time, var;
   int xlate_time[MAXTIMES], xlate_var[MAXVARS];
   int nl[IMAXVARS], lowlev[IMAXVARS];
   struct projection *output_proj;
   struct vcs *output_vcs, *var_vcs[MAXVARS];
   int numproj, numvcs;
   int i, yo;

#if V5D_VERSION >=42 
   printf("Writing a 4.3 file!\n");
#endif

   /* Save current number of projections and VCSs */
   numproj = db->NumProj;
   numvcs = db->NumVcs;

   /*
    * Finish initializing the v5d struct
    */

   /* Output file's projection and VCS */
   output_proj = new_projection( db, v5d->Projection, v5d->Nr, v5d->Nc,
                                 v5d->ProjArgs );
   output_vcs = new_vcs( db, v5d->VerticalSystem, maxnl, 0, v5d->VertArgs );

   /* Grid levels */
   compute_grid_levels( db, output_vcs, lowlev, nl );
   for (i=0;i<db->NumVars;i++) {
      /* truncate number of levels to fit user specified limit */
      if (lowlev[i]+nl[i]>maxnl) {
         if (nl[i]>maxnl) {
            lowlev[i] = 0;
            nl[i] = maxnl;
         }
         else {
            lowlev[i] = maxnl - nl[i];
         }
      }
   }


   /* Setup variables */
   v5d->NumVars = 0;
   for (var=0;var<db->NumVars;var++) {
      if (db->VarSelected[var]) {
         if (v5d->NumVars<MAXVARS) {
            strncpy( v5d->VarName[v5d->NumVars], db->VarNames[var], 10 );
            if (db->Units[var]) {
               strncpy( v5d->Units[v5d->NumVars], db->Units[var], 19 );
               v5d->Units[v5d->NumVars][19] = 0;
            }
            xlate_var[v5d->NumVars] = var;

            v5d->Nl[v5d->NumVars] = nl[var];
#if V5D_VERSION >= 42
            v5d->LowLev[v5d->NumVars] = lowlev[var];
#else
            /* sanity check */
            assert( lowlev[var] == 0 );
#endif
            v5d->NumVars++;
         }
         else {
            printf("Warning: too many variables, %d is limit,", MAXVARS );
            printf(" ignoring %s\n", db->VarNames[var] );
         }
      }
   }

   /* Setup timesteps */
   v5d->NumTimes = 0;
   for (time=0;time<db->NumTimes;time++) {
      if (db->TimeSelected[time]) {
         if (v5d->NumTimes<MAXTIMES) {
            v5d->DateStamp[v5d->NumTimes] = db->DateStamp[time];
            v5d->TimeStamp[v5d->NumTimes] = db->TimeStamp[time];
            xlate_time[v5d->NumTimes] = time;
            v5d->NumTimes++;
         }
         else {
            printf("Warning: too many time steps, %d is limit,", MAXTIMES);
            printf(" ignoring %05d %06d\n", db->DateStamp[time],
                   db->TimeStamp[time] );
         }
      }
   }


   /* actually need a different VCS for each variable */
   for (var=0;var<v5d->NumVars;var++) {
      var_vcs[var] = new_vcs( db, v5d->VerticalSystem, v5d->Nl[var],
#if V5D_VERSION >= 42
                                 v5d->LowLev[var],
#else
                                 0,
#endif
                                 v5d->VertArgs );
   }

   v5d->CompressMode = compressmode;


   if (mf == 1 && mc == 0){
      if (!v5dCreateFile( filename, v5d )) {
         printf("Error in v5dCreateFile\n");
         return -1;
      }
      /*
       * Write grid data
       */
      for (time=0;time<v5d->NumTimes;time++) {
         for (var=0;var<v5d->NumVars;var++) {
            int table_time, table_var;
            float *data;

            /* Translate timestep and variable number from v5d struct indexes */
            /* into grid table indexes. */
            table_time = xlate_time[time];
            table_var = xlate_var[var];

            printf("Time: %d  Var: %s\n", time+1, v5d->VarName[var] );

            /* Get the resampled data for this timestep and variable */
            data = get_combined_resampled_data( db, table_time, table_var,
                                    output_proj, var_vcs[var], v5d->Nl[var],
                                    average );
            if (data) {
               v5dWriteGrid( v5d, time, var, data );
               FREE( data, 9 );
            }
            else {
               if (Debug_i)  printf("missing: %d %d\n", time, var );
               write_missing_grid( v5d, time, var, v5d->Nr, v5d->Nc,v5d->Nl[var]);
            }
         }
      }
      v5dCloseFile( v5d );
      free_resamplers();

      /* free new projection and VCSs made during resampling */
      for (i=db->NumProj-1; i>=numproj; i--) {
         free_projection( db, db->ProjList[i] );
      }
      for (i=db->NumVcs-1; i>=numvcs; i--) {
         free_vcs( db, db->VcsList[i] );
      }
      return 1;
   }

  
   if (mf == 1 && mc == 1){
      int yes;
      if (!v5dCreateFile( filename, v5d )) {
         printf("Error in v5dCreateFile\n");
         return -1;
      }
      /*
       * Write grid data
       */
      for (time=0;time<v5d->NumTimes;time++) {
         for (var=0;var<v5d->NumVars;var++) {
            int table_time, table_var;
            float *data;

            /* Translate timestep and variable number from v5d struct indexes */
            /* into grid table indexes. */
            table_time = xlate_time[time];
            table_var = xlate_var[var];

            printf("Time: %d  Var: %s\n", time+1, v5d->VarName[var] );


            /* Get the resampled data for this timestep and variable */
            data = get_combined_resampled_data( db, table_time, table_var,
                                    output_proj, var_vcs[var], v5d->Nl[var],
                                    average );
            if (data) {
               v5dWriteGrid( v5d, time, var, data );
               FREE( data, 9 );
            }
            else {
               if (Debug_i)  printf("missing: %d %d\n", time, var );
               write_missing_grid( v5d, time, var, v5d->Nr, v5d->Nc,v5d->Nl[var]);
            }
         }
      }
      v5dCloseFile( v5d );
      free_resamplers();

      /* free new projection and VCSs made during resampling */
      for (i=db->NumProj-1; i>=numproj; i--) {
         free_projection( db, db->ProjList[i] );
      }
      for (i=db->NumVcs-1; i>=numvcs; i--) {
         free_vcs( db, db->VcsList[i] );
      }
      yes = vis5d_load_v5dfile( 0, mbs, filename, ctxname);

      return yes;
   }



   
   if (mf == 0 && mc == 1){

      return 0;
/* TODO LATER!!!!! 
      filename[0] = 0;
      yo = vis5d_load_v5dfile(0,  v5d, mbs, filename, ctxname); */
      if ( yo <= 0 ){
         printf("not enough memory please give a file name to write to \n");
/*

         strcpy( message, " not enough memory, please give a file name to write to. ");
         show_error_widget( 0, message);
*/         return 0;
      }
   

      /*
       * Write grid data to a ctx
       */
      for (time=0;time<v5d->NumTimes;time++) {
         for (var=0;var<v5d->NumVars;var++) {
            int table_time, table_var;
            float *data;

            /* Translate timestep and variable number from v5d struct indexes */
            /* into grid table indexes. */
            table_time = xlate_time[time];
            table_var = xlate_var[var];

             printf("Time: %d  Var: %s\n", time+1, v5d->VarName[var] );

            /* Get the resampled data for this timestep and variable */
            data = get_combined_resampled_data( db, table_time, table_var,
                                    output_proj, var_vcs[var], v5d->Nl[var],
                                    average );
            if (data) {
               /*vis5d_insert_grid_into_ctx( 1, time, var, data); */
               FREE( data, 9 );
            }
            else {
/***************** TO DO STUFF ***********************************/
               if (Debug_i)  printf("missing: %d %d\n", time, var );
               write_missing_grid( v5d, time, var, v5d->Nr, v5d->Nc,v5d->Nl[var]);
            }
         }
      }


      free_resamplers();

      /* free new projection and VCSs made during resampling */
      for (i=db->NumProj-1; i>=numproj; i--) {
         free_projection( db, db->ProjList[i] );
      }
      for (i=db->NumVcs-1; i>=numvcs; i--) {
         free_vcs( db, db->VcsList[i] );
      }
      return 1;
   }
/*   strcpy(message, "you must give a file name and/or a context name please");
   show_error_widget( 0, message);
*/ printf("it dosn't work\n");

   return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1