/******************************************************************************
*
    PROGRAM:  SET_LGB.C
    USAGE:    SET_LGB <dbname>

       This program retrieves the max_amp_bin
       in the ANCILLARY_2 structure for
       three consecutive profiles at a time, and assigns the
       85% of the smallest bin no. among these as the last_good_bin for
       the middle profile.  The updated ancillary structure
       is then stored back in the database.

       It also updates the last_good_bin field of the ACCESS_VARIABLES
       structure to the same value as ANCILLARY_2's
       last_good_bin, unless ACCESS_VARIABLES last_good_bin is -1,
       indicating the whole profile is marked bad.

       It turns on bit 9  of the data processing mask for each block to
       indicate that the database has been edited in this manner.
       It operates only on blocks for which bit 8 is on and bit 9 is off;
       this is the way the mask bits are left by dbupdate.

       This program replaces botmpas3 and last_85.
                                                                              *
******************************************************************************/

#include "geninc.h"
#include "data_id.h"                   /* CODAS variable names and IDs   */
#include "adcp.h"                      /* ADCP data structures           */
#include "ioserv.h"                    /* error_found()                  */
#include "use_db.h"                    /* db*_cnf(),  set_dpmask()       */
#include "dbedit.h"                    /* update_acc_var()               */
#include "dpmask.h"                    /* BOTTOM_SOUGHT                  */

#if PROTOTYPE_ALLOWED
int update_db(ANCILLARY_2_TYPE *anc, int min_MAB);
int alloc_structs(void);
#else
int update_db();
int alloc_structs();
#endif

#define NMAX 128                        /* max. no. bins */
#define dbname argv[1]

ANCILLARY_2_TYPE *anc1,*anc2,*anc3;     /* consider 3 profiles at a time */
CONFIGURATION_1_TYPE config;

#if PROTOTYPE_ALLOWED
int main(int argc, char *argv[])
#else
int main(argc, argv)
int argc;
char *argv[];
#endif
{
   ANCILLARY_2_TYPE *temp;
   int              ierr, nsteps, iblkprf[2], MABset, LGBset;
   unsigned int     n;
   int min_MAB;

   if (argc < 2)
   {
      printf("\n ERROR: Invalid no. of arguments");
      printf("\n USAGE: SET_LGB <dbname>\n\n");
      exit(-1);
   }

   if (error_found(alloc_structs(),
      "allocating memory for ancillary structures")) exit(-1);
   if (dbopen_cnf(1, dbname, READ_WRITE, DIR_IN_MEMORY)) exit(-1);

   /*-----------------------------------------------------------------
      LOCATE FIRST BLOCK NOT YET PROCESSED AS INDICATED BY D.P. MASK
     -----------------------------------------------------------------*/
   iblkprf[0] = -1; iblkprf[1] = 0;
   do
   {
      iblkprf[0]++;
      if (dbsrch_cnf(BLOCK_PROFILE_SEARCH, (char *) iblkprf)) goto close;
      if (error_found( ((MABset = check_block_dpmask(BOTTOM_SOUGHT)) == -1),
         "checking data processing mask")) goto close;
      if (error_found( ((LGBset = check_block_dpmask(BOTTOM_MGB)) == -1),
         "checking data processing mask")) goto close;
   } while (LGBset || !MABset);

   printf("First block with data processing mask having BOTTOM_MGB\n");
   printf("cleared or BOTTOM_SOUGHT set is %d.\n", iblkprf[0]);

   if (iblkprf[0] != 0)                 /* need to update last profile of */
      if (dbmove_cnf(-1)) goto close;   /* preceding block from last run  */


   /*-------------------------------------------------------------
       FIRST PROFILE IS UPDATED USING DATA FOR TWO PROFILES ONLY
     -------------------------------------------------------------*/
   n = sizeof(ANCILLARY_2_TYPE);
   if (dbget_cnf(ANCILLARY_2, (char *) anc1, &n, "getting ancillary data"))
      goto close;
   if (dbmove_cnf(1)) goto close;
   n = sizeof(ANCILLARY_2_TYPE);
   if (dbget_cnf(ANCILLARY_2, (char *) anc2, &n, "getting ancillary data"))
      goto close;

   min_MAB = min_val(anc1->max_amp_bin, anc2->max_amp_bin);
   if (dbmove_cnf(-1)) goto close;
   if (error_found(update_db(anc1, min_MAB), "updating database")) goto close;

   /*---------------------------------------------------------
       MAIN PROCESSING LOOP FOR EACH GROUP OF THREE PROFILES
     ---------------------------------------------------------*/
   do
   {
      nsteps = 2;    /* two steps forward here; one back at end of loop. */
                     /* Net move is one step per loop. The
                     one step back is to update the middle
                     profile. */
      DBMOVE(&nsteps, &ierr);
      if (ierr)
      {
         if (ierr != SEARCH_BEYOND_END)
         {
            printf("\n ERROR: %d in DBMOVE", ierr);
            goto close;
         }
      }
      else
      {
         n = sizeof(ANCILLARY_2_TYPE);
         if (dbget_cnf(ANCILLARY_2, (char *) anc3, &n, "getting ancillary data"))
            goto close;

         min_MAB = min_val(
                                min_val(anc2->max_amp_bin, anc1->max_amp_bin),
            min_val(anc2->max_amp_bin, anc3->max_amp_bin));

         if (dbmove_cnf(-1)) goto close;
         n = 2 * sizeof(int);
         dbget_cnf(BLOCK_PROFILE_INDEX, (char *) iblkprf, &n,
                        "getting block and profile indices");
         printf("%2d %4d  %2d\n", iblkprf[0], iblkprf[1], min_MAB);
         if (error_found(update_db(anc2, min_MAB), "updating database"))
            goto close;
      }

      /*--------------------------------------------------------
          ROTATE ARRAY POINTERS TO LOOK AT NEXT GROUP OF THREE
        --------------------------------------------------------*/
      temp = anc1;
      anc1 = anc2;
      anc2 = anc3;
      anc3 = temp;

   } while (ierr != SEARCH_BEYOND_END);

   /*------------------------------------------------------------
       LAST PROFILE IS UPDATED USING DATA FOR LAST TWO PROFILES
     ------------------------------------------------------------*/
   min_MAB = min_val(anc1->max_amp_bin,anc2->max_amp_bin);

   error_found(update_db(anc2, min_MAB), "updating database");

close:
   dbclose_cnf();
   return(0);
}

