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


/*
 * Functions for reading UW NMS model VIS files.
 */


#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "binio.h"
#include "file_i.h"
#include "grid_i.h"
#include "misc_i.h"
#include "proj_i.h"
#include "projlist_i.h"
#include "v5d.h"




/**********************************************************************/
/*****                      VIS file I/O                          *****/
/**********************************************************************/


static char vcscr[64] = {
                '0','1','2','3','4','5','6','7','8','9'
               ,'A','B','C','D','E','F','G','H','I','J'
               ,'K','L','M','N','O','P','Q','R','S','T'
               ,'U','V','W','X','Y','Z','a','b','c','d'
               ,'e','f','g','h','i','j','k','l','m','n'
               ,'o','p','q','r','s','t','u','v','w','x'
               ,'y','z','{','|'
};

static char inv_vcscr[256];


static void init_visreader( void )
{
   int i;

   /* init inv_vcscr array */
   for (i=0;i<64;i++) {
      inv_vcscr[ (int) vcscr[i] ] = i;
   }
}



static int *read_int_block( FILE *f, int *len )
{
   int words, bits, ch, val, i, j, k, count, bytes;
   float a, b;
   char line[80];
   int *buffer;

   /* read number of words, addfac, multfac */
   fscanf( f, "%d %d %f %f", &words, &bits, &a, &b);
   fgetc( f );  /* skip \n */

   buffer = (int *) malloc( words * sizeof(int) );
   bytes = (bits+5) / 6;

   count = 0;
   while (count<words) {

      /* read a line */
      fgets( line, 80, f );

      /* convert line of chars to integers */
      for (i=k=0;i<78/bytes && count<words;i++) {
         for (j=val=0;j<bytes;j++) {
            ch = inv_vcscr[(int) line[k++]];
            val = (val << 6) | ch;
         }
/*         buffer[count++] = val * (int) b + (int) a;*/
         buffer[count++] = val * (int) b - (int) a;
      }

   }

   *len = words;
   return buffer;
}




static float *read_float_block( FILE *f, int *len )
{
   int words, bits, ch, val, i, j, k, count, bytes;
   float a, b;
   char line[80];
   float *buffer;

   /* read number of words, bits, addfac, multfac */
   fscanf( f, "%d %d %f %f", &words, &bits, &a, &b);
   fgetc( f );  /* skip \n */

   buffer = (float *) malloc( words * sizeof(float) );
   bytes = (bits+5) / 6;

   count = 0;
   while (count<words) {

      /* read a line */
      fgets( line, 80, f );

      /* convert line of chars to floats */
      for (i=k=0;i<78/bytes && count<words;i++) {
         for (j=val=0;j<bytes;j++) {
            ch = inv_vcscr[(int) line[k++]];
            val = (val << 6) | ch;
         }
         buffer[count++] = (float) val / b - a;
      }

   }

   *len = words;
   return buffer;
}



static void skip_float_block( FILE *f )
{
   int words, bits, i, count, bytes;
   float a, b;
   char line[80];

   /* read number of words, bits, addfac, multfac */
   fscanf( f, "%d %d %f %f", &words, &bits, &a, &b);
   fgetc( f );  /* skip \n */

   bytes = (bits+5) / 6;

   count = 0;
   while (count<words) {

      /* read a line */
      fgets( line, 80, f );

      /* convert line of chars to floats */
      for (i=0;i<78/bytes && count<words;i++) {
         count++;
      }

   }

}




/**********************************************************************/
/**********************************************************************/


/*
 * Scan the named file, createing a grid_info struct for each grid.  Store
 * the grid_info structs in the grid data base.
 * Input:  name - name of UW VIS file.
 *         db - the grid data base
 * Return:  number of grids found.
 */
