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

   SETFLAGS.C

      This program clears and/or sets profile flag bits.

            Eric Firing
            96/07/27

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

control file structure:

     dbname:          { database name }
     logname:         { logfile name; default is "setflags.log" }
     pg_min:  [ 30 ]  { set PG_BIT wherever percent_good is less }
     clear_range      { include this command to set the }
                      { ACCESS_VARIABLES first_good_bin and last_good_bin }
                      { back to original default: 1 and number of bins. }
                      { PROFILE_FLAGS RANGE_BIT is also cleared.
                      { This option should be rarely if ever needed. }
     set_range_bit    { Include this command to set the RANGE_BIT }
                      { to correspond to the range in ACCESS_VARIABLES. }
                      { The following "clear_" commands all clear their }
                      { respective bits in PROFILE_FLAGS. }
     clear_range_bit
     clear_glitch_bit
     clear_pg_bit
     clear_all_bits
     time_ranges:
     (list of YMDHMS time pairs:)
        (yy/mm/dd hh:mm:ss) to (yy/mm/dd hh:mm:ss)
        .
        .
     end               { optional; required only if another }
                       { set of commands will be included in }
                       { the same control file.  If so, all }
                       { necessary commands must be repeated; }
                       { all variables are cleared except }
                       { dbname: }


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

#include "geninc.h"
#include "time.h"
#include "adcp.h"    /* ACCESS_VARIABLES_TYPE */
#include "adcpflag.h"
#include "data_id.h"
#include "ioserv.h"  /* check_error(), get_parameters() */
#include "use_db.h"  /* db*_cnf(), get_time_range(), print_time_range() */

#define MAX_NBINS 128

static   FILE_NAME_TYPE dbname, logname;
static   int   STEPS;
static   int   pg_min;
static   int   set_range;
static   int   clear_int;
static   int   clear_range;
static   UBYTE bit_mask;

static  UBYTE profile_flags[MAX_NBINS];
static  UBYTE percent_good[MAX_NBINS];

#if PROTOTYPE_ALLOWED
static int set_flags(FILE *fp_cnt, char *dummy, int dummy2);
#else
static int set_flags();
#endif



/*
Main routine
*/

#if PROTOTYPE_ALLOWED
void do_it(FILE *fp_cnt)
#else
void do_it(fp_cnt)
FILE *fp_cnt;
#endif
{


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

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

*/


static   OPTION_TYPE options[] =
   {
      { "end",            0          , NULL          , NULL              },
      { "time_ranges:"  , 0          , set_flags     , NULL              },
      { "skip_to"       , 0          , skip_to       , NULL              },
      { "set_range_bit" , 1          , set_code      , (char *) &set_range},
      { "clear_range"   , 1          , set_code      , (char *) &clear_range},
      { "dbname:"       , TYPE_STRING, op_get_param  , dbname            },
      { "logname:"      , TYPE_STRING, op_get_param  , logname            },
      { "pg_min:"       , TYPE_INT   , op_get_param  , (char *) &pg_min  },
      { "clear_range_bit",(int) RANGE_BIT, logical_or, (char *) &clear_int},
      { "clear_pg_bit"  ,(int) PG_BIT, logical_or    , (char *) &clear_int},
      { "clear_glitch_bit",(int) GLITCH_BIT, logical_or, (char *) &clear_int},
      { "clear_all_bits",(int) ALL_BITS, logical_or  , (char *) &clear_int},
      { NULL            , 0          , NULL,    NULL,                       }
   };


   dbname[0] = 0;
   strcpy(logname, "setflags.log");
   STEPS = 1;
   pg_min = 0;
   set_range = 0;
   clear_range = 0;
   clear_int = 0;


   while (!execute_options(fp_cnt, options, ECHO))
      ;
   fputs("\n Done.\n", stderr);

}


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

#if PROTOTYPE_ALLOWED
static int set_flags(FILE *fp_cnt, char *dummy, int dummy2)
#else
static int set_flags(fp_cnt, dummy, dummy2)
FILE *fp_cnt;
char *dummy;
int   dummy2;
#endif
{
   FILE *fp_log;
   int    IERR, i;
   unsigned int N, npf;
   time_t time_stamp;
   ACCESS_VARIABLES_TYPE access;
   YMDHMS_TIME_TYPE start, end,            /* for time range */
                    this_time,  /* current profile time */
                    last_time;  /* to print last profile time */
   int first = 1;

   /* clear_int contains a 1 for each bit to be cleared;
      bit_mask is a byte with 0 for each bit to be cleared,
      so that it can be "anded" with the profile flag.
      Note that clear_int is also a flag: 0 if no clearing is
      needed, non-zero if there are bits to be cleared.

      If the range bits are to be set to correspond to
      access_variables, or if access variables are to be
      cleared, then we will first clear the range bits.
   */
   if (set_range || clear_range)
      clear_int |= RANGE_BIT;
   bit_mask = ~( (UBYTE)(clear_int) );
   if (dbopen_cnf(1, dbname, READ_WRITE, DIR_IN_MEMORY)) exit(-1);
   if (error_found( ( (fp_log = fopen(logname, "a+t")) == NULL ),
      "opening log file\n\n" )) exit(-1);
   set_msg_file(fp_log);
   time(&time_stamp);
   fprintf(fp_log,
      "\n**************************\n %s**************************\n",
      ctime(&time_stamp));
      fprintf(fp_log, "\n pg_min = %d\n set_range = %d\n clear bits %02X\n",
               pg_min, set_range, clear_int);

/*
---> Start the loop through time ranges listed in the control file.
*/
   while (get_time_range(fp_cnt, &start, &end) == 1)
   {
      print_time_range(stdout, &start, &end);
      print_time_range(fp_log, &start, &end);
      IERR = 0;
      first = 1;

      if (dbsrch_cnf(TIME_SEARCH, (char *)&start) == SEARCH_BEYOND_END)
         goto close;
/*
---> Start the loop through profiles within the time range.
*/
      while (!IERR && check_time(&this_time, &start, &end))
      {
         if (first)
         {
            fprintf(fp_log, "\n processed:  ");
            write_ymdhms_time(fp_log, &this_time);
            first = 0;
         }
         last_time = this_time;

         npf = MAX_NBINS * sizeof(UBYTE);
         if (dbget_cnf(PROFILE_FLAGS, (char *) profile_flags, &npf,
            "getting profile flags")) goto close;
         if (npf == 0)
         {
            report_msg("\n ERROR:  setflags will not work if there is no");
            report_msg("\n         PROFILE_FLAGS variable in the database.\n\n");
            goto close;
         }

         if (clear_int)
         {
            for (i = 0; i < npf; i++)
            {
               profile_flags[i] &= bit_mask;
            }
         }

         if (pg_min > 0)
         {
            N = MAX_NBINS * sizeof(UBYTE);
            if (dbget_cnf(PERCENT_GOOD, (char *) percent_good, &N,
               "getting percent good")) goto close;
            if (N != npf)
            {
               report_msg("\n ERROR:  PROFILE_FLAGS and PERCENT_GOOD are");
               report_msg("\n         different sizes.\n\n");
               goto close;
            }
            for (i=0; i<N; i++)
            {
               if (percent_good[i] < pg_min)
                  profile_flags[i] |= PG_BIT;
            }
         }

         if (set_range | clear_range)
         {
            N = sizeof(ACCESS_VARIABLES_TYPE);
            if (dbget_cnf(ACCESS_VARIABLES, (char *) &access, &N,
               "access")) goto close;
         }

         if (set_range)
         {
            int i0, fgb, lgb;
            /* Bins in access variables are 1-based, not 0-based! */
            fgb = access.first_good_bin - 1;
            lgb = access.last_good_bin - 1;
            /* All range_bits have just been cleared, so
            we need only set those outside the good range.
            */
            for (i = 0; i <fgb ; i++)
               profile_flags[i] |= RANGE_BIT;
            /* If the whole profile was marked bad, then
               last_good_bin is -1 so lgb is -2; hence the
               max_val operation.
            */
            i0 = max_val(lgb+1, 0); /* first bad bin after any good ones */
            for (i = i0; i < npf; i++)
               profile_flags[i] |= RANGE_BIT;
         }

         if (clear_range)
         {
            access.first_good_bin = 1;
            access.last_good_bin = npf; /* should be same as conf1.num_bins */
            if (dbput_cnf(ACCESS_VARIABLES, (char *) &access, &N,
               "writing access variables")) goto close;
            /* Range bits have been cleared. */
         }

         if (dbput_cnf(PROFILE_FLAGS, (char *) profile_flags, &npf,
            "writing profile flags")) goto close;

         DBMOVE(&STEPS, &IERR);   /* IERR is checked at the start of the loop */

      }  /* end of loop through profiles within a time range */

      fprintf(fp_log, " to ");
      write_ymdhms_time(fp_log, &last_time);
      fprintf(fp_log, "\n");

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

   close:
      dbclose_cnf();
      fclose(fp_log);
      printf("\n SETFLAGS time range list completed.\n");

      /* reset flagging parameters */
      pg_min = 0;
      set_range = 0;
      clear_range = 0;
      clear_int = 0;
      return(0);
}
