// $Header: https://oberon.oapd.inaf.it/shins/trunk/shins/src/scicam_ctrl/scicamCtrlIndiDriver.cpp 2012 2019-07-18 13:45:02Z depa $

#include "scicamCtrlIndiDriver.h"

scicamCtrlIndiDriver::scicamCtrlIndiDriver(const std::string& _driverName,
                                           const std::string& _driverVersion,
                                           const std::string& _protocolVersion,
                                           const std::string& _imageFileName)
  :pcf::IndiDriver(_driverName, _driverVersion, _protocolVersion)
{
  U1_LOG(__FUNCTION__ << " contructor ...");
  m_imageFileName = _imageFileName;
  U1_LOG(__FUNCTION__ << " contructor ... Done");
  std::map<std::string, std::string> mapElemNameValText;
  std::map<std::string, double> mapElemNameValNumeric;
  mapElemNameValText.insert(std::pair<std::string, std::string>("text", ""));
  mapElemNameValNumeric.insert(std::pair<std::string, double>("DIT", 0));
  mapElemNameValNumeric.insert(std::pair<std::string, double>("NDIT", 0));

  m_indiImageFileName = createIndiProperty<std::string>(_driverName,"imageFileName", pcf::IndiProperty::Text,
                                                        pcf::IndiProperty::ReadOnly,
                                                        pcf::IndiProperty::Idle,
                                                        mapElemNameValText);

  m_indiCommand = createIndiProperty<std::string>(_driverName,"Command", pcf::IndiProperty::Text,
                                                  pcf::IndiProperty::ReadWrite,
                                                  pcf::IndiProperty::Idle,
                                                  mapElemNameValText);

  m_indiExposure = createIndiProperty<double>(_driverName,"Exposure", pcf::IndiProperty::Number,
                                                       pcf::IndiProperty::ReadWrite,
                                                       pcf::IndiProperty::Idle,
                                                       mapElemNameValNumeric);

  // m_indiDIT = createIndiProperty<double>(_driverName,"DIT", pcf::IndiProperty::Number,
  //                                        pcf::IndiProperty::ReadWrite,
  //                                        pcf::IndiProperty::Idle,
  //                                        mapElemNameValNumeric);

  // m_indiNDIT = createIndiProperty<double>(_driverName,"NDIT", pcf::IndiProperty::Number,
  //                                        pcf::IndiProperty::ReadWrite,
  //                                        pcf::IndiProperty::Idle,
  //                                        mapElemNameValNumeric);

}


scicamCtrlIndiDriver::~scicamCtrlIndiDriver()
{
  //
}


void scicamCtrlIndiDriver::handleGetProperties(const pcf::IndiProperty& _ipRecv)
{
  // ignore if not our device
  if (_ipRecv.hasValidDevice() && _ipRecv.getDevice() != getName())
    return;

  // publish definition if want all properties or a specific one
  if (!_ipRecv.hasValidName() || _ipRecv.getName() == m_indiImageFileName.getName())
    sendDefProperty (m_indiImageFileName);

  if (!_ipRecv.hasValidName() || _ipRecv.getName() == m_indiCommand.getName())
    sendDefProperty (m_indiCommand);

  if (!_ipRecv.hasValidName() || _ipRecv.getName() == m_indiExposure.getName())
    sendDefProperty(m_indiExposure);

  // if (!_ipRecv.hasValidName() || _ipRecv.getName() == m_indiDIT.getName())
  //   sendDefProperty(m_indiDIT);
  // if (!_ipRecv.hasValidName() || _ipRecv.getName() == m_indiDIT.getName())
  //   sendDefProperty(m_indiNDIT);
}


