/* ======================================================================== *\
!
! *
! * 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, 11/2003 <mailto:tbretz@astro.uni-wuerzburg.de>
!
!   Copyright: MAGIC Software Development, 2000-2003
!
!
\* ======================================================================== */

//////////////////////////////////////////////////////////////////////////////
//                                                                          
//  MHEvent
//                                                                          
//  Display a single event in a canvas with as many informations as
//  possible, such as event number, run number, ...
//
//  WARNING: This class is not yet ready!
//
//  Input Containers:
//   MGeomCam
//   [MTaskList]
//   [MImgCleanStd]
//   [MRawEvtData]
//   [MRawRunHeader]
//   [MRawEvtHeader]
//
//  Output Containers:
//   -/-
//
//////////////////////////////////////////////////////////////////////////////
#include "MHEvent.h"

#include <TStyle.h>
#include <TCanvas.h>

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

#include "MMcEvt.hxx"
#include "MMcTrig.hxx"

#include "MHCamera.h"
#include "MParList.h"
#include "MTaskList.h"
#include "MParList.h"
#include "MSignalCam.h"
#include "MRawEvtHeader.h"
#include "MRawRunHeader.h"
#include "MRawEvtData.h"
#include "MImgCleanStd.h"

ClassImp(MHEvent);

using namespace std;

// --------------------------------------------------------------------------
//
MHEvent::MHEvent(EventType_t type) : fHist(NULL), fType(type),
    fMinimum(-1111), fMaximum(-1111)
{
    fName = "MHEvent";
    fTitle = "Single Event display task";

    fClone = new MRawEvtData("MHEventData");
}

// --------------------------------------------------------------------------
//
MHEvent::~MHEvent()
{
    if (fHist)
        delete fHist;

    delete fClone;
}

Bool_t MHEvent::SetupFill(const MParList *plist)
{
    MTaskList *tlist = (MTaskList*)plist->FindObject("MTaskList");

    fImgCleanStd = tlist ? (MImgCleanStd*)tlist->FindObject("MImgCleanStd") : NULL;
    fMcEvt       = (MMcEvt*)plist->FindObject("MMcEvt");
    fTime        = (MTime*)plist->FindObject("MTime");

    fRawEvtData = (MRawEvtData*)plist->FindObject("MRawEvtData");
    if (!fRawEvtData)
        *fLog << warn << "MRawEvtData not found..." << endl;

    fRawRunHeader = (MRawRunHeader*)plist->FindObject("MRawRunHeader");
    if (!fRawRunHeader)
        *fLog << warn << dbginf << "MRawRunHeader not found..." << endl;

    fRawEvtHeader = (MRawEvtHeader*)plist->FindObject("MRawEvtHeader");
    if (!fRawEvtHeader)
        *fLog << warn << dbginf << "MRawEvtHeader not found..." << endl;

    MGeomCam *cam = (MGeomCam*)plist->FindObject("MGeomCam");
    if (!cam)
    {
        *fLog << err << GetDescriptor() << ": No MGeomCam found... aborting." << endl;
        return kFALSE;
    }

    if (fHist)
        delete (fHist);

    fHist = new MHCamera(*cam);
    fHist->AddNotify(fClone);

    fHist->SetMinimum(fMinimum);
    fHist->SetMaximum(fMaximum);

    switch (fType)
    {
    case kEvtSignalRaw:
        fHist->SetName("Signal (raw)");
        fHist->SetYTitle("S [au]");
        break;
    case kEvtSignalDensity:
        fHist->SetName("Signal density");
        fHist->SetYTitle("S [au]");
        break;
    case kEvtPedestal:
        fHist->SetName("Pedestal");
        fHist->SetYTitle("P [au]");
        break;
    case kEvtPedestalRMS:
        fHist->SetName("Pedestal RMS");
        fHist->SetYTitle("\\sigma_{P} [au]");
        break;
    case kEvtPedPhot:
        fHist->SetName("Pedestal");
        fHist->SetYTitle("P [\\gamma]");
        break;
    case kEvtPedPhotRMS:
        fHist->SetName("Pedestal RMS");
        fHist->SetYTitle("\\sigma_{P} [\\gamma]");
        break;
    case kEvtCleaningLevels:
        if (!fImgCleanStd)
        {
            *fLog << err << "MImgCleanStd not found... aborting." << endl;
            return kFALSE;
        }
        fHist->SetName("CleanLevels");
        fHist->SetYTitle("L");
        break;
    case kEvtCleaningData:
        fHist->SetName("CleanData");
        fHist->SetYTitle("L");
        break;
     case kEvtIdxMax:
        fHist->SetName("Max Slice Idx");
        fHist->SetYTitle("t [slice id]");
	fHist->SetPrettyPalette();
        break;
     case kEvtArrTime:
     case kEvtArrTimeCleaned:
        fHist->SetName("Arrival Time");
        fHist->SetYTitle("t [slice id]");
	fHist->SetPrettyPalette();
        break;
     case kEvtTrigPix:
        fHist->SetName("Triggered pix");
        fHist->SetYTitle("ON/OFF");
        fHist->SetPrettyPalette();
        break;
     case kEvtIslandIndex:
        fHist->SetName("Island Index");
        fHist->SetYTitle("Index");
	fHist->SetPrettyPalette();
        break;
    }

    return kTRUE;
}

