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

   PUTNAV.C

   This is part of the ADCP navigation processing system.
   It takes a file with the final estimate of position and
   ship velocity for each profile, specified by time, and
   puts that information into the database.  Latitude and
   longitude go into the directory, and ship's velocity goes
   in the ACCESS_VARIABLES structure.  The data processing
   mask is set to indicate the navigation source.

   started Wed  09-07-1988

   Eric Firing

Sat  12-03-1988  EF
   Corrected handling of BADFLOAT data in the input file, so
   that it causes the access.U_ship_absolute etc. to be set
   to BADFLOAT, and position.degree to BADSHORT.

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

Control file structure:

dbname: [database name]
position_file: [file name]
year_base=  [year base for decimal days]
tolerance=  [seconds of discrepancy allowed between pos file time and db time]
navigation_sources:
   [source1] .... [source n]
      {where the sources are taken from the list:
         gps  transit  loran  omega  radar}
   end

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

#include <math.h>
#include "geninc.h"
#include "data_id.h"
#include "ioserv.h"  /* PARAMETER_LIST_ENTRY_TYPE, OPTION_TYPE, ... */
#include "use_db.h"  /* check_db*() */
#include "adcp.h"
#include "dpmask.h"

#define s_per_day 86400L
#define min_per_day 1440

ULONG nav_source = 0L;

/* 1999/08/04 Pierre Jaccard
   First pluggin for reading navigation from output of getnav
   Definition of NAV_SOURCE_POSITION and new option list
*/
#ifdef USE_GFI_PUTNAV
#define gfiplug_putnav_from_getnav_1
#include "../../gfi/src/plugs/putnav.c"
#undef  gfiplug_putnav_from_getnav_1
#else

static OPTION_TYPE nav_source_options[] =
{
   {"end"         , 0                  , NULL         , NULL},
   {"gps"         , NAV_SOURCE_GPS     , set_long_bit , (char *)&nav_source},
   {"transit"     , NAV_SOURCE_TRANSIT , set_long_bit , (char *)&nav_source},
   {"loran"       , NAV_SOURCE_LORAN   , set_long_bit , (char *)&nav_source},
   {"omega"       , NAV_SOURCE_OMEGA   , set_long_bit , (char *)&nav_source},
   {"radar"       , NAV_SOURCE_RADAR   , set_long_bit , (char *)&nav_source},
   {NULL          , 0                  , NULL         , NULL}
};

#endif /* gfiplug_putnav_from_getnav_1 */

