#include "MGAccuracy.h"

#include <iostream>  // cout

#include <TArc.h>
#include <TLine.h>
#include <TText.h>
#include <TWbox.h>
#include <TGaxis.h>
#include <TGraph.h>
#include <TCanvas.h>

#include "MTime.h"
#include "MAstro.h"
#include "MPointing.h"

ClassImp(MGAccuracy);

using namespace std;

void MGAccuracy::DrawText(const char *c1, const char *c2, const char *c3, const char*txt)
{
    fCanvas->SetEditable(kTRUE);
    fCanvas->cd();

    TText text;
    text.SetTextAlign(22);  // centered, centered (s.TAttText)
    text.DrawText(-150, 265, txt);

    text.SetTextAlign(11);  // left, bottom (s.TAttText)
    text.SetTextColor(3);
    text.DrawText(220, -220, c1);

    text.SetTextColor(5);
    text.DrawText(220, -250, c2);

    text.SetTextColor(2);
    text.DrawText(220, -280, c3);

    fCanvas->SetEditable(kFALSE);
}

void MGAccuracy::DrawCircles(Double_t rad)
{
    fCanvas->SetEditable(kTRUE);
    fCanvas->cd();

    TArc arc;
    arc.SetFillStyle(4000);  // transparent
    arc.SetFillColor(39);
    arc.SetLineColor(3);     // green
    arc.SetLineStyle(2);     // dashed  (s. TAttLine)
    arc.DrawArc(0, 0, rad/2.);         // 0.5se

    arc.SetLineColor(5);     // yellow
    arc.DrawArc(0, 0, rad);            // 1.0se

    arc.SetLineColor(2);     // red
    arc.DrawArc(0, 0, rad*2.);         // 2.0se

    fCanvas->SetEditable(kFALSE);
}

void MGAccuracy::DrawCoordinateSystem()
{
    TWbox box;
    box.DrawWbox(-290, 290, -10, 240,  18,  2, 1);

//    TLine line;
//    line.DrawLine(-65*4,     0, 65*4,    0);
//    line.DrawLine(    0, -65*4,    0, 65*4);

    //
    // Can be replaced by TGaxis axe; in a later root version
    // than 3.01/06. I talked to Rene
    //
    TGaxis *axe;
    axe = new TGaxis(-60*4,   0, 60*4,  0,  -4, 4, 30204, "+-N");
    axe->SetTitle("Az"); // \xb0
    axe->SetBit(kCanDelete);
    axe->Draw();

    axe = new TGaxis(  0, -60*4,  0, 60*4,  -4, 4,   304, "+-N");
    axe->SetTitle("Zd"); // \xb0
    axe->SetLabelOffset(-0.02);
    axe->SetBit(kCanDelete);
    axe->Draw();
}

void MGAccuracy::InitText()
{
    fTxt = new TText(280, 280, "0' / 0'");
    fTxt->SetTextAlign(33); // right, top
    fTxt->SetTextColor(10);
    fTxt->Draw();

    fList->Add(fTxt);
}

void MGAccuracy::InitBar()
{
    fBar = new TLine(0, 0, 0, 0);
    fBar->SetLineColor(kBlack);
    fBar->SetLineStyle(1);
    fBar->SetLineWidth(5);
    fBar->Draw();

    fList->Add(fBar);
}

void MGAccuracy::InitCross()
{
    fLin1 = new TLine(0, 0, 0, 0);
    fLin2 = new TLine(0, 0, 0, 0);

    fLin1->SetLineColor(10); // white (s. TAttFill)
    fLin2->SetLineColor(10); // white
    fLin1->SetLineStyle(1);  // solid (s. TAttLine)
    fLin2->SetLineStyle(1); 

    fLin1->SetLineWidth(2);
    fLin2->SetLineWidth(2);

    fLin1->Draw();
    fLin2->Draw();

    fList->Add(fLin1);
    fList->Add(fLin2);
}