int get_uwvis_info( char *name, struct grid_db *db )
{
   static int init_flag = 0;
   FILE *f;
   int grids = 0;
   int var, numvars, nr, nc, nl;
   float height[MAXLEVELS];
   char ch;
   int i, vcs;

   if (init_flag==0) {
      init_visreader();
      init_flag = 1;
   }


   /* Open the file */
   f = fopen( name, "r" );
   if (!f) {
      return 0;
   }

   fscanf( f, "%d", &numvars );
   if (numvars>MAXVARS) {
      printf("ERROR: %s contains too many variables, limit is %d\n",
             name, MAXVARS );
   }

   /* grid size */
   fscanf( f, "%d", &nc );
   fscanf( f, "%d", &nr );
   fscanf( f, "%d", &nl );
   (void) getc(f);  /* get '\n' */

   /* this is tricky:
    * We look at the next character:
    * if it's a letter then
    *     we read the variable name and extract the height info from header
    * else
    *     read the height values for each grid level (variable delta Z).
    * endif
    */
   ch = getc(f);
   ungetc(ch, f);

   if (isalpha(ch)) {
      vcs = 1;
   }
   else {
      /* Read the height (in meters) of each grid level */
      for (i=0;i<nl;i++) {
         fscanf( f, "%8f", &height[i] );
         height[i] /= 1000.0;    /* convert from meters to km */
      }
      (void) getc(f);  /* get '\n' */
      vcs = 2;
   }


   for (var=0;var<numvars;var++) {
      int *header, header_size;
      char varname[100];
      struct grid_info *info;
      float args[100];

      /* read variable name */
      fgets( varname, 40, f );
      for (i=7;i>=0 && varname[i]==' ';i--) {
         varname[i] = '\0';
      }
      varname[8] = 0;

      /* read data header */
      header = read_int_block( f, &header_size );


      /*
       * Allocate grid info struct and initialize it.
       */
      info = alloc_grid_info();

      info->FileName = strdup( name );
      info->Format = FILE_UWVIS;
      info->Position = ftell(f);    /* save position of data in file */

      info->Nr = nr;
      info->Nc = nc;
      info->Nl = nl;

      info->DateStamp = header[5];
      info->TimeStamp = header[6];
      info->VarName = strdup( varname );

      args[0] = (float) header[22] / 10000.0;
      args[1] = (float) header[23] / 10000.0;
      args[2] = (float) header[24] / 10000.0;
      args[3] = (float) header[25] / 10000.0;
      info->Proj = new_projection( db, PROJ_LINEAR, nr, nc, args );

      if (vcs==1) {
         /* equally spaced km */
         float tophgt = (float) header[31] / 1000.0;
         float hgtinc = (float) header[32] / 1000.0;
         args[0] = tophgt - hgtinc*(nl-1);
         args[1] = hgtinc;
      }
      else {
         /* vcs==2 */
         /* unequally spaced km */
         memcpy( args, height, sizeof(float)*nl );
      }
      info->Vcs = new_vcs( db, vcs, nl, 0, args );

      /*
       * done with this grid
       */
      append_grid( info, db );
      grids++;

      free( header );

#ifdef LEAVEOUT
      {
         float *data;
         int data_size;
         /* read and skip data */
         data = read_float_block( f, &data_size );
         free( data );
      }
#else
      skip_float_block( f );
#endif
   }

   fclose(f);

   return grids;
}




/*
 * Get the grid data described by g.
 * Input:  g - pointer to a grid_info structure.  It tells us which grid
 *             in which file is needed.
 * Return:  pointer to grid data (can be free()'d when finished)
 *          OR return NULL if there's an error.
 */
float *get_uwvis_data( struct grid_info *g )
{
   float *data;
   int count;
   FILE *f;

   /* open file, seek to grid position */
   f = fopen( g->FileName, "r" );
   if (!f) return NULL;

   fseek( f, g->Position, SEEK_SET );

   data = read_float_block( f, &count );

   fclose(f);

   return data;
}



syntax highlighted by Code2HTML, v. 0.9.1