/****************************************************************************/
/* Copyright (c) 2004 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : reson.cc                                                  */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 04/02/2004                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/

#include "unix.h"
#include "reson.h"
#include "Reson6046IF.h"
#include "BooleanAttribute.h"
#include "IntegerAttribute.h"
#include "FloatAttribute.h"
#include "StringAttribute.h"
#include "VerticalModeAttribute.h"
#include "MissionTimeAttribute.h"
#include "MathP.h"
#include "Syslog.h"

#define DEFAULT_STRING_ATTR "\"\""
#define NotSpecified -100000.0

reson::reson()
  : _server(NULL), Behavior(ResonBehaviorName, Sequential)
{
  _sbpDone = False;
  _lossDone = False;
  _hissDone = False;
  _logDone = False;
  _pulseDone = False;
  _init = False;

  Boolean debug = False;

  // Sub-bottom attributes
  attributes.add(new IntegerAttribute("SBP_Mode",
                                      "Sub-bottom profiler on/off (1=On,0=Off)",
				    &_sbpMode, -1));
  attributes.add(new FloatAttribute("SBP_Power", 
                                    "Sub-bottom power level (0.0 or more)",
				    &_sbpPower, -1.));
  attributes.add(new FloatAttribute("SBP_Gain", 
                                    "Sub-bottom receiver gain (0.0 or more)",
				    &_sbpGain, -1.));
  attributes.add(new FloatAttribute("SBP_Duration", 
                                    "Sub-bottom ping duration in milliseconds (more than 0.0)",
				    &_sbpDuration, -1.));

  // Low-freq sidescan attributes
  attributes.add(new IntegerAttribute("LoSS_Mode", 
                                      "Low-freq sidescan on/off (1=On,0=Off)",
				    &_lossMode, -1));
  attributes.add(new FloatAttribute("LoSS_Power",
                                    "Low-freq power level (0.0 or more)",
				    &_lossPower, -1.));
  attributes.add(new FloatAttribute("LoSS_Range",
                                    "Low-freq range (0.0 or more)",
				    &_lossRange, -1.));
  attributes.add(new FloatAttribute("LoSS_Rate",
                                    "Low-freq ping rate (0.0 or more)",
				    &_lossRate, -1.));

  // High-freq sidescan attributes
  attributes.add(new IntegerAttribute("HiSS_Mode",
                                      "High-freq sidescan on/off (1=On,0=Off)",
				    &_hissMode, -1));
  attributes.add(new FloatAttribute("HiSS_Power",
                                    "High-freq power level (0.0 or more)",
				    &_hissPower, -1.));
  attributes.add(new FloatAttribute("HiSS_Range",
                                    "High-freq range (0.0 or more)",
				    &_hissRange, -1.));
  attributes.add(new FloatAttribute("HiSS_Rate",
                                    "High-freq ping rate (0.0 or more)",
				    &_hissRate, -1.));

  // Multibeam attributes
  attributes.add(new IntegerAttribute("MB_Mode",
                                      "Multibeam pinging on/off (1=On,0=Off)",
  				    &_mbMode, -1));

  char soundvelstr[200];
  sprintf(soundvelstr, "%s\n%s\n%s\n%s",
       "Multibeam sound velocity setting in meters/sec",
       "  Value < 0.0 -> do nothing",
       "  Value = 0.0 -> Set sound velocity by CTD",
       "  Value > 0.0 -> Set sound velocity to the value of MB_Sound_Velocity");
  attributes.add(new FloatAttribute("MB_Sound_Velocity",
                                    soundvelstr,
                                    &_mbSoundVelocity, -1.));

  attributes.add(new FloatAttribute("MB_Power",
                                    "Multibeam power level in dB/uPa (0.0 or more)",
				    &_mbPower, -1.));
  attributes.add(new FloatAttribute("MB_Range",
                                    "Multibeam range in meters (0.0 or more)",
				    &_mbRange, -1.));
  attributes.add(new FloatAttribute("MB_Rate",
                                    "Multibeam pings per second (> 0.0)",
				    &_mbRate, -1.));
  attributes.add(new FloatAttribute("MB_Gain",
                                    "Multibeam receiver gain in dB (0.0 or more)",
				    &_mbGain, -1.));
  attributes.add(new FloatAttribute("MB_Pulse_Width",
                                    "Multibeam pulse width in seconds (0.0 or more)",
				    &_mbWidth, -1.));
  attributes.add(new FloatAttribute("MB_Bottom_Detect_Filter_Min_Range",
                                    "Multibeam bottom detection filter: minimum range (0.0 or more). Specifiy all filters.",
				    &_mbBtmMinRange, -1.));
  attributes.add(new FloatAttribute("MB_Bottom_Detect_Filter_Max_Range",
                                    "Multibeam bottom detection filter: maximum range (0.0 or more). Specifiy all filters.",
				    &_mbBtmMaxRange, -1.));
  attributes.add(new FloatAttribute("MB_Bottom_Detect_Filter_Min_Depth",
                                    "Multibeam bottom detection filter: minimum depth (0.0 or more). Specifiy all filters.",
				    &_mbBtmMinDepth, -1.));
  attributes.add(new FloatAttribute("MB_Bottom_Detect_Filter_Max_Depth",
                                    "Multibeam bottom detection filter: maximum depth (0.0 or more). Specifiy all filters.",
				    &_mbBtmMaxDepth, -1.));
  attributes.add(new IntegerAttribute("MB_Bottom_Detect_Range_Mode",
                                      "Bottom detection by range on/off (1=On,0=Off), use in tandem with MB_Bottom_Depth_Mode",
				    &_rangeMode, -1));
  attributes.add(new IntegerAttribute("MB_Bottom_Detect_Range_Recalculation",
                                      "Bottom detection range recalc command (1=Recalc now), not a switch, no need to turn it off",
				    &_mbBtmRecalc, -1));
  attributes.add(new IntegerAttribute("MB_Bottom_Detect_Range_Recalculation_Interval",
                                      "Bottom detection range recalc interval in seconds (0=Never)",
				    &_mbBtmRecalcInt, -1));
  attributes.add(new IntegerAttribute("MB_Bottom_Detect_Depth_Mode",
                                      "Bottom detection by depth on/off (1=On,0=Off), use in tandem with MB_Bottom_Range_Mode",
				    &_depthMode, -1));
  attributes.add(new IntegerAttribute("Snippet_Mode",
                                      "Enable/Disable Snippet Control. Use in conjunction with Window_Size.",
				    &_snippetMode, -1));
  attributes.add(new IntegerAttribute("Window_Size",
                                      "Number of samples around bottom detection for each beam to snippet",
				    &_windowSize, -1));


  attributes.add(new IntegerAttribute("Log_Mode",
                                      "Logging on/off (1=On,0=Off)",
				    &_logMode, -1));

  attributes.add(new StringAttribute("subsys",
				     "Subsystem that will use the new pulse file (LoSS | HiSS | SBP)",
				     &_subsys, DEFAULT_STRING_ATTR));
  attributes.add(new StringAttribute("pulseFile",
				     "New pulse file name",
				     &_filename, DEFAULT_STRING_ATTR));
  try
  {
     if( !_reson) _reson = new Reson6046IF(Reson6046IFServerName);
  }
  catch (SharedObjectClient::MissingServer e) 
  {
     Syslog::write("reson::reson() - Missing server: %s; "
		   "continuing.\n",
		   e.msg);
     _reson = NULL;
  }

}

