// $Header: https://oberon.oapd.inaf.it/shins/trunk/shins/src/obs_ctrl/sequencerI.hpp 3989 2022-07-06 16:55:20Z depa $

// IceLite (from MPIA) 3.6 does not support C++ 11

#ifndef _SEQUENCERI_
#define _SEQUENCERI_

// STDLIB
#include <algorithm>
#include <fstream>
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
#include <vector>
#include <tr1/tuple>


#include <stdio.h>
#include <cstdlib>
// ICE
#include <Ice/Ice.h>

#include <IceUtil/Mutex.h>
#include <IceUtil/Monitor.h>
#include <IceUtil/Thread.h>
#include <IceUtil/Timer.h>
//NICE
// #include <Nice/Log.h>
#include <Nice/App/Application.h>
#include <Nice/Time.h>

// BASDA
#include <Basda/Exception.h>
// #include <Basda/BasdaPy.h>

// BOOST
// #include <boost/signals2/signal.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/condition_variable.hpp>
// #include <boost/thread/future.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
// #include <boost/thread/condition_variable.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>

// LBTO IIF
#include <LbtoIIFInterface2.h>
#include <Ltcs/Iif/ServiceWorkerInterface.h>
#include <Ltcs/Iif/PropertyName.h>


// SHINS
#include "data_mgr/fitsFileI.hpp"
#include "motion_ctrl/motionCtrl.hpp"
#include "util/shins_util.h"
//#include "util/listener.h"
#include "util/logger.h"
#include "util/constants.h"
#include "calunit_ctrl/calunitCtrl.h"
#include "track_ctrl/trackingCtrl.h"
#include "tiptilt_ctrl/tiptiltCtrl.hpp"
#include "obsControl.h"
#include "os_sm.h"
#include "tcs_iif/iifApp.h"
#include "seqISetup.hpp"
#include "seqIDataMgr.hpp"
#include "seqITcs.hpp"
#include "seqISnmp.hpp"

#include "util/shins_util_f.h"

using namespace sharknir;

namespace su = shins::util;
namespace suc = shins::util::constants;
namespace sd = sharknir::dataManager;
namespace bf = boost::filesystem;

using pcf::Socket;
using pcf::System;


class SequencerI;

class DiagnosticRecordVar : public obsControl::DiagnosticRecordVar
{
    public:
    int frameCounter;
    obsControl::SeqByte slopeRecord;
    obsControl::SeqByte asmRecord;
    obsControl::SeqByte ccdRecord;
};

class DiagnosticRecord : public obsControl::DiagnosticRecord
{
    public:
    DiagnosticRecord()
    {
        frameCounter = 0;
        slopeRecord  = obsControl::SeqByte(0,0);
        asmRecord    = obsControl::SeqByte(0,0);
        ccdRecord    = obsControl::SeqByte(0,0);
    }
    DiagnosticRecord(const Ice::Int& _fc,
                     const obsControl::SeqByte& _sr,
                     const obsControl::SeqByte& _ar,
                     const obsControl::SeqByte& _cr)
    {
        frameCounter = _fc;
        slopeRecord  = _sr;
        asmRecord    = _ar;
        ccdRecord    = _cr;
    }

    DiagnosticRecord(const Sharknir::Bcu::OverallDiagnosticRecord& _overallDiagRec)
    {
        frameCounter = _overallDiagRec.frameCounter;
        slopeRecord  = _overallDiagRec.slopeRecord;
        asmRecord    = _overallDiagRec.asmRecord;
        ccdRecord    = _overallDiagRec.ccdRecord;
    }

    int getFrameCounter(const Ice::Current&){
        return frameCounter;
    }
    obsControl::SeqByte getSlopeRecord(const Ice::Current&) {
        return slopeRecord;
    }
    obsControl::SeqByte getAsmRecord(const Ice::Current&) {
        return asmRecord;
    }
    obsControl::SeqByte getCcdRecord(const Ice::Current&) {
        return ccdRecord;
    }
    int setFrameCounter(Ice::Int _frameCounter, const Ice::Current&) {
        frameCounter = _frameCounter;
        return EXIT_SUCCESS;
    }
    int setSlopeRecord(const obsControl::SeqByte& _sr, const Ice::Current&){
        slopeRecord = _sr;
        return EXIT_SUCCESS;
    }
    int setAsmRecord  (const obsControl::SeqByte& _ar, const Ice::Current&){
        asmRecord = _ar;
        return EXIT_SUCCESS;
    }
    int setCcdRecord  (const obsControl::SeqByte& _cr, const Ice::Current&){
        ccdRecord = _cr;
        return EXIT_SUCCESS;
    }
};


