/*****************************************************************************
 * Copyright (c) 2002-2020 MBARI
 * Monterey Bay Aquarium Research Institute, all rights reserved.
 *****************************************************************************
 * @file    deltaTTest.cc
 * @authors r. henthorn
 * @date    07/23/2020
 * @brief   Test program for DeltaT class
 *
 * Project: LRAUV Obstacle Avoidance (oahu)
 * Summary: See @brief
 *****************************************************************************/
/*****************************************************************************
 * Copyright Information:
 * Copyright 2002-2020 MBARI
 * Monterey Bay Aquarium Research Institute, all rights reserved.
 *
 * Terms of Use:
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option)
 * any later version. You can access the GPLv3 license at
 * http://www.gnu.org/licenses/gpl-3.0.html
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details (http://www.gnu.org/licenses/gpl-3.0.html).
 *
 * MBARI provides the documentation and software code "as is", with no
 * warranty, express or implied, as to the software, title, non-infringement
 * of third party rights, merchantability, or fitness for any particular
 * purpose, the accuracy of the code, or the performance or results which you
 * may obtain from its use. You assume the entire risk associated with use of
 * the code, and you agree to be responsible for the entire cost of repair or
 * servicing of the program with which you are using the code.
 *
 * In no event shall MBARI be liable for any damages,whether general, special,
 * incidental or consequential damages, arising out of your use of the
 * software, including, but not limited to,the loss or corruption of your data
 * or damages of any kind resulting from use of the software, any prohibited
 * use, or your inability to use the software. You agree to defend, indemnify
 * and hold harmless MBARI and its officers, directors, and employees against
 * any claim,loss,liability or expense,including attorneys' fees,resulting from
 * loss of or damage to property or the injury to or death of any person
 * arising out of the use of the software.
 *
 * The MBARI software is provided without obligation on the part of the
 * Monterey Bay Aquarium Research Institute to assist in its use, correction,
 * modification, or enhancement.
 *
 * MBARI assumes no responsibility or liability for any third party and/or
 * commercial software required for the database or applications. Licensee
 * agrees to obtain and maintain valid licenses for any additional third party
 * software required.
 *****************************************************************************/

/******************************
 * Headers
 ******************************/

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <getopt.h>
#include <libgen.h>
#include <sys/stat.h>

#ifdef USE_LCM
#include <lcm/lcm-cpp.hpp>
#include "TethysLcmTypes/LrauvLcmMessage.hpp"
#include "LcmMessageReader.h"
#include "LcmDeltaT.h"
#endif

#include "DeltaT.h"
#include "DeltaTLog.h"
#include "macrologger_main.h"
#include "oaUtils.h"
#include "iniparser.h"

/******************************
 * Macros
 ******************************/

#define DEFAULT_PORT   4040
#define DEFAULT_NAME   "deltat"
#define DEFAULT_TRACE  DEBUG_LEVEL
#define SYSLOG_NAME    "syslog.idt"
#define LOG_ENV_VAR    "AUV_LOG_DIR"

/******************************
 * Code
 ******************************/

// parse command line options. fill-out options object. return true if all good.
bool parseOptions(int argc, char const *argv[]);

// configure the DeltaT object as per a config file
void configDeltaT(DeltaT *d, const char* cfgfile);

// explain app usage to user.
void usage();

// command line options
static struct option long_options[] =
{
    {"port",    required_argument, NULL, 'p'},   // DeltaT port (DEFAULT_PORT)
    {"filename",required_argument, NULL, 'f'},   // DeltaT data file name (NULL)
    {"cfg"     ,required_argument, NULL, 'c'},   // DeltaT config file name (NULL)
    {"name",    required_argument, NULL, 'n'},   // DeltaT name (DEFAULT_NAME)
    {"trace",   required_argument, NULL, 't'},   // Trace level (DEFAULT_TRACE)
    {"syslog",  no_argument      , NULL, 's'},   // syslogging to file (false)
    {"log",     no_argument      , NULL, 'l'},   // Log delta t data? (false)
    {"verbose", no_argument      , NULL, 'v'},   // DEBUG to stderr (false)
    {"help",    no_argument      , NULL, '?'},   // print usage
    {NULL, 0, NULL, 0}
};

// hold onto the command line options
static struct long_options
{
    uint32_t port;
    char*    filename;
    char*    cfg;
    char*    name;
    char     trace;
    bool     syslog;  // syslogging is true if syslog non-NULL
    bool     log;
    bool     verbose;
} options;

