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

   FILE  : LOADPING.C
   USAGE : LOADPING <control file name>
   INPUT : 1) producer definition file
           2) ping data files
   OUTPUT: 1) CODAS database
           2) output log file, if requested

   This program is used to create a CODAS database from data in ping
   binary files recorded by ADCP (RC-INSTR).

   The format of control file for loadping of CODAS version 3 is
   different from the previous version. It must have the following
   structure:

   ---------------------------------------------------------------------

      DATABASE_NAME:       <database name>
      DEFINITION_FILE:     <producer definition file>
      OUTPUT_FILE:         <output file name/ none>
      MAX_BLOCK_PROFILES:  <max prfs. in DBNEWBLK>
      NEW_BLOCK_AT_FILE:   <yes/no>
      NEW_BLOCK_AT_HEADER: <yes/no>
      NEW_BLOCK_TIME_GAP(min): <time gap in min>

      PINGDATA_FILES:
          <pingdata file 1>
              [options]
            end
          <pingdata file 2>
              [options]
            end
            ...

   ---------------------------------------------------------------------

   All uppercase terms in the above are keywords and should never be
   changed.  All items in angular brackets are parameters and must be
   supplied by the user.  Items in square brackets are optional.
   Following is a brief explanation of each keyword, parameter, and options.


     (1) DATABASE_NAME:
            database name, up to 5 characters plus path name if needed.

     (2) DEFINITION_FILE:
            producer definition file.

     (3) OUTPUT_FILE:
            output log file name.
            'none' or 'NONE' indicating no output file.

     (4) MAX_BLOCK_PROFILES:
            max number of profiles to be stored in each database block,
            up to 400.

     (5) NEW_BLOCK_AT_FILE:
            yes -- a new database block will be created for each ping file;
            no  -- otherwise.

     (6) NEW_BLOCK_AT_HEADER:
            yes -- a new database block will be created when a new header
                   is encountered in the ping file;
            no  -- otherwise.

     (7) NEW_BLOCK_TIME_GAP(min):
            time gap in minutes (any positive number <= 32767)
            A new database block will be created if the time interval
            between two consecutive profiles exceeds this time gap.

     (8) PINGDATA_FILES:
            list pingdata file names after this line.  Each pingdata
            file name must be followed by the word 'end'.  Between the
            pingdata file name and the word 'end', the user may specify
            any number of options.  There are three kinds of options:

              (a) time_correction:
                     start_header_number: <header number>
                     correct_time:  <yy/mm/dd-hh:mm:ss>
                     PC_time:       <yy/mm/dd-hh:mm:ss>
                     clock_rate:    <PC clock rate>

              (b) skip_header_range: <start hdr No.> to <end hdr No.>

              (c) skip_profile_range:
                     hdr= <hdr No.> prof= <start prf No.> to <end prf No.>

            All non-bracketed items in the above options are keywords
            and must appear as is.  All items in angular brackets are
            parameters and must be supplied by the user.

            Under one pingdata file, all the time_correction options must
            be given in sequential order, and header number and profile
            number in all skip- options must also be given in ascending
            order.

            ---------------------------
            Description of the Options:
            ---------------------------
            (a) time_correction:

                If time_correction is selected, time of corresponding
                profiles will be corrected while loading the database.
                One time correction entry stays in effect until it is
                changed by the next time correction entry, or until the
                end of the current pingdata file.

                start_header_number:
                   indicates where time correction starts.

                correct_time:
                   is the actual time (satellite fix time, t0) when the
                   PC clock was set or observed. It must be in the form
                   of yy/mm/dd-hh:mm:ss.

                PC_time:
                   is the time displayed on the PC clock (pc_time) at time
                   t0. It must be in the form of yy/mm/dd-hh:mm:ss.

                clock_rate:
                   is clock rate correction

                        = 1.0 if clock keeps perfect time;
                        > 1.0 if clock is slow;
                        < 1.0 if clock is fast.

                   LOADPING.EXE program applies the following equation to
                   correct the time:

                      t_correct = t0 + clock_rate * (t_recorded - pc_time)

                   where t_recorded is the time recorded for a profile in
                   ping data file.

                   If the transit fix output file (from SCANPING.EXE) is
                   available, user can use following formula to calculate
                   the clock_rate:

                                            d(fix_time)
                        clock_rate = ------------------------------
                                      d(diff)/86400 + d(fix_time)

                   where
                           diff        = pc_time - fix_time
                           d(fix_time) = fix_time1 - fix_time2
                           d(diff)     = diff1 - diff2.

            (b) skip_header_range:

                If skip_header_range is specified, header(s) in the pingdata
                file within the indicated header range will not be loaded into
                the database.

            (c) skip_profile_range:

                If skip_profile_range is specified, the profile(s) within the
                indicated profile range for the indicated header will not be
                load into the database.

   -----------
   The examples of a control file and output log file are shown in
   ./codas3/adcp/demo/load/loadping.cnt and a9103.lod.
   An example of the producer definition file is given in
   ./codas3/adcp/demo/adcpdb/codas3.def.  An example of a loaded database
   is given in ./codas3/adcp/demo/adcpdb/a9103*.blk.

      ----------------------------------------------------------------------

          Hui Zhu
          89/06/20

94/06/21 - JR - added condition in load_conf() for calling DBENDBLK:
                not only must a block be open, it must also contain
                some profiles before trying to close it and open a
                new one.  Otherwise, some peculiar combination of
                conditions for starting a new block file can cause program
                to crash with a DBENDBLK failure due to PROFILE_DIR_IS_EMPTY.
94/09/01 - JR - added reinitialization of prf_skip every time a new header is
                encountered.  Otherwise, specifying a single profile to be skipped
                under one header will cause the program to ignore another
                skip instruction for the same profile number under a
                subsequent header.  Thanks to Matthew Trunnell at UCSD for
                pointing this out.

