/* ======================================================================== *\
!
! *
! * 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): Harald Kornmayer 1/2001 (harald@mppmu.mpg.de)
!   Author(s): Thomas Bretz  12/2000 (tbretz@uni-sw.gwdg.de)
!
!   Copyright: MAGIC Software Development, 2000-2001
!
!
\* ======================================================================== */

#include "MMonteCarlo.h"

#include <stdlib.h>
#include <iostream.h>

#include <TGLabel.h>        // TGLabel
#include <TGButton.h>       // TGTextButton
#include <TGTextEntry.h>    // TGTextEntry
#include <TGButtonGroup.h>  // TGVButtonGroup

ClassImp(MMonteCarlo)

enum {
    M_BUTTON_COLAREA,
    M_BUTTON_RATE,
    M_BUTTON_THRESHOLD
};

void MMonteCarlo::AddButtons()
{
    TGTextButton *carea = new TGTextButton(fTop1, "Collection Area", M_BUTTON_COLAREA);
    TGTextButton *trate = new TGTextButton(fTop1, "Trigger Rate",    M_BUTTON_RATE);
    TGTextButton *thold = new TGTextButton(fTop1, "Threshold",       M_BUTTON_THRESHOLD);

    fList->Add(carea);
    fList->Add(trate);
    fList->Add(thold);

    carea->Associate(this);
    trate->Associate(this);
    thold->Associate(this);

    TGLayoutHints *laybut = new TGLayoutHints(kLHintsNormal, 5, 5, 10, 10);
    fList->Add(laybut);

    fTop1->AddFrame(carea, laybut);
    fTop1->AddFrame(trate, laybut);
    fTop1->AddFrame(thold, laybut);
}

void MMonteCarlo::AddSetupTab()
{
    //
    // Create Setup Tab
    //
    TGCompositeFrame *frame = CreateNewTab("Setup");

    //
    // Create a button group (it alignes the buttons and make
    // them automatic radio buttons)
    //
    TGVButtonGroup *group = new TGVButtonGroup(frame);
    fList->Add(group);

    //
    // Create three (auto) radio buttons in the button group
    //
    fRadioButton1 = new TGRadioButton(group, "Use unnumbered trigger condition olny.");
    fRadioButton2 = new TGRadioButton(group, "Use only one trigger condition (specify number below).");
    fRadioButton3 = new TGRadioButton(group, "Use a number of trigger conditions (1..n).");

    fRadioButton1->SetState(kButtonDown);

    /*
     FIXME: ~TGRadioButton fails with segfault in GetMainFrame

     fList->Add(fRadioButton1);
     fList->Add(fRadioButton2);
     fList->Add(fRadioButton3);
    */

    //
    // Add the button group (all buttons) as first line
    //
    frame->AddFrame(group);

    //
    // Create entry fields and labels for line 3 and 4
    //

    /*
     * --> use with root >=3.02 <--
     *

     TGNumberEntry *fNumEntry1 = new TGNumberEntry(frame, 3.0, 2, M_NENT_LVL1, kNESRealOne, kNEANonNegative);
     TGNumberEntry *fNumEntry2 = new TGNumberEntry(frame, 2.5, 2, M_NENT_LVL1, kNESRealOne, kNEANonNegative);

     */

    //
    // Align the lines:
    //  - top, left
    //  - padding: top=20, bottom=0, left=20, right=0
    //
    TGLayoutHints *layline = new TGLayoutHints(kLHintsNormal, 20, 0, 20);
    fList->Add(layline);


    //
    // Create a frame for line 3 and 4 to be able
    // to align entry field and label in one line
    //
    TGHorizontalFrame *f = new TGHorizontalFrame(frame, 0, 0);
    fNumEntry = new TGTextEntry(f, "****");
    fNumEntry->SetText("1");
    fList->Add(fNumEntry);

    // --- doesn't work like expected --- fNumEntry1->SetAlignment(kTextRight);
    // --- doesn't work like expected --- fNumEntry2->SetAlignment(kTextRight);

    TGLabel *l = new TGLabel(f, "Trigger Condition Setup.");
    l->SetTextJustify(kTextLeft);
    fList->Add(l);

    //
    // Align the text of the label centered, left in the row
    // with a left padding of 10
    //
    TGLayoutHints *laylabel = new TGLayoutHints(kLHintsCenterY|kLHintsLeft, 10); //, 10); //, 5, 5);
    fList->Add(laylabel);

    //
    // Add one entry field and the corresponding label to each line
    //
    f->AddFrame(fNumEntry);
    f->AddFrame(l, laylabel);

    //
    // Add line 3 and 4 to tab
    //
    frame->AddFrame(f, layline);
}

