#define TIMEZONE_HOUR_OFFSET 0  /* # hours difference between PC time & GMT */
/******************************************************************************

>>>>>>>>>>>>>>> This is a CORRUPTED (truncated) file from
Charlie Flagg's people at BNL.  It shows how some useful
additions were made, so it can be used to modify ping2mat.
I think it was done prior to my Y2K modifications, however,
so beware its extra line adding 1900.
<<<<<<<<<<<<<<<<<<<<<<<


   FILE:   ping2mat.c
   USAGE:  ping2mat <str1> <str2> <str3> <str4> [str5]

           This program is used to retrieve velocity, percent good,
           amplitude, and navigation data for profiles falling within
           the user-specified time range, from a ping binary data file
           into Matlab .mat files.

           The command-line arguments specify the following:

           <str1> = input (ping binary data) file name

           <str2> = min time of time range (yy/mm/dd-hh:mm:ss)
                    or 'E' flag; if 'E' flag, then program will
                    retrieve data for profiles from <str3> hours
                    prior to current time upto the current time

           <str3> = max time of time range (yy/mm/dd-hh:mm:ss)
                    or, if <str2> = 'E', the no. of hours prior to
                    current time to start retrieving from

           <str4> = root of output .mat file name
                    (# of chars. must be <= MAX_DBNAME_LENGTH, see dbext.h)
                    plus optional path specification

           [str5] = an optional string specifying which variables will
                    be selectively retrieved:
                        U = U velocity
                        V = V velocity
                        W = W velocity
                        E = E velocity
                        P = percent good
                        A = amplitude
                        N = navigation
                        B = bottom_track
                        C = configuration1
                    For example, to retrieve U, V, and A data only, one must
                    type UVA (all uppercase).  If this argument is not provided,
                    all 9 variables will be retrieved.

           The program will create a .mat file for each variable retrieved,
           with filename starting with the user-specified root <str4> followed
           by 'u', 'v', 'w', 'e', 'amp', 'pg', 'nav', 'bot', or 'conf1' depending on which variable
           it contains.  It also creates one more .mat file with filename
           starting with the root followed by the keyword 'time'.  It contains
           the time of each profile found within the time range, expressed as a
           double count of the number of days from 01 January 00:00:00 of the
           year in the minimum time specification.

   EXAMPLES:

           ping2mat pingdata.001 87/9/28-6:28:0 87/9/28-6:48:0 out UVN

              retrieves U, V, navigation, and time data from pingdata.001
              for the time range 6:28 to 6:48 of 87/9/28 into the Matlab
              files outu.mat, outv.mat, and outtime.mat.

           ping2mat pingdata.000 E 2.5 ext

              retrieves U, V, W, E, amplitude, percent good, navigation, and
              time data from pingdata.000 from 2-1/2 hours before the current
              system time upto the current system time, into the Matlab files
              extu.mat, extv.mat, extw.mat, extamp.mat, extpg.mat, extnav.mat,
              and exttime.mat.
------------------------------------------------------------------------------

                             Willa Zhu
                              88/04/21
   88/05/24 - WZ - updated to include navigation data
   89/05/24 - WZ - updated for CODAS3 linking
   89/09/05 - JR - removed path of adcp.h because of
                   reorganization of subdirectories
   90/06/29 - JR - replaced <stdlib.h> with "common.h"
   91/05/15 - WZ - changed variable names of NAVIGATION_TYPE to
                   coincide with that in adcp.h
                 - modified the program so that it can handle the
                   case when profiles with different bin numbers
                   within a time range user specified.
   91/09/05 - JR - modified to remove restriction on no. of profiles
                   that could be retrieved at a time (because of unsigned
                   int arg to calloc())
   93/08/12 - JR - modified to also retrieve E (error velocity) on user request

   98/11/24 - YS & CNF - modified to retrieve bin_length, pls_length, blank_length,
                         num_bins, & tr_depth from the pingdata file.
   98/12/14 - YS - modified to retrieve bottom_track data.
   99/03/26 - YS - modified to retrieve tr_temp data.
******************************************************************************/

