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

#include "CARL.h"
#include "BooleanAttribute.h"
#include "IntegerAttribute.h"
#include "FloatAttribute.h"
#include "StringAttribute.h"
#include "MathP.h"
#include "Syslog.h"
#include "System.h"
#include "TimeP.h"

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

static time_t CARL::Locked = 0;

CARL::CARL()
  : Behavior(CARLBehaviorName, Sequential), _server(NULL),
  _inLightSwitch(False), _inRecorderSwitch(False),
  _inRecord(False), _inBrightness(False), _inHomeIris(False),
  _inFstop(False), _timer(-1)
{
  Boolean debug = True;

  _init = False;

  //  Recorder switch 
  attributes.add(new IntegerAttribute("recorderSwitch",
      "Recorder switch (1=On,0=Off)",
              &_recorderSwitch, -1));

  //  Camera switch 
  attributes.add(new IntegerAttribute("cameraSwitch",
      "Camera switch (1=On,0=Off)",
              &_cameraSwitch, -1));
  
  //  CTD switch 
  attributes.add(new IntegerAttribute("ctdSwitch",
                                      "CTD switch (1=On,0=Off)",
              &_ctdSwitch, -1));
  //  Light switch 
  attributes.add(new IntegerAttribute("lightSwitch",
      "Light switch (1=On,0=Off)",
              &_lightSwitch, -1));
  //  Light intensity  
  attributes.add(new IntegerAttribute("brightness",
                                      " (0=Lowest,100=Highest)",
				      &_brightness, -1));

  //  Record start/stop 
  attributes.add(new IntegerAttribute("record",
                                      "Record Button (1=Action!,0=Cut!)",
              &_record, -1));

  //  Home position  
  attributes.add(new IntegerAttribute("homeIris",
                                      "Home the iris motor (1=Home)",
              &_homeIris, -1));

  //  FStop position  
  attributes.add(new IntegerAttribute("fstop",
                                      "Coded FStop position: Valid values are "
                                      "31,32,33,41,42,43,561,562,563,81,82,83"
                                      "111,112,113,161,162,163,221",
              &_fstop, -1));

  //  Target light level for auto-iris function  
  attributes.add(new FloatAttribute("autoIris",
                                      "Auto Iris target light level. Valid values are "
                                      "0.0 => Off; 1.25 to 3.80 on",
              &_autoIris, -1.0));

  //  Reset clipname to current date/time 
  attributes.add(new IntegerAttribute("clipname",
      "Reset clipname to current date and time (1=On,0=Off)",
              &_clipname, -1));

   if (!Behavior::_carl)
   {
     try {
        Behavior::_carl = new CARL_IF("CARLServer");
     }
     catch (Exception e) {
       Syslog::write("CARL Behavior - %s", e.msg);
       Behavior::_carl = NULL;
     }
     catch (...) {
       Syslog::write("CARL Behavior - Exception while connecting to CARLServer");
       Behavior::_carl = NULL;
     }
   }
   _server = Behavior::_carl;

}

CARL::~CARL()
{
   if( !_server) 
   {
      delete _server;
      _server = NULL;
   }
}

void CARL::done()
{
  Syslog::write("CARL::done() - %d all done!", _id);
  setState(Finished);     // Nothing more to do
  Locked = 0;             // Reset lock to allow next CARL behavior to run

  return;  
}


Boolean CARL::shouldBehaviorStart( void ) 
{
  Boolean debug = False;

  if (bothSequence())
  {
    // This behavior can start only when the preceding CARL behavior
    // is finished and unlocks.
    //
    dprintf("CARL %d shouldBehaviorStart - Locked = %ld", _id, Locked);
    if (0 == Locked || time(NULL) > Locked)
    {
      Locked = time(NULL) + _duration;
      return True;
    }
    else
      return False;

  }
  return False;
}