95/08/23 - EF - Moved the setting of nprof_in_hdr to 0 from get_hdr_block to
                header_check.  Previously, for a new header, the profile number
                was not getting reinitialized until after set_skip_hdr; but
                set_skip_hdr needs to know the correct profile number.  This
                caused the profile skipping to go haywire sometimes, such
                as when loading a file in which the time correction changes
                in the middle of a header, so that the file must be loaded
                twice, once for each time correction regime.

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

#include "geninc.h"
#if (HOST_ENVIRONMENT != PC_COMPATIBLE_HOST)
#include "dbglo.h"     /* db */
#endif
#include "ioserv.h"   /* PARAMETER_LIST_ENTRY_TYPE, get_parameters(), report_msg() */
#include "userbuff.h" /* MAX_UB_BYTES */
#include "data_id.h"  /* CODAS VARIABLE NAMES AND IDs                    */
#include "adcp.h"     /* ANCILLARY_1_TYPE, CONFIGURATION_1_TYPE, ... */
#define FIRST_DEC
#include "readping.h" /* HEADER FOR FUNCTIONS USED BY LOADPING & SCANPING */
#include "use_db.h"

#define MAX_ENTRY 100
YMDHMS_TIME_TYPE      pc_time, t0, real_time, t_hold={0, 0, 0, 0, 0, 0};
CONFIGURATION_1_TYPE  conf1_hold;
ACCESS_VARIABLES_TYPE access_var;
NAVIGATION_TYPE       navigation;
DEPTH_RANGE_TYPE      depth_range;

struct TIME_CORR_TYPE
{
   int    hdr_num;
   float  off_rate;
   YMDHMS_TIME_TYPE true_t, pc_t;
};

struct SKIP_HDR_PRF_TYPE
{
   int   begin[2], end[2];
};

/*
  2001/09/18 PJ
  Changes done in function load_conf() do not work if the end of a PINGDATA
  file has to be skipped. Added a special function for closing the database in
  such a case.
*/
void  gfi_special_at_end();          /* 2001/09/18 PJ */
int   n_blocks = 0, n_profiles = 0;  /* 2001/09/18 PJ */

int   cnt_error = 0, pass_num, large_gap = 0,  newly_opened = 0;
int   max_blk_prof, blk_at_file, blk_at_hdr;

struct TIME_CORR_TYPE  t_corr[MAX_ENTRY];
struct SKIP_HDR_PRF_TYPE  skip_hdr_prf[MAX_ENTRY];

int    t_corr_flag, t_corr_ind, nt_corr, start_t_corr;
int    skip_flag, max_time_gap, num_skip_entry, skip_ind;
int    skip_this_hdr, skip_this_prf, prf_skip = -1;
int    load_hdr_flag, load_data_flag, nprof_in_blk;
float  rate;

static FILE_NAME_TYPE dbname, prdname;
SHORT  dep[128];

int    db_open_flag, block_open_flag,
       ier, type, log_file_flag, first_data_load;

int    start_hdr_buf;
char   real_time_buf[20], pc_time_buf[20];
double clock_rate_buf;
char   msg[100];

/* ---------------------  functions -------------------------------- */
#if PROTOTYPE_ALLOWED
int    get_time_para(FILE *fpcnt);
int    get_skip_hdr(FILE *fpcnt);
int    get_skip_prf(FILE *fpcnt);
void   set_access_var(void);
void   set_skip_hdr(void);
void   set_time_corr(void);
void   check_conf(void);
void   set_bin_depth(void);
void   assign_part_anci(void);
void   assign_part_conf(void);
void   list_options_local(void);
double std_dev(double s, double a);
int    load_depth(void);
int    load_conf(void);
int    load_data(void);
void   time_correct(YMDHMS_TIME_TYPE *t);
void   check_time_gap(YMDHMS_TIME_TYPE *t);
#else
int    get_time_para();
int    get_skip_hdr();
int    get_skip_prf();
void   set_access_var();
void   set_skip_hdr();
void   set_time_corr();
void   check_conf();
void   set_bin_depth();
void   assign_part_anci();
void   assign_part_conf();
void   list_options_local();
double std_dev();
int    load_depth();
int    load_conf();
int    load_data();
void   time_correct();
void   check_time_gap();
#endif
/**********************************************************************/

static NAME_LIST_ENTRY_TYPE yorn_type[]=
{
   {"no",        0},
   {"yes",       1},
   {NULL,        0}
};

static NAME_LIST_TYPE name_list[]=
{
  {yorn_type},
};

static PARAMETER_LIST_ENTRY_TYPE parameters[] =
   {
      { " DATABASE_NAME:"          , " %79s", dbname       , TYPE_STRING },
      { " DEFINITION_FILE:"        , " %79s", prdname      , TYPE_STRING },
      { " OUTPUT_FILE:"            , " %79s", logname      , TYPE_STRING },
      { " MAX_BLOCK_PROFILES: "    , " %d"  , &max_blk_prof, TYPE_INT    },
      { " NEW_BLOCK_AT_FILE?"      , " %s"  , &blk_at_file , TYPE_TRANS  },
      { " NEW_BLOCK_AT_HEADER?"    , " %s"  , &blk_at_hdr  , TYPE_TRANS  },
      { " NEW_BLOCK_TIME_GAP(min):", " %d"  , &max_time_gap, TYPE_INT    },
      { " PINGDATA_FILES:"         ,  NULL  , NULL         , 0           },
      { NULL                       ,  NULL  , NULL         , 0           }
   };                   /* parameters[] */

