 /*
* $Header: https://oberon.oapd.inaf.it/shins/trunk/shins/src/iif/Service/LtcsIifServiceWorker.h 3896 2022-04-13 13:24:17Z depa $
*
*/

/** @file
* @since 2011-08-30
* @author kittmann
*/

#pragma once

#include <config.h>
#include <ostream>
#include <string>
#include <vector>
#include <list>
#include <limits>

#include <Python.h>
#include <boost/python.hpp>

#include <Nice/Property.h>
#include <Nice/Time.h>
#include <Nice/Map.h>
#include <Basda/Device.h>
#include <Basda/ServiceLite.h>
#include <Basda/ServiceWorker.h>
#include <Basda/ServiceWorkerSkeleton.h>
#include <Basda/Vino/FitsCard.h>

#include <Ltcs/Iif/ServiceWorkerSkeleton.h>
#include <LbtoIIFInterfaceFactory.h>
#include <LbtoIIFInterface.h>
#include <Ltcs/Iif/IifSide.h>
#include <Ltcs/Iif/Iif2fitsKw.h>

namespace Ltcs
{
/**
 * @brief This class is the wrapper of the IIF interface.
 */
class IifServiceWorker : public Ltcs::IifServiceWorkerSkeleton
{
private:
	struct DeviceAsyncImpl : Basda::DeviceAsync
	{
		virtual int asyncWait(const Nice::Time & _t);
		virtual int asyncStatus(const std::string & _commandName, int _percent);

		IifServiceWorker * m_service;

		/**
		 * @brief member to keep the last command name
		 *
		 * If the current running command is interrupted by another command
		 * the completion bar command name will be changed and need to be
		 * set back to the previous running command. */
		std::string m_commandName;

		int m_percent;
	};

	/**
	* @brief This struct is the implementation of the asynchronous
	*        command status method. */
	struct DeviceCmdAsyncImpl : DeviceAsyncImpl
	{
		/**
		 * @brief asynchronous status
		 */
		virtual int asyncStatus(const std::string & _commandName, int _percent);

	};

	Ice::CommunicatorPtr m_communicator;
	lbto::FactoryPrx m_factory;

#ifdef LN_TCS_SINGLE_ICE
	/** One ICE proxy to the IIF for SX, for DX or for both
	*/
	lbto::IIFServerPrx m_iif;
#else
	lbto::IIFServerPrx m_iif[2];
#endif

	void logResults(const lbto::result _res, const std::string _cmd);

	void status();

	void setReachable(bool _reachable);

	/**
	* @brief This command returns a rotator trajectory for the future.
	*   This is essentially (up to sign and offset) a parallactic angle
	*   predicted by the PCS.
	* @param _startime the start time in UTC scale and in MJD format
	* @param _count    the number of polynomials wanted
	* @param _interval the time interval between polynomials in [seconds]
	* @param _order    the polynomial order in the range 0, 1 or 2.
	* @param _side     the command side. possible values: "left", "right", "both"
	*
	* @return rotator polynomial
	*
	* The command returns an ORDER+2 array of t0, p, [v, [a/2]] values
	* for each polynomial requested in the result strings. v is returned
	* if the order is greater than 0, and a/2 is returned if the order
	* is greater than 1. t0 is in MJD days UT, p is in radians, v is in
	* radians/sec, and a is in radians/sec^2. Thus the position of
	* the rotator at time t is P(t)=p + v*(t-t0)v+ (a/2)*(t-t0)^2.
	* Where (t-t0) is in seconds. Note that a/2, the polynomial coefficient (not a,
	* the second derivative) is returned by
	* the command. */
	virtual Nice::SeqSeqDouble getRotatorPolynomials(double _starttime, int _count,
	                double _interval, int _order, const std::string & _side );

	/*!***********************************
	* @brief One polynomial representation of an angle over time. */
	struct LBTPolynomial
	{
		/**
		* @brief time of start in MJD (UTC) */
		double time;
		/**
		* @brief angle at the time of start (rad) */
		double angle;
		/**
		* @brief first time derivative of angle at the time of start (rad/sec) */
		double v;
		/**
		* @brief second taylor coefficient of angle at the time of start (rad/sec^2) */
		double a;
	};

