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

   UBPRINT.C

   Within a time range, this program prints out the contents
   of the user buffer for each profile.  It assumes either
   the 102-byte buffer or the later 128-byte buffer that
   includes GPS, depending on #defines set in nav.h.


                     Eric Firing
                     88-04-16

   90/08/20 - JR - modified to work with 132-byte buffer
   92/10/20 - JR - modified to work with 72- & 224-byte buffer
   94/10/15 - SS - modified to work with 192-byte buffer
   95/01/02 - EF - changed position output Mat-file name 
                   from <root>_fixes.mat to <root>.maf
----------------------------------------------------------------

control file structure:

     dbname:    (e.g. WEP)
     output: (file name)
     step_size=  (number of profiles to advance)
     year_base=
     variables:
     time_ranges:
     (list of YMDHMS time pairs:)
        (yy/mm/dd hh:mm:ss) to (yy/mm/dd hh:mm:ss)
        .
        .
****************************************************************/
#include <math.h>
#include "geninc.h"
#include "ioserv.h"
#include "use_db.h"
#include "adcp.h"
#include "userbuff.h"
#include "matfile.h"
#include "data_id.h"

#if PROTOTYPE_ALLOWED
void print_time_range_(FILE * fp, YMDHMS_TIME_TYPE * start,
                            YMDHMS_TIME_TYPE * end_time);
void write_att_indices(void);
void write_att(USER_BUFFER_1920_TYPE * u, double dd);
void write_fix_indices(void);
void write_fix(USER_BUFFER_1920_TYPE * u, double dd);
#else
void print_time_range_();
void write_att_indices();
void write_att();
void write_fix_indices();
void write_fix();
#endif

/* matlab output's  of the attitude-function and fixes */
#define N_A_VAR 	29
#define N_F_VAR	    32
MAT_ARRAY_FP_TYPE *mat_att_ptr, *mat_fix_ptr;
double att[N_A_VAR], fix[N_F_VAR];
FILE *fp_mat, *fp_fix_att;


/*
 * The following differs from the version in time_io only in the initial
 * string. The time_io version should be changed to be more general.
 */
#if PROTOTYPE_ALLOWED
void print_time_range_(FILE * fp, YMDHMS_TIME_TYPE * start, YMDHMS_TIME_TYPE * endtime)
#else
void print_time_range_(fp, start, endtime)
   FILE *fp;
   YMDHMS_TIME_TYPE *start, *endtime;
#endif
{
   fprintf(fp, "\n%% Time range: ");
   write_ymdhms_time(fp, start);
   fprintf(fp, " to ");
   write_ymdhms_time(fp, endtime);
}				/* print_time_range_() */

/*
 * Main routine
 */

/* global for use in ubwrite module */
int year_base;
int ub_type;			/* jr+ */

#if PROTOTYPE_ALLOWED
void do_it(FILE * fp_cnt)
#else
void do_it(fp_cnt)
   FILE *fp_cnt;
