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

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
//  MFillH                                                                  //
//                                                                          //
//  This is a common interface (task) to fill mars histograms. Every mars   //
//  histogram which is derived from MH can be filled with this task.        //
//                                                                          //
//  There are two options to use:                                           //
//                                                                          //
//  1) You specifiy the parameter container with which data the             //
//     histogram container should be filled, and the histogram container    //
//     which has to be filled. This can be done by either specifing the     //
//     name of the objects in the parameter list or by specifiing a pointer //
//     to the object. (s. Constructor)                                      //                  //
//                                                                          //
//  2) You specify the name and/or type of the histogram to become filled.  //
//     Any other action imust be taken by the histogram class.              //
//                                                                          //
//  PreProcess: In the preprocessing of this task we setup all pointers     //
//              to instances which are needed and call FillSetup of the     //
//              histogram class with the parameter list as an argument.     //
//                                                                          //
//  Process: The process function calls the Fill member function of the     //
//           histogram class instance (inheriting from MH) with either      //
//           a NULL pointer or a pointer to the corresponding container     //
//           as an argument.                                                //
//                                                                          //
//  WARNING:                                                                //
//   Because MFillH is a generalized task to fill histograms it doesn't     //
//   know about which branches from a file are necessary to fill the        //
//   histograms. If you are reading data from a file which is directly      //
//   filled into a histogram via MFillH, please call either                 //
//   MReadTree::DisableAutoScheme() or enable the necessary branches by     //
//   yourself, using MReadTree::EnableBranch()                              //
//                                                                          //
//   Checkout the Warning in MTaskList.                                     //
//                                                                          //
//  Input Containers:                                                       //
//   A parameter container                                                  //
//                                                                          //
//  Output Containers:                                                      //
//   A histogram container                                                  //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////
#include "MFillH.h"

#include <fstream.h>

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

#include "MH.h"
#include "MParList.h"

ClassImp(MFillH);

// --------------------------------------------------------------------------
//
// Initializes name and title of the object. It is called by all
// constructors.
//
void MFillH::Init(const char *name, const char *title)
{
    fName  = name  ? name  : "MFillH";
    fTitle = title ? title : "Task to fill Mars histograms";

    fH            = NULL;
    fParContainer = NULL;
}

// --------------------------------------------------------------------------
//
// Default Constructor. This is to support some root-stuff.
// Never try to use it yourself!
//
MFillH::MFillH()
{
    Init(NULL, NULL);
}

// --------------------------------------------------------------------------
//
// Constructor.
//
// 1) - par is the name of the parameter container which should be filled into
//      the histogram
//    - hist is the name of the histogram container (which must have been
//      derived from MH)
//
//    In this case MH::Fill is called with a pointer to the corresponding
//    histogram instance.
//
// 2) - hist is the name and/or type of the histogram.
//      1) The name and type is identical, eg: "MHHillas"
//      2) They are not identical, eg: "MyHistogram [MHHillas]"
//         This searches for a class instance of MHHillas with the name
//         "MyHistogram". If it doesn't exist one is created.
//
//    In this case PreProcess calls MH::SetupFill with a pointer to the
//    parameter list and MH::Fill is called with a NULL-pointer.
//
MFillH::MFillH(const char *hist, const char *par, const char *name, const char *title)
{
    Init(name, title);

    fHName = hist;
    fParContainerName = par;

    if (title)
        return;

    fTitle = "Fill " + fHName;
    if (!par)
        return;

    fTitle += " from " + fParContainerName;
}

// --------------------------------------------------------------------------
//
// Constructor.
//
// 1) - par is a pointer to the instance of your parameter container from which
//      the data should be used to fill the histogram.
//    - hist is the name of the histogram container (which must have been
//      derived from MH)
//
//    In this case MH::Fill is called with a pointer to the corresponding
//    histogram instance.
//
// 2) - hist is the name and/or type of the histogram.
//      1) The name and type is identical, eg: "MHHillas"
//      2) They are not identical, eg: "MyHistogram [MHHillas]"
//         This searches for a class instance of MHHillas with the name
//         "MyHistogram". If it doesn't exist one is created. Everything
//         which is between the first '[' and the last ']' in the string
//         is used as the histogram type.
//
//    In this case PreProcess calls MH::SetupFill with a pointer to the
//    parameter list and MH::Fill is called with a NULL-pointer.
//
//
MFillH::MFillH(const char *hist, MParContainer *par, const char *name, const char *title)
{
    Init(name, title);

    fHName = hist;
    fParContainer = par;
    fParContainerName = par->GetName();

    if (!title)
        fTitle = "Fill " + fHName + " from " + par->GetDescriptor();
}

// --------------------------------------------------------------------------
//
// Constructor.
//
// - par is a pointer to the instance of your parameter container from which
//   the data should be used to fill the histogram.
// - hist is a pointer to the instance of your histogram container (which must
//   have been derived from MH) into which the data should flow
//
MFillH::MFillH(MH *hist, const char *par, const char *name, const char *title)
{
    Init(name, title);

    fH = hist;
    fHName = hist->GetName();
    fParContainerName = par;

    if (title)
        return;

    fTitle = (TString)"Fill " + hist->GetDescriptor();
    if (!par)
        return;

    fTitle += " from " + fParContainerName;
}