class GetFitsFileJob : public IceUtil::Shared
{
public:
    GetFitsFileJob(const obsControl::AMD_Sequencer_sashaGetFitsFilePtr& _psGF, boost::shared_ptr<SeqDataMgr> _DataMgrPtr, const dictDetSetup& _dSashaSetup, const std::string& _instMode);
    void execute();
private:
    bool getFitsFile();
    boost::shared_ptr<SeqDataMgr> DataMgrPtr;
    obsControl::AMD_Sequencer_sashaGetFitsFilePtr psGF;
    dictDetSetup dSashaSetup;
    std::string instMode;
    std::string outFileName;
    int status;
};


class IceCallCounter
{
    IceUtil::Mutex & seqMutex;
    int & seqCounter;
    int callCounter;
public:
    IceCallCounter(IceUtil::Mutex & seq_mutex, int & counter);
    ~IceCallCounter();
    int getCounter() const {return callCounter;};
};

typedef IceUtil::Handle<GetFitsFileJob> GetFitsFileJobPtr;

// typedef IceUtil::Handle<dictTipTiltSetup> dictTipTiltSetupPtr;

// class BCUInitTask : public IceUtil::TimerTask
// {
// private:
//   tiptiltCtrlPtr m_ptrTipTiltCtrl;
//   boost::shared_ptr<dictTipTiltSetup> m_ptrDictSetup;
//   Ice::Int m_status;
// public:
//   BCUInitTask(tiptiltCtrlPtr _ptrTipTiltCtrl);
//   ~BCUInitTask();
//   void setDictionary(const dictTipTiltSetup& _dictSetup);
//   Ice::Int getStatus();
//   virtual void runTimerTask();
// };
// typedef IceUtil::Handle<BCUInitTask> BCUInitTaskPtr;

// this class implements an Ice servant
// NOTE remember to add the additional parameter const Ice::Current& to each method implementing an interface operation
class SequencerI : public obsControl::Sequencer, virtual public IceUtil::Mutex
{
private: // members
// boost::shared_ptr<IceUtil::Mutex> m_ptrMtxStateMachine;
  boost::shared_ptr<motionCtrl> m_motion;
  boost::shared_ptr<calunitCtrl> m_calibration;
  boost::shared_ptr<trackingCtrl> m_track;
  boost::shared_ptr<tiptiltCtrl> m_tiptilt;

  boost::shared_ptr<SeqSetup> m_seqSetup;
  boost::shared_ptr<SeqDataMgr> m_seqDataMgr;
  boost::shared_ptr<SeqTcs> m_seqTcs;
  boost::shared_ptr<SeqSnmp> m_seqSnmp;

    shins::util::mapPosType m_mainMapNamedPos;


    // following flag says if subsystem will be initialized
  // this information is provided in obs_ctrl.cfg as ICE property
  // and passed to this class constructor
  bool trackActive;
  bool tiptiltActive;

    int  m_argc;
    std::vector<std::string> m_argv;


  std::string m_LBTSide;
  boost::mutex m_mtxStateMachine;
  boost::condition_variable m_stCond;
  IceUtil::Mutex m_mtxSeq;
  boost::shared_ptr<IceUtil::Monitor<IceUtil::Mutex> > m_ptrMonSeq;
  boost::shared_ptr<osfsm::OSFsm> m_ptrStateMachine;
  boost::shared_ptr<boost::asio::io_service> m_ptrIoService;
  // BCUInitTaskPtr m_BCUTaskPtr;

  std::string m_indiImageFileName;
  bf::path m_insroot;
  Ltcs::IifServiceWorkerInterfacePtr m_iif;

//  std::map<std::string, std::string> m_mapFitsKeywords;
//  std::map<std::string, std::string> m_mapFitsKeywordsComments;
//
  std::string m_strAliasFileName;
  std::map<std::string, std::string> m_mapCfgFiles;


