/****************************************************************************/
/* Copyright (c) 2014 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : CARLServer.cc                                                 */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 11/07/2014                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include <process.h>

#include "Syslog.h"
#include "CARLServer.h"
#include "KiPro.h"
#include "NavigationIF.h"
#include "StringAttribute.h"
#include "IntegerAttribute.h"
#include "FloatAttribute.h"
#include "ModtronixMsg.h"
#include "ModtronixOutput.h"

/*
CLASS
CARLServer

DESCRIPTION
Server Interface for video CAmera Recorder and Logger

AUTHOR
Henthorn

*/

CARLServer::CARLServer(const char* configFileName)
   : _attributes(CARL_IFServerName), _aja_online(False), _navIF(NULL)
{
   // Load attributes from config file
   //
   _attributes.add(new StringAttribute("KiProIP", "KiProIP",
               &_aja_ip, "134.89.32.54"));

   _attributes.add(new IntegerAttribute("InitPower", "Initial Power State",
               &_init_power, 1L));

   _attributes.add(new StringAttribute("ModtronixIP", "ModtronixIP",
               &_mod_ip, "134.89.32.55"));

   _attributes.add(new StringAttribute("ModtronixPort", "ModtronixPort",
               &_mod_port, "54123"));

   _attributes.add(new IntegerAttribute("ModtronixPeriod", "Sample period",
               &_mod_period, -1L));

   AttributeParser::parse(configFileName, &_attributes);

   System::copyToLogDir(configFileName);

   _msgQ = new ModtronixMsg();

   _mod_output  = new ModtronixOutput();

   try {
     _navIF = new NavigationIF("navigation", 2);
   }
   catch (SharedObjectClient::MissingServer e) {
      Syslog::write("CARLServer - Missing server: %s\n",
                    e.msg);
      _navIF = NULL;
   }
   catch (...) {
      Syslog::write("CARLServer - caught something!\n");
      throw;
   }

}

CARLServer::~CARLServer()
{

}

DeviceIF::Status CARLServer::initialize()
{
   // Set media state to 'Record' by default
   //
   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::get_env_data(float *temp, float *humidity,
                                          float *fwd_h2o, float *aft_h2o,
                                          short *h2o_alarm)
{
   _mod_output->read();
   *temp = _mod_output->data.temp;
   *humidity = _mod_output->data.humidity;
   *fwd_h2o = _mod_output->data.h2o_fwd;
   *aft_h2o = _mod_output->data.h2o_aft;
   *h2o_alarm = _mod_output->data.h2o_alarm;
   return DeviceIF::Ok;
}

// Use light level of zero to turn auto-iris function off.
//
DeviceIF::Status CARLServer::auto_iris(float target_light_level)
{
   ModtronixMsg::Message msg(ModtronixMsg::EZAutoFS);
   msg._float = target_light_level;
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);
   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::camera_bus_on()
{
   ModtronixMsg::Message msg(ModtronixMsg::CameraOn);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);
   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::camera_bus_off()
{
   ModtronixMsg::Message msg(ModtronixMsg::CameraOff);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);
   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::camera_lights_on()
{
   Syslog::write("CARLServer::camera_lights_on");
   ModtronixMsg::Message msg(ModtronixMsg::LightsOn);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);
   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::camera_lights_off()
{
   Syslog::write("CARLServer::camera_lights_off");
   ModtronixMsg::Message msg(ModtronixMsg::LightsOff);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);
   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::light_level(short level)
{
   Syslog::write("CARLServer::light_level %d", level);
   ModtronixMsg::Message msg(ModtronixMsg::LightLevel, level);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);
   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::ctd_on()
{
   ModtronixMsg::Message msg(ModtronixMsg::CtdOn);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);
   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::ctd_off()
{
   ModtronixMsg::Message msg(ModtronixMsg::CtdOff);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);
   return DeviceIF::Ok;
}

