#ifndef MCOSY_H
#define MCOSY_H

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

#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


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

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
    };

    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...

    ZdAz  fTrackingError; // Tracking Offset between SE and calc-pos [re]
    ZdAz  fOffset;        // Offset between se and re coordinate system [re]
    ZdAz  fZdAzSoll;      // Soll position when moving
    RaDec fRaDec;         // Position to track
    int   fTracking;      // Flag for present tracking action
    ZdAz  fAccuracy;      // Actual accuracy of Tracking
    ZdAz  fVelocity;      // Actual velocity of Tracking

    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;

    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();     // [se]

    Bool_t RequestRePos();
    Bool_t SetVelocity(const ZdAz &v);
    void SetPosVelocity(const Float_t ratio, Float_t vel, Float_t acc);

    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();

    int  SetPosition(const ZdAz &dst);

    void TerminateApp();

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

    int StopWaitingForSDO() const;
    void CheckForError();

    void StopMovement();
    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