#if PROTOTYPE_ALLOWED
void do_it(FILE *fp_cnt)
#else
void do_it(fp_cnt)
FILE *fp_cnt;
#endif
{
   char buf[120];
   FILE *fp_pos;
   ULONG nav_bit_mask;
   struct {
      double t, ref_u, ref_v, ship_u, ship_v, lon, lat, filt_fract;
   } nav;
   LONG hun_lon, hun_lat;
   YMDHMS_TIME_TYPE search_time, profile_time;
   DMSH_POSITION_TYPE position[2];
   ACCESS_VARIABLES_TYPE access;
   ULONG dpmask = 0;
   static double tdif, tolerance;

   unsigned int pt_size = sizeof(YMDHMS_TIME_TYPE);
   unsigned int access_size = sizeof(ACCESS_VARIABLES_TYPE);
   unsigned int dpmask_size = sizeof(ULONG);
   unsigned int pos_size = sizeof(DMSH_POSITION_TYPE) * 2;

   /* data types for DBGET and DBPUT */
   int time_type = TIME;
   int dpmask_type = DATA_PROC_MASK;
   int access_type = ACCESS_VARIABLES;
   int position_type = POSITION;

   int search_mode = TIME_SEARCH;
   int ierr = 0;

   int found;
   int IERR = 0, STEP = 1;    /* for DBMOVE */

   static FILE_NAME_TYPE dbname, posfilename;
   static int year_base;

   static PARAMETER_LIST_ENTRY_TYPE putnav_params[] =
   {
      {" dbname:"             , " %79s"  , dbname        , TYPE_STRING},
      {" position_file:"      , " %79s"  , posfilename   , TYPE_STRING},
      {" year_base="          , " %d"    , &year_base    , TYPE_INT},
      {" tolerance="          , " %lf"   , &tolerance    , TYPE_DOUBLE},
      {" navigation_sources:" , NULL     , NULL          , 0},
      {NULL                   , NULL     , NULL          , 0}
   };

   check_error(get_parameters(fp_cnt, putnav_params, NULL),
                        "getting putnav parameters");

   tolerance /= s_per_day;  /* convert from seconds to decimal days */

   check_dbopen(1, dbname, READ_WRITE, DIR_IN_MEMORY);
   printf("\n\n DATABASE:  %s SUCCESSFULLY OPENED", dbname);

   fp_pos = check_fopen(posfilename, "r");

   if (execute_options(fp_cnt, nav_source_options, ECHO) <= 0) exit(-1);

   /* Build a mask with 0 for each possible nav source, 1
      elsewhere. When ANDed with the data processing mask,
      it will turn off all nav source bits, and leave the
      rest alone.
   */
      nav_bit_mask = ~0L & ~(1L<<NAV_SOURCE_GPS)
                         & ~(1L<<NAV_SOURCE_TRANSIT)
                         & ~(1L<<NAV_SOURCE_LORAN)
                         & ~(1L<<NAV_SOURCE_RADAR)
                         & ~(1L<<NAV_SOURCE_OMEGA);

   /* (Perhaps sscanf should be checked separately.) */

/* 1999/08/04 Pierre Jaccard
   Second pluggin for reading navigation from output of getnav
   The original loop and scanning had to be a little modified
*/
#ifdef USE_GFI_PUTNAV
#define gfiplug_putnav_from_getnav_2
#include "../../gfi/src/plugs/putnav.c"
#undef  gfiplug_putnav_from_getnav_2
#else


   while ( IERR == 0 && getline_nc(fp_pos, buf, 120) != EOF  &&
      sscanf(buf, " %lf  %lf %lf %lf %lf %lf %lf %lf",
                       &nav.t, &nav.ref_u, &nav.ref_v,
                       &nav.ship_u, &nav.ship_v, &nav.lon, &nav.lat,
                       &nav.filt_fract) == 8)
   {
#endif /* gfiplug_putnav_from_getnav_2 */

      /* Search the db by time, using a time 10 seconds before
         the time read from the file, to guard against truncation
         error.  Then make sure the profile found has a time
         close to the time from the file.
      */
      yd_to_ymdhms_time(nav.t-tolerance, year_base, &search_time);

      DBGET(&time_type, (char *)&profile_time, &pt_size, &ierr);
      if (error_found(ierr, "DBGET time")) goto close_all;
      tdif = nav.t - year_day(&profile_time, year_base);
      if (fabs(tdif) <= tolerance)
         found = 1;   /* proceed */
      else            /* look for it */
      {
         ierr = 0;  /* This is a temporary fix for a CODAS bug */
         DBSRCH(&search_mode, (char *) &search_time, &ierr);
         printf("\n  STARTING FROM : ");
         write_ymdhms_time(stdout, &search_time);

         switch (ierr)
         {
            case 0:
               DBGET(&time_type, (char *)&profile_time, &pt_size, &ierr);
               if (error_found(ierr, "DBGET time")) goto close_all;
               tdif = nav.t - year_day(&profile_time, year_base);
               if (fabs(tdif) > tolerance)
               {
                  puts("\nprofile time ");
                  write_ymdhms_time(stdout, &profile_time);
                  printf(" does not agree with\ntarget time %f\n", nav.t);
                  found = 0;
               }
               else
                  found = 1;
               break;
            case SEARCH_BEFORE_BEGINNING:
               printf("\nWarning: search before beginning.\n");
               found = 0;
               break;
            case SEARCH_BEYOND_END:
               printf("\nError: search beyond end.\n");
               goto close_all;
            default:
               if (error_found(ierr,"DBSRCH"))  goto close_all;
               break;
         }
      }

      if (found == 1)
      {

         /* If we got to here, we are ready to convert the ship
            velocity and position into the appropriate forms, and
            store them.  In case of input flagged bad, it is
            assumed that all the velocities in the input
            file will be BADFLOAT, so no special provision
            has to be made to flag the access variables
            accordingly.  Position does have to be handled
            explicitly, however.
         */
         if (nav.ref_u >= ADJ_BADFLOAT)
         {
            printf("\n   BAD DATA AT TIME : %f  ",nav.t);
            position[0].degree = BADSHORT;
            position[1].degree = BADSHORT;
         }
         else
         {
            hun_lon = (long) (nav.lon * 360000.0);
            hun_lat = (long) (nav.lat * 360000.0);
            HUNPOS(  position,      &hun_lon);
            HUNPOS( (position + 1), &hun_lat);
         }

         DBPUT(&position_type, (char *)position, &pos_size, &ierr);
         if (error_found(ierr, "DBPUT position")) goto close_all;

         DBGET(&access_type, (char *)&access, &access_size, &ierr);
         if (error_found(ierr, "DBGET access variables")) goto close_all;

         access.U_ship_absolute = (float) nav.ship_u;
         access.V_ship_absolute = (float) nav.ship_v;
         DBPUT(&access_type, (char *)&access, &access_size, &ierr);
         if (error_found(ierr, "DBPUT access variables")) goto close_all;

         /* Now the data processing mask has to be set.  This is really
            needed only once per block, but it is easier to do it every
            time than to keep checking for new blocks.
         */
         DBGET(&dpmask_type, (char *)&dpmask, &dpmask_size, &ierr);
         if (error_found(ierr, "DBGET dpmask")) goto close_all;

         dpmask &= nav_bit_mask;     /* reset all nav bits */
         dpmask |= nav_source;       /* set the correct ones */
         dpmask |= (1L<<POSITIONS_OPTIMIZED);

         DBPUT(&dpmask_type, (char *)&dpmask, &dpmask_size, &ierr);
         if (error_found(ierr, "DBPUT dpmask")) goto close_all;
      }
      IERR = 0;
      DBMOVE(&STEP, &IERR);
   }

   close_all:
   DBCLOSE(&ierr);
   check_error(ierr, "DBCLOSE");
   fclose(fp_pos);
   return;
}

