//
// This File contains the definition of the MGCoordinate-class
//
//   Author: Thomas Bretz
//   Version: V1.0 (1-8-2000)

#include "MGCoordinate.h"

#include <stdlib.h>    // atoi
#include <iostream>  // cout

#include <TSystem.h>
#include <TGLabel.h>
#include <TGTextEntry.h>

#include "slalib.h"
#include "slamac.h"

ClassImp(MGCoordinate);

using namespace std;

enum {
    IDM_kDeg,
    IDM_kMin,
    IDM_kSec
};

MGCoordinate::MGCoordinate(const TGWindow* p, const Int_t type,
                           const Int_t flag, const char *txt,
                           const Int_t deg, const UInt_t min, const UInt_t sec)
: TGFrame(p, 119, flag==1?76:46-(TString(txt).IsNull()?23:0), kSunkenFrame|kFixedSize), fSign('+'), fDeg(deg), fMin(min), fSec(sec), fLabel(0)
{
    fList = new MGList;

    const Int_t offset = TString(txt).IsNull() ? 23 : 0;

    // p = pointer to MainFrame (not owner)
    if (flag==1)
    {
        fTextEntryDeg = new TGTextEntry(this, "****", IDM_kDeg);
        fTextEntryMin = new TGTextEntry(this, "***",  IDM_kMin);
        fTextEntrySec = new TGTextEntry(this, "***",  IDM_kSec);
        // fTextEntryDeg->SetAlignment(kTextCenterX);
        // fTextEntryMin->SetAlignment(kTextCenterX);
        // fTextEntrySec->SetAlignment(kTextCenterX);
        fTextEntryDeg->Move( 7, 26-offset);
        fTextEntryMin->Move(47, 26-offset);
        fTextEntrySec->Move(81, 26-offset);
        fTextEntryDeg->MapWindow();
        fTextEntryMin->MapWindow();
        fTextEntrySec->MapWindow();
        fList->Add(fTextEntrySec);
        fList->Add(fTextEntryMin);
        fList->Add(fTextEntryDeg);

        Set(fTextEntryDeg, fDeg);
        Set(fTextEntryMin, fMin);
        Set(fTextEntrySec, fSec);
    }

    const int ypos = (flag==1?56:26)-offset;

    fLabelDeg = new TGLabel(this, "*****");
    fLabelMin = new TGLabel(this, "****");
    fLabelSec = new TGLabel(this, "****");
    fLabelDeg->SetTextJustify(kTextRight);
    fLabelMin->SetTextJustify(kTextRight);
    fLabelSec->SetTextJustify(kTextRight);
    fLabelDeg->Move(13, ypos);
    fLabelMin->Move(53, ypos);
    fLabelSec->Move(87, ypos);
    fLabelDeg->MapWindow();
    fLabelMin->MapWindow();
    fLabelSec->MapWindow();
    fList->Add(fLabelSec);
    fList->Add(fLabelDeg);
    fList->Add(fLabelMin);

    Set(fLabelDeg, fDeg);
    Set(fLabelMin, fMin);
    Set(fLabelSec, fSec);

    if (!TString(txt).IsNull())
    {
        fLabel = new TGLabel(this, txt);
        fLabel->SetTextJustify(kTextLeft);
        fLabel->Move(4, 4);
        fLabel->MapWindow();
        fList->Add(fLabel);
    }

    TGLabel *label;

    const char *sdeg = type==kETypeDeg ? "\xb0" : "h";
    const char *smin = type==kETypeDeg ? "'"    : "m";
    const char *ssec = type==kETypeDeg ? "\""   : "s";

    if (flag==1)
    {
        label = new TGLabel(this, sdeg);
        label->SetTextJustify(kTextLeft);
        label->Move(37, 29-offset);
        label->MapWindow();
        fList->Add(label);

        label = new TGLabel(this, smin);
        label->SetTextJustify(kTextLeft);
        label->Move(71, 29-offset);
        label->MapWindow();
        fList->Add(label);

        label = new TGLabel(this, ssec);
        label->SetTextJustify(kTextLeft);
        label->Move(107, 29-offset);
        label->MapWindow();
        fList->Add(label);
    }

    label = new TGLabel(this, sdeg);
    label->SetTextJustify(kTextLeft);
    label->Move(39, ypos);
    label->MapWindow();
    fList->Add(label);

    label = new TGLabel(this, smin);
    label->SetTextJustify(kTextLeft);
    label->Move(73, ypos);
    label->MapWindow();
    fList->Add(label);
 
    label = new TGLabel(this, ssec);
    label->SetTextJustify(kTextLeft);
    label->Move(107, ypos);
    label->MapWindow();
    fList->Add(label);

    MapWindow();
}