#include "common.h"
#include <time.h>     /* UNIX time functions, variables & structures   */
#include "dbhost.h"   /* PROTOTYPE_ALLOWED */
#include "dbext.h"    /* YMDHMS_TIME_TYPE, SHORT, ... */
#include "misc.h"     /* split_path() */
#include "time_.h"    /* TIMCMP(), DIFTIM() */
#include "use_db.h"   /* write_ymdhms_time() */
#include "ioserv.h"   /* check_error(), check_fopen() */
#include "matfile.h"  /* savemat(), MAT_ARRAY_FP_TYPE, etc. */
#define FIRST_DEC
#include "readping.h"  /* declaration of global variables, structures,  */

#define U_VEL 0  /* used also as array indices so sequential */
#define V_VEL 1
#define W_VEL 2
#define E_VEL 3
#define PGOOD 4
#define AMP   5
#define NAV   6
#define BOT   7
#define CONF1 8
#define PTIME 9

#define fp_u    fptr[U_VEL]
#define fp_v    fptr[V_VEL]
#define fp_w    fptr[W_VEL]
#define fp_e    fptr[E_VEL]
#define fp_pg   fptr[PGOOD]
#define fp_amp  fptr[AMP]
#define fp_nav  fptr[NAV]
#define fp_bot  fptr[BOT]
#define fp_conf1 fptr[CONF1]
#define fp_time fptr[PTIME]

typedef struct
{
   YMDHMS_TIME_TYPE min, max;
} TIMERANGE_TYPE;

typedef struct
{
   double bin_length;
   double pls_length;
   double blnk_length;
   double num_bins;
   double tr_depth;
   double tr_temp;
} TEMP_CONF1_TYPE;

TEMP_CONF1_TYPE temp_conf1;

static union
{
   long longs[2];
   double d;
} NaN;


/* ---------------------  functions ------------------ */

#if PROTOTYPE_ALLOWED
void load_data(FILE *fp_tmp, FILE *fptr[], MAT_ARRAY_FP_TYPE *nav_mat_ptr,
                MAT_ARRAY_FP_TYPE *bot_mat_ptr, MAT_ARRAY_FP_TYPE *conf1_mat_ptr);
void copy_temp_to_matfile(FILE *fptr[], FILE *fp_tmp, int max_bin);
void open_files(FILE *fptr[], char *variables, char *root);
void print_usage(void);
void save_time(FILE *fpmat, TIMERANGE_TYPE t, YMDHMS_TIME_TYPE now);
YMDHMS_TIME_TYPE time_stamp(void);
TIMERANGE_TYPE scan_timerange(char *smin, char *smax, YMDHMS_TIME_TYPE now);
#else
void load_data();
void copy_temp_to_matfile();
void open_files();
void print_usage();
void save_time();
YMDHMS_TIME_TYPE time_stamp();
TIMERANGE_TYPE scan_timerange();
#endif

/*-------------------   MAIN  ---------------------*/