Boolean CARLServer::is_ctd_on()
{
   _mod_output->read();
   return (_mod_output->data.ctd_power == 1);
}

DeviceIF::Status CARLServer::recorder_on()
{
   ModtronixMsg::Message msg(ModtronixMsg::RecorderOn);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);
   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::recorder_off()
{
   ModtronixMsg::Message msg(ModtronixMsg::RecorderOff);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);
   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::start_recording()
{
   Syslog::write("CARLServer::start_recording()...");
   ModtronixMsg::Message msg(ModtronixMsg::Action);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);

   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::stop_recording()
{
   Syslog::write("CARLServer::stop_recording()...");
   ModtronixMsg::Message msg(ModtronixMsg::Cut);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);

   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::recorder_time(TimeIF::TimeSpec *ts)
{
   ts->seconds = 123;
   ts->nanoSeconds = 456;
   return DeviceIF::Ok;
}

Boolean CARLServer::is_camera_on()
{
   _mod_output->read();
   return (_mod_output->data.camera_power == 1);
}

Boolean CARLServer::is_recorder_on()
{
   _mod_output->read();
   return (_mod_output->data.recorder_power == 1);
}

Boolean CARLServer::aja_ready()
{
   _mod_output->read();
   return _mod_output->data.recorder_ready;
}

short CARLServer::are_lights_on()
{
   Boolean debug = False;

   _mod_output->read();
   dprintf("CARLServer::are_lights_on() - levels:%d\tlight1:%d\tlight2:%d\tlight3:%d\tlight4:%d",
      _mod_output->data.light_level, _mod_output->data.light_power[0],
      _mod_output->data.light_power[1], _mod_output->data.light_power[2],
      _mod_output->data.light_power[3]);
   return 100*_mod_output->data.light_level +
          (1*_mod_output->data.light_power[0] +
           2*_mod_output->data.light_power[1] +
           4*_mod_output->data.light_power[2] +
           8*_mod_output->data.light_power[3]);
}

DeviceIF::Status CARLServer::sync_time()
{
   Syslog::write("CARLServer::sync_time()");
   ModtronixMsg::Message msg(ModtronixMsg::Sync);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);

   return DeviceIF::Ok;
}

DeviceIF::Status CARLServer::record_mode()
{
   Syslog::write("CARLServer::record_mode()");
   ModtronixMsg::Message msg(ModtronixMsg::RecordMode);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);

   return DeviceIF::Ok;
}

Boolean CARLServer::is_recording()
{
   _mod_output->read();
   return _mod_output->data.recording;
}

DeviceIF::Status CARLServer::data_mode()
{
   Syslog::write("CARLServer::data_mode()");
   ModtronixMsg::Message msg(ModtronixMsg::DataMode);
   _msgQ->write(&msg);
   triggerEvent(CARL_IF::MessagesWaiting);

   return DeviceIF::Ok;
}

int CARLServer::spawnAuxTasks()
{
   Syslog::write("CARLServer::initialize() - spawning aux tasks...");
   char errorBuf[256];
   char* on = _init_power ? "-o" : "";
   char buf[256];
   sprintf(buf, "%ld", _mod_period);
   pid_t pid;
   switch ((pid = fork())) {

   case 0:
      // In child
      // Execute driver program

      Syslog::write("CARLServer::spawnAuxTasks() - modtronix %s -h %s -p %s -m %s",
         on, _mod_ip, _mod_port, buf);
      execlp("modtronix", "modtronix", on, "-h", _mod_ip, "-p", _mod_port,
             "-m", buf, (char*)NULL);

      // If execution arrives here, we have encountered an error
      sprintf(errorBuf, "CARLServer::spawnServer() - exec() of \"%s\" failed", "modtronix");
      perror(errorBuf);
      break;

   case -1:
      perror("CARLServer::spawnServer() - fork() failed");
      return -1;

   default:
      return pid;
  }


   return 0;
}