MGCoordinate::~MGCoordinate()
{
    delete fList;
}

Double_t MGCoordinate::GetVal() const
{
    const Int_t sgn = fSign=='-' ? -1 : 1;

    return (Double_t)sgn*(60*(60*fDeg+fMin)+fSec)/3600;
}

void MGCoordinate::Print(Option_t *o) const
{
    if (fLabel)
        cout << fLabel->GetText()->GetString() << " ";
    cout << fSign << fDeg << "\xb0 " << fMin << "' " << fSec << "\"" << endl;
}

void MGCoordinate::Set(TGLabel *label, Int_t val)
{
    char txt[20];

    sprintf(txt, "%s%d", label == fLabelDeg && fSign=='-'?"-":"", val);

    label->SetText(new TGString(txt));
}

void MGCoordinate::Set(TGTextEntry *entry, Int_t val)
{
    char txt[20];

    sprintf(txt, "%s%d", entry == fTextEntryDeg && fSign=='-'?"-":"", val);

    entry->SetText(txt);
}

void MGCoordinate::SetVal(const Double_t d)
{
    int dms[4];
    char sign;

    //** ndp    int     number of decimal places of arcseconds
    //** angle  double  angle in radians
    //** sign   char*   '+' or '-'
    //** idmsf  int[4]  degrees, arcminutes, arcseconds, fraction

    slaDr2af(0, d*D2PI/360.0, &sign, dms);

    fSign = sign;
    fDeg = dms[0];
    fMin = dms[1];
    fSec = dms[2];

    Set(fLabelDeg, fDeg);
    Set(fLabelMin, fMin);
    Set(fLabelSec, fSec);

    // Set(fTextEntryDeg, fDeg);
    // Set(fTextEntryMin, fMin);
    // Set(fTextEntrySec, fSec);
}


Bool_t MGCoordinate::Set(TGLabel *label, Int_t &val, TGTextEntry *entry)
{
    TString text = entry->GetText();

    Int_t newval = abs(atoi(text));

    Bool_t ok = (entry == fTextEntryDeg || (newval>=0 && newval<60));

    if (entry==fTextEntryDeg)
        fSign = text.Contains("-") ? '-' : '+';

    if (ok)
    {
        val = newval;
        Set(label, val);
    }

    Set(entry, val);

    return ok;
}

Bool_t MGCoordinate::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2)
{
    if (GET_MSG(msg)!=kC_TEXTENTRY || GET_SUBMSG(msg)!=kTE_ENTER)
        return kTRUE;

    // kC_TEXTENTRY        = 4,
    // kTE_TEXTCHANGED     = 1,
    // kTE_ENTER           = 2,

    switch (mp1)
    {
    case IDM_kDeg:
        if (!Set(fLabelDeg, fDeg, fTextEntryDeg))
            fTextEntryDeg->SelectAll();
        else
        {
            fTextEntryMin->SetFocus();
            fTextEntryMin->SelectAll();
        }
        return kTRUE;

    case IDM_kMin:
        if(!Set(fLabelMin, fMin, fTextEntryMin))
            fTextEntryMin->SelectAll();
        else
        {
            fTextEntrySec->SetFocus();
            fTextEntrySec->SelectAll();
        }
        return kTRUE;

    case IDM_kSec:
        if (!Set(fLabelSec, fSec, fTextEntrySec))
            fTextEntrySec->SelectAll();
        else
        {
            fTextEntryDeg->SetFocus();
            fTextEntryDeg->SelectAll();
        }
        return kTRUE;
    }

    return kTRUE;
}