MGAccuracy::MGAccuracy(const TGWindow* p, const UInt_t w)
: MGEmbeddedCanvas("Accuracy", p, w, 300), fColorScale(360*60/16384)
{
    // FIXME: Overload MapWindow in newer Root versions to remove
    //        the contents of the graph!
    fGraph = new TGraph;
    fGraph->SetPoint(0, 0, 0);
    fGraph->SetLineColor(kBlue);
    fGraph->SetMarkerColor(kBlue);
    fGraph->SetMarkerStyle(kFullDotMedium);
    fGraph->Draw("LP");
    fList->Add(fGraph);

    DrawCoordinateSystem();

    InitText();
    InitCross();
    InitBar();

    InitCanvas();

    SetNoContextMenu();

    MTime t(-1);
    fTime = t.GetAxisTime();
}

MGAccuracy::~MGAccuracy()
{
}

// dist [deg]
void MGAccuracy::UpdateText(Float_t dist)
{
    dist *= 3600.; // [sec]

    int rs = TMath::FloorNint(fmod(dist, (float)60.));

    dist /= 60.;   // [min]
    int rm = (int)dist;

    char txt[100];
    rm ? sprintf(txt, "%d'%02d\"", rm, rs) : sprintf(txt, "%d\"", rs);

    fTxt->SetText(fTxt->GetX(), fTxt->GetY(), txt);

    fBar->SetY2(dist*60); // [sec]
    if (dist<fColorScale) //1*360*60/16384
        fBar->SetLineColor(kGreen);
    else
        if (dist<2*fColorScale) //2*360*60/16384
            fBar->SetLineColor(kYellow);
        else
            fBar->SetLineColor(kRed);

    SetModified();
}

// dist [deg]
void MGAccuracy::UpdateGraph(Float_t dist)
{
    MTime t(-1);
    const Double_t dtime = t.GetAxisTime()-fTime; // range [-0.5h, 0h]

    dist *= 60; // min

    static int odist = -1;
    if (odist==(int)(dist*10*60) && dtime<10)
        return;

    odist = (int)(dist*10*60);

    fGraph->SetPoint(fGraph->GetN(), dtime, dist*60);

    const Double_t ntime = dtime;
    for (int i=0; i<fGraph->GetN(); i++)
    {
        Double_t x, y;
        fGraph->GetPoint(i, x,       y);
        fGraph->SetPoint(i, x-ntime, y);
        //cout << i << ":  " << x-ntime << " / " << y << endl;
    }
    while (fGraph->GetN()>0)
    {
        Double_t x, y;
        fGraph->GetPoint(0, x, y);

        if (x==-ntime && y==0)
        {
            fGraph->RemovePoint(0);
            continue;
        }

        if (x>-4.75*60)
            break;

        fGraph->RemovePoint(0);
    }

    fTime = t.GetAxisTime();

    SetModified();
}

void MGAccuracy::Update(Float_t pzd, Float_t azd, Float_t aaz)
{
    const double dist = MAstro::GetDevAbs(pzd, azd, aaz);

    UpdateText(dist);
    UpdateGraph(dist);
}

void MGAccuracy::UpdateCross(Float_t x, Float_t y)
{
    //
    // x["], y["]
    //
    static int X = ~0;
    static int Y = ~0;

    int pixx = (int)(x/fPix);  // [pix]
    int pixy = (int)(y/fPix);  // [pix]

    if (X==pixx && Y==pixy)
        return;

    X = pixx;
    Y = pixy;

    fLin1->SetX1(x-5.);
    fLin1->SetX2(x+5.);

    fLin2->SetX1(x-5.);
    fLin2->SetX2(x+5.);

    fLin1->SetY1(y-5.);
    fLin1->SetY2(y+5.);

    fLin2->SetY1(y+5.);
    fLin2->SetY2(y-5.);

    SetModified();
}

void MGAccuracy::Update(ZdAz &pos, ZdAz &dev)
{
    // Estimate the distance in az direction on the camera plane
    const double daz = MAstro::GetDevAbs(pos.Zd(), 0, dev.Az())*3600.;

    //cout << "--> T: " << dev.Az()*60 << " " << dev.Zd()*60. << endl;

    UpdateCross(TMath::Sign(daz, dev.Az()), dev.Zd()*3600.);
    Update(pos.Zd(), dev.Zd(), dev.Az());

    UpdateCanvas();
}