	/** dd2keys[i] is the index in keys() associated with ddents[i]. */
	vector<int> dd2keys;
	void initXml();
	void initDD(const Ltcs::IifSide station);


public:
	/** Name of the file with DD keys and values .
	* The file contents shows keys and values separated by a blank
	* Typically $INSROOT/var/log/IifSnapshot */
	string m_fMonit;

	/** Name of the ASCII template file.
	* The file contents follows the standard of the cfitsio template header cards.
	* Typically $INSROOT/var/log/ltcsSnapshot.tpl .
	* @since 2017-06-23  */
	string m_fFtpl;

	/** The SX/DX side(s) at which the instrument is registered by the
	* telescope operator/TCS (not necessarily authorized !), left, right, both or none.  */
	Ltcs::IifSide m_iifSidReg;

	/** The SX/DX side(s) at which the instrument is configured according to iif-svc.cfg
	* left, right or both. 	*/
	Ltcs::IifSide m_iifSidCfg;

	/** The set of keywords to be reported (FITS and liifSnapshotGUI)  */
	vector<Ltcs::Iif2fitsKw> m_keys;

	/** The DD entries to be requested from the IIF
	* The type is typedef'd in src/iif/Interface/LbtoIIFInterface.h . */
	lbto::SeqDD m_ddents;

	/** The star set of the most recent preset */
	lbto::SeqPos2 m_scat;

	/** The KFP coordinates of m_scat (hashed from a previous getKFPCoordinates() call */
	Nice::SeqPoint m_kfpHash[2];


	IifServiceWorker ( const Nice::JointPtr & _config );

	virtual ~IifServiceWorker();

	virtual void init();

	virtual void deinit();

	virtual void activate();

	virtual void deactivate();

	virtual void terminate();

	virtual void errorOffline();
	virtual void errorStandby();
	virtual void errorOnline();
	virtual void errorWorking();

	virtual void idleOffline();
	virtual void idleStandby();
	virtual void idleOnline();

	virtual void stop();

	virtual void abort();

	virtual bool isReachable();
	virtual bool isIifReachable();

	template <typename TTYPE> std::string getAny(const char * ddnam, std::string propnam, const char *lognam =0);


	virtual double getDouble(const std::string & ddnam, const std::string & lognam);
#if 0
	virtual int getInt(const std::string & ddnam, const std::string & lognam);
	virtual std::string getString(const std::string & ddnam, const std::string & lognam);
#endif

	virtual std::string getRA();
	virtual double getRAradians();

	virtual std::string getDEC();
	virtual double getDECradians();

	virtual double getParallacticAngle();
	virtual double getAlt();
	virtual double getAz();
	virtual double getEpoch();

	virtual std::string getUTC();
	virtual std::string getLST();
	virtual double getHourAngle();
//    virtual std::string getHourAngleHms();

	virtual std::string setPresetTelescope(int _raH, int _raMin, double _raSec, int _decDeg, int _decMin, double _decSec);

	virtual std::string setPresetTelescopeCat(const lbto::SeqPos2 & stars);
	virtual std::string setPresetTelescopeStar(const lbto::position2 & star);
	virtual lbto::result iifSyncPresetTelescope(double leftRotAngle,  const std::string & leftRotMode,  const std::string & leftTelescopeMode,
	                                            double rightRotAngle, const std::string & rightRotMode, const std::string & rightTelescopeMode);
	virtual lbto::result iifSyncOffsetPointing (double leftOffX,  double leftOffY,  const std::string & leftCoordSys,  const std::string & leftMoveType,
	                                            double rightOffX, double rightOffY, const std::string & rightCoordSys, const std::string & rightMoveType);


	virtual std::string setOffsetGuiding(double _ra, double _dec, const std::string & _coordSys, const std::string & _side);