#if PROTOTYPE_ALLOWED
void main(int argc, char *argv[])
#else
void main(argc, argv)
int argc;
char *argv[];
#endif
{
   int i, nprof = 0, max_bin = 0, end_flag = 0;
   double offset;
   FILE_NAME_TYPE path, fname, root;
   YMDHMS_TIME_TYPE now;
   static FILE *fp_tmp, *fptr[10] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
   TIMERANGE_TYPE time_range;
   static char variables[10] = "UVWPANEBC";
   MAT_ARRAY_FP_TYPE *time_mat_ptr, *nav_mat_ptr, *bot_mat_ptr, *conf1_mat_ptr;

   NaN.longs[0] = NaN_d_0;
   NaN.longs[1] = NaN_d_1;
   now = time_stamp();

   /*---------------------- process args -------------------------------------*/
   if (argc < 5 || argc > 6) print_usage();

   fpb = check_fopen(argv[1], "rb");
   time_range = scan_timerange(argv[2], argv[3], now);

   printf("\n  time range:  ");
   write_ymdhms_time(stdout, &(time_range.min));
   printf(" to ");
   write_ymdhms_time(stdout, &(time_range.max));

   split_path(argv[4], path, fname); /* truncate root to MAX_DBNAME_LENGTH char */
   strcpy(root, path);
   strcat(root, fname);

   if (argc == 6) strcpy(variables, argv[5]);           /* selective retrieval */
   open_files(fptr, variables, root);
   fp_tmp = check_fopen("uvwepa.tmp", "w+b");
   for (i = U_VEL; i <= PTIME; i++)
      if (fptr[i]) save_time(fptr[i], time_range, now);
   time_mat_ptr = start_mat_array(fp_time, 'd', "time", 'c', 1);
   if (fp_nav)
      nav_mat_ptr  = start_mat_array(fp_nav , 'd', "nav" , 'c', 2);
   if (fp_bot)
      bot_mat_ptr  = start_mat_array(fp_bot , 'f', "bot" , 'c', 3);
   if (fp_conf1)
      conf1_mat_ptr  = start_mat_array(fp_conf1 , 'd', "conf1" , 'c', 6);

   /*---------------------- read from ping file ------------------------------*/
   initial();
   while ( (file_status = read_record(fpb)) > 0 && !end_flag )
   {
      header_check();
      if (hdr_flag)
      {
         if (file_note_flag) free(file_notes);
         hdr_flag = 0;
         get_hdr_block();
         temp_conf1.bin_length = conf1.bin_length;
         temp_conf1.pls_length = conf1.pls_length;
         temp_conf1.blnk_length = conf1.blank_length;
         temp_conf1.num_bins = (float)conf1.num_bins;
         temp_conf1.tr_depth = conf1.tr_depth;
       }
      else
      {
         if (data_flag)
         {
            get_data_block();
            if (!bad_data_flag)
            {
               prof_time.year += 1900;
               if (TIMCMP(&time_range.min, &prof_time) <= 1)
               {
                  if (TIMCMP(&prof_time, &time_range.max) <= 1)
                  {
                     offset = year_day(&prof_time, time_range.min.year);
                     add_to_mat_array(time_mat_ptr, (char *) &offset);
                     temp_conf1.tr_temp = temp_offset-(temp_scale*ancil1.tr_temp)/4096;
                     load_data(fp_tmp, fptr, nav_mat_ptr, bot_mat_ptr, conf1_mat_ptr);
                     nprof++;
                     if (max_bin < conf1.num_bins) max_bin = conf1.num_bins;
                  }
                  else end_flag = 1;
               }
            }
            else
               printf("\n  WARNING: bad data found in HDR %d PRF %d\n",
                  nhdr_block, nprof_in_hdr);
         }
         data_flag = 0;
         if (user_buffer_flag) free(user_buffer_block);
      }

      start_blk = 0;
      bad_data_flag = 0;
   }

   if (file_status == 0) printf("\n  end of file %s\n", bname);
   else if (!end_flag) printf("\n  file read error\n");

   fclose(fpb);

   /*---------------------- create mat files ---------------------------------*/
   if (nprof > 0)
   {
      copy_temp_to_matfile(fptr, fp_tmp, max_bin);
      end_mat_array(time_mat_ptr);
      if (fp_nav)
         end_mat_array(nav_mat_ptr);
      if (fp_bot)
         end_mat_array(bot_mat_ptr);
      if (fp_conf1)
         end_mat_array(conf1_mat_ptr);
      printf("\n  %d profiles retrieved, max no. of bins = %d.\n", nprof, max_bin);
   }
   else
   {
      printf("\n  No data found within given time range.\n");
   }
   remove("uvwepa.tmp");
}

#if PROTOTYPE_ALLOWED
void load_data(FILE *fp_tmp, FILE *fptr[], MAT_ARRAY_FP_TYPE *nav_mat_ptr,
               MAT_ARRAY_FP_TYPE *bot_mat_ptr, MAT_ARRAY_FP_TYPE *conf1_mat_ptr)