reson::~reson()
{
   if( !_reson) 
   {
      delete _reson;
      _reson = NULL;
   }
}


Boolean reson::shouldBehaviorStart( void ) 
{
     return bothSequence();
}

void reson::execute()
{
  DeviceIF::Status status;
  Boolean debug = True;

  _logDone  = (_logMode < 0);
  _sbpDone  = (_sbpMode < 0 && _sbpPower < 0. && _sbpGain < 0. && _sbpDuration < 0.);
  _hissDone = (_hissMode < 0 && _hissPower < 0. && _hissRate < 0. && _hissRange < 0.);
  _lossDone = (_lossMode < 0 && _lossPower < 0. && _lossRate < 0. && _lossRange < 0.);

  _mbDone = (_mbMode < 0 && _mbPower < 0. && _mbRate < 0. && _mbRange < 0. &&
       _mbSoundVelocity < 0. &&
	     _mbGain < 0. && _mbWidth < 0 &&
	     _mbBtmMinRange < 0. && _mbBtmMaxRange < 0. &&
	     _mbBtmMinDepth < 0. && _mbBtmMaxDepth < 0. &&
       _mbBtmRecalc < 0 && _mbBtmRecalcInt < 0 && 
       _rangeMode < 0 && _depthMode < 0 && _snippetMode < 0 && _windowSize < 0);

  _pulseDone = (strcmp(_subsys, DEFAULT_STRING_ATTR) == 0) ||
               (strcmp(_filename, DEFAULT_STRING_ATTR) == 0);

  Syslog::write("Reson Behavior::log=%d,sbp=%d,%f | hiss=%d,%f,%f,%f | loss=%d,%f,%f,%f | mb=%d,%f,%f,%f,%f,%f,%f | pulse=%s,%s",
                _logMode,_sbpMode,_sbpPower,
		_hissMode,_hissPower,_hissRate,_hissRange,
                _lossMode,_lossPower,_lossRate,_lossRange,
                _mbMode,_mbPower,_mbRate,_mbRange,_mbGain,_mbWidth,_mbSoundVelocity,
		_subsys,_filename);

// Interface to Reson server opened in LayeredControl
//
  _server = _reson;
  
  // Perform the sub-bottom action
  if (!_sbpDone)
  {
    if (_sbpPower > 0.)
    {
      Syslog::write("Reson Behavior: Setting SBP power to %f", _sbpPower);
      status = _server->setPingPower(Reson6046IF::SubBottom, _sbpPower);
      if (DeviceIF::Ok == status) _sbpPower = -1.;
    }
    if (_sbpMode > 0)
    {
      Syslog::write("Reson Behavior: Starting subbottom profiler");
      status = _server->startSubsystem(Reson6046IF::SubBottom);
      if (DeviceIF::Ok == status) _sbpMode = -1;
    }
    else if(_sbpMode == 0)
    {
      Syslog::write("Reson Behavior: Stopping subbottom profiler");
      status = _server->stopSubsystem(Reson6046IF::SubBottom);
      if (DeviceIF::Ok == status) _sbpMode = -1;
    }
    if (_sbpGain > 0.)
    {
      Syslog::write("Reson Behavior: Setting SBP gain to %f", _sbpGain);
      status = _server->setSBPGain(_sbpGain);
      if (DeviceIF::Ok == status) _sbpGain = -1.;
    }
    if (_sbpDuration > 0.)
    {
      Syslog::write("Reson Behavior: Setting SBP duration to %f", _sbpDuration);
      status = _server->setSBPDuration(_sbpDuration);
      if (DeviceIF::Ok == status) _sbpDuration = -1.;
    }
  }

  // Perform the low freq sidescan action
  if (!_lossDone)
  {
    if (_lossPower > 0.)
    {
      Syslog::write("Reson Behavior: Setting SSLo power to %f",_lossPower);
      status = _server->setPingPower(Reson6046IF::SideScanLow, _lossPower);
      if (DeviceIF::Ok == status) _lossPower = -1.;
    }

    if (_lossRange > 0.)
    {
      Syslog::write("Reson Behavior: Setting SSLo range to %f",_lossRange);
      status = _server->setPingRange(Reson6046IF::SideScanLow, _lossRange);
      if (DeviceIF::Ok == status) _lossRange = -1.;
    }

    if (_lossRate > 0.)
    {
      Syslog::write("Reson Behavior: Setting SSLo rate to %f",_lossRate);
      status = _server->setPingRate(Reson6046IF::SideScanLow, _lossRate);
      if (DeviceIF::Ok == status) _lossRate = -1.;
    }

    if (_lossMode > 0)
    {
      Syslog::write("Reson Behavior: Starting lo-freq SS");
      status = _server->startSubsystem(Reson6046IF::SideScanLow);
      if (DeviceIF::Ok == status) _lossMode = -1;

    }
    else if (_lossMode == 0)
    {
      Syslog::write("Reson Behavior: Stopping lo-freq SS");
      status = _server->stopSubsystem(Reson6046IF::SideScanLow);
      if (DeviceIF::Ok == status) _lossMode = -1;
    }
  }

  // Perform the high freq sidescan action
  if (!_hissDone)
  {
    if (_hissPower > 0.)
    {
      Syslog::write("Reson Behavior: Setting SSHi power to %f",_hissPower);
      status = _server->setPingPower(Reson6046IF::SideScanHigh, _hissPower);
      if (DeviceIF::Ok == status) _hissPower = -1.;
    }

    if (_hissRange > 0.)
    {
      Syslog::write("Reson Behavior: Setting SSHi range to %f",_hissRange);
      status = _server->setPingRange(Reson6046IF::SideScanHigh, _hissRange);
      if (DeviceIF::Ok == status) _hissRange = -1.;
    }

    if (_hissRate > 0.)
    {
      Syslog::write("Reson Behavior: Setting SSHi rate to %f",_hissRate);
      status = _server->setPingRate(Reson6046IF::SideScanHigh, _hissRate);
      if (DeviceIF::Ok == status) _hissRate = -1.;
    }

    if (_hissMode > 0)
    {
      Syslog::write("Reson Behavior: Starting hi-freq SS");
      status = _server->startSubsystem(Reson6046IF::SideScanHigh);
      if (DeviceIF::Ok == status) _hissMode = -1;
    }
    else if (_hissMode == 0)
    {
      Syslog::write("Reson Behavior: Stopping hi-freq SS");
      status = _server->stopSubsystem(Reson6046IF::SideScanHigh);
      if (DeviceIF::Ok == status) _hissMode = -1;
    }
  }

  // Perform the Multibeam actions
  if (!_mbDone)
  {
    if (_mbSoundVelocity > 0.)
    {
      // Set sound velocity to the value in _mbSoundVelocity
      //
      Syslog::write("Reson Behavior: Setting MB sound velocity to %f", _mbSoundVelocity);
    }
    else if (_mbSoundVelocity == 0.)
    {
      // Have reson process reset the sound velocity by getting the value from
      // the CTD
      //
      Syslog::write("Reson Behavior: Tell Multibeam to set MB sound velocity");
    }
    status = _server->setMBSoundVelocity(_mbSoundVelocity);
    if (DeviceIF::Ok == status) _mbSoundVelocity = -1.;

    if (_mbPower >= 0.)
    {
      Syslog::write("Reson Behavior: Setting MB power to %f",_mbPower);
      status = _server->setPingPower(Reson6046IF::Multibeam, _mbPower);
      if (DeviceIF::Ok == status) _mbPower = -1.;
    }

    if (_mbRange >= 0.)
    {
      Syslog::write("Reson Behavior: Setting MB range to %f",_mbRange);
      status = _server->setPingRange(Reson6046IF::Multibeam, _mbRange);
      if (DeviceIF::Ok == status) _mbRange = -1.;
    }

    if (_mbRate > 0.)  // Must be > 0.0
    {
      Syslog::write("Reson Behavior: Setting MB rate to %f",_mbRate);
      status = _server->setPingRate(Reson6046IF::Multibeam, _mbRate);
      if (DeviceIF::Ok == status) _mbRate = -1.;
    }

    if (_mbGain >= 0.)
    {
      Syslog::write("Reson Behavior: Setting MB gain to %f",_mbGain);
      status = _server->setRxGain(Reson6046IF::Multibeam, _mbGain);
      if (DeviceIF::Ok == status) _mbGain = -1.;
    }

    if (_mbWidth >= 0.)
    {
      Syslog::write("Reson Behavior: Setting MB pulse width to %f", _mbWidth);
      status = _server->setPulseWidth(Reson6046IF::Multibeam, _mbWidth);
      if (DeviceIF::Ok == status) _mbWidth = -1.;
    }

    if (_mbBtmMinRange >= 0. && _mbBtmMaxRange >= 0. &&
	_mbBtmMinDepth >= 0. && _mbBtmMaxDepth >= 0.)
    {
      Syslog::write("Reson Behavior: Setting MB Bottom detection filter %f:%f:%f:%f",
		    _mbBtmMinRange, _mbBtmMaxRange, _mbBtmMinDepth, _mbBtmMaxDepth);
      status = _server->setMBBottomDetectionFilters(_mbBtmMinRange, _mbBtmMaxRange,
						    _mbBtmMinDepth, _mbBtmMaxDepth);
      if (DeviceIF::Ok == status) _mbBtmMinRange = _mbBtmMaxRange =
				  _mbBtmMinDepth = _mbBtmMaxDepth = -1.;
    }
    
    if (_snippetMode > -1)
    {
      Syslog::write("Reson Behavior: Turning on snippet control - window size = %d", _windowSize);
      status = _server->setMBSnippetControl((_snippetMode > 0), _windowSize);
      if (DeviceIF::Ok == status) _snippetMode = -1;
    }

    // If either depth or range mode switches are specified, invoke server method
    if (_depthMode >= 0 || _rangeMode >= 0)
    {
      Syslog::write("Reson Behavior: Turning on bottom detection modes: %d, %d", _depthMode, _rangeMode);
      status = _server->setMBBottomDetectDepthRangeOn((_depthMode > 0), (_rangeMode > 0));
      if (DeviceIF::Ok == status) _depthMode = _rangeMode = -1;
    }

    // If bottom detection params recalc command is set, invoke server method
    if (_mbBtmRecalc > 0)
    {
      Syslog::write("Reson Behavior: Recalculating bottom detection ranges: %d",
                    _mbBtmRecalc);
      status = _server->setMBBottomDetectRecalc();
      if (DeviceIF::Ok == status) _mbBtmRecalc = -1;
    }

    // If bottom detection params recalc interval is set, invoke server method
    if (_mbBtmRecalcInt >= 0)
    {
      Syslog::write("Reson Behavior: Setting recalculation interval: %d",
                    _mbBtmRecalcInt);
      status = _server->setMBBottomDetectRecalcInterval(_mbBtmRecalcInt);
      if (DeviceIF::Ok == status) _mbBtmRecalcInt = -1;
    }

    if (_mbMode > 0)
    {
      Syslog::write("Reson Behavior: Starting MB pinging");
      status = _server->startSubsystem(Reson6046IF::Multibeam);
      if (DeviceIF::Ok == status) _mbMode = -1;
    }
    else if (_mbMode == 0)
    {
      Syslog::write("Reson Behavior: Stopping MB pinging");
      status = _server->stopSubsystem(Reson6046IF::Multibeam);
      if (DeviceIF::Ok == status) _mbMode = -1;
    }

  }

  // Perform the logging action
  if (!_logDone)
  {
    unsigned char errorCnt = 0;
    if (_logMode  & 0x01)
    {
      Syslog::write("Reson Behavior: Starting logging");
      status = _server->startLogging();
      if (DeviceIF::Ok != status) errorCnt++;
    }
    else
    {
      Syslog::write("Reson Behavior: Stopping logging");
      status = _server->stopLogging();
      if (DeviceIF::Ok != status) errorCnt++;
    }

    if (_logMode & 0x02)
    {
      Syslog::write("Reson Behavior: Starting 7k Center Logging");
      status = _server->start7KCenterLogging();
      if (DeviceIF::Ok != status) errorCnt++;
    }
    else
    {
      Syslog::write("Reson Behavior: Stopping 7k Center Logging");
      status = _server->stop7KCenterLogging();
      if (DeviceIF::Ok != status) errorCnt++;
    }

    if (errorCnt == 0) {
	_logMode = -1;
	_logDone = True;
    }

  }

  if (!_pulseDone)
  {
    Reson6046IF::ResonSonarSystems subsystem = Reson6046IF::PLC;  // Invalid for this cmd

    if (!strcasecmp(_subsys,"SBP")) subsystem = Reson6046IF::SubBottom;
    else if (!strcasecmp(_subsys,"LoSS")) subsystem = Reson6046IF::SideScanLow;
    else if (!strcasecmp(_subsys,"HiSS")) subsystem = Reson6046IF::SideScanHigh;
    
    if (subsystem == Reson6046IF::PLC)
    {
      _pulseDone = True;
      Syslog::write("Reson Behavior: Invalid subsystem (%s) specified for pulse file change", _subsys);
    }
    else
    {
      Syslog::write("Reson Behavior: Setting pulse filename for %d to %s", 
                     subsystem, _filename);
      status = _server->setPulseFilename(subsystem, _filename);
      if (DeviceIF::Ok == status) _pulseDone = True;
    }
  }

  // Finished if all actions performed successfully
  if (_sbpDone && _logDone && _lossDone && _hissDone && _pulseDone)
    setState(Finished);

  return;
}


Boolean reson::validInput()
{
  Boolean valid = True;

  return valid;
}

