#ifndef MARS_MAstroCatalog
#define MARS_MAstroCatalog

#ifndef ROOT_TVector3
#include <TVector3.h>
#endif
#ifndef ROOT_TExMap
#include <TExMap.h>
#endif
#ifndef ROOT_TList
#include <TList.h>
#endif

class MTime;
class MObservatory;
class TArrayI;
class TGToolTip;

class MVector3 : public TVector3
{
private:
    enum VectorType_t
    {
        kIsInvalid,
        kIsRaDec,
        kIsZdAz,
        kIsAltAz,
        kIsArbitrary
    };

    VectorType_t fType;

    TString fName;

public:
    /*
     MVector3(Double_t theta=0, Double_t phi=0, Double_t mag=1)
     {
     SetMagThetaPhi(exp(mag), theta, phi);
     }*/
    MVector3() { fType=kIsInvalid; }
    MVector3(const TVector3 &v3) : TVector3(v3) { fType=kIsArbitrary; }
    Double_t Magnitude() const { return -2.5*TMath::Log10(Mag()); }

    void SetRaDec(Double_t ra, Double_t dec, Double_t mag)
    {
        fType = kIsRaDec;
        SetMagThetaPhi(pow(10, -mag/2.5), TMath::Pi()/2-dec, ra);
    }
    void SetName(const TString &str) { fName = str.Strip(TString::kBoth); }
    void SetZdAz(Double_t zd, Double_t az, Double_t mag)
    {
        fType = kIsZdAz;
        SetMagThetaPhi(pow(10, -mag/2.5), zd, az);
    }
    void SetAltAz(Double_t alt, Double_t az, Double_t mag)
    {
        fType = kIsAltAz;
        SetMagThetaPhi(pow(10, -mag/2.5), TMath::Pi()/2-alt, az);
    }

    const char *GetName() const { return fName; }

    MVector3 GetZdAz(const MObservatory &obs, Double_t gmst) const;
    MVector3 GetZdAz(const MTime &time, MObservatory &obs) const;
    MVector3 GetRaDec(const MObservatory &obs, Double_t gmst) const;
    MVector3 GetRaDec(const MTime &time, MObservatory &obs) const;

    ClassDef(MVector3, 1)
};

class MAstroCatalog : public TObject
{
private:
    Double_t fLimMag;    // [1]   Limiting Magnitude
    Double_t fRadiusFOV; // [deg] Radius of Field of View

    TGToolTip *fToolTip; //!

    void ShowToolTip(Int_t px, Int_t py, const char *txt);

    TString FindToken(TString &line, Char_t tok=',');

    Int_t   atoi(const TSubString &sub);
    Float_t atof(const TSubString &sub);
    Int_t   atoi(const TString &s);
    Float_t atof(const TString &s);

//#if ROOT_VERSION_CODE < ROOT_VERSION(4,00,03)
    Bool_t fPlainScreen;  //! Just a dummy!!!! ([Set,Is]Freezed)
//#endif

protected:
    enum {
        kHasChanged  = BIT(15),
        kGuiActive   = BIT(16),
        kPlainScreen = BIT(17)
    };

    TExMap   fMapG;
    TList    fList;      // List of stars loaded
    MVector3 fRaDec;     // pointing position

    MObservatory *fObservatory; // Possible obervatora location
    MTime        *fTime;        // Possible observation time

    virtual Int_t  Convert(const TRotation &rot, TVector2 &v, Int_t type=0);
    virtual Bool_t DrawLine(const TVector2 &v0, Double_t dx, Double_t dy, const TRotation &rot, Int_t type);
    virtual void   AddPrimitives(Option_t *o);
    virtual void   DrawPrimitives(Option_t *o);
    virtual void   SetRangePad();
    void  Draw(const TVector2 &v0, const TRotation &rot, TArrayI &dx, TArrayI &dy, Int_t stepx, Int_t stepy, Int_t type);
    void  DrawNet(const TVector2 &v0, const TRotation &rot, Int_t type);
    void  DrawStar(Double_t x, Double_t y, const TVector3 &v, Bool_t t, const char *txt=0);
    void  Paint(Option_t *o="");
    Int_t DistancetoPrimitive(Int_t px, Int_t py);
    void  Update();

    void ExecuteEventKbd(Int_t keycode, Int_t keysym);
    void ExecuteEvent(Int_t event, Int_t mp1, Int_t mp2);

    void DeleteMap()
    {
        Long_t key, val;
        TExMapIter map(&fMapG);
        while (map.Next(key, val))
        {
            delete (TObject*)(key);
            if (!val)
                continue;

            delete (TString*)(val);
         /*
            Long_t key2, val2;
            TExMapIter map2(&fMapG);
            while (map2.Next(key2, val2))
                if (val==val2)
                {
                    delete (TObject*)key;
                    fMapG.Remove(key);
                }*/
        }
        fMapG.Delete();
    }
    void DrawMap()
    {
        Long_t key, val;
        TExMapIter map(&fMapG);
        while (map.Next(key, val))
            ((TObject*)key)->Draw();
    }

public:
    MAstroCatalog();
    ~MAstroCatalog();

    void SetTime(const MTime &time);
    void SetObservatory(const MObservatory &obs);
    void SetLimMag(Double_t mag) { fLimMag=mag;    Update(); } // *MENU* *ARGS={mag=>fLimMag}
    void SetRadiusFOV(Double_t deg)
    {
        //const Double_t max = TestBit(kPlainScreen) ? 90 : 55;
        const Double_t max = TestBit(kPlainScreen) ? 180 : 90;
        if (deg>max)
            deg=max;
        if (deg<=0)
            deg=1;

        fRadiusFOV=deg;

        Update();
    } // *MENU* *ARGS={deg=>fRadiusFOV}
    void SetRaDec(Double_t ra, Double_t dec) { fRaDec.SetRaDec(ra, dec, 1); Update(); }
    void SetRaDec(const TVector3 &v)         { fRaDec=v; Update(); }
    void SetGuiActive(Bool_t b=kTRUE)        { b ? SetBit(kGuiActive) : ResetBit(kGuiActive); }

    void   SetPlainScreen(Bool_t b=kTRUE)    { b ? SetBit(kPlainScreen) : ResetBit(kPlainScreen); Update(); } // *TOGGLE* *GETTER=IsPlainScreen
    Bool_t IsPlainScreen() const             { return TestBit(kPlainScreen); }

    Double_t GetLimMag() const { return fLimMag; }
    Double_t GetRadiusFOV() const { return fRadiusFOV; }

    void Delete(Option_t *o="") { fList.Delete(); DeleteMap(); }

    Int_t ReadXephem(TString catalog = "/usr/X11R6/lib/xephem/catalogs/YBS.edb");
    Int_t ReadNGC2000(TString catalog = "ngc2000.dat");
    Int_t ReadBSC(TString catalog = "bsc5.dat");

    void Print(Option_t *o="") const { fList.Print(); }

    TList *GetList() { return &fList; }

    void Draw(Option_t *o="");

    void EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected);

    ClassDef(MAstroCatalog, 1)
};
#endif
