/*
 * seqIDataMgr.h
 *
 *  Created on: Mar 18, 2022
 *      Author: Fulvio Laudisio
 */

#ifndef OBS_CTRL_SEQIDATAMGR_HPP_
#define OBS_CTRL_SEQIDATAMGR_HPP_

#include <fitsio.h>

#include "IMessage.hpp"
#include "IXmlParser.hpp"
#include "IElement.hpp"
#include "IProperty.hpp"
#include "IBase.hpp"
#include "IIn.hpp"
#include "IOut.hpp"
#include "Socket.hpp"
#include "System.hpp"


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

//#include "util/indiClient2.h"
#include "util/Macro.h"
#include "util/convert.h"
#include "util/shins_util.h"


using indi::IBase;
using indi::IMessage;
using indi::IOut;
using indi::IProperty;
using indi::IIn;
using indi::IElement;
using indi::IXmlParser;

using pcf::System;

namespace su = shins::util;
namespace suc = shins::util::constants;


struct FitsKeyValues
{
    int BZero;
    int BScale;
};

struct SInstrumentHeader
{
    su::tagElementHeader cal_fiber_focus_lamp;
    su::tagElementHeader cal_fiber_defocus_lamp;
    su::tagElementHeader cal_flat_field_lamp;

    su::tagElementHeader cal_mirror_dep;
    su::tagElementHeader cal_fiber_dep;
    su::tagElementHeader cal_filter_dep;

    su::tagElementHeader shutter;
    su::tagElementHeader inbeam_dep;
    su::tagElementHeader pupil_lens_dep;
    su::tagElementHeader inbeam_tt;

    su::tagElementHeader apodizer_w;
    su::tagElementHeader coro_slit_w;
    su::tagElementHeader lyot_grism_w;
    su::tagElementHeader sci_filt_w1;
    su::tagElementHeader sci_filt_w2;
    su::tagElementHeader db_filt_w;
    su::tagElementHeader nd_filt_w;

    su::tagElementHeader derotator;
    su::tagElementHeader adc;

    su::tagElementHeader instrument_mode;
    su::tagElementHeader adc_mode;
    su::tagElementHeader drot_mode;
    su::tagElementHeader mask_comb;
    su::tagElementHeader filt_combo;

    float temperature_start, temperature_end;
    bool init;
};

struct STelescopeEnv
{
    float dimm_seeing_zenith, dimm_seeing_elevation, dimm_mean_flux, lbt_pressure, lbt_temp, lbt_humidity, lbt_dewpoint, lbt_wind_speed, lbt_wind_dir, lbt_wind_dir_raw, lbt_wind_speed_front, lbt_wind_dir_front, lbt_wind_dir_raw_front;
    float air_mass, moon_alt, moon_az, sun_alt, sun_az, parallactic_angle;

    float achieved_alt, achieved_az, mcs_elevation, mcs_azimuth; //target_alt, target_az
    float epoch, target_ra, target_dec, achieved_ra, achieved_dec;
    float ao_ref_ra, ao_ref_dec, ao_ref_mag, guide_star_ra, guide_star_dec, target_decoffset, target_raoffset;
    float ao_offsetx, ao_offsety, ao_offsetz;
    float tel_trk_RA, tel_trk_DEC, zenith_dist;
    std::string az_tracking_state, el_tracking_state, tcs_dec, tcs_ra, utc, lst, telescope_mode, ao_mode, pointing_model, hour_angle;
    bool lbt_weather_alive;
};

