/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// MReadTree                                                               //
//                                                                         //
// This tasks opens all branches in a specified tree and creates the       //
// corresponding parameter containers if not already existing in the       //
// parameter list.                                                         //
//                                                                         //
// The Process function reads one events from the tree. To go through the  //
// events of one tree make sure that the event number is increased from    //
// outside. It makes also possible to go back by decreasing the number.    //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

#include "MReadTree.h"

#include <fstream.h>

#include <TFile.h>
#include <TTree.h>
#include <TObjArray.h>

#include "MLog.h"
#include "MTime.h"
#include "MParList.h"

ClassImp(MReadTree)

MReadTree::MReadTree(const char *fname, const char *tname,
                     const char *name, const char *title)
{
    *fName  = name  ? name  : "MReadTree";
    *fTitle = title ? title : "Task to loop over all events in one single tree";

    //
    // open the input stream
    //
    fFileName = fname;
    fTreeName = tname;
}

Bool_t MReadTree::PreProcess (MParList *pList)
{
    //
    // open file
    //
    fFile = new TFile(fFileName, "READ");

    if (!fFile->IsOpen())
    {
        *fLog << "MReadTree::PreProcess: ERROR: Cannot open file '";
        *fLog << fFileName << "'" << endl;
        return kFALSE;
    }

    fTree = (TTree*)fFile->Get(fTreeName);

    if (!fTree)
    {
        *fLog << "MReadTree::PreProcess: ERROR: Cannot open tree '";
        *fLog << fTreeName << "'" << endl;
        return kFALSE;
    }

    fNumEntries = (UInt_t)fTree->GetEntries();
    fNumEntry   = 0;

    *fLog << "File: '" << fFileName << "'  Tree: '" << fTreeName;
    *fLog << "' with " << fNumEntries << " Entries opened." << endl;

    //
    // Get all branches of this tree and
    // create the Iterator to loop over all branches
    //
    TIter Next(fTree->GetListOfBranches());
    TBranch *branch=NULL;
    
    //
    // loop over all tasks for processing
    //
    while ( (branch=(TBranch*)Next()) )
    {
        //
        // Get Name of Branch
        //
        const char *name = branch->GetName();

        //
        // check if object is existing in the list
        //
        MParContainer *pcont = (MParContainer*)pList->FindObject(name);

        if (!pcont)
        {
            //
            // if object is not existing in the list try to create one
            //
            *fLog << "MReadTree::PreProcess - WARNING: '" << name << "' not found... creating." << endl;

            //
            // try to get class from root environment
            //
            TClass *cls = gROOT->GetClass(name);

            if (!cls)
            {
                //
                // if class is not existing in the root environment
                // we cannot proceed reading this branch
                //
                *fLog << "MReadTree::PreProcess - Warning: Class '" << name << "' not existing in dictionary. Branch skipped." << endl;
                continue;
            }

            //
            // create the container and add it to the list
            //
            pcont = (MParContainer*)cls->New();
            *fLog << pcont << endl;
            pList->AddToList(pcont);
        }

        //
        // here pcont is a pointer the to container in which the data from
        // the actual branch should be stored - enable branch.
        //
        branch->SetAddress(&pcont);
    }

    return kTRUE;
}

Bool_t MReadTree::Process()
{
    //
    // check for end of file
    //
    if (fNumEntry==fNumEntries)
        return kFALSE;

    //
    // get entry
    //
    fTree->GetEntry(fNumEntry );

    fNumEntry ++ ; 

    return kTRUE;
}

Bool_t MReadTree::PostProcess()
{
    //
    // Close File
    //
    fFile->Close();

    return kTRUE;
}

Bool_t MReadTree::GetEvent() 
{
  // Get the Event with the current EventNumber fNumEntry 
  //
  fTree->GetEntry(fNumEntry );

  return kTRUE;
}
Bool_t MReadTree::DecEventNum(UInt_t dec)
{
    //
    // Decrease the number of the event which is read by Process() next
    // by one or more
    //

    //!
    //! this function makes Process() read the event one (or more) before
    //! the actual position (event) in the tree
    //!
    if (fNumEntry < dec/*+1*/)
    {
        *fLog << "MReadTree::SetPrevEvent: WARNING: " << fNumEntry/*-1*/ << "-" << dec << " out of Range." << endl;
        return kFALSE;
    }

    fNumEntry -= dec/*+1*/;
    return kTRUE;
}

Bool_t MReadTree::IncEventNum(UInt_t inc)
{
    //
    // Increase the number of the event which is read by Process() next
    // by one or more
    //

    //!
    //! this function makes Process() read the next (or more) after
    //! the actual position (event) in the tree
    //! (Be careful: IncEventNum() or IncEventNum(1) does not chenge anything
    //!  in the standard behaviour of the task)
    //!
    if (fNumEntry+inc/*-1*/ >= fNumEntries)
    {
        *fLog << "MReadTree::SkipEvents: WARNING: " << fNumEntry/*-1*/ << "+" << inc << " out of Range." << endl;
        return kFALSE;
    }

    fNumEntry += inc/*-1*/;
    return kTRUE;
}

Bool_t MReadTree::SetEventNum(UInt_t nr)
{
    //
    // this function makes Process() read event number nr next
    //
    if (nr>=fNumEntries)
    {
        *fLog << "MReadTree::SetEventNum: WARNING: " << nr << " out of Range." << endl;
        return kFALSE;
    }

    fNumEntry = nr;
    return kTRUE;
}