	virtual std::string setOffsetPointing(double _ra, double _dec, const std::string & _coordSys, const std::string & _moveType, const std::string & _side);

	virtual Nice::SeqSeqDouble getRotatorPolynomials(Nice::Date _startTime);
	virtual Nice::SeqPoint getKFPCoordinates(const std::string & _side);
	virtual lbto::SeqPos2 getPresetStars();

	void poll();
	void snapshot();
	bool isSlewing();
	operator Nice::SkyPoint();

	static double hexToDeg(const std::string & hdms);
	virtual Basda::VinoFitsCardBox getFits(const double & _pixscal=0);
	virtual void toKVPairFile();
	virtual std::string getObject();
	virtual std::string getLINCstation();

	virtual Ltcs::IifSide getParam();

	virtual lbto::result iifAcquireRefAO(bool repointFlag, const std::string & side);

	virtual lbto::result iifAuthorize();

	virtual lbto::result iifAuthorize2(const std::string & side);

	virtual lbto::result iifBinocularControl(const std::string & flag);

	virtual lbto::result iifCheckRefAO(const std::string & side);

	virtual lbto::result iifClearHotspot();

	virtual lbto::result iifClearNonSidereal(bool override);

	virtual lbto::result iifClearOffset();

	virtual lbto::result iifClearReference();

	virtual lbto::result iifClearStars();

	virtual lbto::result iifCorrectModesAO(const lbto::SeqModes & modes, const std::string & side );

	virtual lbto::result iifGetKFPCoordinates(const lbto::SeqPos & list, const std::string & side);

	virtual lbto::result iifGetKFPCoordinates2(const lbto::SeqPos2 & list, const std::string & side);

	virtual lbto::result iifGetParameter(const lbto::SeqDD & _dd);

	virtual lbto::result iifGetRotatorPolynomials(double start, int count, double interval, int order, const std::string & side );

	virtual lbto::result iifGetRotatorTrajectory(double seconds, double interval, double start, const std::string & side);

	virtual lbto::result iifLogEvent(const std::string & event, const std::string & description);

	virtual lbto::result iifMaximizeWrapTime(bool azflag, bool rotflag, const std::string & side);

	virtual lbto::result iifModifyAO(int NModes, double Freq, int Nbins, double TTmod, const std::string & F1spec, const std::string & F2spec, const std::string & side);

	virtual lbto::result iifMove(double x, double y, double z, 
	                             double rx, double ry, double rz,
	                             int dflag, const std::string & movetype,
	                             const std::string & ope, int time,
	                             const std::string & side);

	virtual lbto::result iifMoveFocus(double absPos, const std::string & ope, const std::string & side );

	virtual lbto::result iifMoveXY(double xmov, double ymov, const std::string & ope, const std::string & side);

	virtual lbto::result iifMoveXYZ(double xmov, double ymov, double zmov, const std::string & side );

	virtual lbto::result iifOffsetGuiding(double angle, double offx, double offy, const std::string & _coordsys, const std::string & side);

	virtual lbto::result iifOffsetPointing(double _rotangle, 
	                                       double _offx,
	                                       double _offy,
	                                       const std::string & _coordsys,
	                                       const std::string & _ope,
	                                       const std::string & _np,
	                                       const std::string & _movetype,
	                                       const std::string & _side);

	virtual lbto::result iifOffsetPointing2(double _rotangle,
	                                        double _offx,
	                                        double _offy,
	                                        const std::string & _coordsys,
	                                        const std::string & _movetype,
	                                        const std::string & _side);

	virtual lbto::result iifOffsetXYAO(double DeltaX, double DeltaY, const std::string & side );

	virtual lbto::result iifOffsetZAO(double DeltaZ, const std::string & side);

	virtual lbto::result iifPauseAO(const std::string & side);

	virtual lbto::result iifPauseGuiding(const std::string & side);

	virtual lbto::result iifPresetAO(const std::string & AOMode, const std::string & side);

	virtual lbto::result iifPresetFlatAO(const std::string & flat, const std::string & side );