Bool_t MHEvent::Fill(const MParContainer *par, const Stat_t weight)
{
    if (fHist->IsFreezed())
        return kTRUE;

    if (!par)
        return kFALSE;

    const MCamEvent *event = dynamic_cast<const MCamEvent*>(par);
    if (!event)
    {
        *fLog << err << par->GetDescriptor() << " doesn't inherit from MCamEvent... abort." << endl;
        return kFALSE;
    }

    if (fRawEvtData)
        fRawEvtData->Copy(*fClone);

    switch (fType)
    {
    case kEvtSignalRaw:   // Get Content without pixel-size scaling
        fHist->SetCamContent(*event, 3);
        break;
    case kEvtSignalDensity:
        fHist->SetCamContent(*event, 0);
        break;
    case kEvtPedestal:
        fHist->SetCamContent(*event, 0);
        break;
    case kEvtPedestalRMS:
        fHist->SetCamContent(*event, 2);
        break;
    case kEvtPedPhot:
        fHist->SetCamContent(*event, 4);
        break;
    case kEvtPedPhotRMS:
        fHist->SetCamContent(*event, 5);
        break;
    case kEvtCleaningLevels:
        {
            TArrayF lvl(2);
            lvl[0] = fImgCleanStd->GetCleanLvl2();
            lvl[1] = fImgCleanStd->GetCleanLvl1();
            fHist->SetCamContent(*event, 0);
            fHist->SetLevels(lvl);
        }
        break;
    case kEvtCleaningData:
        fHist->SetCamContent(*event, 0);
        break;
    case kEvtIdxMax:
        fHist->SetCamContent(*event, 5);
        break;
    case kEvtArrTime:
        fHist->SetCamContent(*event, 6);
        break; 
    case kEvtArrTimeCleaned:
        fHist->SetCamContent(*event, 8);
        break; 
    case kEvtTrigPix:
        fHist->SetCamContent(*event, 0);
        break; 
    case kEvtIslandIndex:
        fHist->SetCamContent(*event, 5);
        break; 
    }

    TString s;
    if (fRawEvtHeader)
    {
        s += "Event #";
        s += fRawEvtHeader->GetDAQEvtNumber();
    }
    if (fRawEvtHeader && fRawRunHeader)
        s += " of ";

    if (fRawRunHeader)
    {
        s += "Run #";
        s += fRawRunHeader->GetRunNumber();
    }
    if (fTime)
    {
        s += " (";
        s += fTime->GetString();
        s += ")";
    }

    if (fMcEvt)
    {
        TString txt("#splitline{");

        txt += fMcEvt->GetParticleName();
        txt += " ";

        s.Insert(0, txt);

        s += "}{  E=";

        s+= fMcEvt->GetEnergyStr();

        s += " r=";
        s += (int)(fMcEvt->GetImpact()/100+.5);
        s += "m Zd=";
        s += 0.1*TMath::Nint(fMcEvt->GetTelescopeTheta()*180/TMath::Pi()*10);
        s += "\\circ ";
        if (fMcEvt->GetPhotElfromShower()>=10000)
            s += Form("%dk", (Int_t)(fMcEvt->GetPhotElfromShower()/1000.+.5));
        else
            if (fMcEvt->GetPhotElfromShower()>=1000)
                s += Form("%.1fk", fMcEvt->GetPhotElfromShower()/1000.);
            else
                s += fMcEvt->GetPhotElfromShower();
        s += "PhEl}";
    }

    gPad=NULL;
    fHist->SetTitle(s);

    return kTRUE;
}

void MHEvent::Paint(Option_t *)
{
    TVirtualPad *pad = gPad;

    pad->GetPad(2)->cd(1);
    if (gPad->FindObject(Form("Proj_%p", this)))
    {
        TH1 *h=fHist->Projection(Form("Proj_%p", this));
        if (h->GetMaximum()>0)
            gPad->SetLogy();
    }

    pad->GetPad(2)->cd(2);
    if (gPad->FindObject(Form("ProfR_%p", this)))
        fHist->RadialProfile(Form("ProfR_%p", this));

    pad->GetPad(2)->cd(3);
    if (gPad->FindObject(Form("ProfA_%p", this)))
        fHist->AzimuthProfile(Form("ProfA_%p", this));
}

void MHEvent::Draw(Option_t *)
{
    if (!fHist)
    {
        *fLog << warn << "MHEvent::Draw - fHist==NULL not initialized." << endl;
        return;
    }

    TVirtualPad *pad = gPad ? gPad : MakeDefCanvas(this);
    pad->SetBorderMode(0);

    AppendPad();

    pad->Divide(2,1);

    pad->cd(1);
    gPad->SetPad(0.01, 0.01, 0.75, 0.99);
    gPad->SetBorderMode(0);
    fHist->Draw();

    pad->cd(2);
    gPad->SetPad(0.75, 0.01, 0.99, 0.99);
    gPad->SetBorderMode(0);
    gPad->Divide(1,3);

    pad = gPad;

    pad->cd(1);
    gPad->SetBorderMode(0);

    TH1 *h = fHist->Projection(Form("Proj_%p", this), 50);
    h->SetTitle("Projection");
    h->SetBit(kCanDelete);
    h->Draw();

    pad->cd(2);
    gPad->SetBorderMode(0);

    h = (TH1*)fHist->RadialProfile(Form("ProfR_%p", this), 20);
    h->SetTitle("Radial Profile");
    h->SetBit(kCanDelete|TH1::kNoStats);
    h->Draw();

    pad->cd(3);
    gPad->SetBorderMode(0);
    h = (TH1*)fHist->AzimuthProfile(Form("ProfA_%p", this), 30);
    h->SetTitle("Azimuth Profile");
    h->SetBit(kCanDelete|TH1::kNoStats);
    h->Draw();
}
