/* comp_to_v5d.c */

/* Convert old COMP file to new .v5d file */

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <binio.h>
#include <v5d.h>



/*
 * Global vars describing the file header.
 */
static int NumTimes, NumVars;
static int Nr, Nc, Nl, nl[MAXVARS];
static float NorthLat[MAXTIMES];
static float WestLon[MAXTIMES];
static float LatInc, LonInc;
static char VarName[MAXVARS][10];
static float MinVal[MAXVARS], MaxVal[MAXVARS];
static float Bottom, HgtInc;
static int DateStamp[MAXTIMES], TimeStamp[MAXTIMES];
static int projection;
static float proj_args[4];
static int vertical;
static float vert_args[2];


#if SIZEOF_SIGNED_CHAR == 1
  typedef signed char  int_1;
#else
/*  defined(stellar) || defined(hp) || defined(sun) */
  typedef char         int_1;     /* 1-byte signed integer */
#endif


/*
 * Read the header info in the COMP* file and put into global vars.
 */
static int read_comp_header( int f )
{
   int id, gridtimes, gridvars, i, j, ip;

   /* read id */
   read_int4( f, &id );

   if (id==0x80808080 || id==0x80808081) {
      float top;

      if (id==0x80808080) {
         gridtimes = 300;
         gridvars = 20;
      }
      else {
         gridtimes = 400;
         gridvars = 30;
      }

      read_int4( f, &NumTimes );
      read_int4( f, &NumVars );
      read_int4( f, &Nr );
      read_int4( f, &Nc );
      read_int4( f, &Nl );

      read_float4( f, &NorthLat[0] );
      read_float4( f, &WestLon[0] );
      read_float4( f, &top );
      read_float4( f, &LatInc );
      read_float4( f, &LonInc );
      read_float4( f, &HgtInc );
      Bottom = top - HgtInc * (Nl-1);
      for (i=1;i<NumTimes;i++) {
         NorthLat[i] = NorthLat[0];
         WestLon[i] = WestLon[0];
      }

      /* read dates and times */
      read_int4_array( f, DateStamp, gridtimes );
      read_int4_array( f, TimeStamp, gridtimes );

      /* read parm names */
      for (i=0;i<gridvars;i++) {
         if ( read_bytes(f, VarName[i], 4)!=4 ) {
            printf("Error:  Unable to read parameter names.\n");
            return 0;
         }
         /* remove trailing spaces, if any */
         for (j=7;j>0;j--) {
            if (VarName[i][j]==' ' || VarName[i][j]==0)
              VarName[i][j] = 0;
            else
              break;
         }
      }
   }
   else if (id==0x80808082 || id==0x80808083) {
      float height[MAXLEVELS];

      read_int4( f, &gridtimes );

      read_int4( f, &NumVars );
      read_int4( f, &NumTimes );
      read_int4( f, &Nr );
      read_int4( f, &Nc );
      read_int4( f, &Nl );
      read_float4( f, &LatInc );
      read_float4( f, &LonInc );

      read_float4_array( f, height, Nl );
      Bottom = height[0];
      HgtInc = (height[Nl-1] - height[0]) / (Nl-1);

      for (ip=0;ip<NumVars;ip++) {
         if ( read_bytes(f, VarName[ip], 8)!=8 ) {
            printf("Error:  Unable to read parameter names.\n");
            return 0;
         }
         /* remove trailing spaces, if any */
         for (j=7;j>0;j--) {
            if (VarName[ip][j]==' ' || VarName[ip][j]==0)
              VarName[ip][j] = 0;
            else
              break;
         }
      }

      read_float4_array( f, MinVal, NumVars );
      read_float4_array( f, MaxVal, NumVars );
      read_int4_array( f, TimeStamp, gridtimes );
      read_int4_array( f, DateStamp, gridtimes );
      read_float4_array( f, NorthLat, gridtimes );
      read_float4_array( f, WestLon, gridtimes );
   }

   for (i=0;i<NumTimes;i++) {
      TimeStamp[i] = v5dSecondsToHHMMSS( TimeStamp[i] );
      DateStamp[i] = v5dDaysToYYDDD( DateStamp[i] );
   }
   return id;
}