	virtual lbto::result iifPresetTelescope(double rotangle, const std::string & rotmode, const std::string & mode, const std::string & side);


#if 0
	static lbto::result iifPresetTelescope2(lbto::IIFServerPrx m_iif, double rotangle,
	                                const std::string rotmode,
	                                const std::string mode,
	                                const std::string side);
#endif

	virtual lbto::result iifRefineAO(const std::string & method, const std::string & side);

	virtual void iifRemove();

	virtual lbto::result iifResumeAO(const std::string & side);

	virtual lbto::result iifResumeGuiding(const std::string & side);

	virtual lbto::result iifRotateCommon(double z, double angle, double direction, const std::string & side);

	virtual lbto::result iifRotatePrimary(double distance, double angle, double direction, const std::string & side);

	virtual lbto::result iifRotateZ(double angle, const std::string & movetype, const std::string & side );

	virtual lbto::result iifRotHold(const std::string & side );

	virtual lbto::result iifRotReady(bool enable, const std::string & side);

	virtual lbto::result iifRotServicePosition(double angle, const std::string & side );

	virtual lbto::result iifRotTrack(const std::string & side);

	virtual lbto::result iifRunAO(const std::string & repointFlag, const std::string & side);

	virtual lbto::result iifSendWavefront(const lbto::SeqWF & wfs, const std::string & OPE, const std::string & side);

	virtual lbto::result iifSetAGWFilter(int filterNumber, const std::string & side);

	virtual lbto::result iifSetGuidingBinning(int factor, const std::string & side);

	virtual lbto::result iifSetGuidingHotspot(double coord1, double coord2, const std::string & movetype, const std::string & side);

	virtual lbto::result iifSetHotspot(double _offx, double _offy);

	virtual lbto::result iifSetNonSidereal(const lbto::nonsidereal & target, bool override);

	virtual lbto::result iifSetOffset(double _offx, double _offy, const std::string & _coordsys);

	virtual lbto::result iifSetOffset2(double coord1, double coord2, const std::string & system, const std::string & movetype);

	virtual lbto::result iifSetParameter(const lbto::SeqDD & list);

	virtual lbto::result iifSetPMTerm(const std::string & _name, double value, const std::string & side );

	virtual lbto::result iifSetPMTerm2(const std::string & _name, double value, const std::string & movetype, const std::string & side);

	virtual lbto::result iifSetReference(const lbto::SeqPos & list);

	virtual lbto::result iifSetReference2(const lbto::SeqPos2 & list);

	virtual lbto::result iifSetReference22(const lbto::SeqPos2 & list, const std::string & side);

	virtual lbto::result iifSetStars(const lbto::SeqPos & _stars);

	virtual lbto::result iifSetStars2(const lbto::SeqPos2 & list);

	virtual lbto::result iifSetStars22(const lbto::SeqPos2 & list, const std::string & side);

	virtual lbto::result iifSetTarget(double coord1, double coord2, const std::string & coordsys, double epoch, float wl);

	virtual lbto::result iifStandby(int level, const std::string & side);

	virtual lbto::result iifStartAO(const std::string & side);

	virtual lbto::result iifStepFocus(double relPos, const std::string & ope, const std::string & side);

	virtual lbto::result iifStopAO(const std::string & reason, const std::string & side);

	virtual lbto::result iifTipTilt(double xrot, double yrot, const std::string & ope, const std::string & side);

	virtual lbto::result iifUpdateNonSiderealTarget( double RArate, double DECrate);

	virtual lbto::result iifUpdatePointingReference(const std::string & offset_coord, const std::string & side);

	virtual lbto::result iifUpdateTargetWavelength(float wavelength, const std::string & side);

protected:
	Basda::VinoFitsCardBox getFitsWithWcs(const double pixsc=0., const double ctrpx[] =0, const double wcsAng = std::numeric_limits<double>::quiet_NaN());
private:

};
typedef IceUtil::Handle<Ltcs::IifServiceWorker> IifServiceWorkerPtr;
}