///////////////////////////////////////////////////////////////////
// Get the Ki Pro timecode
//
DeviceIF::Status CARLServer::get_timecode(float *timecode)
{
   _mod_output->read();
   Syslog::write("CARLServer::get_timecode() - %f", _mod_output->data.timecode);
   *timecode = _mod_output->data.timecode;
   return DeviceIF::Ok;
}

///////////////////////////////////////////////////////////////////
// Get the remaining media from the Ki Pro
//
DeviceIF::Status CARLServer::available_media(short *media)
{
   Boolean debug = False;
   _mod_output->read();
   *media = _mod_output->data.available_media;
   dprintf("CARLServer::available_media() = %d", *media);
   return DeviceIF::Ok;
}

///////////////////////////////////////////////////////////////////
// Set the Ki Pro clip name
//
DeviceIF::Status CARLServer::set_clipname(CARL_IF::Clipname clipname)
{
   char *cn = strlen(clipname) == 0? "" : clipname;
   if (cn)
   {
      ModtronixMsg::Message msg(ModtronixMsg::Clipname, clipname);
      msg._int = _navIF? (int)_navIF->depth() : 1;

      _msgQ->write(&msg);
      triggerEvent(CARL_IF::MessagesWaiting);
      Syslog::write("CARLServer::set_clipname() - using depth: %d from _navIF? %d",
         msg._int, (_navIF != NULL));
   }
   return DeviceIF::Ok;
}

///////////////////////////////////////////////////////////////////
// Get the CARL status
//
DeviceIF::Status CARLServer::get_status(CARL_IF::Status *s)
{
   _mod_output->read();
   s->recorder_alive = _mod_output->data.recorder_ready;
   s->data_mode = _mod_output->data.mode;
   s->available_media = _mod_output->data.available_media;
   s->timecode = _mod_output->data.timecode;

   s->camera_power = _mod_output->data.camera_power;
   s->recorder_power = _mod_output->data.recorder_power;
   s->ctd_power = _mod_output->data.ctd_power;
   s->lights_on = _mod_output->data.light_power[0] +
                  _mod_output->data.light_power[1] +
                  _mod_output->data.light_power[2] +
                  _mod_output->data.light_power[3];
   s->temperature = _mod_output->data.temp;
   s->humidity = _mod_output->data.humidity;
   s->fwd_water_alarm = _mod_output->data.h2o_fwd;
   s->aft_water_alarm = _mod_output->data.h2o_aft;

   return DeviceIF::Ok;
}

///////////////////////////////////////////////////////////////////
// Control of the Iris motor controller
//
DeviceIF::Status CARLServer::iris_control(CARL_IF::IrisCmds cmd, short fstop)
{
   Boolean debug = True;
   ModtronixMsg::Message msg;
   switch (cmd)
   {
      case CARL_IF::Home:
         dprintf("CARLServer::iris_control - home\n");
         msg._msg = ModtronixMsg::EZHome;
         _msgQ->write(&msg);
         triggerEvent(CARL_IF::MessagesWaiting);
         _mod_output->data.motor_action = 1;
         break;

      case CARL_IF::AutoFS:
         dprintf("CARLServer::iris_control - auto fs\n");
         msg._msg = ModtronixMsg::EZAutoFS;
         _msgQ->write(&msg);
         triggerEvent(CARL_IF::MessagesWaiting);
         break;

      case CARL_IF::FStop:
         msg._msg = ModtronixMsg::EZFStop;
         msg._int = fstop;
         dprintf("CARLServer::iris_control - fstop %d\n", fstop);
         _msgQ->write(&msg);
         triggerEvent(CARL_IF::MessagesWaiting);
         _mod_output->data.motor_action = 1;
         break;

   }
   _mod_output->write();
   return DeviceIF::Ok;
}

Boolean CARLServer::motor_action()
{
   Boolean debug = False;
   _mod_output->read();
   dprintf("CARLServer::motor_action - %d", _mod_output->data.motor_action);
   return (_mod_output->data.motor_action);
}

