/* ======================================================================== *\
!
! *
! * 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  12/2000 (tbretz@uni-sw.gwdg.de)
!
!   Copyright: MAGIC Software Development, 2000-2001
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// MParList                                                                //
//                                                                         //
// This class contains a list of different parameter containers.           //
//                                                                         //
// A parameter container is an object which is derived from                //
// MParContainer.                                                          //
//                                                                         //
// Normally a parameter container is used for data exchange between two    //
// tasks at runtime.                                                       //
//                                                                         //
// You can add every parameter container (Named object) to the             //
// instance and access it from somewhere else via its Name.                //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////
#include "MParList.h"

#include <TNamed.h>
#include <TClass.h>

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

ClassImp(MParList)

// --------------------------------------------------------------------------
//
//  default constructor
//  creates an empty list
//
MParList::MParList(const char *name, const char *title)
{
    *fName  = name  ? name  : "MParList";
    *fTitle = title ? title : "List of Parameter Containers";

    //
    // This sets a flag that the list is the owner, which means
    // that the destructor of the list deletes all it's objects
    //
    fAutodelete.SetOwner();
}

// --------------------------------------------------------------------------
//
// copy constructor
//
MParList::MParList(MParList &ts)
{
    fContainer.AddAll(&ts.fContainer);
}

// --------------------------------------------------------------------------
//
//  create the Iterator over the tasklist
//
void MParList::SetLogStream(MLog *log)
{
    TIter Next(&fContainer);

    MParContainer *cont=NULL;

    //
    // loop over all tasks for preproccesing
    //
    while ( (cont=(MParContainer*)Next()) )
        cont->SetLogStream(log);

    MParContainer::SetLogStream(log);
}

// --------------------------------------------------------------------------
//
//  Add an Container to the list.
//
//  If 'where' is given, the object will be added after this.
//
Bool_t MParList::AddToList(MParContainer *obj, MParContainer *where)
{
    //
    //  check if the object (you want to add) exists
    //

    if (!obj) return kTRUE;

    *fLog << "Adding " << obj->GetName() << " to " << GetName() << "... " << flush;
  //
    //  check if it is in the list yet
    //
    if (fContainer.FindObject(obj))
    {
        *fLog << dbginf << "Container already added" << endl;
        return kTRUE;
    }

    //
    //  check if you want to add the new parameter container somewhere
  //  special (in that case you specify "where") 
    //
    if (where)
    {
        if (!fContainer.FindObject(where))
        {
            *fLog << dbginf << "Cannot find parameter container after which the new one should be added!" << endl;
            return kFALSE;
        }
    }

    fContainer.Add(obj);
    *fLog << "Done." << endl;

    return kTRUE;
}

// --------------------------------------------------------------------------
//
//  Find an object in the list.
//  'name' is the name of the object you are searching for.
//
TObject *MParList::FindObject(const char *name) const
{
    return (TObject*)fContainer.FindObject(name);
}

// --------------------------------------------------------------------------
//
//  Find an object in the list.
//  'name' is the name of the object you are searching for.
//  If the object doesn't exist we try to create one from the
//  dictionary. If this isn't possible NULL is returned.
//
//  An object which was created automatically is deleted automatically in
//  the destructor of the parameter list, too. This means, that if an
//  object should survive (eg. Histograms) you MUST create it by yourself
//  and add it to the parameter list.
//
//  By default (you don't specify an object name) the object name is
//  the same as the classname
//
//  If the classname (default classname) is of the structure
//  "Name;something" - containing a semicolon - evarything which is
//  after the last appearance of a semicolon is stripped to get the
//  Name of the Class. Normally this is used to number your objects.
//  "Name;1", "Name;2", ...
//
MParContainer *MParList::FindCreateObj(const char *classname, const char *objname)
{
    //
    // If now object name (name of the object to identify it in the
    // List) is given use it's classname as the objectname
    //
    if (!objname)
        objname = classname;

    //
    // Check if the classname is a 'numbered' name (like: "MTime;2")
    // if so strip the number from the classname.
    //
    // Becareful: We check for the last occurance of a ';' only and we
    // also don't check if a number follows or something else.
    //
    // Rem: I use a TString to make the code more readyble and to get
    // the new object deleted automatically
    //
    TString cname(classname);
    const char *semicolon = strrchr(cname, ';');

    if (semicolon)
        cname.Remove(semicolon-cname);

    //
    // Try to find a object with this object name which is already
    // in the List. If we can find one we are done.
    //
    MParContainer *pcont = (MParContainer*)FindObject(objname);

    if (pcont)
        return pcont;

    //
    // if object is not existing in the list try to create one
    //
    *fLog << dbginf << "Object '" << objname << "' of type '" << cname << "' not found... creating." << endl;

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

    if (!cls)
    {
        //
        // if class is not existing in the root environment
        //
        *fLog << dbginf << "Class '" << cname << "' not existing in dictionary." << endl;
        return NULL;
    }

    //
    // create the parameter container of the the given class type
    //
    pcont = (MParContainer*)cls->New();

    //
    // If a name different to the classname was given,
    // set the new object name of the object
    //
    pcont->SetName(objname);

    //
    // Now add the object to the parameter list
    //
    AddToList(pcont);

    //
    // The object was automatically created. This makes sure, that such an
    // object is deleted together with the list
    //
    fAutodelete.Add(pcont);

    //
    //  Find an object in the list.
    //  'name' is the name of the object you are searching for.
    //
    return pcont;
}

// --------------------------------------------------------------------------
//
//   print some information about the current status of MParList
//
void MParList::Print(Option_t *t)
{
    *fLog << dbginf << "ParList: " << this->GetName() << " <" << this->GetTitle() << ">" << endl;
    *fLog << endl;
}

// --------------------------------------------------------------------------
//
//   Sets the flags off all containers in the list (and the list
//   itself) to unchanged
//
void MParList::SetHasChanged(Bool_t flag)
{
    TIter Next(&fContainer);

    MParContainer *cont=NULL;

    //
    // loop over all tasks for preproccesing
    //
    while ( (cont=(MParContainer*)Next()) )
        cont->SetHasChanged(flag);

    MParContainer::SetHasChanged(flag);
}

void MParList::Reset()
{
    return;
    TIter Next(&fContainer);

    MParContainer *cont=NULL;

    //
    // loop over all tasks for preproccesing
    //
    while ( (cont=(MParContainer*)Next()) )
        cont->Reset();
}