MMonteCarlo::MMonteCarlo(const TGWindow *main, const TGWindow *p,
                         const UInt_t w, const UInt_t h)
: MBrowser(main, p, w, h)
{
    AddButtons();
    AddSetupTab();

    MapSubwindows();

    Layout();

    SetWindowName("MonteCarlo Main");
    SetIconName("MonteCarlo");

    MapWindow();
} 

// ======================================================================
#include <TObjArray.h>

#include "MParList.h"
#include "MTaskList.h"
#include "MEvtLoop.h"

#include "MReadTree.h"

#include "MHMcRate.h"
#include "MHMcEnergy.h"

#include "MMcTriggerRateCalc.h"
#include "MMcThresholdCalc.h"
#include "MMcCollectionAreaCalc.h"

#include "../mmc/MMcTrig.hxx" // FIXME: see FIXME below

Int_t MMonteCarlo::GetDim() const
{
    return 0;
    Int_t dim = atoi(fNumEntry->GetText());

    if (dim<0)
    {
        dim=0;
        fNumEntry->SetText("0");
    }

    if (fRadioButton1->GetState())
        dim = 0;

    if (fRadioButton2->GetState())
        dim = -dim;

    return dim;
}

void MMonteCarlo::CalculateCollectionArea() const
{
    //
    // first we have to create our empty lists
    //
    MParList plist;

    MTaskList tlist;
    plist.AddToList(&tlist);

    //
    // FIXME: This line is needed that root finds the MMc-classes in the
    // dictionary when calling the constructor of MReadTree
    // I don't have any idea why...
    // Rem: This happens only in this GUI!
    //
    MMcTrig trig;

    //
    // Setup out tasks:
    //  - First we have to read the events
    //  - Then we can fill the efficiency histograms
    //
    MReadTree reader("Events", fInputFile);
    reader.UseLeaf("fImpact");
    reader.UseLeaf("fEnergy");
    reader.UseLeaf("fNumFirstLevel");

    tlist.AddToList(&reader);

    MMcCollectionAreaCalc effi;
    tlist.AddToList(&effi);

    //
    // set up the loop for the processing
    //
    MEvtLoop magic;
    magic.SetParList(&plist);

    //
    // Start to loop over all events
    //
    if (!magic.Eventloop())
        return;

    //
    // Now the histogram we wanted to get out of the data is
    // filled and can be displayd
    //
    plist.FindObject("MHMcCollectionArea")->DrawClone();
}

void MMonteCarlo::CalculateTriggerRate() const
{
    // This macro has two input parameter:
    // dim : = 0 -> root file with 1 trigger condition.
    //       > 0 -> number of trigger condition to be analised 
    //              in multi conditon file.
    //       < 0 -> selects the -dim trigger condition.
    //
    // first we have to create our empty lists
    //
    const Int_t dim = GetDim();

    MParList plist;
    MTaskList tlist;

    //
    // Setup the parameter list.
    //  - we do not need to create any other container. All of them
    //    are created automatically without loss - we don't have to
    //    access them-
    //
    //  - we need to create MHMcRate only. The other containers
    //    are created automatically without loss - we don't have to
    //    access them-
    //  - MHMcRate must be created by us because we need the pointer
    //    to it and if it would get created automatically it would also be
    //    deleted automatically
    //  - Actually, depending on using a single trigger option MonteCarlo
    //    file or a multyple trigger option, a MHMcRate or an array of 
    //    MHMcRate are needed.
    //
    plist.AddToList(&tlist);

    //
    // You don't have to add the MHMcRate container here by hand.
    // But if you want to print or display these containers later on
    // it is necessary (Rem: No printing or displaying is done in this
    // macro yet)
    //
    const UInt_t from = dim>0 ?   1 : -dim;
    const UInt_t to   = dim>0 ? dim : -dim;
    const Int_t  num  = to-from+1;

    TObjArray hists(MParList::CreateObjList("MHMcRate", from, to));
    hists.SetOwner();

    //
    // Check if the list really contains the right number of histograms
    //
    if (hists.GetEntriesFast() != num)
        return;

    //
    // Add the histograms to the paramater list.
    //
    plist.AddToList(&hists);

    //
    // FIXME: This line is needed that root finds the MMc-classes in the
    // dictionary when calling the constructor of MReadTree
    // I don't have any idea why...
    // Rem: This happens only in this GUI!
    //
    MMcTrig trig;

    //
    // Setup out tasks:
    //  - First we have to read the events
    //  - Then we can calculate rates, for what the number of
    //    triggered showers from a empty reflector file for the
    //    analised trigger conditions should be set (BgR[])
    //
    MReadTree reader("Events", fInputFile);
    reader.UseLeaf("fImpact");
    reader.UseLeaf("fEnergy");
    reader.UseLeaf("fPhi");
    reader.UseLeaf("fTheta");
    reader.UseLeaf("fNumFirstLevel");
    reader.UseLeaf("fPhotElfromShower");

    tlist.AddToList(&reader);

    Float_t BgR[10]={660, 4, 0, 0, 0, 0, 0, 0, 0, 0};

    MMcTriggerRateCalc crate(dim, 14, BgR, 100000);
    tlist.AddToList(&crate);

    //
    // set up the loop for the processing
    //
    MEvtLoop magic;
    magic.SetParList(&plist);

    //
    // Start to loop over all events
    //
    if (!magic.Eventloop())
        return;

    hists.Print();
}