// --------------------------------------------------------------------------
//
// Constructor.
//
// - par is a pointer to the instance of your parameter container from which
//   the data should be used to fill the histogram.
// - hist is the name of the histogram container (which must have been
//   derived from MH)
//
MFillH::MFillH(MH *hist, MParContainer *par, const char *name, const char *title)
{
    Init(name, title);

    fH = hist;
    fHName = hist->GetName();
    fParContainer = par;
    fParContainerName = par->GetName();

    if (!title)
        fTitle = (TString)"Fill " + hist->GetDescriptor() + " from " + par->GetDescriptor();
}

TString MFillH::ExtractName(const char *name) const
{
    TString type = name;

    const Ssiz_t first = type.First('[');
    const Ssiz_t last  = type.First(']');

    if (!first || !last || first>=last)
        return type;

    return type.Remove(first).Strip(TString::kBoth);
}

TString MFillH::ExtractClass(const char *name) const
{
    TString type = name;

    const Ssiz_t first = type.First('[');
    const Ssiz_t last  = type.First(']');

    if (!first || !last || first>=last)
        return type;

    const Ssiz_t length = last-first-1;

    TString strip = fHName(first+1, length);
    return strip.Strip(TString::kBoth);
}

// --------------------------------------------------------------------------
//
// Checks the parameter list for the existance of the parameter container. If
// the name of it was given in the constructor. It checks also for the
// existance of the histogram container in the parameter list if a name was
// given. If it is not available it tried to create a histogram container
// with the same type as the given object name.
//
Bool_t MFillH::PreProcess(MParList *pList)
{
    //
    // Try to get the histogram container with name fHName from list
    // or create one with this name
    //
    if (!fH)
    {
        const TString cls  = ExtractClass(fHName);
        const TString name = ExtractName(fHName);

        TObject *obj=NULL;
        if (cls==name)
            obj = pList->FindObject(fHName);

        if (!obj)
        {
            if (cls==name)
                *fLog << inf << "Object '" << fHName << "' not found in parlist... trying to create one." << endl;
            obj = pList->FindCreateObj(cls, name);
        }

        if (!obj)
            return kFALSE;

        //
        // We were successfull getting it. Check whether it really inherits
        // from MH, FindCreateObj does only check for inheritance from
        // 'type'.
        //
        if (!obj->InheritsFrom(MH::Class()))
        {
            *fLog << err << dbginf << obj->GetName() << " doesn't inherit ";
            *fLog << "from MH - cannot be used for MFillH... aborting." << endl;
            return kFALSE;
        }

        fH = (MH*)obj;
    }

    //
    // Now we have the histogram container available. Try to Setup Fill.
    //
    if (!fH->SetupFill(pList))
    {
        *fLog << err << dbginf << "Error: calling SetupFill for ";
        *fLog << fH->GetDescriptor() << "... aborting." << endl;
        return kFALSE;
    }

    //
    // If also a parameter container is already set we are done.
    //
    if (fParContainer)
        return kTRUE;

    //
    // If a name is given try to find the input container in the
    // list. If it could not be found we cannot proceed.
    //
    if (fParContainerName.IsNull())
    {
        fParContainer = pList;
        return kTRUE;
    }

    fParContainer = (MParContainer*)pList->FindObject(fParContainerName);
    if (fParContainer)
        return kTRUE;

    *fLog << err << dbginf << "'" << fParContainerName << "' [MParContainer] not found... aborting." << endl;
    return kFALSE;
}

// --------------------------------------------------------------------------
//
// Fills the data from the parameter conatiner into the histogram container
//
Bool_t MFillH::Process()
{
    return fH->Fill(fParContainer);
} 

// --------------------------------------------------------------------------
//
// Set the ReadyToSave flag of the histogram container, because now all data
// has been filled into the histogram.
//
Bool_t MFillH::PostProcess()
{
    //
    // Now all data is in the histogram. Maybe some final action is
    // necessary.
    //
    if (!fH->Finalize())
    {
        *fLog << err << dbginf << "Error: calling Finalize for ";
        *fLog << fH->GetDescriptor() << "... aborting." << endl;
        return kFALSE;
    }

    fH->SetReadyToSave();
    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Implementation of SavePrimitive. Used to write the call to a constructor
// to a macro. In the original root implementation it is used to write
// gui elements to a macro-file.
//
void MFillH::StreamPrimitive(ofstream &out) const
{
    if (fH)
        fH->SavePrimitive(out);

    if (fParContainer)
        fParContainer->SavePrimitive(out);

    out << "   MFillH " << GetUniqueName() << "(";

    if (fH)
        out << "&" << fH->GetUniqueName();
    else
        out << "\"" << fHName << "\"";

    if (fParContainer)
        out << ", &" << fParContainer->GetUniqueName();
    else
        if (!fParContainerName.IsNull())
            out << ", \"" << fParContainerName << "\"";

    out << ");" << endl;
}
