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

/////////////////////////////////////////////////////////////////////////////
//
// MTaskEnv
//
// If you want to create a new task inside a macro you will have to compile
// your macro using macro.C++, because the root interpreter cannot use
// uncompiled classes. To workaround this problem you can write simple
// funcions (which can be handled by CINT) and use MTaskEnv.
//
// This is a simple way to develop new code in a macro without need
// to compile it.
//
// Example:
//    Int_t Process()
//    {
//       gLog << "Processing..." << endl;
//       return kTRUE;
//    }
//
//    void main()
//    {
//       MTaskEnv task;
//       task.SetProcess(Process);
//       MTaskList list;
//       list.AddToList(&task);
//    }
//
//
//  Input Containers:
//   -/-
//
//  Output Containers:
//   -/-
//
/////////////////////////////////////////////////////////////////////////////
#include "MTaskEnv.h"

#include <TClass.h>

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

ClassImp(MTaskEnv);

using namespace std;
// --------------------------------------------------------------------------
//
// Default Constructor. Takes name and title of the interactive task
//
MTaskEnv::MTaskEnv(const char *name, const char *title) : fTask(0)
{
    fName  = name  ? name  : "MTaskEnv";
    fTitle = title ? title : "Task setup from Environment file";
}

MTaskEnv::~MTaskEnv()
{
    if (TestBit(kIsOwner))
        delete fTask;
}

MTask *MTaskEnv::GetTask(const char *name) const
{
    //
    // try to get class from root environment
    //
    TClass *cls = gROOT->GetClass(name);
    Int_t rc = 0;
    if (!cls)
        rc =1;
    else
    {
        if (!cls->Property())
            rc = 5;
        if (!cls->Size())
            rc = 4;
        if (!cls->IsLoaded())
            rc = 3;
        if (!cls->HasDefaultConstructor())
            rc = 2;
    }

    if (rc)
    {
        *fLog << err << dbginf << "Cannot create new instance of class '" << name << "': ";
        switch (rc)
        {
        case 1:
            *fLog << "gROOT->GetClass() returned NULL." << endl;
            return NULL;
        case 2:
            *fLog << "no default constructor." << endl;
            return NULL;
        case 3:
            *fLog << "not loaded." << endl;
            return NULL;
        case 4:
            *fLog << "zero size." << endl;
            return NULL;
        case 5:
            *fLog << "no property." << endl;
            return NULL;
        }
    }

    if (!cls->InheritsFrom(MTask::Class()))
    {
        *fLog << " - Class doesn't inherit from MTask." << endl;
        return NULL;
    }

    //
    // create the parameter container of the the given class type
    //
    MTask *task = (MTask*)cls->New();
    if (!task)
    {
        *fLog << " - Class has no default constructor." << endl;
        *fLog << " - An abstract member functions of a base class is not overwritten." << endl;
        return NULL;
    }

    task->SetName(fName);
    task->SetTitle(fTitle);

    return task;
}

void MTaskEnv::SetDefault(const char *def)
{
    if (TestBit(kIsOwner) && fTask)
        delete fTask;

    fTask = GetTask(def);
    if (!fTask)
        *fLog << err << dbginf << "ERROR - No default Task setup..." << endl;

    SetBit(kIsOwner);
}

Bool_t MTaskEnv::ReInit(MParList *list)
{
    return fTask->ReInit(list);
}

Int_t MTaskEnv::PreProcess(MParList *list)
{
    if (!fTask)
    {
        *fLog << err << GetDescriptor() << " - ERROR: Not task setup." << endl;
        return kFALSE;
    }

    *fLog << fTask->ClassName() << " - " << flush;
    return fTask->CallPreProcess(list);
}

Int_t MTaskEnv::Process()
{
    return fTask->CallProcess();
}

Int_t MTaskEnv::PostProcess()
{
    return fTask->CallPostProcess();
}

Int_t MTaskEnv::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
{
    if (!IsEnvDefined(env, prefix, print))
        return kFALSE;

    TString task = GetEnvValue(env, prefix, "");
    task.ReplaceAll("\015", "");
    task = task.Strip(TString::kBoth);
    fTask = GetTask(task.Data());
    if (!fTask)
    {
        *fLog << err << GetDescriptor() << " - ERROR: No task matching '";
        *fLog << task << "' could be setup." << endl;
        return kERROR;
    }

    SetBit(kIsOwner);

    return fTask->ReadEnv(env, prefix, print);
}

Bool_t MTaskEnv::WriteEnv(TEnv &env, TString prefix, Bool_t print) const
{
    return fTask->WriteEnv(env, prefix, print);
}