#endif
{
   FILE *fp_out[14];
   int IERR, iblkprf[2], blksave = -99, n, nbuf, n_ub, i;
   YMDHMS_TIME_TYPE start, endtime, this_time;	/* for time range */
   /* current profile time */
   NAVIGATION_TYPE navdata;
   STRUCT_DEF_ENTRY_TYPE *ub_def;	/* pointer to user buffer structure
                                         * definition from block file */
   double d_dtime;

   /*---------- end of auto declarations for do_it -----------------*/

   /* e.f.: buffer is big; must be static allocation */
   static char buffer[MAX_UB_BYTES], out_filename[80], mat_filename[80];


   /***************************************************************
      static variables needed for initialization of
      the parameter array

   */

   static FILE_NAME_TYPE dbname, root;
   static char variable_name[20];
   static int STEPS;
   int iprint[16];		/* index into array of print functions */

   void write_user_buffer();
   void write_transit_fixes();
   void write_transit_summary();
   void write_gps_summary();
   void write_L_fixes();
   void write_avg_gps_summary();
   void write_gps_cal();
   void write_raw2_messages();
   void write_gps_fixes();
   void write_ashtech_att();	/* new option which is explicit for 192-byte
                                 * buffer */


   static void (*ub_write[]) () =
   {
      write_user_buffer,
      write_transit_fixes,
      write_transit_summary,
      write_gps_summary,
      write_gps_summary,	/* This function uses fix[2] & fix[3] for
                             * 192-byte buffer */
      write_L_fixes,
      write_avg_gps_summary,
      write_avg_gps_summary,	/* This function uses fix[2] & fix[3] for
                                 * 192-byte buffer */
      write_gps_cal,
      write_raw2_messages,
      write_gps_fixes,
      write_gps_fixes,		/* This function uses fix[2] & fix[3] for
                             * 192-byte buffer */
      write_ashtech_att
   };

   static NAME_LIST_ENTRY_TYPE ub_variables[] =
   {
      {"complete", 0},
      {"TRANSIT_fix", 1},
      {"TRANSIT_summary", 2},
      {"GPS_summary", 3},
      {"GPS2_summary", 4},
      {"L_fix", 5},
      {"avg_GPS_summary", 6},
      {"avg_GPS2_summary", 7},
      {"GPS_cal", 8},
      {"raw2_message", 9},
      {"GPS_fix", 10},
      {"GPS2_fix", 11},
      {"attitude", 12},
      {"attitude_mat", 13},
      {"position", 14},
      {"end", BADINT},
      {NULL, BADINT}
   };

   /*
    * The following array indicates the offset within the userbuffer if
    * offset=0 values are taken from fix[0] & fix[1], if offset=1 values are
    * taken from fix[2] & fix[3]
    */

   static int arr[] = {0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0};

   static NAME_LIST_ENTRY_TYPE ub_extensions[] =
   {
      {".ub", 0},
      {".trf", 1},
      {".trs", 2},
      {".gps", 3},
      {".gp2", 4},
      {".lfx", 5},
      {".ags", 6},
      {".ag2", 7},
      {".gcl", 8},
      {".mg2", 9},
      {".gfx", 10},
      {".gf2", 11},
      {".att", 12},
      {".mat", 13},
      {".maf", 14},
      {NULL, BADINT}
   };

   static NAME_LIST_TYPE param_name_lists[] = {ub_variables};

   static PARAMETER_LIST_ENTRY_TYPE parameters[] =
   {
      {" dbname:", " %79s", dbname, TYPE_STRING},
      {" output:", " %79s", root, TYPE_STRING},
      {" step_size=", " %d", &STEPS, TYPE_INT},
      {" year_base=", " %d", &year_base, TYPE_INT},
      {" variables:", " %19s", variable_name, TYPE_STRING},
      {NULL, NULL, NULL, 0}
   };				/* parameters[] */

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

   if (get_parameters(fp_cnt, parameters, param_name_lists))
      exit(-1);
   check_dbopen(1, dbname, READ_ONLY, DIR_IN_MEMORY);
   i = 0;
   while (BADINT != (iprint[i] = get_code(ub_variables, variable_name)))
   {
      switch (iprint[i])
      {
         case 13:
            new_extension(mat_filename, root, get_name(ub_extensions, iprint[i]));
            fp_mat = check_fopen(mat_filename, "wb");
            write_att_indices();
            mat_att_ptr = start_mat_array(fp_mat, 'd', "att", 'c', N_A_VAR);
            break;
         case 14:
            new_extension(mat_filename, root, get_name(ub_extensions, iprint[i]));
            fp_fix_att = check_fopen(mat_filename, "wb");
            write_fix_indices();
            mat_fix_ptr = start_mat_array(fp_fix_att, 'd', "fix", 'c', N_F_VAR);
            break;
         default:
            new_extension(out_filename, root, get_name(ub_extensions, iprint[i]));
            fp_out[i] = check_fopen(out_filename, "w");
            fprintf(fp_out[i], "%%  User buffers for:\n");
            fprintf(fp_out[i],
            "%%  dbname: %s;  step_size= %d;  year_base= %d;  variable: %s;",
                dbname, STEPS, year_base, variable_name);
      }
      check_error((1 != fscanf(fp_cnt, "%19s", variable_name)),
                  "scanning variable list");
      i++;
   }

   check_error((
                (ub_def = (STRUCT_DEF_ENTRY_TYPE *) malloc(STRUCT_DEF_ENTRY_SIZE)) == NULL),
               "allocating memory for user buffer definition");
   strcpy(ub_def->hdr.name, "USER_BUFFER");	/* to dbget USER_BUFFER
                                                 * strdef */

   check_error((fscanf(fp_cnt, " time_ranges:") != 0),
               "reading time range start");
   /*
    * ---> Start the loop through time ranges listed in the control file.
    */
   while (get_time_range(fp_cnt, &start, &endtime) == 1)
   {
      check_dbsrch(TIME_SEARCH, (char *) &start);
      for (i = 0; iprint[i] != BADINT; i++)
      {
         if ((iprint[i] == 13) || (iprint[i] == 14))
            continue;
         fprintf(fp_out[i], "\n\n");
         print_time_range_(fp_out[i], &start, &endtime);
         fprintf(fp_out[i], "\n");
      }
      print_time_range(stdout, &start, &endtime);
      IERR = 0;

      /*
       * ---> Start the loop through profiles within the time range.
       */
      while (!IERR && check_time(&this_time, &start, &endtime))
      {
         check_dbget(BLOCK_PROFILE_INDEX, (char *) iblkprf, sizeof(iblkprf),
                 "getting block-profile index");
         if (iblkprf[0] != blksave) /* check ub definition for each block */
         {
            blksave = iblkprf[0];
            n = check_dbget(STRUCTURE_DEF, (char *) ub_def, 0,
                    "getting user buffer structure no.of bytes");
            check_error((n <= 0), "cannot get user buffer structure definition");
            check_error(
                ((ub_def = (STRUCT_DEF_ENTRY_TYPE *)
                  realloc((char *) ub_def, n)) == NULL),
                "allocating memory for user buffer definition");
            check_dbget(STRUCTURE_DEF, (char *) ub_def, n,
                "getting user buffer structure definition");
            if (strcmp((ub_def + 1)->elem.name, "version") == 0)
            {
               check_error(
                  (0 >= (nbuf = check_dbget(USER_BUFFER, buffer, MAX_UB_BYTES,
                          "reading user buffer"))),
                   "no user buffer in first profile of this block");
               ub_type = ((USER_BUFFER_1281_TYPE *) buffer)->version;
               if (ub_type != 1281 && ub_type != 1320 && ub_type != 720 && ub_type != 1920 && ub_type != 2240)
               {
                  printf("\n ERROR: Incorrect user buffer version %d", ub_type);
                  printf("\n Run CONVADCP first\n\n");
                  return;
               }
            }
            else if (strcmp((ub_def + 1)->elem.name, "fix") == 0)
               ub_type = 1021;
            else
            {
               printf("\n ERROR: Unknown user buffer type");
               return;
            }
         }
         nbuf = check_dbget(USER_BUFFER, buffer, MAX_UB_BYTES,
                    "reading user buffer");

         if (nbuf != (n_ub = (int) (ub_type / 10)))
         {
            printf("\n WARNING: Mismatch between user buffer size & definition:");
            printf("\n %d bytes recorded,", nbuf);
            printf(" %d bytes expected", n_ub);
#if 0
            return;
#else				/* Fri  09-14-1990  make the error non-fatal */
            /* Zero out the unstored bytes. */
            for (i = nbuf; i < n_ub; i++)
               buffer[i] = 0;
#endif
         }
#define ubfix ((USER_BUFFER_1920_TYPE *)(buffer))->fix[i]
         if (ub_type == 1920)  /* 94/12/12 JR+:  check for missing fix */
         {
            for (i = 0; i < 4; i++)
               if (ubfix.nsat == 0)  /* that should be indicative... */
                  ubfix.pc_seconds = ubfix.gps_seconds = BADLONG;
         }

         check_dbget(NAVIGATION, (char *) &navdata, sizeof(navdata),
                 "reading navigation");

         d_dtime = year_day(&this_time, year_base);
         for (i = 0; iprint[i] != BADINT; i++)
         {
            if (iprint[i] == 13)
            {
               write_att((USER_BUFFER_1920_TYPE *) buffer, d_dtime);
               continue;
            }
            else if (iprint[i] == 14)
            {
               write_fix((USER_BUFFER_1920_TYPE *) buffer, d_dtime);
               continue;
            }
            else
            {
               (*ub_write[iprint[i]]) (fp_out[i], buffer, &this_time, &navdata, arr[iprint[i]]);
            }
         }
         DBMOVE(&STEPS, &IERR); /* IERR is checked at the start of the loop */
      }				/* end of loop through profiles within a time
                     * range */
      /* For the average_gps_summary types, we need to print the
      last end-of-ensemble fix from the last profile. 
      */
      for (i = 0; iprint[i] != BADINT; i++)
      {
         if (iprint[i] == 6 || iprint[i] == 7)
         {
            USER_BUFFER_2240_TYPE *u = (USER_BUFFER_2240_TYPE *)buffer;
            int offset = arr[iprint[i]];
            u->fix[2*offset].msg_type = 0;  /* flag, to mark it invalid */
            (*ub_write[iprint[i]]) (fp_out[i], u, &this_time, &navdata, offset);
         }
      }
      

   }				/* end of loop through time ranges read from
                     * control file */


   for (i = 0; iprint[i] != BADINT; i++)
   {
      if (iprint[i] == 13)
      {
         end_mat_array(mat_att_ptr);
         fclose(fp_mat);
         continue;
      }
      else if (iprint[i] == 14)
      {
         end_mat_array(mat_fix_ptr);
         fclose(fp_fix_att);
         continue;
      }
      else
         fclose(fp_out[i]);
   }
   DBCLOSE(&IERR);
   check_error(IERR, "DBCLOSE");
   printf("\nUBPRINT completed.\n");
   return;
}