// deltaTTest main
// read, parse, and optionally log packets from an imagenex delta t
int main(int argc, char const *argv[])
{
   // get options
   if (!parseOptions(argc, argv))
   {
      usage();
      exit(0);
   }

   // setup AUV_LOG_DIR using setenv() for use by other components
   if (options.log) setLogDir(LOG_ENV_VAR, getenv(LOG_ENV_VAR));

   // open optional syslogging FILE
   if (options.syslog)
   {
      // create the path to the syslog file
      const char* ald = getenv(LOG_ENV_VAR);
      if (NULL == ald) ald = ".";
      char* syslogfile = (char*)malloc(strlen(ald)+strlen(SYSLOG_NAME)+2);
      sprintf(syslogfile, "%s/%s", ald, SYSLOG_NAME);

      // open the syslog
      if (NULL == openMLOutstream(syslogfile))
      {
         LOG_ERROR("deltaTTest: could not open syslogging file %s", syslogfile);
      }
      free(syslogfile);
   }

   if (MLOUTSTREAM) LOG_INFO("There is an output file");

   LOG_INFO("deltaTTest: name=%s, port=%d, trace=%0x, log=%s, verbose=%s "
            "data=%s, cfg=%s",
          options.name, options.port, options.trace,
          options.log?"yes":"no", options.verbose?"yes":"no",
          options.filename, options.cfg);

   /* code */
   setMLLevel(options.trace);
   setMLVerbose(options.verbose);

   // test the dtor
   DeltaT* idt = new DeltaT("delete me", 33333, false);
   delete idt;

   ////////////////////////////////////////////////////////////////////////
   // Create DeltaT with config object
   DeltaT::DeltaTConfig config = {options.name, options.port, options.log,
                                  options.filename, 1000};
   //idt = new DeltaT(options.name, options.port, options.log);
#ifdef USE_LCM
   LOG_INFO("Using LCM");
   idt = new LcmDeltaT(config);
#else
   idt = new DeltaT(config);
#endif

   // setup DeltaT beamformer as per the idt ini file
   if (options.cfg) DeltaT::configDeltaT(idt, options.cfg);

   // if the connection is good, read and optionally log 83p data forever
   if (idt->getSock() > 0)
   {
      while (1)
      {
         //sleep(2);  // allow packets to queue up
         Idt83pData data83p;
         while (idt->getData(&data83p))   // get all the waiting packet
         {
            LOG_DEBUG(
                "\t83P pingtime:%.2f\tbeams:%d\tinterval:%d ms\trange:%.2f",
                data83p.pingtime, data83p.nbeams,
                data83p.interval, data83p.altitude);
         }
      }
   }

   delete idt;
   return 0;
}

// parse command line options. fill-out options object. return true if all good.
bool parseOptions(int argc, char const *argv[])
{
   // set the defaults first
   options.port     = DEFAULT_PORT;
   options.filename = NULL;
   options.cfg      = NULL;
   options.name     = strdup(DEFAULT_NAME);
   options.trace    = DEFAULT_TRACE;
   options.syslog   = false;
   options.log      = false;         // just trace
   options.verbose  = false;         // no debug or info output to stderr

   // now get the options
   char *trace = NULL;
   int opt = 0, long_index = 0;
   while ((opt = getopt_long(argc, (char *const *)argv, "c:f:p:n:st:lv?",
                  long_options, &long_index )) != -1)
   {
      if (opt == 'p')
      {
         options.port = abs(atoi(optarg));
      }
      else if (opt == 'f')
      {
         options.filename = strdup(optarg);
      }
      else if (opt == 'c')
      {
         options.cfg = strdup(optarg);
      }
      else if (opt == 'l')
      {
         options.log = true;
      }
      else if (opt == 'v')
      {
         options.verbose = true;
      }
      else if (opt == 'n')
      {
         options.name = strdup(optarg);
      }
      else if (opt == 's')
      {
         options.syslog = true;
      }
      else if (opt == 't')
      {
         trace = strdup(optarg);
      }
      else if (opt == '?')
      {
         return false;
      }
      else
      {
         fprintf(stderr, "Unknown option '%c'\n", opt);
         return false;
      }
   }

   // encode the trace option to a macrologger log level
   if (trace)
   {
      bool bad = false;
      if (!strcasecmp(trace, "ERROR"))
         options.trace = ERROR_LEVEL;
      else if (!strcasecmp(trace, "INFO"))
         options.trace = INFO_LEVEL;
      else if (!strcasecmp(trace, "DEBUG"))
         options.trace = DEBUG_LEVEL;
      else if (!strcasecmp(trace, "NONE"))
         options.trace = NO_LOG;
      else
         bad = true;

      delete trace;

      if (bad) return false;
   }

   // all good
   return true;
}

// explain app usage to user.
void usage()
{
   fprintf(stderr,
    "Usage:\n"
    "  deltaTTest [OPTIONS]  A test program and data logger for the DeltaT\n"
    "                        interface class\n"
    "  Options\n"
    "    -?, --help              Print this help\n"
    "    -p, --port     NUM      Use this port to get Delta T data (4040)\n"
    "    -f, --filename pathname Use this raw file for the Delta T data (no)\n"
    "    -c, --cfg      pathname Use this config file to init the beamformer\n"
    "    -n, --name     STRING   Use this name for the Delta T driver(deltat)\n"
    "    -s, --syslog            Divert syslogging to syslog.idt (no divert)\n"
    "    -l, --log               Log data to a deltatlog.log file (no log)\n"
    "    -v, --verbose           Show DEBUG and INFO messages on console (no)\n"
    "    -t, --trace    CHOICE   Use one of NONE, ERROR, INFO, DEBUG (INFO)\n\n"
    "  Example\n"
    "    deltaTTest -p 4050 -l --trace DEBUG --syslog -v --cfg deltat.cfg"
    "    # use port 4050,log 83P data,trace level DEBUG to syslog.idt only, init using deltat.cfg\n"
    ""
    "    deltaTTest -f delatlog.raw --trace DEBUG --syslog"
    "    # read data from deltatlog.raw,trace level DEBUG to syslog.idt only\n");
   return;
}

