// @(#)root/base:$Id$
// Author: Rene Brun   02/09/2000

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//______________________________________________________________________________
//
// TTask is a base class that can be used to build a complex tree of Tasks.
// Each TTask derived class may contain other TTasks that can be executed
// recursively, such that a complex program can be dynamically built and executed
// by invoking the services of the top level Task or one of its subtasks.
//
// Use the TTask::Add function to add a subtask to an existing TTask.
// To execute a TTask, one calls the ExecuteTask function. ExecuteTask will
// call recursively:
//     - the TTask::Exec function of the derived class
//     - TTask::ExecuteTasks to execute for each task the list of its subtasks.
// If the top level task (see example below) is added to the list of Root
// browsable objects, the tree of tasks can be visualized by the Root browser.
// The browser can be used to start a task, set break points at the beginning
// of a task or when the task has completed. At a breakpoint, data structures
// generated by the execution up this point may be inspected asyncronously
// and then the execution can be resumed by selecting the "Continue" function
// of a task.
//
// A Task may be active or inactive (controlled by TTask::SetActive).
// When a task is not active, its sub tasks are not executed.
//
// A TTask tree may be made persistent, saving the status of all the tasks.
//
// The picture in the Root browser below has been generated by executing
// the following script:
//
//{ //------------------script tasks.C---------------------------
//   TTask *aliroot  = new TTask("aliroot","ALICE reconstruction main task");
//   TTask *geominit = new TTask("geomInit","Initialize ALICE geometry");
//   TTask *matinit  = new TTask("matInit","Initialize ALICE materials");
//   TTask *physinit = new TTask("physInit","Initialize Physics processes");
//   TTask *tracker  = new TTask("tracker","Track reconstruction manager");
//   TTask *tpcrec   = new TTask("tpcrec","TPC reconstruction");
//   TTask *itsrec   = new TTask("itsrec","ITS reconstruction");
//   TTask *muonrec  = new TTask("muonRec","Muon Reconstruction");
//   TTask *phosrec  = new TTask("phosRec","Phos Reconstruction");
//   TTask *richrec  = new TTask("richRec","Rich Reconstruction");
//   TTask *trdrec   = new TTask("trdRec","TRD Reconstruction");
//   TTask *globrec  = new TTask("globRec","Global Track Reconstruction");
//   TTask *pstats   = new TTask("printStats","Print Run Statistics");
//   TTask *run      = new TTask("run","Process one run");
//   TTask *event    = new TTask("event","Process one event");
//   aliroot->Add(geominit);
//   aliroot->Add(matinit);
//   aliroot->Add(physinit);
//   aliroot->Add(run);
//   run->Add(event);
//   event->Add(tracker);
//   event->Add(muonrec);
//   event->Add(phosrec);
//   event->Add(richrec);
//   event->Add(trdrec);
//   event->Add(globrec);
//   tracker->Add(tpcrec);
//   tracker->Add(itsrec);
//   run->Add(pstats);
//
//   gROOT->GetListOfBrowsables()->Add(aliroot,"aliroot");
//   new TBrowser;
//} //-------------------------------------------------------------
//
//Begin_Html
/*
<img src="gif/tasks.gif">
*/
//End_Html

#include "Riostream.h"
#include "TTask.h"
#include "TBrowser.h"
#include "TROOT.h"
#include "TRegexp.h"

TTask *TTask::fgBeginTask  = 0;
TTask *TTask::fgBreakPoint = 0;

ClassImp(TTask)

//______________________________________________________________________________
TTask::TTask()
{
   // Default constructor invoked when reading a TTask object from a file.

   fHasExecuted = kFALSE;
   fActive      = kTRUE;
   fBreakin     = 0;
   fBreakout    = 0;
   fTasks       = 0;
}

//______________________________________________________________________________
TTask::TTask(const char* name, const char *title)
      : TNamed(name,title)
{
   // Standard constructor.

   fHasExecuted = kFALSE;
   fActive      = kTRUE;
   fBreakin     = 0;
   fBreakout    = 0;
   fTasks       = new TList();
}
//______________________________________________________________________________