/*
 * Read the next 3-D grid from the file.
 */
static int read_grid( int f, int id, float data[] )
{
   int compsize = ((Nr*Nc*Nl+3)/4)*4;
   float ga[MAXLEVELS], gb[MAXLEVELS];
   int_1 compdata[MAXROWS*MAXCOLUMNS*MAXLEVELS];
   int p, lev, i;
   float min, max;
   int missing_count;

   if (id==0x80808080 || id==0x80808081) {
      read_float4( f, &ga[0] );
      read_float4( f, &gb[0] );
      for (i=1;i<Nl;i++) {
         ga[i] = ga[0];
         gb[i] = gb[0];
      }
   }
   else if (id==0x80808082 || id==0x80808083) {
      int mcfile, mcgrid;
      if (id==0x80808083) {
         read_int4( f, &mcfile );
         read_int4( f, &mcgrid );
      }
      read_float4_array( f, ga, Nl );
      read_float4_array( f, gb, Nl );
   }

   if (read_bytes( f, compdata, compsize )!=compsize) {
      printf("read_bytes failed\n");
   }

   min = 10000.0;
   max = -min;
   missing_count = 0;

   /* decompress */
   p = 0;
   for (lev=0;lev<Nl;lev++) {
      float ga_inv = 1.0 / ga[lev];
      float gb_val = gb[lev];
      for (i=0;i<Nr*Nc;i++) {
         if (compdata[p] == 127) {
            data[p] = MISSING;
            missing_count++;
         }
         else {
            data[p] = ( (float) (int) compdata[p] - gb_val ) * ga_inv;
            if (data[p]>max)
               max = data[p];
            if (data[p]<min)
               min = data[p];
         }
         p++;
      }
   }

   printf("min=%g max=%g missing=%d\n", min, max, missing_count );
   return 1;
}




int main( int argc, char *argv[] )
{
   int infile;
   int id;
   int compressmode, i;

   if (argc==1) {
      printf("Usage:\n");
      printf("   comp_to_v5d compfile outfile.v5d\n");
      printf("Options:\n");
      printf("   -compress N\n");
      printf("      Specifies compress to N bytes per grid point where\n");
      printf("      N = 1, 2 or 4.\n");
      exit(0);
   }

   compressmode = 1; /* default */

   for (i=2;i<argc;i++) {
      if (strcmp(argv[i],"-compress")==0 && i+1<argc) {
         compressmode = atoi( argv[i+1] );
         i++;
      }
   }

   infile = open( argv[1], O_RDONLY );
   if (infile<0) {
      printf("Error:  couldn't open %s for reading\n", argv[1] );
      exit(0);
   }

   id = read_comp_header( infile );
   if (id) {
      for (i=0; i<NumVars; i++) nl[i] = Nl;
      projection = 1;
      proj_args[0] = NorthLat[0];
      proj_args[1] = WestLon[0];
      proj_args[2] = LatInc;
      proj_args[3] = LonInc;
      vertical = 1;
      vert_args[0] = Bottom;
      vert_args[1] = HgtInc;
      if (v5dCreate( argv[2], NumTimes, NumVars, Nr, Nc, nl,
                     (const char (*)[10]) VarName, TimeStamp, DateStamp,
                     compressmode,
                     projection, proj_args, vertical, vert_args)) {
/*
      if (v5dCreateSimple( argv[2], NumTimes, NumVars, Nr, Nc, Nl,
                           VarName, TimeStamp, DateStamp,
                           NorthLat[0], LatInc,
                           WestLon[0], LonInc,
                           Bottom, HgtInc )) {
*/

         int time, var;
         float *data;

         data = (float *) malloc( Nr * Nc * Nl * sizeof(float) );

         /* Read each 3-D grid, decompress it and write to output file */
         for (time=0;time<NumTimes;time++) {
            for (var=0;var<NumVars;var++) {
               read_grid( infile, id, data );

               v5dWrite( time+1, var+1, data );
            }
         }

         v5dClose();
      }
      else {
         printf("Error:  couldn't create output file: %s\n", argv[2] );
      }
   }

   return 0;
}



syntax highlighted by Code2HTML, v. 0.9.1