static OPTION_TYPE load_options[] =
{
    {"end"                , 0, NULL         , (char *) NULL},
    {"skip_header_range:" , 0, get_skip_hdr , (char *) NULL},
    {"skip_profile_range:", 0, get_skip_prf , (char *) NULL},
    {"time_correction:"   , 0, get_time_para, (char *) NULL},
    {NULL                 , 0, NULL         , NULL}
};

static PARAMETER_LIST_ENTRY_TYPE time_correct_para[] =
{
      { " start_header_number:", " %d"  , &start_hdr_buf , TYPE_INT    },
      { " correct_time:"       , " %39s", real_time_buf  , TYPE_STRING },
      { " PC_time:"            , " %39s", pc_time_buf    , TYPE_STRING },
      { " clock_rate:"         , "%lf"  , &clock_rate_buf, TYPE_DOUBLE },
      { NULL                   , NULL   , NULL           , 0           }
};                   /* time_correct_para[] */

/***********************************************************************/
#if PROTOTYPE_ALLOWED
void do_it(FILE *fpcnt)
#else
void do_it(fpcnt)
FILE *fpcnt;
#endif
{
   int  db_id, im, i;

   printf("\n-------------- start ----------------\n");

   for (pass_num = 0; (pass_num < 2) && (!cnt_error); pass_num++)
   {
      if (pass_num == 0) printf("pass 1: checking the control file.\n");
      else
      {
         fseek(fpcnt,0,0);
         printf("pass 2: loading pingdata file into database.\n");
      }

      if (get_parameters(fpcnt, parameters, name_list)) exit(-1);

      log_file_flag = 1;
      if ((strcmp(logname,"NONE") == 0 ) ||
         (strcmp(logname,"none") == 0 ) )  log_file_flag = 0;
      if (log_file_flag)
      {
        if ((fplog = fopen(logname, "w")) == NULL)
        {
          printf("\n ERROR: Cannot open file %s.\n",logname);
          exit(-1);
        }
        else
          set_msg_file(fplog);
      }
      if (pass_num == 0 && log_file_flag)
         fprintf(fplog,"\n***** ERROR FOUND IN CONTROL FILE ****\n");

      if (max_blk_prof > OPTIMUM_PROFILES_PER_BLOCK)
         max_blk_prof = OPTIMUM_PROFILES_PER_BLOCK;
/*
 ---> CREATE DATABASE
*/
      if (pass_num == 1)
      {
         db_id = 1;
         im = 0;

         DBCREATE(&db_id,dbname,prdname,&im,&ier);
         if (DBERROR(&ier, "creating database")) return;

         db_open_flag = 1;
         block_open_flag = 0;
         first_data_load = 1;
         for (i = 0; i < 128; i++) profile_flags[i] = 0;
      }

      while (fscanf(fpcnt,"%s",bname) == 1)
      {
         if ((fpb = fopen(bname, "rb")) == NULL)
         {
            sprintf(msg,"\n ERROR: opening file %s.\n\n",bname);
            report_msg(msg);
            cnt_error = 1;
         }
         else
         {
            sprintf(msg,"\nData file name: %s \n",bname);
            report_msg(msg);
         }

         nt_corr = 0;
         t_corr_flag = 0;
         start_t_corr = 0;
         num_skip_entry = 0;
         skip_flag = 0;

         if (execute_options(fpcnt, load_options, ECHO) <= 0)
         {
            cnt_error = 1;
            goto close_cnt;
         }
         t_corr_ind = 0;
         skip_ind = 0;
         
         if (pass_num == 1)
         {
            initial();
            while ((file_status = read_record(fpb)) > 0)
            {
               header_check();
               if (hdr_flag)
               {
                  sprintf(msg,"\nHeader %d",nhdr_block);
                  report_msg(msg);
                  hdr_flag = 0;
                  skip_this_hdr = 0;
                  skip_this_prf = 0; /* jr+: 94/02/03 need to reset for each header! */
                  prf_skip = -1;     /* jr+: 94/09/01 need to reset for each header! */
                  if (skip_flag) set_skip_hdr();
                  if (!skip_this_hdr)
                  {
                     if(get_hdr_block()) goto close;
                     assign_part_conf();
                     set_access_var();
                     if (t_corr_flag) set_time_corr();

                     if (!newly_opened &&
                        (load_hdr_flag || blk_at_hdr ||
                        (blk_at_file && nhdr_block == 1)) && !(bad_data_flag))
                     {
                        set_bin_depth();
                        if (load_conf()) goto close;
                        if (load_depth()) goto close;
                        newly_opened = 1;
                     }
                     if (file_note_flag) free(file_notes);
                  }
               }
               else if (!skip_this_hdr)
               {
                  if (skip_flag && (prf_skip != nprof_in_hdr))
                  {
                     skip_this_prf = 0;
                     set_skip_hdr();
                  }
                  if (!skip_this_prf && data_flag)
                  {
                     if (get_data_block()) goto close;
                     check_time_gap(&prof_time);
                     if (large_gap && (!newly_opened))
                     {
                        set_bin_depth();
                        if (load_conf()) goto close;
                        if (load_depth()) goto close;
                        newly_opened = 1;
                     }
                     assign_part_anci();
                     if ((load_data_flag) && !(bad_data_flag))
                     {
                        if (load_data())
                           goto close;
                        else
                           newly_opened = 0;
                     }
                     if (user_buffer_flag) free(user_buffer_block);
                     data_flag = 0;
                  }
               }
               if (bad_data_flag)
                  fprintf(fplog,"\n ERROR: Bad data found in HDR %d PRF %d",
                     nhdr_block,nprof_in_hdr);
               start_blk = 0;
               bad_data_flag = 0;

            }
         }

         if (file_status == 0)
            sprintf(msg,"\nend of file %s\n",bname);
         else
            sprintf(msg,"\n ERROR: Reading file %s.\n",bname);
         report_msg(msg);
         fclose(fpb);
      }

      close:
         if (pass_num == 1)
         {
            if (block_open_flag)
            {
              /* 2001/09/18 PJ 
                 Special sirutation if no profiles have been loaded into the
                 database 
              */
              if(n_profiles == 0){    
                gfi_special_at_end(); 
              }                       
              else{
                /* 2001/09/18 PJ 
                   This was the origianl code. It will be executed if some
                   profiles have been loaded in current block. 
                */
                DBENDBLK(&ier);
                DBERROR(&ier, "DBENDBLK");
              }
            }

            DBCLOSE(&ier);
            if (DBERROR(&ier,"closing database\n\n")) return;
            report_msg("\nDATABASE CLOSED SUCCESSFULLY\n\n");
         }
      close_cnt:
         if (log_file_flag) fclose(fplog);
   }
}

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