TTask& TTask::operator=(const TTask& tt)
{
   //assignment operator (PLEASE DO NOT USE THIS IS WRONG)
   if(this!=&tt) {
      TNamed::operator=(tt);
      fTasks->Delete();
      TIter next(tt.fTasks);
      TTask *task;
      while ((task = (TTask*)next())) {
         fTasks->Add(new TTask(*task));
      }
      fOption=tt.fOption;
      fBreakin=tt.fBreakin;
      fBreakout=tt.fBreakout;
      fHasExecuted=tt.fHasExecuted;
      fActive=tt.fActive;
   }
   return *this;
}

//______________________________________________________________________________
TTask::TTask(const TTask &other) : TNamed(other)
{
   // Copy constructor.
   fTasks = new TList();
   TIter next(other.fTasks);
   TTask *task;
   while ((task = (TTask*)next())) {
      fTasks->Add(new TTask(*task));
   }
   fOption = other.fOption;
   fBreakin = other.fBreakin;
   fBreakout = other.fBreakout;
   fHasExecuted = kFALSE;
   fActive = other.fActive;
}

//______________________________________________________________________________
TTask::~TTask()
{
   // Delete a task and its subtasks.
   if (!fTasks) return;
   fTasks->Delete();
   delete fTasks;
}

//______________________________________________________________________________
void TTask::Abort()
{
   // Abort current tree of tasks.
   // After this call, the tree of tasks is ready to be executed again.
   // The application must take care of cleaning data structures created
   // by previous executions.

   if (!fgBeginTask) {
      printf(" Nothing to abort: No task currently running\n");
      return;
   }
   CleanTasks();
   fgBeginTask  = 0;
   fgBreakPoint = 0;
}

//______________________________________________________________________________
void TTask::Browse(TBrowser *b)
{
   // Browse the list of tasks.
   // It is recommended to add the top level task to the list of
   // ROOT browsables by:
   //    gROOT->GetListOfBrowsables()->Add(myTopLevelTask)

   fTasks->Browse(b);
}

//______________________________________________________________________________
void TTask::CleanTasks()
{
   // Reset tasks state: breakpoints and execute flags
   // also invokes the Clear function of each task to clear all data
   // structures created by a previous execution of a task.

   if (fBreakin)  fBreakin  = 1;
   if (fBreakout) fBreakout = 1;
   fHasExecuted = kFALSE;
   Clear();
   TIter next(fTasks);
   TTask *task;
   while((task=(TTask*)next())) {
      task->CleanTasks();
   }
}

//______________________________________________________________________________
void TTask::Clear(Option_t *)
{
   // Recursively call the Clear function of this task and its subtasks.
   // The Clear function must be implemented for each derived class
   // to clear all data structures created by a previous execution of a task.
   // This function is automatically called by the CleanTasks function.
}

//______________________________________________________________________________
void TTask::Continue()
{
   // Resume execution at the current break point.

   if (!fgBeginTask) {
      printf(" No task to continue\n");
      return;
   }
   fgBreakPoint = 0;

   fgBeginTask->ExecuteTasks(fOption.Data());

   if (!fgBreakPoint) {
      fgBeginTask->CleanTasks();
      fgBeginTask = 0;
   }
}

//______________________________________________________________________________
void TTask::Exec(Option_t *)
{
   // Dummy Execute.
   // This function must be redefined in the derived classes.
}

//______________________________________________________________________________
void TTask::ExecuteTask(Option_t *option)
{
   // Execute main task and its subtasks.
   // When calling this function, the Exec function of the corresponding class
   // is invoked, then the list of its subtasks is executed calling recursively
   // all the subtasks, etc.
   //
   // The option parameter may be used to select different execution steps
   // within a task. This parameter is passed also to all the subtasks.

   if (fgBeginTask) {
      Error("ExecuteTask","Cannot execute task:%s, already running task: %s",GetName(),fgBeginTask->GetName());
      return;
   }
   if (!IsActive()) return;

   fOption = option;
   fgBeginTask = this;
   fgBreakPoint = 0;

   if (fBreakin) return;
   if (gDebug > 1) {
      TROOT::IndentLevel();
      std::cout<<"Execute task:"<<GetName()<<" : "<<GetTitle()<<std::endl;
      TROOT::IncreaseDirLevel();
   }
   Exec(option);

   fHasExecuted = kTRUE;
   ExecuteTasks(option);

   if (gDebug > 1) TROOT::DecreaseDirLevel();
   if (fBreakout) return;

   if (!fgBreakPoint) {
      fgBeginTask->CleanTasks();
      fgBeginTask = 0;
   }
}