void MMonteCarlo::CalculateThreshold() const
{
    const Int_t dim = GetDim();

    //
    // This macro fill the container MHMcEnergies using the task
    // MMcThresholdCalc and shows the results.
    //
    MParList plist;

    MTaskList tlist;
    plist.AddToList(&tlist);

    //
    // Setup the parameter list
    // - You need create the container MHMcEnergies.
    //    + You need to put the number of trigger conditions when
    //      you declarete the MHMcEnergies
    //    + If you don't put any dimension to MHMcEnergies it works
    //      taking only the trigger information from MMcTrig
    //

    //
    // Create numtriggerconditions histograms of type MHMcEnergy
    // and store the histograms in an TObjArray
    //
    const UInt_t from = dim>0 ?   1 : -dim;
    const UInt_t to   = dim>0 ? dim : -dim;
    const Int_t  num  = to-from+1;

    TObjArray hists(MParList::CreateObjList("MHMcEnergy", from, to));
    hists.SetOwner();

    //
    // Check if the list really contains the right number of histograms
    //
    if (hists.GetEntriesFast() != num)
        return;

    //
    // Add the histograms to the paramater list.
    //
    plist.AddToList(&hists);

    //
    // FIXME: This line is needed that root finds the MMc-classes in the
    // dictionary when calling the constructor of MReadTree
    // I don't have any idea why...
    // Rem: This happens only in this GUI!
    //
    MMcTrig trig;

    //
    // Setup the task list
    // - You need the read and the MMcThresholdCalc tasks
    // - You have to fill the histograms for the Energy threshold
    //    + You need to put the number of trigger conditions when
    //      you declarete the MMcThresholdCalc
    //    + If you don't put any dimension to MMcThresholdCalc it works
    //      like one dimension MMcThresholdCalc
    //
    MReadTree read("Events", fInputFile);
    read.UseLeaf("fEnergy");
    read.UseLeaf("fNumFirstLevel");

    MMcThresholdCalc calc(dim);
    tlist.AddToList(&read);
    tlist.AddToList(&calc);

    MEvtLoop evtloop;
    evtloop.SetParList(&plist);

    //
    // Begin the loop (if the loop wasn't successfull
    // don't try to draw the results
    //
    if (!evtloop.Eventloop())
        return;

    //
    // Now you can display the results
    //
    TIter Next(&hists);
    TObject *obj;
    while ((obj=Next()))
    obj->DrawClone();
}

// ======================================================================

Bool_t MMonteCarlo::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2)
{
    if (GET_MSG(msg) == kC_COMMAND && GET_SUBMSG(msg) == kCM_BUTTON)
        switch (parm1)
        {
        case M_BUTTON_COLAREA:
            CalculateCollectionArea();
            return kTRUE;

        case M_BUTTON_RATE:
            CalculateTriggerRate();
            return kTRUE;

        case M_BUTTON_THRESHOLD:
            CalculateThreshold();
            return kTRUE;
        }

    return MBrowser::ProcessMessage(msg, parm1, parm2);
}