#else
void load_data(fp_tmp, fptr, nav_mat_ptr, bot_mat_ptr, conf1_mat_ptr)
FILE *fp_tmp, *fptr[];
MAT_ARRAY_FP_TYPE *nav_mat_ptr, *bot_mat_ptr, *conf1_mat_ptr;
#endif
{
   if (record_velx && fp_u)
   {
      fputc(U_VEL, fp_tmp);
      fwrite(&conf1.num_bins, sizeof(SHORT), 1, fp_tmp);
      fwrite(u, sizeof(SHORT), conf1.num_bins, fp_tmp);
   }

   if (record_vely && fp_v)
   {
      fputc(V_VEL, fp_tmp);
      fwrite(&conf1.num_bins, sizeof(SHORT), 1, fp_tmp);
      fwrite(v, sizeof(SHORT), conf1.num_bins, fp_tmp);
   }

   if (record_velz && fp_w)
   {
      fputc(W_VEL, fp_tmp);
      fwrite(&conf1.num_bins, sizeof(SHORT), 1, fp_tmp);
      fwrite(w, sizeof(SHORT), conf1.num_bins, fp_tmp);
   }

   if (record_error && fp_e)
   {
      fputc(E_VEL, fp_tmp);
      fwrite(&conf1.num_bins, sizeof(SHORT), 1, fp_tmp);
      fwrite(e, sizeof(SHORT), conf1.num_bins, fp_tmp);
   }

   if (perc_good_flag && fp_pg)
   {
      fputc(PGOOD, fp_tmp);
      fwrite(&conf1.num_bins, sizeof(SHORT), 1, fp_tmp);
      fwrite(pg, sizeof(UBYTE), conf1.num_bins, fp_tmp);
   }

   if (amplitude_flag && fp_amp)
   {
      fputc(AMP, fp_tmp);
      fwrite(&conf1.num_bins, sizeof(SHORT), 1, fp_tmp);
      fwrite(amp, sizeof(UBYTE), conf1.num_bins, fp_tmp);
   }

   if (bottom_track_flag && fp_nav)
      add_to_mat_array(nav_mat_ptr, (char *) &navigation);
      add_to_mat_array(bot_mat_ptr, (char *) &bottom_track);

   add_to_mat_array(conf1_mat_ptr, (char *) &temp_conf1);
}

#if PROTOTYPE_ALLOWED
void copy_temp_to_matfile(FILE *fptr[], FILE *fp_tmp, int max_bin)
#else
void copy_temp_to_matfile(fptr, fp_tmp, max_bin)
FILE *fptr[], *fp_tmp;
int  max_bin;
#endif
{
   int var, i;
   SHORT *short_buff, nbin;
   UBYTE *ubyte_buff;
   DOUBLE *double_buff;
   MAT_ARRAY_FP_TYPE *mat_ptr[6];

   check_error( (
      (short_buff = (SHORT *) calloc(max_bin, sizeof(SHORT))) == NULL ||
      (ubyte_buff = (UBYTE *) calloc(max_bin, sizeof(UBYTE))) == NULL ||
      (double_buff = (DOUBLE *) calloc(max_bin, sizeof(DOUBLE))) == NULL),
      "insufficient memory" );

   if (fp_u) mat_ptr[U_VEL]  = start_mat_array(fp_u  , 'd', "u"  , 'c', max_bin);
   if (fp_v) mat_ptr[V_VEL]  = start_mat_array(fp_v  , 'd', "v"  , 'c', max_bin);
   if (fp_w) mat_ptr[W_VEL]  = start_mat_array(fp_w  , 'd', "w"  , 'c', max_bin);
   if (fp_e) mat_ptr[E_VEL]  = start_mat_array(fp_e  , 'd', "e"  , 'c', max_bin);
   if (fp_pg) mat_ptr[PGOOD] = start_mat_array(fp_pg , 'd', "pg" , 'c', max_bin);
   if (fp_amp) mat_ptr[AMP]  = start_mat_array(fp_amp, 'd', "amp", 'c', max_bin);

   rewind(fp_tmp);
   while ( (var = fgetc(fp_tmp)) != EOF )
   {
      fread(&nbin, sizeof(SHORT), 1, fp_tmp);
      switch(var)
      {
         case U_VEL:
         case V_VEL:
         case W_VEL:
         case E_VEL:
            fread(short_buff, sizeof(SHORT), nbin, fp_tmp);
            for (i = 0; i < nbin; i++)
            {
               if (short_ mat_ptr[PGOOD] = start_mat_array(fp_pg , 'd', "pg" , 'c', max_bin);
   if (fp_amp) mat_ptr[AMP]  = start_mat_array(fp_amp, 'd', "amp", 'c', max_bin);

   rewind(fp_tmp);
   while ( (var = fgetc(fp_tmp)) != EOF )
   {
      fread(&nbin, sizeof(SHORT), 1, fp_tmp);
      switch(var)
      {
         case U_VEL:
         case V_VEL:
         case W_VEL:
         case E_VEL:
            fread(short_buff, sizeof(SHORT), nbin, fp_tmp);
            for (i = 0; i < nbin; i++)
            {
               if (short_