void scicamCtrlIndiDriver::handleNewProperty(const pcf::IndiProperty& _ipRecv)
{
  std::cout << __FUNCTION__ << std::endl;
  std::time_t now;
  struct tm y2k = {0};
  std::ostringstream strSeconds;
  std::istringstream inStream;
  std::string strCommand = "";
  std::string strDataDir = shins::util::get_env("SHINS_DATA"); //"/home/tan_unstable/SHARK-NIR/shins/branches/unstable/data/";
  std::vector<std::string> splitVec;
  double dit, ndit;

  y2k.tm_hour = 0;   y2k.tm_min = 0; y2k.tm_sec = 0;
  y2k.tm_year = 100; y2k.tm_mon = 0; y2k.tm_mday = 1;
  double seconds;

  if (_ipRecv.getName() == m_indiImageFileName.getName())
    {
      W_LOG("::" << __FUNCTION__ << " ReadOnly object");
      return;
    }

  if (_ipRecv.getName() == m_indiCommand.getName())
    {
      strCommand = _ipRecv["text"].getValue();
      // strCommand = _ipRecv["text"];
      if ((strCommand == "go"))// && (strCommand != m_indiCommand["text"].getValue()))
        {
          //start exposure
          m_indiCommand["text"] = strCommand;
          m_indiCommand.setState(pcf::IndiProperty::Ok);
          sendSetProperty(m_indiCommand);
        }
      if (boost::algorithm::starts_with(strCommand, "1 savedata"))
      // if ((strCommand == "1 savedata"))// && (strCommand != m_indiCommand["text"].getValue()))
        {
          // pcf::IndiProperty tmpP(m_indiImageFileName);
          // savedata
          m_indiCommand["text"] = strCommand;
          m_indiCommand.setState(pcf::IndiProperty::Ok);
          sendSetProperty(m_indiCommand);
          // data must be saved with appropriate method,
          // then the filename is returned to the client
          // by defining the related property
          std::time(&now);
          seconds = std::difftime(now,std::mktime(&y2k));
          strSeconds << std::fixed << std::setprecision(0) << seconds;

          boost::split( splitVec, strCommand,
                        boost::algorithm::is_any_of(" "), boost::algorithm::token_compress_on );
          if (splitVec.size() == 3)
            m_indiImageFileName["text"] = strDataDir + splitVec[2];
          else
            m_indiImageFileName["text"] = strDataDir + "dss2.04.39.17.8+22.21.03.4_10x10.fits";
          // "scicamImage" + strSeconds.str() + ".txt";
          m_indiImageFileName.setState(pcf::IndiProperty::Ok);
          sendSetProperty(m_indiImageFileName);
          U1_LOG("Image saved on: " << m_imageFileName);
        }
      if (boost::algorithm::contains(strCommand, "lbtintpar"))
        {
          pcf::IndiProperty tmpP(m_indiExposure);
          std::vector< std::string > vecSplit;
          vecSplit = shins::util::split_with_boost(strCommand, " ");
          tmpP["DIT"] = shins::util::convertStringToType<double>(vecSplit[0]);
          tmpP["NDIT"] = shins::util::convertStringToType<int>(vecSplit[1]);
          m_indiCommand["text"] = strCommand;
          m_indiCommand.setState(pcf::IndiProperty::Ok);
          tmpP.setState(pcf::IndiProperty::Ok);
          sendSetProperty(m_indiCommand);
          handleNewProperty(tmpP);
        }
    }
  if (_ipRecv.getName() == m_indiExposure.getName())
    {
      dit = shins::util::convertStringToType<double>(_ipRecv["DIT"].getValue());
      ndit = shins::util::convertStringToType<double>(_ipRecv["NDIT"].getValue());
      try
        {
          if ((dit < 0) || (ndit < 0))
            {
              throw std::invalid_argument("Invalid value for DIT and/or NDIT!");
            }
          else
            {
              m_indiExposure["DIT"] = dit;
              m_indiExposure["NDIT"] = ndit;
              m_indiExposure.setState(pcf::IndiProperty::Ok);
              sendSetProperty(m_indiExposure);
            }
        }catch (std::exception)
        {
          std::cout << "Does DIT and NDIT contains characters?" << std::endl;
        }
    }
}


void scicamCtrlIndiDriver::execute()
{
  //U1_LOG("::" << __FUNCTION__);
}


int main(int argc, char* argv[])
{
  // INDI related variables, costants and initializations --------------------------
  const std::string	INDI_DRIVER_DEVICE = "SCICAM";
  const std::string INDI_DRIVER_VERSION	= "0.1";
  const std::string INDI_PROTOCOL_VERSION	= "1.23";
  std::string szIndiPath = "/home/tan/SHARK-NIR/shins/branches/unstable/indi";

  szIndiPath = (szIndiPath.length() == 0) ? (".") : (szIndiPath);

  // pcf::Logger::init(szIndiPath + "/logs/" + INDI_DRIVER_DEVICE, INDI_DRIVER_DEVICE);

  int iErr = pcf::Config::init(szIndiPath + "/config/", INDI_DRIVER_DEVICE + ".conf");

  // if (iErr != pcf::ConfigFile::ErrNone)
  //   {
  //     pcf::Logger msgInfo;
  //     msgInfo << pcf::Logger::enumError << "Config for '" << INDI_DRIVER_DEVICE
  //             << "' had an error: "
  //     	      << pcf::Config::getErrorMsg(iErr) << std::endl;
  //   }
  // ---------------------------------------------------------------------------------

  int status = EXIT_SUCCESS;
  std::string strImageFilename = "scicamImage.txt";//argv[1];

  scicamCtrlIndiDriver scicam(INDI_DRIVER_DEVICE, INDI_DRIVER_VERSION, INDI_PROTOCOL_VERSION, strImageFilename);

  scicam.activate();

  scicam.processIndiRequests();

  scicam.deactivate();

  return status;
}