class SeqDataMgr
{
    Ice::PropertiesPtr m_props;
public:
    int  getJsonStatus(std::string & jsonStatus);
    SeqDataMgr(Ltcs::IifServiceWorkerInterfacePtr &_iif, Ice::PropertiesPtr prop);
    ~SeqDataMgr();
    void UpdateTcsInterface(Ltcs::IifServiceWorkerInterfacePtr &_iif){ m_iif = _iif; };
    int setContext(const std::map<std::string, std::string> & _osContext);
    int setLampsStatus(const std::map<std::string, std::string> & _osLampsStatus);
    int sashaSetup(const std::map<std::string, std::string> & _dSashaSetup);
    int sashaSetup2(const std::map<std::string, std::string> & _dSashaSetup);
    int sashaSetFrequency(const std::map<std::string, std::string> & _dSashaSetup);
    int sashaExpose(std::vector<std::string> & out_files);
    int sashaEnableSave(const std::map<std::string, std::string> & _dSashaSetup);
    void abortExposure();
    void setFlags(uint64_t flags, uint64_t more_flags);
    void unsetFlags(uint64_t flags, uint64_t more_flags);
    void toggleFlags(uint64_t flags, uint64_t more_flags);
    void SetMotorStatusCallback(void (* pCB)(su::tagElementHeader & el)){m_pGetMotorStatus = pCB;};
    void SetRtcStatusCallback(const std::string & (* pCB)(const std::string & key)){m_pGetRtcStatus = pCB;};
    void SetTcsPresetCallback(const su::STcsPreset & (* pCB)()){m_pGetTcsPreset = pCB;};
    void updateInstrumentHeader();
    static const su::SObContext & GetObContext(){ return m_pSeqDataMgr->m_obContext;};

private:
    int sashaEndSetup(std::map<std::string, std::string> & _dTimeoutSetup, bool ndit_changed);
    std::string GetReadoutRegion(int & xmin, int & xmax, int & ymin, int & ymax);
    void (* m_pGetMotorStatus)(su::tagElementHeader & el);
    const std::string & (* m_pGetRtcStatus)(const std::string & key);
    const su::STcsPreset & (* m_pGetTcsPreset)();
    float getMeanTemperature();
//    boost::shared_ptr<indiClient2> m_ptrIc2;
    std::map<std::string, std::string> m_mapFitsKeywords;
    std::map<std::string, std::string> m_mapFitsKeywordsComments;
    std::map<std::string, std::string> m_rtcKeywords;
    int SetFitsValues(fitsfile * fptr);
    Ltcs::IifServiceWorkerInterfacePtr m_iif;

    // FLAGS
    bool m_bFastSavingMode;

    bool m_bReceivingFitsFile;
    bool m_bSaveOnlyExposedFiles;
    bool m_bSaveIncomingBlob;
    bool m_bFlagChanged;
    bool m_bBlobArrived;
    bool m_bReceivedEof;
    bool m_bInstrumentSetupUpdated;
    bool m_bForcePropertySet;
    bool m_bTest01;
    su::STcsPreset m_TcsPreset;

    su::SObContext m_obContext;
    std::map<std::string, std::string> m_sashaSetup;
    std::vector<std::string> m_timeoutSetup;
    SInstrumentHeader m_instrumentHeader;

    int m_ExpectedBlobs;
    int m_timoeout_multiplier;

    void getTelescopeEnv(STelescopeEnv & env);
    void getMaskCombo(SInstrumentHeader & ih);
    IceUtil::Mutex m_getFitsMutex;
    int m_getFitsAbortFlag;
    int UpdateFitFile(fitsfile * pInFit, fitsfile * ptrFits);
    static void * fit_mem_realloc(void * old_pointer, size_t new_size);
    static SeqDataMgr * m_pSeqDataMgr;

    pthread_t m_indi_tid;
    std::vector<IProperty> m_newProperties;
    IceUtil::Mutex m_newPropMutex;
    IceUtil::Mutex m_exposeMutex;
    void StartIndiClientThread();
    static void * indi_client_thread(void * pMe);
    std::string full_property_string(const IProperty &prop);
    void UpdateProperty(const IProperty & prop);
    void CheckUpdateProperty(const IProperty & prop);
    void SendNewProperty(IProperty & prop);
    void SaveIncomingFile(const IProperty & prop);
    void LogCfitsioStack(int n);
    std::string m_last_generated_file;
    std::vector<std::string> m_last_generated_files;
    std::map<std::string, IProperty &> m_sashaProps;
    IProperty sashaSave;
    IProperty sashaObjName;
    IProperty sashaNumSeqs;
    IProperty sashaSeqNum;
    IProperty sashaAcquire;
    IProperty sashaNumCoadds;
    IProperty sashaNumDrops;
    IProperty sashaNumReads;
    IProperty sashaNumGroups;
    IProperty sashaNumResets;
    IProperty sashaReadout;
    IProperty sashaReadoutRegion;
    IProperty sashaBlob;
    IProperty sashaLargestFileNumber;
    IProperty sashaExposeProp;
    IProperty sharknirTemperatureDetector;
    IProperty sharknirTemperatureColdFinger;
    IProperty sharknirTemperatureInnerVessel;
    IProperty sharknirTemperatureOuterVessel;
    IProperty sashaPressure;
    IProperty sashaStop;
    IProperty sashaFrequencyMode;
    IProperty sashaExposureTime;
    IProperty sashaEnableCont;
    IProperty sashaIntegrationTime;
    IProperty lbtLeftInstrument;

    std::map<std::string, bool> m_sashaPropsSet;
    bool WaitSetMessages(int timeout);
    bool WaitStartAcquireOff(unsigned int timeout);
    bool WaitBLOB(unsigned int timeout);
    std::map<std::string, float> m_sashaTiming;
    std::map<std::string, float> m_sashaSizes;
    unsigned int estimateTiming();
    unsigned int estimateBlobDelivery();
    int checkContinuousFlag();
};


#endif /* OBS_CTRL_SEQIDATAMGR_HPP_ */