void CARL::execute()
{
  DeviceIF::Status status;
  Boolean debug = False;

  dprintf("CARL - Id:%d, Duration:%f, cameraSwitch:%d, recorderSwitch:%d, "
              "lightSwitch:%d, brightness:%d, record:%d, homeIris:%d, fstop:%d, "
              "auto-iris:%.2f \n",
              _id, _duration, _cameraSwitch, _recorderSwitch, _lightSwitch,
              _brightness, _record, _homeIris, _fstop, _autoIris);

  // Set the time at which the behavior should be finished
  //
  if (_timer <= 0)
  {
    // Must be the first call to execute
    _timer = Time::milliseconds() + (_duration*1000);
    Syslog::write("CARL - Id:%d, Duration:%f, cameraSwitch:%d, recorderSwitch:%d, "
              "lightSwitch:%d, brightness:%d, record:%d, homeIris:%d, fstop:%d, "
              "auto-iris:%.2f \n",
              _id, _duration, _cameraSwitch, _recorderSwitch, _lightSwitch,
              _brightness, _record, _homeIris, _fstop, _autoIris);
  }

  if (Time::milliseconds() > _timer)
  {
    Syslog::write("CARL::execute() - CARL id %d timeout! (%ld > %ld) ", _id,
      Time::milliseconds(), _timer);
    //setState(Finished);     // Nothing more to do
    //return;
  }

  if (NULL == _server)
  {
    Syslog::write("CARL::execute() - Sorry, not connected to server");
    return;
  }

  // Anything else to do?
  //
  if (_recorderSwitch < 0     &&
      _cameraSwitch < 0       &&
      _ctdSwitch < 0          &&
      _lightSwitch < 0        &&
      _brightness < 0         &&
      _fstop < 0              &&
      _autoIris < 0.0 &&
      _homeIris < 0           &&
      _clipname < 0           &&
      _record < 0 )
  {
    done();
    return;
  }

  // Perform the actions listed in the behavior once
  //
  // camera switch
  //
  if (_cameraSwitch != -1)
  {
    // Request the switch to be set or reset
    //
    if (_cameraSwitch > 0)
    {
      Syslog::write("CARL Behavior %d: Turning camera on", _id);
      _server->camera_bus_on();
    }
    else if (_cameraSwitch == 0)
    {
      Syslog::write("CARL Behavior %d: Turning camera off", _id);
      _server->camera_bus_off();
    }
    _cameraSwitch = -1;
  }


  // Recorder switch
  //
  if (_recorderSwitch != -1)
  {
    if (_recorderSwitch > 0)
    {
      Syslog::write("CARL Behavior %d: Turning recorder on", _id);
      _server->recorder_on();
    }
    else if (_recorderSwitch == 0)
    {
      Syslog::write("CARL Behavior %d: Turning recorder off", _id);
      _server->recorder_off();
    }
    _recorderSwitch = -1;
  }

  // FStop - 170127: Chaffey suggested the order should be: iris, lights, record
  //
  if (_fstop > -1)
  {
    Syslog::write("CARL Behavior %d: set the fstop to %d", _id, _fstop);
    _server->iris_control(CARL_IF::FStop, _fstop);
    _fstop = -1;      // Reset after usage
  }

  // Home
  //
  if (_homeIris > 0)
  {
    Syslog::write("CARL Behavior %d: Home the iris motor", _id);
    _server->iris_control(CARL_IF::Home, 0);
    _homeIris = -1;      // Reset after usage
  }

  // Auto Iris
  //
  if (_autoIris > -1.0)
  {
    Syslog::write("CARL Behavior %d: set the auto-iris value to %.2f", _id, _autoIris);
    _server->auto_iris(_autoIris);
    _autoIris = -1.0;      // Reset after usage
  }

  // Light switch
  //
  if (_lightSwitch != -1)
  {
    if (_lightSwitch > 0)
    {
      _lightSwitch = 1;
      Syslog::write("CARL Behavior %d: Turning lights on", _id);
      _server->camera_lights_on();
    }
    else if (_lightSwitch == 0)
    {
      Syslog::write("CARL Behavior %d: Turning lights off", _id);
      _server->camera_lights_off();
    }
    _lightSwitch = -1;         // Done with light switch
  }

  // Light brightness (should be before light switch)
  //
  if (_brightness != -1) {
    if (_brightness > 90) _brightness = 90;
    Syslog::write("CARL Behavior %d: Setting brightness to %d",
      _id, _brightness);
    _server->light_level(_brightness);
    _brightness = -1;
  }

  // Reset clipname
  //
  if (_clipname != -1) {
    Syslog::write("CARL Behavior %d: Setting clipname", _id);
    _server->set_clipname("");
    _clipname = -1;
  }

  // Record button
  //
  if (_record != -1)
  {
    if (_record > 0)
    {
      Syslog::write("CARL Behavior %d: action!", _id);
      _server->start_recording();
    }
    else if (_record == 0)
    {
      Syslog::write("CARL Behavior %d: cut!", _id);
      _server->stop_recording();
    }
    _record = -1;      // Reset after usage
    Syslog::write("CARL Behavior %d: resetting record", _id);
  }

  return;
}


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

  if (_recorderSwitch < -1 || _recorderSwitch > 1)
  {
    Syslog::write("CARL Behavior %d: invalid value for recorderSwitch: %d",
      _id, _recorderSwitch);
    valid = False;
  }

  if (_ctdSwitch < -1 || _ctdSwitch > 1)
  {
    Syslog::write("CARL Behavior %d: invalid value for ctdSwitch: %d",
      _id, _ctdSwitch);
    valid = False;
  }

  if (_lightSwitch < -1 || _lightSwitch > 1)
  {
    Syslog::write("CARL Behavior %d: invalid value for lightSwitch: %d", 
      _id, _lightSwitch);
    valid = False;
  }

  if (_brightness < -1 || _brightness > 100)
  {
    Syslog::write("CARL Behavior %d: invalid value for brighness: %d",
      _id, _brightness);
    valid = False;
  }

  if (_fstop >= 0)
  {
    if ( (_fstop < 31) ||
         (_fstop > 33  && _fstop <  41) ||
         (_fstop > 43  && _fstop <  81) ||
         (_fstop > 83  && _fstop < 111) ||
         (_fstop > 113 && _fstop < 161) ||
         (_fstop > 163 && _fstop < 221) ||
         (_fstop > 221 && _fstop < 561) ||
         (_fstop > 563)
       )
    {
       Syslog::write("CARL Behavior %d: invalid value for fstop: %d",
        _id, _fstop);
       valid = False;
    }
  }

  if ( _autoIris == 0.0 || _autoIris == -1.0 || (_autoIris >= 1.25 && _autoIris <= 3.8) )
  {
    // We're good
  }
  else
  {
     Syslog::write("CARL Behavior %d: invalid value for autoIris: %.2f",
      _id, _autoIris);
     valid = False;
  }

  return valid;
}