#if PROTOTYPE_ALLOWED
int get_time_para(FILE *fpcnt)
#else
int get_time_para(fpcnt)
FILE *fpcnt;
#endif
{
  int  i, yr;

   if (get_parameters(fpcnt, time_correct_para, NULL))
      cnt_error = 1;
   else
   {
      if (start_hdr_buf <= 0)
      {
         sprintf(msg,"ERROR in time_correction: start_header_number = %d.\n",
            start_hdr_buf);
         report_msg(msg);
         cnt_error = 1;
      }
      else
         t_corr[nt_corr].hdr_num = start_hdr_buf;

      if (sscanf(real_time_buf,"%d/%hd/%hd-%hd:%hd:%hd",
         &yr,
         &t_corr[nt_corr].true_t.month,
         &t_corr[nt_corr].true_t.day,
         &t_corr[nt_corr].true_t.hour,
         &t_corr[nt_corr].true_t.minute,
         &t_corr[nt_corr].true_t.second) != 6)
      {
         report_msg("ERROR in time_correction:\n   incorrect format of ");
         sprintf(msg,"correct_time ==> %s\n",real_time_buf);
         report_msg(msg);
         cnt_error = 1;
      }
      else
      {
         t_corr[nt_corr].true_t.year = yr4digit(yr);
         t0 = t_corr[nt_corr].true_t;
      }
      if (sscanf(pc_time_buf,"%d/%hd/%hd-%hd:%hd:%hd",
         &yr,
         &t_corr[nt_corr].pc_t.month,
         &t_corr[nt_corr].pc_t.day,
         &t_corr[nt_corr].pc_t.hour,
         &t_corr[nt_corr].pc_t.minute,
         &t_corr[nt_corr].pc_t.second) != 6)
      {
         report_msg("ERROR in time_correction: \n");
         sprintf(msg,"  incorrect format of PC_time ==> %s\n",pc_time_buf);
         report_msg(msg);
         cnt_error = 1;
      }
      else
      {
         t_corr[nt_corr].pc_t.year =  yr4digit(yr);
         pc_time = t_corr[nt_corr].pc_t;
      }

      t_corr[nt_corr].off_rate = clock_rate_buf;

      for (i = 0; i < nt_corr; i++)
      {
         if (t_corr[nt_corr].hdr_num <= t_corr[i].hdr_num)
         {
            sprintf(msg," ERROR in time correction:\n   start_header_number %d",
               t_corr[nt_corr].hdr_num);
            report_msg(msg);
            report_msg(" not in sequential order.\n");
            cnt_error = 1;
            i = nt_corr;
         }
      }
      if (nt_corr++ >= MAX_ENTRY)
      {
         sprintf(msg,
            " WARNING: The max No. of time correction exceed %d entries.\n",
            MAX_ENTRY);
         report_msg(msg);
         cnt_error = 1;
      }
   }

   t_corr_flag = 1;
   return(0);
}

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

#if PROTOTYPE_ALLOWED
int get_skip_hdr(FILE *fpcnt)
#else
int get_skip_hdr(fpcnt)
FILE *fpcnt;
#endif
{
   int  h1, h2, i, err_found=0;

   if ((fscanf(fpcnt,"  %d to %d ",&h1,&h2) < 2 ))
   {
      report_msg("ERROR in skip_header_range.\n");
      cnt_error = 1;
   }
   else
   {
      if (h1 > h2)
         err_found = 1;
      else
         for (i = 0; i < num_skip_entry; i++)
         {
            if (h1 <= skip_hdr_prf[i].begin[0])
            {
               cnt_error = 1;
               i = num_skip_entry;
               err_found = 1;
            }
         }
         if (err_found)
         {
            sprintf(msg, "ERROR in skip_header_range:\n   %d to %d. ", h1, h2);
            report_msg(msg);
            report_msg("(duplicated or not in sequential order)\n");
            cnt_error = 1;
         }
         else
         {
            skip_hdr_prf[num_skip_entry].begin[0] = h1;
            skip_hdr_prf[num_skip_entry].end[0] = h2;
            skip_hdr_prf[num_skip_entry].begin[1] = -1;
            skip_hdr_prf[num_skip_entry].end[1] = -1;

            if (num_skip_entry++ >= MAX_ENTRY)
            {
               sprintf(msg,
                  " WARNING: the max No. of header skip exceed %d entries.\n",
                  MAX_ENTRY);
               report_msg(msg);
               cnt_error = 1;
            }
         }
   }
   skip_flag = 1;
   return(0);
}

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

