/* ======================================================================== *\
!
! *
! * 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
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//
// MReadReports                                                                   //
//
/////////////////////////////////////////////////////////////////////////////
#include "MReadReports.h"

#include <TChain.h>
#include <TChainElement.h>

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

#include "MTime.h"
#include "MParList.h"
#include "MReadTree.h"
#include "MTaskList.h"

ClassImp(MReadReports);

using namespace std;

MReadReports::MReadReports()
{
    fName = "MRead";
    fTitle = "MReadReports";

    fTrees  = new MTaskList("MReadReports");
    fChains = new TList;

    fTrees->SetOwner();
    fChains->SetOwner();
}

MReadReports::~MReadReports()
{
    TObject *o=0;
    TIter NextC(fChains);
    while ((o=NextC()))
    {
        delete *GetTime((TChain*)o);
        delete  GetTime((TChain*)o);
    }

    delete fTrees;
    delete fChains;
}

void MReadReports::AddToBranchList(const char *name)
{
    MTask::AddToBranchList(name);
}

void MReadReports::AddTree(const char *tree, const char *time)
{
    /*
    if (fTrees->GetNumTasks()>0)
    {
        *fLog << warn << "WARNING - AddTree must be called before AddFile... ignored." << endl;
        *fLog << dbg << fTrees->GetNumTasks() << endl;
        return kFALSE;
    }
    */
    MReadTree *t = new MReadTree(tree);
    t->SetName(tree);
    t->SetTitle(time?time:"");

    //FIXME!
    //t->DisableAutoScheme();

    fTrees->AddToList(t);
    //    return kTRUE;
}

Int_t MReadReports::AddFile(const char *fname, Int_t entries)
{
    Int_t n=0;

    TIter NextT(fTrees->GetList());
    MReadTree *tree=0;
    while ((tree=(MReadTree*)NextT()))
        n += tree->AddFile(fname, entries);

    return n;
}

Int_t MReadReports::PreProcess(MParList *plist)
{
    fList = (MTask*)plist->FindObject("MTaskList");

    fChains->Delete();

    Int_t i=0;

    TIter NextT(fTrees->GetList());
    MReadTree *tree=0;
    while ((tree=(MReadTree*)NextT()))
    {
        TString tn(tree->GetTitle());
        if (tn.IsNull())
        {
            tn += "MTime";
            tn += tree->GetName();
            tn += ".";
        }

        TString tn2(tn);
        tn2 += "*";

        // FIXME: Should be tree->AddToBranchList such that
        //        each run a new 'table' is created, but
        //        MRead is searching for MTaskList in the
        //        parameter list.
        //AddToBranchList((const char*)tn2);

        //
        // SetBranchStatus wants to have a pointer to a pointer
        //
        MTime **tx = new MTime*;
        *tx = new MTime;

        TChain *c=new TChain(tree->GetName());
        c->SetBranchStatus("*", 0);
        c->SetBranchAddress(tn, tx);
        tn+="*";
        c->SetBranchStatus(tn, 1);
        c->Add((TChain*)tree->fChain);
        c->GetEntry(0);

        fChains->Add(c);

        i++;
    }

    fPos.Set(i);

    return fTrees->CallPreProcess(plist);
}

MTime** MReadReports::GetTime(TChain *c) const
{
    TChainElement *e=(TChainElement*)c->GetStatus()->At(1);
    return (MTime**)e->GetBaddress();
}

Int_t MReadReports::Process()
{
    while (fChains->GetSize())
    {
        Int_t i=0;

        MTime tmin;

        Int_t nmin=0;

        TIter NextC(fChains);
        TChain *c=0;
        while ((c=(TChain*)NextC()))
        {
            MTime &t = **GetTime(c);

            if (t.GetHour()<12)
                t.SetTime((Byte_t)(t.GetHour()+24), t.GetMin(), t.GetSec(), t.GetNanoSec());

            if (i==0)
                tmin = t;

            if (t < tmin)
            {
                tmin = t;
                nmin = i;
            }
            i++;
        }

        TChain *chain = (TChain*)fChains->At(nmin);

        chain->GetEntry(++fPos[nmin]);

        // FIXME: Use Stream ID and call CallProcess() ?
        if (((MTask*)fTrees->GetList()->At(nmin))->CallProcess())
        {
            /*
             *fLog << dbg << ((MReadTree*)fTrees->At(nmin))->GetTreeName() << " " << flush;

             if (tmin.GetHour()>=24)
             tmin.SetTime((Byte_t)(tmin.GetHour()-24), tmin.GetMin(), tmin.GetSec(), tmin.GetNanoSec());
             tmin.Print();
             */

            fList->SetStreamId(fTrees->GetList()->At(nmin)->GetName());
            return kTRUE;
        }

        delete *GetTime(chain);
        delete  GetTime(chain);
        // FIXME: Is it really deleted?
        fChains->Remove(chain);
    }

    return kFALSE;
}

Int_t MReadReports::PostProcess()
{
    return fTrees->CallPostProcess();
}

void MReadReports::PrintStatistics(const Int_t lvl, Bool_t title) const
{
    MRead::PrintStatistics(lvl, title);
    fTrees->PrintStatistics(lvl, title);
}
