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

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// MTaskList                                                               //
//                                                                         //
// Collection of tasks to be processed in the eventloop                    //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

#include "MTaskList.h"

#include "MLog.h"
#include "MParList.h"
#include "MInputStreamID.h"

ClassImp(MTaskList)

// --------------------------------------------------------------------------
//
// the name for the task list must be the same for all task lists
// because the task list (at the moment) is identified by exactly
// this name in the parameter list (by MEvtLoop::SetParList)
//
MTaskList::MTaskList(const char *title)
{
    *fName  = "MTaskList";
    *fTitle = title ? title : "List for Tasks";
}

// --------------------------------------------------------------------------
//
//   CopyConstructor
//   creates a new TaskList and put the contents of an existing
//   TaskList in the new TaskList.
//
MTaskList::MTaskList(MTaskList &ts)
{
  fTasks.AddAll(&ts.fTasks);
}

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

    MTask *task=NULL;

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

    MParContainer::SetLogStream(log);
}


// --------------------------------------------------------------------------
//
// schedule task for execution, whether as first task, or after
// 'where'. 'tType' is the event type which should be processed
//
Bool_t MTaskList::AddToList(MTask *task, const char *type, MTask *where)
{
    if (!task)
        return kTRUE;

    const char *name = task->GetName();

    // FIXME: We agreed to put the task into list in an ordered way.

    if (fTasks.FindObject(task))
    {
        *fLog << "WARNING: MTaskList::AddToList: Task already existing." << endl;
        return kTRUE;
    }

    if (fTasks.FindObject(name))
    {
        *fLog << "WARNING: MTaskList::AddToList: '" << name << "' exists in List already." << endl;
        return kTRUE;
    }

    if (where)
    {
        if (!fTasks.FindObject(where))
        {
            printf("ERROR: MTaskList::AddToList: Cannot find task after which the new task should be scheduled!\n");
            return kFALSE;
        }
    }

    *fLog << "Adding " << name << " to " << GetName() << " for " << type << "... " << flush;

    task->SetStreamId(type);
    fTasks.Add(task);

    *fLog << "Done." << endl;

    return kTRUE;
}

// --------------------------------------------------------------------------
//
// do pre processing (before eventloop) of all tasks in the task-list
//
Bool_t MTaskList::PreProcess( MParList *pList )
{ 
    *fLog << "Preprocessing... " << flush;

    fParList = pList;

    //
    //  create the Iterator over the tasklist
    //
    TIter Next(&fTasks);

    MTask *task=NULL;

    //
    // loop over all tasks for preproccesing
    //
    while ( (task=(MTask*)Next()) )
    {
        *fLog << task->GetName() << "... " << flush;

        if (!task->PreProcess(fParList))
            return kFALSE;
    }

    *fLog << endl;

    return kTRUE;
}

// --------------------------------------------------------------------------
//
// do the event execution of all tasks in the task-list
//
Bool_t MTaskList::Process()
{
    //
    // Reset the HasChanged flag.
    // Reset all containers.
    //
    fParList->SetHasChanged(kFALSE);
    fParList->Reset();

    //
    //  create the Iterator for the TaskList
    //
    TIter Next(&fTasks);
    MTask *task=NULL;

    //
    // loop over all tasks for processing
    //
    while ( (task=(MTask*)Next()) )
    {
        //
        // if the task has the wrong stream id skip it.
        //
        if (strcmp(GetStreamId(), task->GetStreamId()) &&
            strcmp(task->GetStreamId(), "All"))
            continue;

        //
        // if it has the right stream id execute the Process() function
        // and check what the result of it is.
        //
        switch (task->Process())
        {
        case kTRUE:
            //
            // everything was OK: go on
            //
            continue;

        case kFALSE:
            //
            // an error occured: stop eventloop
            //
            return kFALSE;

        case kCONTINUE:
            //
            // something occured: skip the rest of the tasks for this event
            //
            break;
        }
    }
    return kTRUE;
}

// --------------------------------------------------------------------------
//
// do post processing (before eventloop) of all tasks in the task-list
//
Bool_t MTaskList::PostProcess()
{
    *fLog << "Postprocessing... " << flush;

    // FIXME: At the moment all tasks are post processed independ of
    // whether it was preprocessed or not.

    //
    // Reset the HasChanged flag.
    // Reset all containers.
    //
    fParList->SetHasChanged(kFALSE);
    fParList->Reset();

    //
    //  create the Iterator for the TaskList
    //
    TIter Next(&fTasks);

    MTask *task=NULL;

    //
    //  loop over all tasks for postprocessing
    //
    while ( (task=(MTask*)Next()) )
    {
        *fLog << task->GetName() << "... " << flush;

        if (!task->PostProcess())
            return kFALSE;
    }

    *fLog << endl;

    return kTRUE;
}

// --------------------------------------------------------------------------
void MTaskList::Print(Option_t *t)
{
  *fLog << "TaskList: " << this->GetName() << " <" <<  this->GetTitle() << ">" << endl;
  
  fTasks.Print();

  *fLog << endl;
}