  std::list<GetFitsFileJobPtr> _getFitsFileJobs;

  int m_IceCallCounter;
  IceUtil::Mutex m_IceCallMutex;

Ice::PropertiesPtr m_props;
public:
SequencerI(const std::map<std::string, bool>& _mapFlags,
           boost::shared_ptr<osfsm::OSFsm>& _ptrSM,
           boost::shared_ptr<boost::asio::io_service> _ptrIoService,
           Ice::PropertiesPtr props);

~SequencerI();


virtual Ice::Int osLogBanner(const std::string & _banner, const Ice::Current & _c);

virtual Ice::Int getPosition (const IceUtil::Optional<std::string>& _unit,
                              const sharknir::dictSetupPos& _inDictPosition,
                              sharknir::dictSetupPos& _outDictPosition,
                              const Ice::Current&);

virtual Ice::Int setFlags(Ice::Int flags, Ice::Int moreFlags, const Ice::Current & _c);
virtual Ice::Int unsetFlags(Ice::Int flags, Ice::Int moreFlags, const Ice::Current & _c);
virtual Ice::Int toggleFlags(Ice::Int flags, Ice::Int moreFlags, const Ice::Current & _c);

virtual Ice::Int getStatus(const sharknir::dictStatus & inDictStatus, sharknir::dictStatus & outDictStatus, const Ice::Current & _c);
virtual Ice::Int getJsonStatus(std::string & jsonStatus, const Ice::Current & _c);

virtual Ice::Int getInternalSeqFloatVariable(const std::string & var, sharknir::SeqFloat & result, const Ice::Current & _c);

virtual Ice::Int setContext(const dictSetupNamedPos & _osContext, const Ice::Current & _c);
virtual Ice::Int setLampsStatus(const dictSetupNamedPos & _osLampsStatus, const Ice::Current & _c);

virtual std::string getCurrentDataDirectory(const ::Ice::Current& _c){ return su::getCurrentDataDirectory();}

void CheckTipTilt();


/////////////////
// MOTION CTRL //
/////////////////
virtual Ice::Int moveDeviceToNegativeLimit(const std::vector<std::string>& _vecDevAlias, const Ice::Current&);
virtual Ice::Int moveDeviceToPositiveLimit(const std::vector<std::string>& _vecDevAlias, const Ice::Current&);

virtual Ice::Int setupMotionDict(const dictSetupPos& dSetup, const Ice::Current&);
// virtual int setupMotion(const dictNonSciAssembly& d, const std::string& strSetup, const Ice::Current&);
virtual Ice::Int initMotion     (const std::vector<std::string>& _vecDevAlias, const Ice::Current&);
virtual Ice::Int initMotionStart(const std::vector<std::string>& _vecDevAlias, const Ice::Current&);
virtual Ice::Int initMotionWait (const std::vector<std::string>& _vecDevAlias, const IceUtil::Optional<Ice::Long>& _time, const Ice::Current&);

virtual Ice::Int initMotionAll(const Ice::Current&);
virtual Ice::Int initMotionAllStart(const Ice::Current&);
virtual Ice::Int initMotionAllWait(const IceUtil::Optional<Ice::Long>& _time, const Ice::Current&);

//////////////////
// CALUNIT CTRL //
//////////////////
virtual Ice::Int initCalibUnit     (const std::vector<std::string>& _vecDevAlias, const Ice::Current&);
virtual Ice::Int initCalibUnitStart(const std::vector<std::string>& _vecDevAlias, const Ice::Current&);
virtual Ice::Int initCalibUnitWait (const std::vector<std::string>& _vecDevAlias, const IceUtil::Optional<Ice::Long>& _time, const Ice::Current&);

virtual Ice::Int initCalibUnitAll(const Ice::Current&);
virtual Ice::Int initCalibUnitAllStart(const Ice::Current&);
virtual Ice::Int initCalibUnitAllWait(const IceUtil::Optional<Ice::Long>& _time, const Ice::Current&);

virtual Ice::Int setupCalibUnitDict(const dictSetupPos& dSetup, const Ice::Current&);
virtual Ice::Int setupCalibration(const dictNonSciAssembly& d, const std::string& strSetup, const Ice::Current&);

////////////////
// TRACK CTRL //
////////////////
virtual Ice::Int initTracking     (const std::vector<std::string>& _vecDevAlias, const Ice::Current&);
virtual Ice::Int initTrackingStart(const std::vector<std::string>& _vecDevAlias, const Ice::Current&);
virtual Ice::Int initTrackingWait (const std::vector<std::string>& _vecDevAlias, const IceUtil::Optional<Ice::Long>& _time, const Ice::Current&);

virtual Ice::Int initTrackingAll(const Ice::Current&);
virtual Ice::Int initTrackingAllStart(const Ice::Current&);
virtual Ice::Int initTrackingAllWait(const IceUtil::Optional<Ice::Long>& _time, const Ice::Current&);

virtual Ice::Int trackingStop      (const Ice::Current&);
virtual Ice::Int trackingAbort     (const Ice::Current&);
virtual Ice::Int trackingStart2    (Ice::Double _dateMjd, Ice::Double _position, const Ice::Current & _c);
virtual Ice::Int trackingStart     (const Ice::Current & _c);
virtual Ice::Int trackingWait      (const IceUtil::Optional<Ice::Long>& _time, const Ice::Current&);
virtual Ice::Int trackingTestStart (Ice::Double _startPosDegree, Ice::Double _endPosDegree, Ice::Double _speedDegreeSec, const Ice::Current & _c);
virtual Ice::Int resetPosition(const std::string & _devAlias, const Ice::Current & _c);

virtual Ice::Int setupTracking(const dictTrackingMode& dSetup, const Ice::Current&);
virtual Ice::Int trackingIsMoving(std::map<string, bool>& _mapDev, const Ice::Current&);

virtual Ice::Int setDerotationParameters(Ice::Int numPolynomials, Ice::Double samplingRate, Ice::Double frequency, Ice::Int polynomialOrder, Ice::Int faultTolerance, Ice::Int samplesPerSegment, const Ice::Current & _c);
virtual Ice::Int setDerotationParameters1(Ice::Int numPolynomials, Ice::Double samplingRate, Ice::Double frequency, const Ice::Current & _c);
virtual Ice::Int setDerotationParameters2(Ice::Int polynomialOrder, Ice::Int faultTolerance, Ice::Int samplesPerSegment, const Ice::Current & _c);
virtual Ice::Int setDerotationParameters3(Ice::Double debug1, Ice::Double debug2, Ice::Double debug3, const Ice::Current & _c);
virtual Ice::Int setDerotationParameters4(Ice::Double debug4, Ice::Double debug5, Ice::Double debug6, const Ice::Current & _c);
virtual Ice::Int sharkDerotatorBacklashProcedure(const Ice::Current & _c);

virtual Ice::Int setAdcCorrectionParameters(Ice::Double co, Ice::Double p0, Ice::Double p1, Ice::Double t0, Ice::Double t1, const Ice::Current & _c);
virtual Ice::Int setAdcCoRotationOffset(Ice::Double corotation, const Ice::Current & _c);
virtual Ice::Int setAdcCounterRotationOffset(Ice::Double counterrotation, const Ice::Current & _c);


////////////////
// INSTRUMENT //
////////////////
virtual Ice::Int changeState(const std::string& _state, const IceUtil::Optional<sharknir::SeqString>& _vecDevAlias, const Ice::Current&);

virtual Ice::Int initInstrument(const Ice::Current&);
virtual Ice::Int initInstrumentStart(const Ice::Current&);
virtual Ice::Int initInstrumentWait(const IceUtil::Optional<Ice::Long>& _time, const Ice::Current&);

virtual Ice::Int moveDevices(const dictSetupNamedPos& _dSetupPositions, const Ice::Current & _c);
virtual Ice::Int moveDevicesStart(const dictSetupNamedPos& _dSetupPositions, const Ice::Current & _c);
virtual Ice::Int moveDevicesWait(const Ice::Current & _c);

virtual Ice::Int setupInstrument(const dictSetupNamedPos& _dSetupPositions, const Ice::Current & _c);
virtual Ice::Int setupInstrumentAbsolutePosition(const dictSetupPos& _dSetupPos, const IceUtil::Optional<dictDevUnit>& _dUnit, const Ice::Current&);
virtual Ice::Int setupInstrumentRelativePosition(const dictSetupPos& _dSetupPos, const IceUtil::Optional<dictDevUnit>& _dUnit, const Ice::Current&);

virtual Ice::Int parkInstrument     (const IceUtil::Optional<dictSetupPos>& _dSetupPos, const IceUtil::Optional<dictDevUnit>& _dUnit, const Ice::Current&);

///////////////////////
// REAL-TIME TIPTILT //
///////////////////////
virtual Ice::Int RTCTTInit             (const dictTipTiltSetup& _dictTipTiltSetup, const Ice::Current&);                 //std::string& _tiptiltMode,
virtual Ice::Int RTCTTSetup            (const Ice::Current&);                 //std::string& _tiptiltMode,
virtual Ice::Int RTCTTStart            (const Ice::Current&);
virtual Ice::Int RTCTTResetBCU         (const Ice::Current&);
virtual Ice::Int RTCTTSwitchCcdMode    (const dictTipTiltSetup &_dtiptiltSetup, const Ice::Current &);
virtual Ice::Int RTCTTSetCentroidPos   (Ice::Float centroidX, Ice::Float centroidY, const Ice::Current&);
virtual Ice::Int RTCTTModeUpload       (const sharknir::SeqFloat& _seqModes, bool absolute, const Ice::Current&);
virtual Ice::Int RTCTTConfigCamera     (const dictTipTiltSetup& _dictTipTiltSetup, const Ice::Current&);
virtual Ice::Int RTCTTEnableLoop       (const dictTipTiltSetup& _dictTipTiltSetup, const Ice::Current&);
virtual Ice::Int RTCTTCloseLoop        (const Ice::Current&);
virtual Ice::Int RTCTTOpenLoop         (const Ice::Current&);
virtual Ice::Int RTCTTStop             (const Ice::Current&);

virtual Ice::Int RTCTTIsInit           (bool& _isInit, const Ice::Current&);

virtual Ice::Int RTCTTEnableDiagnostic (const dictTipTiltSetup& _dictTipTiltSetup, const Ice::Current&);
virtual Ice::Int RTCTTGetDiagnostics   (Ice::Int _nMaxRecords, obsControl::SeqDiagnosticRecord& _diagnosticRecord, const Ice::Current&);

virtual Ice::Int RTCTTTeccamSetup      (const sharknir::dictDetSetup& _dTECCAMSetup, const Ice::Current&);
virtual Ice::Int RTCTTTeccamExpose     (const sharknir::dictDetSetup& _dTECCAMSetup, std::string & _fileName, const Ice::Current&);

virtual Ice::Int RTCTTWriteTimeHistory (const dictTipTiltSetup& _dictTipTiltSetup, const Ice::Current &);
virtual Ice::Int RTCTTEnableTimeHistory(const dictTipTiltSetup& _dictTipTiltSetup, const Ice::Current &);

virtual Ice::Int RTCTTExecuteSetup     (const dictTipTiltSetup &_execSetup, const Ice::Current&);

/////////////////////
// RTC - LOW LEVEL //
/////////////////////
virtual Ice::Int RTCTTSendCameraCommand(const std::string& _command, std::string& _reply, const Ice::Current&);
virtual Ice::Int RTCTTRead(Ice::Int address, Ice::Int size,const std::string & memory, sharknir::SeqInt & read_data, const Ice::Current & _c);
virtual Ice::Int RTCTTReadSingle(Ice::Int address, Ice::Int size,const std::string & memory, sharknir::SeqFloat & read_data, const Ice::Current & _c);
virtual Ice::Int RTCTTWrite(const sharknir::SeqInt & command, Ice::Int address, const std::string & memory, const Ice::Current & _c);
virtual Ice::Int RTCTTWriteSingle(const sharknir::SeqFloat & command, Ice::Int address, const std::string & memory, const Ice::Current & _c);

////////////////////
// STOP AND ABORT //
////////////////////
virtual Ice::Int emergencyAbortAll(const Ice::Current&);
virtual Ice::Int stopMotion(const std::vector<std::string>& _vecDevAlias, const Ice::Current&);
virtual Ice::Int abortMotion(const std::vector<std::string>& _vecDevAlias, const Ice::Current&);
// ------------------------------------

///////////////////////
// Scientific camera //
///////////////////////
virtual Ice::Int sashaSetup       (const dictDetSetup& _dSashaSetup, const Ice::Current&);
virtual Ice::Int sashaSetFrequency(const dictDetSetup& _dSashaSetup, const Ice::Current&);
virtual Ice::Int sashaEnableSave  (const dictDetSetup& _dSashaSetup, const Ice::Current&);
virtual Ice::Int sashaExpose      (std::vector<std::string> &  _out_files, const Ice::Current&);
virtual Ice::Int sashaAbortExposure(const Ice::Current &_c);

Ice::Int sashaGetFitsFile(const dictDetSetup& _dSashaSetup, const std::string& _instMode, std::string& _outFilename);
virtual Ice::Int sashaGetFitsFileSync(const dictDetSetup& _dSashaSetup, const std::string& _instMode, std::string & _outFilename, const Ice::Current&);
virtual void sashaGetFitsFile_async(const obsControl::AMD_Sequencer_sashaGetFitsFilePtr&, const dictDetSetup& _dSashaSetup, const std::string& _instMode, const Ice::Current& = Ice::Current());


virtual Ice::Int sashaGetIndiMsges(const dictDetSetup& _dSashaSetup, const Ice::Current&);


//int SetFITSValues(fitsfile * fptr, FitsKeyValues & fit_key_values);


// ------------------------------------

//////////////////
// DATA MANAGER //
//////////////////
virtual Ice::Int datamgrCreateEmptyFile(const std::string& _inFileName,
                                        std::string& _outFilename,
                                        const Ice::Current&);
virtual Ice::Int datamgrPrintFITS(const std::string& _key,
                                  const std::string& _value,
                                  const IceUtil::Optional<std::string>& _comment,
                                  const IceUtil::Optional<std::string>& _filename,
                                  const Ice::Current&);

virtual Ice::Int datamgrMergeHeaders(const IceUtil::Optional<std::string>& _filenameOrig,
                                     const IceUtil::Optional<std::string>& _fileNameNew,
                                     const Ice::Current&);
virtual Ice::Int datamgrArchiveFITS(const IceUtil::Optional<std::string>& _absFileName, const Ice::Current&);


/////////////////////
// Telescope / TCS //
/////////////////////
virtual Ice::Int BinocularControl(const std::string& _flag, const Ice::Current&);

virtual Ice::Int OffsetPointing(const dictTelescopeSetup& _tel_sup, const Ice::Current&);

virtual Ice::Int PresetTelescope(const dictTelescopeSetup & _tel_setup, const Ice::Current & _c);
virtual Ice::Int RunAO(const dictTelescopeSetup& _tel_sup, const Ice::Current&);
virtual Ice::Int SendWavefront(const lbto::SeqWF& _zernikeC, const std::string& _ope, const Ice::Current&);
virtual Ice::Int MoveFocus(Ice::Double _absPos, const std::string& _ope, const Ice::Current&);
virtual Ice::Int OffsetZAO(Ice::Double _deltaZ, const std::string& _side, const Ice::Current&);
virtual Ice::Int OffsetXYAO(Ice::Double DeltaX, Ice::Double DeltaY, const std::string & _side, const Ice::Current & _c);
virtual Ice::Int ApplyWaffleAO(const dictTelescopeSetup& _telSup, const Ice::Current&);
virtual Ice::Int setDdParameters(const dictTelescopeSetup & DdEntries, sharknir::SeqString & outMsgs, const Ice::Current & _c);
virtual Ice::Int getDdParameters(const sharknir::SeqString & seqEntries, sharknir::SeqString & outMsgs, const Ice::Current & _c);

Ice::Int pointingCorrectionStart(Ice::Float _freq, Ice::Int& _thrdID, const Ice::Current&);
Ice::Int pointingCorrectionStop(Ice::Int _thrdID, const Ice::Current&);

};


#endif