#if PROTOTYPE_ALLOWED
int get_skip_prf(FILE *fpcnt)
#else
int get_skip_prf(fpcnt)
FILE *fpcnt;
#endif
{
   int  h1, p1, p2, i, err_found = 0;

   if (fscanf(fpcnt, "  hdr= %d  prof= %d to %d ", &h1, &p1, &p2) < 3)
   {
      report_msg("ERROR in skip_profile_range.\n");
      cnt_error = 1;
   }
   else
   {
      if (p1 > p2)
         err_found = 1;
      else
         for (i = 0; i < num_skip_entry; i++)
         {
            if ((h1 < skip_hdr_prf[i].end[0]) ||
               (h1 == skip_hdr_prf[i].end[0] &&
               (p1 < skip_hdr_prf[i].end[1] || skip_hdr_prf[i].end[1] == -1)))
            {
               cnt_error = 1;
               i = num_skip_entry;
               err_found = 1;
            }
         }
         if (err_found)
         {
            sprintf(msg,
               "ERROR in skip_profile_range:  hdr= %d prof= %d to %d. ",
               h1, p1, p2);
            report_msg(msg);
            report_msg("(duplicated or not in sequectial order)\n");
            cnt_error = 1;
         }
         else
         {
            skip_hdr_prf[num_skip_entry].begin[0] = h1;
            skip_hdr_prf[num_skip_entry].end[0] = h1;
            skip_hdr_prf[num_skip_entry].begin[1] = p1;
            skip_hdr_prf[num_skip_entry].end[1] = p2;

            if (num_skip_entry++ >= MAX_ENTRY)
            {
               sprintf(msg,
                  "WARNING: the max No. of header skip exceed %d enties.\n",
                  MAX_ENTRY);
               report_msg(msg);
               cnt_error = 1;
            }
         }
   }
   skip_flag = 1;
   return(0);
}

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

#if PROTOTYPE_ALLOWED
void set_access_var(void)  /* set velocity reference data */
#else
void set_access_var()  /* set velocity reference data */
#endif
{
   access_var.first_good_bin = 1;
   access_var.last_good_bin = conf1.num_bins;
   access_var.U_ship_absolute = BADFLOAT;
   access_var.V_ship_absolute = BADFLOAT;
   access_var.user_flag_1 = BADSHORT;
   access_var.user_flag_2 = BADSHORT;
   access_var.user_flag_3 = BADSHORT;
   access_var.user_flag_4 = BADSHORT;
}

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

#if PROTOTYPE_ALLOWED
void set_bin_depth(void)  /* calculate the bin depth */
#else
void set_bin_depth()  /* calculate the bin depth */
#endif
{
   int i;
   double first_bin;

   first_bin = conf1.tr_depth + conf1.blank_length +
               (conf1.bin_length + conf1.pls_length) / 2;
   for (i = 0; i < conf1.num_bins; i++)
      dep[i] = first_bin + i * conf1.bin_length;
   depth_range.min_depth = first_bin;
   depth_range.max_depth = dep[conf1.num_bins-1];
}

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

#if PROTOTYPE_ALLOWED
void assign_part_conf(void)  /*  assign some values of conf1 */
#else
void assign_part_conf()  /*  assign some values of conf1 */
#endif
{
   conf1.compensation = 0;
   if (heading_compensate)
      conf1.compensation = (conf1.compensation | 1);
   if (pitch_compensate)
      conf1.compensation = (conf1.compensation | 2);
   if (roll_compensate)
      conf1.compensation = (conf1.compensation | 4);
   conf1.ping_interval = BADFLOAT;
   conf1.unused1 = conf1.unused2 = conf1.unused3 = conf1.unused4 = BADFLOAT;
   conf1.ev_threshold = BADSHORT;

   load_hdr_flag = 1;
   load_data_flag = 1;
   if (block_open_flag) check_conf();

   conf1_hold = conf1;
}

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

#if PROTOTYPE_ALLOWED
void check_conf(void)
#else
void check_conf()  /* check if current conf are the same as previouse
                      one. if not, new data block will be opened */
#endif
{
   char *p1, *p2;
   int i, stop;

   p1 = (char*) &conf1_hold;
   p2 = (char*) &conf1;

   i = 0;
   stop = 0;
   while (!stop && (i < sizeof(CONFIGURATION_1_TYPE)))
   {
      if (*(p1+i) != *(p2+i)) stop = 1;
      i++;
   }
   if (!stop) load_hdr_flag = 0;
}

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

#if PROTOTYPE_ALLOWED
void set_time_corr(void)
#else
void set_time_corr()
#endif
{
   if (t_corr_ind < nt_corr)
   {
      if (nhdr_block < t_corr[0].hdr_num)
         start_t_corr = 0;
      else
      {
         if (nhdr_block >= t_corr[t_corr_ind].hdr_num)
            t_corr_ind++;
         start_t_corr = 1;
      }
   }
}

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

#if PROTOTYPE_ALLOWED
void set_skip_hdr(void)
#else
void set_skip_hdr()
#endif
{
   int h1, h2, p1, p2;
   /* jr-+ 94/02/03: if (skip_ind <= num_skip_entry) */
   if (skip_ind < num_skip_entry)
   {
      if (nhdr_block >= skip_hdr_prf[0].begin[0])
      {
         h1 = skip_hdr_prf[skip_ind].begin[0];
         h2 = skip_hdr_prf[skip_ind].end[0];
         p1 = skip_hdr_prf[skip_ind].begin[1];
         p2 = skip_hdr_prf[skip_ind].end[1];
         if (nhdr_block >= h1 && nhdr_block <= h2)
         {
            if (p1 == -1 && p2 == -1)
            {
               load_hdr_flag = 0;
               load_data_flag = 0;
               skip_this_hdr = 1;
               report_msg("    not loaded. ");
               if (nhdr_block == h2) skip_ind++;
            }
            else
               if (nprof_in_hdr >= p1 && nprof_in_hdr <= p2)
               {
                  if (prf_skip != nprof_in_hdr)
                  {
                     sprintf(msg, "\n   %3d   not loaded.", nprof_in_hdr);
                     report_msg(msg);
                  }
                  skip_this_prf = 1;
                  prf_skip = nprof_in_hdr;
                  if (nprof_in_hdr == p2) skip_ind++;
               }
         }
      }
   }
}

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