#if PROTOTYPE_ALLOWED
int update_db(ANCILLARY_2_TYPE *anc, int min_MAB)
#else
int update_db(anc, min_MAB)
ANCILLARY_2_TYPE *anc;
int min_MAB;
#endif
{
   unsigned int n;
   int lgb;

   if (anc->last_good_bin == -1) /* profile is flagged bad; don't change it */
      return(0);

   if (min_MAB == MAXSHORT)
   {
      n = sizeof(CONFIGURATION_1_TYPE);
      dbget_cnf(CONFIGURATION_1, (char *) &config, &n, "getting configuration");
      lgb = config.num_bins;
   }
   else
   {
      lgb = (int) floor( 0.85 * min_MAB );
   }

   if (anc->last_good_bin != lgb)
   {
      anc->last_good_bin = lgb;
      n = sizeof(ANCILLARY_2_TYPE);
      if (dbput_cnf(ANCILLARY_2, (char *) anc, &n, "storing ancillary data"))
         return(1);
      if (error_found(update_acc_var(anc->last_good_bin),
         "updating access variables")) return(1);
      if (error_found(set_block_dpmask(BOTTOM_MGB),
         "setting data processing mask")) return(1);
   }
   return(0);
}

#if PROTOTYPE_ALLOWED

int alloc_structs(void)
#else
int alloc_structs()
#endif
{
   if (((anc1 = (ANCILLARY_2_TYPE *) malloc(sizeof(ANCILLARY_2_TYPE))) == NULL)
      || ((anc2 = (ANCILLARY_2_TYPE *) malloc(sizeof(ANCILLARY_2_TYPE))) == NULL)
      || ((anc3 = (ANCILLARY_2_TYPE *) malloc(sizeof(ANCILLARY_2_TYPE))) == NULL))
      return(1);
   return(0);
}

