#ifndef MCOSY_H
#define MCOSY_H

#include "coord.h"
#include "msgqueue.h"
#include "network.h"
#include "MThread.h"
#include "MBending.h"

#ifndef MARS_Mobservatory
#include "MObservatory.h"
#endif

#define kDEG ((char)0x9c)  // Linux 'ø'

#define WM_WAIT         WM_NULL
//#define WM_PRESET       0x1000
#define WM_POSITION     0x1001
#define WM_TRACK        0x1002
#define WM_STOP         0x1003
//#define WM_CALIB        0x1004
#define WM_TPOINT       0x1005
#define WM_NEWTRACK     0x1006
#define WM_LOADBENDING  0x1007
#define WM_RESETBENDING 0x1008
#define WM_CALCALTAZ    0x1009
#define WM_HOME         0x100a
#define WM_TESTSE       0x100b
#define WM_GEAR         0x100c
#define WM_DISPLAY      0x100d
#define WM_TRACKPOS     0x100e

class ShaftEncoder;
class Macs;
class MGCosy;
class MCosy;
class TH1;

class MTTalk : public MThread
{
private:
    MCosy *fCosy;

    void *Thread();

public:
    MTTalk(MCosy *cosy) : MThread(false), fCosy(cosy)
    {
        SetPriority(10);
        Detach();
        Start();
    }
    ~MTTalk() { cout << "~MTTalk::MTTalk" << endl; }
};

class TTimer;
class MCosy : public Network, public MsgQueue, public TObject
{
    friend class MTTalk;

private:
    enum
    {
        kError    = 0x01,
        kMoving   = 0x02,
        kTracking = 0x04,
        kStopping = 0x08,
        kStopped  = 0x10
    };

    const MObservatory::LocationName_t fObservatory;

    ShaftEncoder *fZd1;
    ShaftEncoder *fZd2;
    ShaftEncoder *fAz;

    Macs *fMac1;
    Macs *fMac2;
    Macs *fMac3;

    MGCosy *fWin;

    TTimer *fUpdateGui;
    MTTalk *fTTalk;       // should be outsourced, like the starguider.
                          // with a generic interface to both...

    enum BackgroundAction_t
    {
        kBgdNone,
        kBgdTracking,
        kBgdSeTest,
        kBgdSeTestDispl,
        kBgdGear,
        kBgdGearDispl
    };

    BackgroundAction_t fBackground;    // Flag for present backgroundthread

    ZdAz  fTrackingError; // [rad] Tracking Offset between SE and calc-pos
    ZdAz  fOffset;        // Offset between se and re coordinate system [re]
    ZdAz  fZdAzSoll;      // [rad] Soll position when moving
    RaDec fRaDec;         // Position to track
    ZdAz  fAccuracy;      // Actual accuracy of Tracking
    ZdAz  fVelocity;      // Actual velocity of Tracking
    ZdAz  fMin;
    ZdAz  fMax;

    TH1  *fHist;
    Bool_t fTriggerDisplay;

    XY kGearRatio;        // describing the gear of the system [re/se]
    XY kGearRatio2;       // describing the gear of the system [re/deg]

    MBending fBending;

    UInt_t fStatus;

    ofstream *tpout;

    Bool_t AlignTrackingPos(ZdAz pointing, ZdAz &za) const;
    Bool_t CheckRange(const ZdAz &d) const;
    Double_t Starguider(Double_t mjd, ZdAz &dest) const;

    double Rad2SE(double rad) const;
    double Rad2ZdRE(double rad) const;
    double Rad2AzRE(double rad) const;
    double Deg2ZdRE(double rad) const;
    double Deg2AzRE(double rad) const;

    void SetStatus(UInt_t stat) { fStatus = stat; }
    UInt_t GetStatus() const { return fStatus; }

    ZdAz GetRePos();
    ZdAz GetRePosPdo();
    ZdAz GetSePos() const; // [se]

    Bool_t RequestRePos();
    Bool_t SetVelocity(const ZdAz &v);

    void SetPosVelocity(const Float_t ratio, Float_t vel);

    void DoRelPos(const ZdAz &rd, const Bool_t axe1, const Bool_t axe2);

    void InitSync();
    bool InitTracking();
    void LimitSpeed(ZdAz *vt, const ZdAz &vcalc) const;

    void TalkThread();
    void TalkThreadTracking();
    void TalkThreadSeTest();
    void TalkThreadGear();

    void DisplayHistTestSe(Bool_t del=kTRUE);
    void DisplayHistGear(Bool_t del=kTRUE);

    int  SetPosition(const ZdAz &dst, Bool_t track=kFALSE);

    void TerminateApp();

    void TrackPosition(const RaDec &dst); // ra, dec [rad]

    int StopWaitingForSDO() const;
    void CheckForError();

    void StopMovement();
    void StopTracking();

    void WaitForEndMovement();

    void Constructor(Int_t id1, Int_t id2, Int_t id3, Int_t id4, Int_t id5, Int_t id6);
    void ConstructorSE(Int_t id1, Int_t id2, Int_t id3);
    void ConstructorDemo();

    void ReadConfig();

    bool CheckNetwork();

public:
    MCosy(int mode, const char *dev, const int baud, MLog &out=gLog);
    ~MCosy();

    void Start();
    void Stop();

    void *Proc(int msg, void *mp);

    Bool_t HandleTimer(TTimer *t);

    // static ZdAz CorrectTarget(const ZdAz &src, const ZdAz &dst);
    //    static ZdAz RaDec2ZdAz(const double mjd, const RaDec &pos, const RaDec &pm=RaDec(0,0));

    ClassDef(MCosy, 0)
};

#endif
