#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() { 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; }

    ClassDef(MVector3, 1) // A specialized TVector3 storeing a star-name
};

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

    TExMap     fMapG;      //! A map with all gui primitives and tooltips
    TGToolTip *fToolTip;   //! The tooltip currently displayed

    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

    virtual Int_t ConvertToPad(const TVector3 &w, TVector2 &v) const;
    virtual void  AddPrimitives(TString o);
    virtual void  SetRangePad(Option_t *o);

    Int_t     Convert(const TRotation &rot, TVector2 &v) const;
    void      Draw(const TVector2 &v0, const TRotation &rot, TArrayI &dx, TArrayI &dy, Int_t stepx, Int_t stepy, Int_t type);
    void      DrawPrimitives(Option_t *o);
    Bool_t    DrawLine(const TVector2 &v0, Double_t dx, Double_t dy, const TRotation &rot, Int_t type);
    void      DrawGrid(const TVector3 &v0, const TRotation &rot, Int_t type);
    TRotation AlignCoordinates(const TVector3 &v) const;
    void      Paint(Option_t *o="");
    Int_t     DistancetoPrimitive(Int_t px, Int_t py);
    //void      RecursiveRemove(TObject *obj);
    void      PaintMap();
    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();
    }

protected:
    enum {
        kHasChanged  = BIT(15), // Display has changed
        kGuiActive   = BIT(16), // GUI is interactive
        kPlainScreen = BIT(17), // View is a plain screen view
        kMirrorX     = BIT(18), // Mirror display in X
        kMirrorY     = BIT(19), // Mirror display in Y
        kNoToolTips  = BIT(20)  // suppress tooltips
    };

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

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

    virtual TString GetPadTitle() const;
    TRotation GetGrid(Bool_t local);
    void      DrawStar(Double_t x, Double_t y, const TVector3 &v, Bool_t t, const char *txt=0);
    void      Update(Bool_t upd=kFALSE);

    void      ExecuteEventKbd(Int_t keycode, Int_t keysym);
    void      ExecuteEvent(Int_t event, Int_t mp1, Int_t mp2);
    TObject  *PickObject(Int_t px, Int_t py, TString &str) const;
    char     *GetObjectInfo(Int_t px, Int_t py) const;

    void AddMap(TObject *k, void *v=0)
    {
        fMapG.Add(fMapG.GetSize(), (Long_t)k, (Long_t)v);
    }

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

    void   SetNoToolTips(Bool_t b=kTRUE)     { b ? SetBit(kNoToolTips) : ResetBit(kNoToolTips); } // *TOGGLE* *GETTER=HasNoToolTips
    Bool_t HasNoToolTips() const             { return TestBit(kNoToolTips); }

    Double_t GetLimMag() const { return fLimMag; } // Get Limiting Magnitude
    Double_t GetRadiusFOV() const { return fRadiusFOV; } // Get maximum radius of Field Of View

    void Delete(Option_t *o="") { fList.Delete(); DeleteMap(); } // Delete list of stars

    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(); } // Print all stars

    TList *GetList() { return &fList; } // Return list of stars

    void Draw(Option_t *o="");
    void SetDrawOption(Option_t *option="")
    {
        TObject::SetDrawOption(option);
        Update(kTRUE);
    } //*MENU*

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

    ClassDef(MAstroCatalog, 1) // Display class for star catalogs
};
#endif
