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

    FILE:  READPING.C

           These are routines for reading various parts of
           a ping file.  They are used by loadping, scanping,
           and ping2mat.  Headers are in file PINGSUB.H

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

#include "common.h"
#include "dbhost.h"
#include "readping.h"   /* get_ubyte(), get_double(), ... */
#include "ioserv.h"    /* report_msg() */
#include "use_db.h"

/*---------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void initial(void)   /* initialize file variables */
#else
void initial()   /* initialize file variables */
#endif
{
   nhdr_block = 0;
   hdr_flag = 0;
   start_blk = 0;
   bad_data_flag = 0;
}

/*------------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
int read_record(FILE *fp)  /* read 128 bytes (1 rec) from binary file */
#else
int read_record(fp)  /* read 128 bytes (1 rec) from binary file */
FILE *fp;
#endif
{
   int nblk;

   if (fread(record_nbyte,128,1,fp) != 1)
   {
      if (feof(fp)) 
         return(0);
      else
         return(-1);
   }

   nblk = record_nbyte[0] * 0x100 + record_nbyte[1];
   if (!(nblk == 0)) 
   {
      if (!(nblk - nblk_in_prf == 1)) 
         bad_data_flag = 1;
      else
         nblk_in_prf++;
   }
   else
   {
      if (start_blk == 1)
         bad_data_flag = 1;
      else  
         start_blk = 1;
      nblk_in_prf = 0;
   }
   byte_count = 2;
   return(1);
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void turn_off_flag(void)   /* turn all profile flags */
#else
void turn_off_flag()   /* turn all profile flags */
#endif
{
   file_note_flag = 0;
   bottom_track_para_flag = 0;
   ABER_para_flag = 0;
   record_RPHT_stat_flag = 0;
   velocity_flag = 0;
   amplitude_flag = 0;
   perc_good_flag = 0;
   bottom_track_flag = 0;
   user_buffer_flag = 0;
   CTD_data_flag = 0;
   spw_data_flag = 0;
   raw_doppler_flag = 0;
   raw_amplitude_flag = 0;
   raw_spw_data_flag = 0;
   three_beam_flag = 0;
   beam_stats_flag = 0;
   standard_dev_flag = 0;
}

/*-------------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
int header_check(void)  
#else
int header_check()  /* Check if it is header block. Identification
                       is the 1st four bytes 00 00 FF FF. */
#endif
{
   UBYTE header_flag[4];

   header_flag[0] = header_flag[1] = 0;
   header_flag[2] = header_flag[3] = 255;
   if (*((LONG*) (record_nbyte)) == *((LONG*) (header_flag)))
   {
      nhdr_block++;
      hdr_flag = 1;
      nprof_in_hdr = 0; /* EF 95/08/23 */
   }
   else if (*((SHORT*) (record_nbyte)) == 0)
   {
      data_flag = 1;
      nprof_in_hdr++;
   }
   return(0);
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
int collect_flag()  /* collect header flags and data flags */
#else
int collect_flag()  /* collect header flags and data flags */
#endif
{
  int flag;
  byte_count = 4;       /* header flag collection */
  while (record_nbyte[byte_count] > 0)
  {
     flag = record_nbyte[byte_count];
     switch(flag) {
       case 4:
        file_note_flag = 1;
        break;
       case 5:
        bottom_track_para_flag = 1;
        break;
       case 8:
        ABER_para_flag = 1;
        break;
        }
     byte_count++;
   }

   byte_count++;     /* data flag collection */
   while (record_nbyte[byte_count] > 0)
   {
      flag = record_nbyte[byte_count];
      switch(flag) {
        case 8:
          record_RPHT_stat_flag = 1;
          break;
        case 11:
          velocity_flag = 1;
          break;
        case 13:
          amplitude_flag = 1;
          break;
        case 14:
          perc_good_flag = 1;
          break;
        case 15:
          bottom_track_flag = 1;
          break;
        case 16:
          user_buffer_flag = 1;
          break;
        case 17:
          CTD_data_flag = 1;
          break;
        case 18:
          spw_data_flag = 1;
          break;
        case 19:
          raw_doppler_flag = 1;
          break;
        case 20:
          raw_amplitude_flag = 1;
          break;
        case 21:
          raw_spw_data_flag = 1;
          break;
        case 22:
          three_beam_flag = 1;
          break;
        case 23:
          beam_stats_flag = 1;
          break;
        case 24:
          standard_dev_flag = 1;
          break;
        }
      byte_count++;
   }
   byte_count++;
   return(0);
}

/*------------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
int get_hdr_block(void)  /* read header block data */
#else
int get_hdr_block()  /* read header block data */
#endif
{
   int i;
   double bin_length;

   turn_off_flag();
   collect_flag();

   IBM_software_version = get_uint();  /* IBM software times 100 */
   ADCP_software_version = get_uint();
   disk_transducer_serial_No = get_uint();
   conf1.freq_transmit = (float)get_uint();
   disk_config1 = get_uint();         /* fixed at 65535 */
   disk_config2 = get_uint();         /* fixed at 65535 */
   disk_sys_serial = get_uint();      /* fixed at 65535 */
   disk_up_down = get_ubyte();        /* 85 = "U" = upward */
                                      /* 68 = "D" = downward */
   disk_cave_vex = get_ubyte();       /* 65 = "A" = concave */
                                      /* 88 = "X" = convex */
   block_length = get_uint();         /* fixed at 128 */
   conf1.pgs_ensemble = (SHORT) get_uint();  /* usually = 1 */

   conf1.num_bins = (SHORT) get_ubyte();  /* from 8 to 128 */

   bin_length = (double) get_ubyte(); /* pwr of 2. from 0 to 5 */
   conf1.bin_length = (float) pow(2.0, bin_length);
   conf1.pls_length = (float) get_ubyte();
   conf1.blank_length = (float) get_ubyte();

   false_target = get_ubyte();
   sig_to_noise = get_ubyte();
   conf1.ens_threshold = (SHORT) get_ubyte();
   h_time.year = (USHORT) yr4digit( (int) get_ubyte() );
   h_time.month = get_ubyte();
   h_time.day = get_ubyte();
   h_time.hour = get_ubyte();
   h_time.minute = get_ubyte();
   h_time.second = get_ubyte();
   hundredths = get_ubyte();
   get_cruise_id();                    /* cruise id up to 60 bytes */
   zero_velocity = get_ubyte();        /* fixed at 83 = ship_zero_velo */
   serial_parallel = get_ubyte();      /* 83 = "S", 80 = "P" */
   conf1.bot_track = (SHORT) get_ubyte();      /* 0 = OFF, 255 = ON */
   record_return_header_block = get_ubyte();   /* 0 = OFF, 225 = ON */
                                          /* v1.00 - 1.04: always 0 */
   record_return_data_block = get_ubyte();     /* 0 = OFF, 225 = ON */
   transformed_data = get_ubyte();             /* 0 = OFF, 255 = ON */
                                  /* v1.04 this bytes is always 225 */
                   /* v1.00 - 1,03 spare byte with random assigment */
   record_velx = get_ubyte();           /* 0 = OFF, 255 = ON */
   record_vely = get_ubyte();           /* 0 = OFF, 255 = ON */
   record_velz = get_ubyte();           /* 0 = OFF, 255 = ON */
   record_error = get_ubyte();          /* 0 = OFF, 255 = ON */

   roll_compensate = get_ubyte();        /* 0 = OFF, 255 = ON */
   pitch_compensate = get_ubyte();       /* 0 = OFF, 255 = ON */
   heading_compensate = get_ubyte();     /* 0 = OFF, 255 = ON */

   conf1.heading_bias = (float) get_double();
   conf1.rol_offset = (float) get_double();
   conf1.pit_offset = (float) get_double();
   conf1.hd_offset = (float) get_double();
   roll_range = get_double();
   pitch_range = get_double();
   conf1.avg_interval = (float) get_double();
   conf1.top_ref_bin = (SHORT) get_ubyte();
   conf1.bot_ref_bin = (SHORT) get_ubyte();

   reject_error_set = get_double();
   temp_scale = get_double();
   temp_offset = get_double();
   salinity = get_double();              /* v1.00 - v1.03 fixed at 0 */
                                         /* v1.04 actual salinity */
   conf1.tr_depth = (float) get_double();
   Xducer_angles = get_double();

   if(ABER_para_flag)
     for(i=0; i<13; i++) get_ubyte();   /* 13 bytes 0s. */

   if (file_note_flag) {
      get_file_notes();
      if(file_notes == NULL) return(1);
      }
   /* nprof_in_hdr = 0; moved to header_check 95/08/23 by EF */
   return(0);
}

/*--------------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void get_cruise_id(void)  /* read cruise id */
#else
void get_cruise_id()  /* read cruise id */
#endif
{
   int i;
   USHORT id_length;

   id_length = get_ubyte();
   for (i=0; i<(int)id_length; i++)
   {
      cruise_id[i] = get_ubyte();
   }
}

/*--------------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void get_file_notes(void)  /* read file notes */
#else
void get_file_notes()  /* read file notes */
#endif
{
   int i, j;

   note_length = get_uint();
   file_notes = (char *) calloc(note_length,sizeof(char));
   if (file_notes == NULL) {
      report_msg(" no heaps for file_notes \n");
      return;
     }

   fprintf(fplog,"\nFile Notes: ");
   j = 0;
   for (i=0; i<(int)note_length; i++)
   {
      j++;
      *(file_notes+i) = get_ubyte();
      if (log_file_flag) {
         if((j>=50) && (*(file_notes+i) == ' ')) {
           fprintf(fplog,"\n            ");
           j = 0;
           }
         fprintf(fplog,"%c",*(file_notes+i));
         }
   }
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
int get_data_block(void)  /* read data block */
#else
int get_data_block()  /* read data block */
#endif
{
   read_record_prefix();

   if(!bad_data_flag && record_RPHT_stat_flag)
         read_RPHT_stat();
   if(!bad_data_flag && velocity_flag)
         read_velocity();
   if(!bad_data_flag && amplitude_flag)
         read_amplitude();
   if(!bad_data_flag && perc_good_flag)
         read_perc_good();
   if(!bad_data_flag && bottom_track_flag)
         read_bottom_data();
   if(!bad_data_flag && user_buffer_flag) 
   {
      read_user_buffer();
      if (user_buffer_block == NULL)
      {
         report_msg("ERROR: Insufficient memory to read in user buffer.\n");
         return(1);
      }
   }
   if(!bad_data_flag && CTD_data_flag)
         read_CTD_data();
   if(!bad_data_flag && spw_data_flag)
         read_ave_spw_data();
   if(!bad_data_flag && raw_doppler_flag)
         read_raw_doppler_data();
   if(!bad_data_flag && raw_amplitude_flag)
         read_raw_amplitude_data();
   if(!bad_data_flag && raw_spw_data_flag)
         read_raw_spw_data();
   if(!bad_data_flag && three_beam_flag)
         read_percent_3_beam_sol();
   if(!bad_data_flag && beam_stats_flag)
         read_beam_statistic();
   if(!bad_data_flag && standard_dev_flag)
         read_standard_dev();
   return(0);
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_record_prefix(void)  /* read data prefix */
#else
void read_record_prefix()  /* read data prefix */
#endif
{
   hdr_rec_num = get_uint();
   prof_time.year = (USHORT) yr4digit( (int) get_ubyte() );
   prof_time.month = get_ubyte();
   prof_time.day = get_ubyte();
   prof_time.hour = get_ubyte();
   prof_time.minute = get_ubyte();
   prof_time.second = get_ubyte();
   hundredths = get_ubyte();
   ensemble_num = get_uint();
   ancil1.pgs_sample = (SHORT) get_uint();
   spare = get_uint();
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_RPHT_stat(void)
#else
void read_RPHT_stat()
#endif
{
   double factor = 360.0 / 65536.0; /* for converting to degrees */

   ancil2.last_roll = (float) get_double() * factor;
   ancil2.last_pitch = (float) get_double() * factor;
   ancil2.last_heading = (float) get_double() * factor;
   ancil2.last_heading -= conf1.hd_offset;
   if (ancil2.last_heading > 360.0) ancil2.last_heading -= 360.0;
   if (ancil2.last_heading > 360.0) ancil2.last_heading -= 360.0; /* jr+ 94/01 */
   if (ancil2.last_heading <   0.0) ancil2.last_heading += 360.0;
   if (ancil2.last_heading <   0.0) ancil2.last_heading += 360.0; /* jr+ 94/01 */
   ancil2.last_temp = temp_offset - temp_scale * (float) get_double() / 4096;

   ancil2.mn_roll = (float) get_double();
   ancil2.mn_pitch = (float) get_double();
   ancil1.mn_heading = (float) get_double();
   if (ancil2.last_heading > 360.0) ancil2.last_heading -= 360.0; /* jr+ 94/01 */
   if (ancil2.last_heading <   0.0) ancil2.last_heading += 360.0; /* jr+ 94/01 */
   ancil1.tr_temp = (float) get_double();
   sum_roll_squar = get_double();
   sum_pitch_squar = get_double();
   sum_heading_squar = get_double();
   sum_temp_squar = get_double();
   num_samp_for_ave = get_uint();
   gyro_ok = get_ubyte();
}

/*--------------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_velocity(void)  /* read velocity */
#else
void read_velocity()  /* read velocity */
#endif
{
   int i;

   for (i=0; i<conf1.num_bins; i++)
   {
      if (record_velx != 0) {
         u[i] = get_uint();
         if (u[i] == 19999) u[i] = BADSHORT;
      }
      if (record_vely != 0) {
        v[i] = get_uint();
        if (v[i] == 19999)  v[i] = BADSHORT;
      }
      if (record_velz != 0) {
         w[i] = get_uint();
         if (w[i] == 19999) w[i] = BADSHORT;
      }
      if (record_error != 0) {
         e[i] = get_uint();
         if (e[i] == 19999)  e[i] = BADSHORT;
      }
   }
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_amplitude(void)
#else
void read_amplitude()
#endif
{
   int i;

   for (i=0; i<conf1.num_bins; i++)
      amp[i] = get_ubyte();
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_perc_good(void)
#else
void read_perc_good()
#endif
{
   int i;

   for (i=0; i<conf1.num_bins; i++)
      pg[i] = get_ubyte();
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_bottom_data(void)
#else
void read_bottom_data()
#endif
{
   double data_holder[10];
   int i;

   for (i=0; i<10; i++)
   {
      data_holder[i] = get_double();
      if(data_holder[0] == 30000) bottom_flag = 0;
      else
        if(i == 0) bottom_flag = 1;

      if ((data_holder[i] == 30000) || (data_holder[i] == 19999) )
      {
         if(i <= 3 ) data_holder[i] = BADFLOAT;
         else data_holder[i] = BADDOUBLE;
      }
   }
   bottom_track.u = (float) data_holder[0];
   bottom_track.v = (float) data_holder[1];
   if(data_holder[0] < ADJ_BADFLOAT)
      bottom_track.u /= 1000;            /* convert unit to m/s */
   if(data_holder[0] < ADJ_BADFLOAT)
      bottom_track.v /= 1000;            /* convert unit to m/s */
   bottom_track.depth = (float) data_holder[2];
   conf1.avg_interval = data_holder[3];
   navigation.latitude  = data_holder[4];
   navigation.longitude = data_holder[5];
   navigation.speed     = data_holder[6];
   navigation.direction = data_holder[7];
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_user_buffer(void)
#else
void read_user_buffer()
#endif
{
   int i;

   user_buffer_count = get_uint();
   user_buffer_block = (UBYTE *) calloc(user_buffer_count,sizeof(UBYTE));
   if (user_buffer_block == NULL) return;           
   for (i=0; i<(int)user_buffer_count; i++)
      *(user_buffer_block+i) = get_ubyte();
}

/*------------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_CTD_data(void)
#else
void read_CTD_data()
#endif
{
   SHORT i;

   i = get_uint();  /* fixed = 64 */
   for (i=0; i< 16; i++)
      CTDstrip[i] = get_reverse_long();
}

/*-------------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_ave_spw_data(void)
#else
void read_ave_spw_data()
#endif
{
   int i;

   for (i=0; i<conf1.num_bins; i++)
      ave_spw_width[i] = get_ubyte();
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_raw_doppler_data(void)
#else
void read_raw_doppler_data()
#endif
{
   int i, j;

   for (i=0; i<conf1.num_bins; i++)
      for (j=0; j<4; j++)
         raw_doppler[i*4+j] = (SHORT) get_uint();
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_raw_amplitude_data(void)
#else
void read_raw_amplitude_data()
#endif
{
   int i, j;

   for (i=0; i<conf1.num_bins; i++)
      for (j=0; j<4; j++)
         raw_amplitude[i*4+j] = get_ubyte();
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_raw_spw_data(void)
#else
void read_raw_spw_data()
#endif
{
   int i, j;

   for (i=0; i<conf1.num_bins; i++)
      for (j=0; j<4; j++)
         raw_spectral_width[i*4+j] = get_ubyte();
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_percent_3_beam_sol(void)
#else
void read_percent_3_beam_sol()
#endif
{
   int i;

   for (i=0; i<conf1.num_bins; i++)
      percent_3_beam[i] = get_ubyte();
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_beam_statistic(void)
#else
void read_beam_statistic()
#endif
{
   int i;

   for (i=0; i<4; i++)
      beam_stats[i] = get_ubyte();
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
void read_standard_dev(void)
#else
void read_standard_dev()
#endif
{
   int i;

   n_bin_RSD = get_ubyte();

   for (i=0; i<(int)n_bin_RSD; i++)
   {
      if (IBM_software_version <= 224)
      {
         u_std_dev[i] = (SHORT) get_ubyte();
         v_std_dev[i] = (SHORT) get_ubyte();
         w_std_dev[i] = (SHORT) get_ubyte();
         ev_std_dev[i] = (SHORT) get_ubyte();
      }
      else
      {
         u_std_dev[i] = (SHORT) get_uint();
         v_std_dev[i] = (SHORT) get_uint();
         w_std_dev[i] = (SHORT) get_uint();
         ev_std_dev[i] = (SHORT) get_uint();
      }
   }
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
double get_double(void)
#else
double get_double()
#endif
{
  union {
     double real;
     UBYTE byte_holder[8];
     } d;
  int i;

#if (HOST_ENVIRONMENT == PC_COMPATIBLE_HOST)
   for (i=0; i<8; i++)
#else
   for (i=7; i>=0; i--)
#endif
   {
      if (byte_count >127)
         read_record(fpb);
      if (bad_data_flag)
         d.byte_holder[i] = BADBYTE;
      else
      {
         d.byte_holder[i] = record_nbyte[byte_count];
         byte_count++;
      }
   }

  if(zero_double((UBYTE *) (d.byte_holder))) d.real = 0;
  else if(bad_double((UBYTE *) (d.byte_holder))) d.real = BADDOUBLE;

  return(d.real);
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
USHORT get_uint(void)
#else
USHORT get_uint()
#endif
{
   USHORT u_i;
   UBYTE  byte_holder[2];
   int    i;

   for (i=0; i<2; i++)
   {
      if (byte_count >127)
         read_record(fpb);
      if (bad_data_flag)
         byte_holder[i] = BADBYTE;
      else
      {
         byte_holder[i] = record_nbyte[byte_count];
         byte_count++;
      }
   }
   u_i = byte_holder[0] * 256 + byte_holder[1];
   return(u_i);
}

/*-----------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
LONG get_reverse_long(void)
#else
LONG get_reverse_long()
#endif
{
   LONG   value;
   UBYTE  byte_holder[4];
   int    i;

   for (i=0; i<4; i++)
   {
      if (byte_count >127)
         read_record(fpb);
      if (bad_data_flag)
         byte_holder[i] = BADBYTE;
      else
      {
         byte_holder[i] = record_nbyte[byte_count];
         byte_count++;
      }
   }
   value = byte_holder[0] + byte_holder[1] * 0x100L +
           byte_holder[2] * 0x10000L + byte_holder[3] * 0x1000000L;
   return(value);
}

/*---------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
UBYTE get_ubyte(void)
#else
UBYTE get_ubyte()
#endif
{
   UBYTE ub_value;

   if (byte_count > 127)
      read_record(fpb);
   if (bad_data_flag)
      ub_value = BADBYTE;
   else
   {
      ub_value = record_nbyte[byte_count];
      byte_count++;
   }
   return(ub_value);
}

/*-------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
int bad_double(UBYTE *b) 
#else
int bad_double(b)  /* return 1 if b is an infinity or a denormalized number */
                  /* infinity = a huge exponent ;
                  denormalized = a tiny exponent with fraction > 0 */

UBYTE *b;
#endif
{
   int m, n;

#if (HOST_ENVIRONMENT == PC_COMPATIBLE_HOST)
   m = 7;
   n = 6;
#else
   m = 0;
   n = 1;
#endif
   if( ((b[n] & 0xf0) == 0xf0) &&
       ( ((b[m] & 0xff) == 0xff)|| ((b[m] & 0xff) == 0x7f)) )
      return(1);
   else
      if( ((b[n] & 0xf0) == 0) &&
        ( ((b[m] & 0xff) == 0) || ((b[m] & 0xff) == 0x80))  )
        return(1);
   else return(0);

}

/*-------------------------------------------------------*/

#if PROTOTYPE_ALLOWED
int zero_double(UBYTE *b)
#else
int zero_double(b)  /* return 1 if b is equal to zero */
                /* zero = tiny exponent with fraction 0 */

UBYTE *b;
#endif
{
   int j;

#if (HOST_ENVIRONMENT == PC_COMPATIBLE_HOST)
   j = 0;
   while(b[j] == 0 && j<6) j++;
   if((j == 6) && (b[6] == 0) && ((b[7] == 0)||(b[7] == 0x80)) ) return (1);
   else return (0);
#else
   j = 2;
   while(b[j] == 0 && j<8) j++;
   if((j == 8) && ((b[0] == 0)||(b[0] == 0x80)) && (b[1] == 0) ) return (1);
   else return (0);
#endif
}