#if PROTOTYPE_ALLOWED
int load_conf(void)
#else
int load_conf()  /* load conf into database */
#endif
{
   unsigned int n;
   long data;

/* CLOSE LAST BLOCK AND CREATE A NEW BLOCK IF NEW
   CONFIGUATION INFO ===>
*/
   if (block_open_flag && nprof_in_blk > 0)  /* 94/06/21 - JR added && condition */
   {
      DBENDBLK(&ier);
      if (DBERROR(&ier,"DBENDBLK"))
      {
         sprintf(msg,"\n close old, open new DBENDBLK ier = %d",ier);
         report_msg(msg);
         return(1);
      }
      block_open_flag = 0;
   }

   if (!block_open_flag)
   {
     n_blocks++ ;           /* 2001/09/18 PJ */
     n_profiles = 0;        /* 2001/09/18 PJ */
     nprof_in_blk = 0;
     DBNEWBLK(&ier);
     if (DBERROR(&ier,"DBNEWBLK"))
       return(1);
     block_open_flag = 1;
   }

   if (t_corr_flag)
   {
      type = DATA_PROC_MASK;
      data = 1L;
      n = 4;
      DBADD(&type, (char *) &data, &n, &ier);
      if (DBERROR(&ier, "DBADD DATA_PROC_MASK"))
      {
         fprintf(fplog,
            "\n DBADD data processing mask to turn on time correction bit.");
         return(1);
      }
   }

   type = CONFIGURATION_1;
   n = sizeof(CONFIGURATION_1_TYPE);
   DBADD(&type, (char *)&conf1, &n, &ier);
   if (DBERROR(&ier, "DBADD CONFIGURATION_1"))
   {
      sprintf(msg, "\n DBADD nhdr_block = %d conf ier = %d", nhdr_block, ier);
      report_msg(msg);
      return(1);
   }

   if (file_note_flag)
   {
      n = note_length;
      type = BLOCK_COMMENTS;
      DBADD(&type, file_notes, &n, &ier);
      if (DBERROR(&ier, "DBADD BLOCK_COMMENTS"))
      {
          sprintf(msg,
             "\n DBADD ensemble_num = %d file_notes ier = %d", ensemble_num, ier);
          report_msg(msg);
          return(1);
      }
   }
   return(0);
}

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

#if PROTOTYPE_ALLOWED
int load_depth(void)
#else
int load_depth()  /* load bin depth into database */
#endif
{
   unsigned int n;

   type = DEPTH;
   n = conf1.num_bins*sizeof(SHORT);
   DBADD(&type, (char *)dep, &n, &ier);
   if (DBERROR(&ier, "DBADD DEPTH"))
   {
      sprintf(msg,
         "\n DBADD nhdr_block = %d depth ier = %d", nhdr_block, ier);
      report_msg(msg);
      return(1);
   }
   return(0);
}

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

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

   ancil2.std_roll = ((float)
      std_dev(sum_roll_squar,(double) ancil2.mn_roll)) * factor;
   ancil2.std_pitch = ((float)
      std_dev(sum_pitch_squar,(double) ancil2.mn_pitch)) * factor;
   ancil2.std_heading = ((float)
      std_dev(sum_heading_squar,(double) ancil1.mn_heading)) * factor;
   ancil2.std_temp = ((float)
      std_dev(sum_temp_squar,(double)ancil1.tr_temp)) * temp_scale / 4096;
   ancil2.mn_roll = ancil2.mn_roll * factor;
   ancil2.mn_pitch = ancil2.mn_pitch * factor;
   ancil1.mn_heading = ancil1.mn_heading * factor - conf1.hd_offset;
   if (ancil1.mn_heading > 360.0) ancil1.mn_heading -= 360.0;
   if (ancil1.mn_heading <   0.0) ancil1.mn_heading += 360.0;
   ancil1.tr_temp = temp_offset - (temp_scale * ancil1.tr_temp / 4096);

   t =  (double) ancil1.tr_temp;
   ancil1.snd_spd_used = 1449.2 + 4.6 * t - 0.055*t*t
      + 0.00029*(t*t*t) + (1.34 - 0.01*t) * (salinity - 35.0);

   ancil1.best_snd_spd = BADFLOAT;
   ancil1.anc6 = BADSHORT;
   ancil1.anc7 = BADSHORT;
   ancil1.anc8 = BADSHORT;
   ancil1.anc9 = BADSHORT;
   ancil1.anc10 = BADSHORT;
   ancil2.watrk_hd_misalign = ancil2.botrk_hd_misalign = 0.0;
   ancil2.watrk_scale_factor = ancil2.botrk_scale_factor = 1.0;
   ancil2.rol_misalign = ancil2.pit_misalign = 0.0;
   ancil2.unused1 = BADFLOAT;
   ancil2.ocean_depth = BADSHORT;
   ancil2.max_amp_bin = BADSHORT;
   ancil2.last_good_bin = conf1.num_bins;
   ancil2.anc21 = BADSHORT;
   ancil2.anc22 = BADSHORT;
   ancil2.anc23 = BADSHORT;
}

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

#if PROTOTYPE_ALLOWED
double std_dev(double Ss, double Av)
#else
double std_dev(Ss, Av) /* calculate the standard dev */
double Ss, Av;
#endif
{
   double std, x;

   x = Ss / num_samp_for_ave-Av * Av;
   if (x > 0)
      std = sqrt(x);
   else
      std = 0;
   return(std);
}

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

