/* ======================================================================== *\
!
! *
! * This file is part of MARS, the MAGIC Analysis and Reconstruction
! * Software. It is distributed to you in the hope that it can be a useful
! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
! * It is distributed WITHOUT ANY WARRANTY.
! *
! * Permission to use, copy, modify and distribute this software and its
! * documentation for any purpose is hereby granted without fee,
! * provided that the above copyright notice appear in all copies and
! * that both that copyright notice and this permission notice appear
! * in supporting documentation. It is provided "as is" without express
! * or implied warranty.
! *
!
!
!   Author(s): Thomas Bretz, 05/2005 <mailto:tbretz@astro.uni-wuerzburg.de>
!
!   Copyright: MAGIC Software Development, 2000-2005
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//
// MHWeather
//
// Display weather data and the corresponding event rate
//
////////////////////////////////////////////////////////////////////////////
#include "MHWeather.h"

#include <TH1.h>
#include <TPad.h>
#include <TCanvas.h>
#include <TGaxis.h>

#include "MLog.h"
#include "MLogManip.h"

#include "MParList.h"

#include "MTime.h"
#include "MReportCC.h"
#include "MEventRate.h"

ClassImp(MHWeather);

using namespace std;

void MHWeather::ResetGraph(TGraph &g) const
{
    g.Set(1);
    g.SetPoint(0, 0, 0); // Dummy Point
    g.SetEditable();     // Used as flag: First point? yes/no
}

void MHWeather::InitGraph(TGraph &g) const
{
    ResetGraph(g);
    g.SetMarkerStyle(kFullDotMedium);
}

void MHWeather::AddPoint(TGraph &g, Double_t x, Double_t y) const
{
    if (g.IsEditable())
    {
        g.RemovePoint(0);
        g.SetEditable(kFALSE);
    }

    g.SetPoint(g.GetN(), x, y);
}

// --------------------------------------------------------------------------
//
// Setup histograms 
//
MHWeather::MHWeather(const char *name, const char *title)
{
    fName  = name  ? name  : "MHWeather";
    fTitle = title ? title : "Graphs for weather data";

    // Init Graphs

    fHumidity.SetNameTitle("Humidity", "Humidity");
    fTemperature.SetNameTitle("Temperature", "Temperature");
    fSolarRadiation.SetNameTitle("SolarRadiation", "Solar Radiation");
    fWindSpeed.SetNameTitle("WindSpeed", "Wind Speed");
    fEventRate.SetNameTitle("EventRate", "Event Rate at CC-REPORT time");

    InitGraph(fHumidity);
    InitGraph(fTemperature);
    InitGraph(fSolarRadiation);
    InitGraph(fWindSpeed);
    InitGraph(fEventRate);

    fHumidity.SetMarkerColor(kBlue);
    fTemperature.SetMarkerColor(kRed);
}

// --------------------------------------------------------------------------
//
// Setup the Binning for the histograms automatically if the correct
// instances of MBinning
//
Bool_t MHWeather::SetupFill(const MParList *plist)
{
    fReport = (MReportCC*)plist->FindObject("MReportCC");
    if (!fReport)
    {
        *fLog << warn << "MReportCC not found... abort." << endl;
        return kFALSE;
    }
    fRate = (MEventRate*)plist->FindObject("MEventRate");
    if (!fRate)
    {
        *fLog << warn << "MEventRate not found... abort." << endl;
        return kFALSE;
    }

    // Reset Graphs
    ResetGraph(fHumidity);
    ResetGraph(fTemperature);
    ResetGraph(fSolarRadiation);
    ResetGraph(fWindSpeed);
    ResetGraph(fEventRate);

    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Fill the histograms with data from a MMuonCalibPar and
// MMuonSearchPar container.
//
Bool_t MHWeather::Fill(const MParContainer *par, const Stat_t w)
{
    const MTime *t = dynamic_cast<const MTime*>(par);
    if (!t)
    {
        *fLog << err <<"MHWeather::Fill - ERROR: MTime not given as argument... abort." << endl;
        return kERROR;
    }

    const Double_t tm = t->GetAxisTime();

    AddPoint(fTemperature,    tm, fReport->GetTemperature());
    AddPoint(fHumidity,       tm, fReport->GetHumidity());
    AddPoint(fSolarRadiation, tm, fReport->GetSolarRadiation());
    AddPoint(fWindSpeed,      tm, fReport->GetWindSpeed());
    AddPoint(fEventRate,      tm, fRate->GetRate());

    return kTRUE;
}

void MHWeather::DrawGraph(TGraph &g, const char *y) const
{
    TH1 *h = g.GetHistogram();
    if (h)
    {
        delete h;
        g.SetHistogram(0);
        h = g.GetHistogram();
    }
    if (h)
    {
        TAxis *axe = h->GetXaxis();
        axe->SetLabelSize(0.033);
        axe->SetTimeFormat("%H:%M:%S %F1995-01-01 00:00:00 GMT");
        axe->SetTimeDisplay(1);
        axe->SetTitle("Time");
        if (y)
            h->SetYTitle(y);
    }
}

// --------------------------------------------------------------------------
//
// Update position of an axis on the right side of the histogram
//
void MHWeather::UpdateRightAxis(TGraph &g) const
{
    TH1 &h = *g.GetHistogram();

    const Double_t max = h.GetMaximum();
    if (max==0)
        return;

    TGaxis *axis = (TGaxis*)gPad->FindObject("RightAxis");
    if (!axis)
        return;

    axis->SetX1(g.GetXaxis()->GetXmax());
    axis->SetX2(g.GetXaxis()->GetXmax());
    axis->SetY1(gPad->GetUymin());
    axis->SetY2(gPad->GetUymax());
    axis->SetWmax(max);
}

// --------------------------------------------------------------------------
//
// Draw an axis on the right side of the histogram
//
void MHWeather::DrawRightAxis(const char *title) const
{
    TGaxis *axis = new TGaxis(gPad->GetUxmax(), gPad->GetUymin(),
                              gPad->GetUxmax(), gPad->GetUymax(),
                              0, 1, 510, "+L");
    axis->SetName("RightAxis");
    axis->SetTitle(title);
    axis->SetTitleOffset(0.9);
    axis->SetTextColor(kRed);
    axis->SetBit(kCanDelete);
    axis->Draw();
}

// --------------------------------------------------------------------------
//
// This displays the TGraph like you expect it to be (eg. time on the axis)
// It should also make sure, that the displayed time always is UTC and
// not local time...
//
void MHWeather::Draw(Option_t *opt)
{
    TVirtualPad *pad = gPad ? gPad : MakeDefCanvas(this);
    pad->SetBorderMode(0);

    AppendPad();

    pad->Divide(2,2);

    pad->cd(1);
    gPad->SetBorderMode(0);
    gPad->SetGridx();
    gPad->SetGridy();
    fHumidity.Draw("AP");
    fTemperature.Draw("P");
    DrawRightAxis("T [\\circ C]");

    pad->cd(2);
    gPad->SetBorderMode(0);
    gPad->SetGridx();
    gPad->SetGridy();
    fSolarRadiation.Draw("AP");

    pad->cd(3);
    gPad->SetBorderMode(0);
    gPad->SetGridx();
    gPad->SetGridy();
    fEventRate.Draw("AP");

    pad->cd(4);
    gPad->SetBorderMode(0);
    gPad->SetGridx();
    gPad->SetGridy();
    fWindSpeed.Draw("AP");
}

void MHWeather::Paint(Option_t *o)
{
    // If this is set to early the plot remains empty in root 5.12/00
    if (fHumidity.GetN()>0)
    {
        fHumidity.SetMinimum(0);
        fHumidity.SetMaximum(100);
    }
    if (fTemperature.GetN()>0)
    {
        fTemperature.SetMinimum(-25);
        fTemperature.SetMaximum(45);
    }
    if (fWindSpeed.GetN()>0)
        fWindSpeed.SetMinimum(0);
    if (fSolarRadiation.GetN()>0)
        fSolarRadiation.SetMinimum(0);
    if (fEventRate.GetN()>0)
        fEventRate.SetMinimum(0);

    DrawGraph(fHumidity,       "H [%]");
    DrawGraph(fSolarRadiation, "R [W/m^{2}]");
    DrawGraph(fTemperature,    "T [\\circ C]");
    DrawGraph(fWindSpeed,      "km/h");
    DrawGraph(fEventRate,      "f [Hz]");

    gPad->cd(1);

    if (gPad)
    {
        fHumidity.GetHistogram()->GetYaxis()->SetTitleColor(kBlue);
        UpdateRightAxis(fTemperature);
    }
}