//______________________________________________________________________________
void TTask::ExecuteTasks(Option_t *option)
{
   // Execute all the subtasks of a task.

   TIter next(fTasks);
   TTask *task;
   while((task=(TTask*)next())) {
      if (fgBreakPoint) return;
      if (!task->IsActive()) continue;
      if (task->fHasExecuted) {
         task->ExecuteTasks(option);
         continue;
      }
      if (task->fBreakin == 1) {
         printf("Break at entry of task: %s\n",task->GetName());
         fgBreakPoint = this;
         task->fBreakin++;
         return;
      }

      if (gDebug > 1) {
         TROOT::IndentLevel();
         std::cout<<"Execute task:"<<task->GetName()<<" : "<<task->GetTitle()<<std::endl;
         TROOT::IncreaseDirLevel();
      }
      task->Exec(option);
      task->fHasExecuted = kTRUE;
      task->ExecuteTasks(option);
      if (gDebug > 1) TROOT::DecreaseDirLevel();
      if (task->fBreakout == 1) {
         printf("Break at exit of task: %s\n",task->GetName());
         fgBreakPoint = this;
         task->fBreakout++;
         return;
      }
   }
}

//______________________________________________________________________________
void TTask::ls(Option_t *option) const
{
   // List the tree of tasks.
   // Indentation is used to identify the task tree.

   TROOT::IndentLevel();
   std::cout <<GetName()<<"\t"<<GetTitle()<<std::endl;
   TROOT::IncreaseDirLevel();

   TString opta = option;
   TString opt  = opta.Strip(TString::kBoth);

   TRegexp re(opt, kTRUE);

   TObject *obj;
   TIter nextobj(fTasks);
   while ((obj = (TObject *) nextobj())) {
      TString s = obj->GetName();
      if (s.Index(re) == kNPOS) continue;
      obj->ls(option);
   }
   TROOT::DecreaseDirLevel();
}
 TTask.cxx:1
 TTask.cxx:2
 TTask.cxx:3
 TTask.cxx:4
 TTask.cxx:5
 TTask.cxx:6
 TTask.cxx:7
 TTask.cxx:8
 TTask.cxx:9
 TTask.cxx:10
 TTask.cxx:11
 TTask.cxx:12
 TTask.cxx:13
 TTask.cxx:14
 TTask.cxx:15
 TTask.cxx:16
 TTask.cxx:17
 TTask.cxx:18
 TTask.cxx:19
 TTask.cxx:20
 TTask.cxx:21
 TTask.cxx:22
 TTask.cxx:23
 TTask.cxx:24
 TTask.cxx:25
 TTask.cxx:26
 TTask.cxx:27
 TTask.cxx:28
 TTask.cxx:29
 TTask.cxx:30
 TTask.cxx:31
 TTask.cxx:32
 TTask.cxx:33
 TTask.cxx:34
 TTask.cxx:35
 TTask.cxx:36
 TTask.cxx:37
 TTask.cxx:38
 TTask.cxx:39
 TTask.cxx:40
 TTask.cxx:41
 TTask.cxx:42
 TTask.cxx:43
 TTask.cxx:44
 TTask.cxx:45
 TTask.cxx:46
 TTask.cxx:47
 TTask.cxx:48
 TTask.cxx:49
 TTask.cxx:50
 TTask.cxx:51
 TTask.cxx:52
 TTask.cxx:53
 TTask.cxx:54
 TTask.cxx:55
 TTask.cxx:56
 TTask.cxx:57
 TTask.cxx:58
 TTask.cxx:59
 TTask.cxx:60
 TTask.cxx:61
 TTask.cxx:62
 TTask.cxx:63
 TTask.cxx:64
 TTask.cxx:65
 TTask.cxx:66
 TTask.cxx:67
 TTask.cxx:68
 TTask.cxx:69
 TTask.cxx:70
 TTask.cxx:71
 TTask.cxx:72
 TTask.cxx:73
 TTask.cxx:74
 TTask.cxx:75
 TTask.cxx:76
 TTask.cxx:77
 TTask.cxx:78
 TTask.cxx:79
 TTask.cxx:80
 TTask.cxx:81
 TTask.cxx:82
 TTask.cxx:83
 TTask.cxx:84
 TTask.cxx:85
 TTask.cxx:86
 TTask.cxx:87
 TTask.cxx:88
 TTask.cxx:89
 TTask.cxx:90
 TTask.cxx:91
 TTask.cxx:92
 TTask.cxx:93
 TTask.cxx:94
 TTask.cxx:95
 TTask.cxx:96
 TTask.cxx:97
 TTask.cxx:98
 TTask.cxx:99
 TTask.cxx:100
 TTask.cxx:101
 TTask.cxx:102
 TTask.cxx:103
 TTask.cxx:104
 TTask.cxx:105
 TTask.cxx:106
 TTask.cxx:107
 TTask.cxx:108
 TTask.cxx:109
 TTask.cxx:110
 TTask.cxx:111
 TTask.cxx:112
 TTask.cxx:113
 TTask.cxx:114
 TTask.cxx:115
 TTask.cxx:116
 TTask.cxx:117
 TTask.cxx:118
 TTask.cxx:119
 TTask.cxx:120
 TTask.cxx:121
 TTask.cxx:122
 TTask.cxx:123
 TTask.cxx:124
 TTask.cxx:125
 TTask.cxx:126
 TTask.cxx:127
 TTask.cxx:128
 TTask.cxx:129
 TTask.cxx:130
 TTask.cxx:131
 TTask.cxx:132
 TTask.cxx:133
 TTask.cxx:134
 TTask.cxx:135
 TTask.cxx:136
 TTask.cxx:137
 TTask.cxx:138
 TTask.cxx:139
 TTask.cxx:140
 TTask.cxx:141
 TTask.cxx:142
 TTask.cxx:143
 TTask.cxx:144
 TTask.cxx:145
 TTask.cxx:146
 TTask.cxx:147
 TTask.cxx:148
 TTask.cxx:149
 TTask.cxx:150
 TTask.cxx:151
 TTask.cxx:152
 TTask.cxx:153
 TTask.cxx:154
 TTask.cxx:155
 TTask.cxx:156
 TTask.cxx:157
 TTask.cxx:158
 TTask.cxx:159
 TTask.cxx:160
 TTask.cxx:161
 TTask.cxx:162
 TTask.cxx:163
 TTask.cxx:164
 TTask.cxx:165
 TTask.cxx:166
 TTask.cxx:167
 TTask.cxx:168
 TTask.cxx:169
 TTask.cxx:170
 TTask.cxx:171
 TTask.cxx:172
 TTask.cxx:173
 TTask.cxx:174
 TTask.cxx:175
 TTask.cxx:176
 TTask.cxx:177
 TTask.cxx:178
 TTask.cxx:179
 TTask.cxx:180
 TTask.cxx:181
 TTask.cxx:182
 TTask.cxx:183
 TTask.cxx:184
 TTask.cxx:185
 TTask.cxx:186
 TTask.cxx:187
 TTask.cxx:188
 TTask.cxx:189
 TTask.cxx:190
 TTask.cxx:191
 TTask.cxx:192
 TTask.cxx:193
 TTask.cxx:194
 TTask.cxx:195
 TTask.cxx:196
 TTask.cxx:197
 TTask.cxx:198
 TTask.cxx:199
 TTask.cxx:200
 TTask.cxx:201
 TTask.cxx:202
 TTask.cxx:203
 TTask.cxx:204
 TTask.cxx:205
 TTask.cxx:206
 TTask.cxx:207
 TTask.cxx:208
 TTask.cxx:209
 TTask.cxx:210
 TTask.cxx:211
 TTask.cxx:212
 TTask.cxx:213
 TTask.cxx:214
 TTask.cxx:215
 TTask.cxx:216
 TTask.cxx:217
 TTask.cxx:218
 TTask.cxx:219
 TTask.cxx:220
 TTask.cxx:221
 TTask.cxx:222
 TTask.cxx:223
 TTask.cxx:224
 TTask.cxx:225
 TTask.cxx:226
 TTask.cxx:227
 TTask.cxx:228
 TTask.cxx:229
 TTask.cxx:230
 TTask.cxx:231
 TTask.cxx:232
 TTask.cxx:233
 TTask.cxx:234
 TTask.cxx:235
 TTask.cxx:236
 TTask.cxx:237
 TTask.cxx:238
 TTask.cxx:239
 TTask.cxx:240
 TTask.cxx:241
 TTask.cxx:242
 TTask.cxx:243
 TTask.cxx:244
 TTask.cxx:245
 TTask.cxx:246
 TTask.cxx:247
 TTask.cxx:248
 TTask.cxx:249
 TTask.cxx:250
 TTask.cxx:251
 TTask.cxx:252
 TTask.cxx:253
 TTask.cxx:254
 TTask.cxx:255
 TTask.cxx:256
 TTask.cxx:257
 TTask.cxx:258
 TTask.cxx:259
 TTask.cxx:260
 TTask.cxx:261
 TTask.cxx:262
 TTask.cxx:263
 TTask.cxx:264
 TTask.cxx:265
 TTask.cxx:266
 TTask.cxx:267
 TTask.cxx:268
 TTask.cxx:269
 TTask.cxx:270
 TTask.cxx:271
 TTask.cxx:272
 TTask.cxx:273
 TTask.cxx:274
 TTask.cxx:275
 TTask.cxx:276
 TTask.cxx:277
 TTask.cxx:278
 TTask.cxx:279
 TTask.cxx:280
 TTask.cxx:281
 TTask.cxx:282
 TTask.cxx:283
 TTask.cxx:284
 TTask.cxx:285
 TTask.cxx:286
 TTask.cxx:287
 TTask.cxx:288
 TTask.cxx:289
 TTask.cxx:290
 TTask.cxx:291
 TTask.cxx:292
 TTask.cxx:293
 TTask.cxx:294
 TTask.cxx:295
 TTask.cxx:296
 TTask.cxx:297
 TTask.cxx:298
 TTask.cxx:299
 TTask.cxx:300
 TTask.cxx:301
 TTask.cxx:302
 TTask.cxx:303
 TTask.cxx:304
 TTask.cxx:305
 TTask.cxx:306
 TTask.cxx:307
 TTask.cxx:308
 TTask.cxx:309
 TTask.cxx:310
 TTask.cxx:311
 TTask.cxx:312
 TTask.cxx:313
 TTask.cxx:314
 TTask.cxx:315
 TTask.cxx:316
 TTask.cxx:317
 TTask.cxx:318
 TTask.cxx:319
 TTask.cxx:320
 TTask.cxx:321
 TTask.cxx:322
 TTask.cxx:323
 TTask.cxx:324
 TTask.cxx:325
 TTask.cxx:326
 TTask.cxx:327
 TTask.cxx:328
 TTask.cxx:329
 TTask.cxx:330
 TTask.cxx:331
 TTask.cxx:332
 TTask.cxx:333
 TTask.cxx:334
 TTask.cxx:335
 TTask.cxx:336
 TTask.cxx:337
 TTask.cxx:338
 TTask.cxx:339
 TTask.cxx:340
 TTask.cxx:341
 TTask.cxx:342
 TTask.cxx:343
 TTask.cxx:344
 TTask.cxx:345
 TTask.cxx:346
 TTask.cxx:347
 TTask.cxx:348