#if PROTOTYPE_ALLOWED
int load_data(void)
#else
int load_data()
#endif
{
   unsigned int n;
#if (HOST_ENVIRONMENT != PC_COMPATIBLE_HOST)
   char buff[MAX_UB_BYTES];
   int nv;
#endif

   if ((nprof_in_blk >= max_blk_prof) ||
      ((!first_data_load) && (old_buf_count != user_buffer_count)))
   {
      if (load_conf())  return(1);
      if (load_depth()) return(1);
   }

   if (prof_time.second == 60 )
   {
      prof_time.second = 0;
      (prof_time.minute)++;
   }

   if (log_file_flag)
      fprintf(fplog,"\n   %3d   %04d/%02d/%02d %02d:%02d:%02d ",
         nprof_in_hdr, prof_time.year, prof_time.month, prof_time.day,
         prof_time.hour, prof_time.minute, prof_time.second);

   if (start_t_corr)
      time_correct(&prof_time);
   else
      real_time = prof_time;

   n_profiles++; /* 2001/09/18 PJ */
   DBNEWPRF(&real_time,&ier); 
   if (DBERROR(&ier,"DBNEWPRF")) return(1);

   if (amplitude_flag)
   {
      type = AMP_SOUND_SCAT;
      n = conf1.num_bins;
      DBADD(&type, (char *) amp, &n, &ier);
      if (DBERROR(&ier,"DBADD AMP_SOUND_SCAT")) return(1);
   }

   if (record_velx != 0)
   {
      type = U;
      n = conf1.num_bins * sizeof(SHORT);
      DBADD(&type, (char *)u, &n, &ier);
      if (DBERROR(&ier,"DBADD U velocity")) return(1);
   }

   if (record_vely != 0)
   {
      type = V;
      n = conf1.num_bins * sizeof(SHORT);
      DBADD(&type, (char *)v, &n, &ier);
      if (DBERROR(&ier,"DBADD V velocity")) return(1);
   }

   type = PROFILE_FLAGS;
   n = conf1.num_bins * sizeof(UBYTE);
   DBADD(&type, (char *) profile_flags, &n, &ier);
   if (DBERROR(&ier, "DBADD PROFILE_FLAGS")) return(1);

   type = ANCILLARY_1;
   n = sizeof(ANCILLARY_1_TYPE);
   DBADD(&type, (char *)&ancil1, &n, &ier);
   if (DBERROR(&ier,"DBADD ANCILLARY_1")) return(1);

   type = ANCILLARY_2;
   n = sizeof(ANCILLARY_2_TYPE);
   DBADD(&type, (char *)&ancil2, &n, &ier);
   if (DBERROR(&ier,"DBADD ANCILLARY_2")) return(1);

   type = ACCESS_VARIABLES;
   n = sizeof(ACCESS_VARIABLES_TYPE);
   DBADD(&type, (char *)&access_var, &n, &ier);
   if (DBERROR(&ier,"DBADD ACCESS_VARIABLES")) return(1);

   if (record_velz != 0)
   {
      type = W;
      n = conf1.num_bins * sizeof(SHORT);
      DBADD(&type, (char *)w, &n, &ier);
      if (DBERROR(&ier,"DBADD W velocity")) return(1);
   }

   if (record_error != 0)
   {
      type = ERROR_VEL;
      n = conf1.num_bins * sizeof(SHORT);
      DBADD(&type, (char *)e, &n, &ier);
      if (DBERROR(&ier,"DBADD ERROR_VEL")) return(1);
   }

   if (perc_good_flag)
   {
      type = PERCENT_GOOD;
      n = conf1.num_bins;
      DBADD(&type, (char *) pg, &n, &ier);
      if (DBERROR(&ier,"DBADD PERCENT_GOOD")) return(1);
   }

   if (three_beam_flag)
   {
      type = PERCENT_3_BEAM;
      n = conf1.num_bins;
      DBADD(&type, (char *) percent_3_beam, &n, &ier);
      if (DBERROR(&ier,"DBADD PERCENT_3_BEAM")) return(1);
   }

   if (spw_data_flag)
   {
      type = SPECTRAL_WIDTH;
      n = conf1.num_bins;
      DBADD(&type, (char *) ave_spw_width, &n, &ier);
      if (DBERROR(&ier,"DBADD SPECTRAL WIDTH")) return(1);
   }

   if (standard_dev_flag)
   {
      type = U_STD_DEV;
      n = n_bin_RSD * sizeof(SHORT);
      DBADD(&type, (char *)u_std_dev, &n, &ier);
      if (DBERROR(&ier,"DBADD U_STD_DEV")) return(1);

      type = V_STD_DEV;
      DBADD(&type, (char *)v_std_dev, &n, &ier);
      if (DBERROR(&ier,"DBADD V_STD_DEV")) return(1);

      type = W_STD_DEV;
      DBADD(&type, (char *)w_std_dev, &n, &ier);
      if (DBERROR(&ier,"DBADD W_STD_DEV")) return(1);

      type = EV_STD_DEV;
      DBADD(&type, (char *)ev_std_dev, &n, &ier);
      if (DBERROR(&ier,"EV_STD_DEV")) return(1);
   }

   if (raw_doppler_flag)
   {
      type = RAW_DOPPLER;
      n = 4 * conf1.num_bins * sizeof(SHORT);
      DBADD(&type, (char *)raw_doppler, &n, &ier);
      if (DBERROR(&ier,"DBADD RAW_DOPPLER")) return(1);
   }

   if (raw_amplitude_flag)
   {
      type = RAW_AMP;
      n = 4 * conf1.num_bins;
      DBADD(&type, (char *) raw_amplitude, &n, &ier);
      if (DBERROR(&ier,"DBADD RAW_AMP")) return(1);
   }

   if (raw_spw_data_flag)
   {
      type = RAW_SPECTRAL_WIDTH;
      DBADD(&type, (char *) raw_spectral_width, &n, &ier);
      if (DBERROR(&ier,"DBADD RAW_SPECTRAL_WIDTH")) return(1);
   }

   if (beam_stats_flag)
   {
      type = BEAM_STATS;
      n = sizeof(beam_stats);
      DBADD(&type, (char *) beam_stats, &n, &ier);
      if (DBERROR(&ier, "DBADD BEAM_STATS")) return(1);
   }

   if (bottom_track_flag)
   {
      type = NAVIGATION;
      n = sizeof(navigation);
      DBADD(&type, (char *)&navigation, &n, &ier);
      if (DBERROR(&ier, "DBADD NAVIGATION")) return(1);

      type = BOTTOM_TRACK;
      n = sizeof(bottom_track);
      DBADD(&type, (char *)&bottom_track, &n, &ier);
      if (DBERROR(&ier, "DBADD BOTTOM_TRACK")) return(1);
   }

   if (user_buffer_flag)
   {
#if (HOST_ENVIRONMENT != PC_COMPATIBLE_HOST)
#define UB_VALUE_TYPE db->data_list[USER_BUFFER].value_type
      if (UB_VALUE_TYPE == STRUCT_VALUE_CODE) nv = - user_buffer_count;
      else nv = user_buffer_count / VALUE_SIZE[UB_VALUE_TYPE];

      if (convert_select(buff, (char *)user_buffer_block, PC_COMPATIBLE_HOST, HOST_ENVIRONMENT,
              nv, UB_VALUE_TYPE, "USER_BUFFER", db->block_strdef) == BADUINT)
      {
         report_msg("ERROR: In converting user buffer\n");
         return(1);
      }
      move_byte(buff, (char *)user_buffer_block, user_buffer_count);
#endif
      type = USER_BUFFER;
      n = user_buffer_count;
      DBADD(&type, (char *) user_buffer_block, &n, &ier);
      if (DBERROR(&ier, "DBADD USER_BUFFER")) return(1);
      old_buf_count = user_buffer_count;
   }

   if (CTD_data_flag)
   {
      type = ADCP_CTD;
      n = 64;
      DBADD(&type, (char *) CTDstrip, &n, &ier);
      if (DBERROR(&ier, "DBADD ADCP_CTD")) return(1);
   }

   type = DEPTH_RANGE;
   n = sizeof(DEPTH_RANGE_TYPE);
   DBADD(&type, (char *) &depth_range, &n, &ier);
   if (DBERROR(&ier, "DBADD DEPTH_RANGE")) return(1);

   DBENDPRF(&ier);
   if (DBERROR(&ier, "DBENDPRF")) return(1);

   nprof_in_blk++;
   first_data_load = 0;
   return(0);
}

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

#if PROTOTYPE_ALLOWED
void time_correct(YMDHMS_TIME_TYPE *curr_time)
#else
void time_correct(curr_time)
YMDHMS_TIME_TYPE *curr_time;
#endif
{
   int  s1, temp_sec;
   long offset, t, time_diff;
   long m, m1, m0;

   pc_time = t_corr[t_corr_ind-1].pc_t;
   t0 = t_corr[t_corr_ind-1].true_t;
   rate = t_corr[t_corr_ind-1].off_rate;
   offset = TIMDIF(&pc_time,curr_time);
   t = offset*rate;
   m1 = t / 60;
   s1 = t % 60;
   m0 = TIMMIN(&t0);
   m = m0 + m1;
   temp_sec = t0.second + s1;
   if (temp_sec >= 60)
   {
      m++;
      temp_sec -= 60;
   }
   else if (temp_sec < 0)
   {
      m--;
      temp_sec += 60;
   }
   MINTIM(&real_time, &m);
   real_time.second = temp_sec;

   time_diff = TIMDIF(curr_time, &real_time);
   if (log_file_flag)
      fprintf(fplog, "   +  %ld:%02ld ", time_diff/60, time_diff%60);
}
/*----------------------------------------------------------------------- */

#if PROTOTYPE_ALLOWED
void check_time_gap(YMDHMS_TIME_TYPE *t)
#else
void check_time_gap(t)
YMDHMS_TIME_TYPE *t;
#endif
{
  unsigned long delt;
  int m;

  if (t_hold.year)
  {
     delt = TIMDIF(&t_hold,t);
     m = delt/60;
  }
  else
     m = 0;
  t_hold = *t;

  if (m >= max_time_gap) large_gap = 1;
  else large_gap = 0;
}

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

/* 2001/09/18 PJ 

   Insert a fake profile in current opened block and remove it. This is
   necessary at the end of loading if the last profiles in PINGDATA files had
   to be skipped. Otherwise, one gets a PROFILE_DIR_IS_EMPTY error as well as
   a segmentation fault on some systems.
*/
void gfi_special_at_end(void)
{
  
  int dbid=1, dbmode=1, dbmem=0, dbsrch=TIME_SEARCH;

  prof_time.year  = 1970;
  prof_time.month = 01;
  prof_time.day   = 01;
  prof_time.hour  = prof_time.minute = prof_time.second = 0;

  DBNEWPRF(&prof_time, &ier);
  DBERROR(&ier, "DBNEWPRF: fake profile");
  DBENDPRF(&ier);
  DBERROR(&ier, "DBENDPRF: fake profile");
  DBENDBLK(&ier);
  DBERROR(&ier, "DBENDBLK: fake block");                
  DBCLOSE(&ier);
  DBERROR(&ier, "DBCLOSE: fake block");

  DBOPEN(&dbid, dbname, &dbmode, &dbmem, &ier);
  DBERROR(&ier, "DBOPEN: fake block");
  DBSRCH(&dbsrch, (char *) &prof_time, &ier);
  DBERROR(&ier, "DBSRCH: searching fake blk");
  DBDELBLK(&ier); 
  DBERROR(&ier, "DBDELBLK");

  /*
  DBCLOSE(&ier);
  DBERROR(&ier, "DBCLOSE: fake block");
  */
  
  return;
}

