#ifndef MARS_MJOptimizeBase
#define MARS_MJOptimizeBase

#ifndef MARS_MJob
#include "MJob.h"
#endif

class MTask;
class MFilter;

class MJOptimizeBase : public MJob
{
protected:
    Int_t  fDebug;
    Bool_t fEnableWeights;  // Enable using weights

    TList fRules;           // Contains the parameters which can be accessed by matrix column
    TList fTrainParameters; // Parameters in the last columns

    TList fPreCuts;         // Cuts executed for training and testing
    TList fTrainCuts;       // Cuts executed only in training
    TList fTestCuts;        // Cuts executed only in testing
    TList fPreTasks;        // Tasks executed before cut execution
    TList fPostTasks;       // Tasks executed after cut execution
    TList fTestTasks;       // Tasks executed after cut execution for testing

    void AddCut(TList &l, const char *rule);
    void AddPar(TList &l, const char *rule, const char *name);
    void Add(TList &l, MTask *f);

public:
    MJOptimizeBase() : fDebug(-1), fEnableWeights(kFALSE)
    {
    }

    void AddPreTask(MTask *t)                    { Add(fPreTasks,  t); }
    void AddPreTask(const char *rule,
                    const char *name="MWeight")  { AddPar(fPreTasks, rule, name); }

    void AddPostTask(MTask *t)                   { Add(fPostTasks, t); }
    void AddPostTask(const char *rule,
                     const char *name="MWeight") { AddPar(fPostTasks, rule, name); }

    void AddTestTask(MTask *t)                   { Add(fTestTasks, t); }
    void AddTestTask(const char *rule,
                     const char *name="MWeight") { AddPar(fTestTasks, rule, name); }

    void SetDebug(Bool_t b=kTRUE)      { fDebug = b; }

    void SetWeights(const char *rule)  { if (fEnableWeights) return; fEnableWeights=kTRUE; AddPostTask(rule); }
    void SetWeights(MTask *t)          { if (fEnableWeights) return; fEnableWeights=kTRUE; AddPostTask(t);    }

    void AddPreCut(const char *rule)   { AddCut(fPreCuts, rule); }
    void AddPreCut(MFilter *f)         { Add(fPreCuts, (MTask*)(f)); }

    void AddTrainCut(const char *rule) { AddCut(fTrainCuts, rule); }
    void AddTrainCut(MFilter *f)       { Add(fTrainCuts, (MTask*)(f)); }

    void AddTestCut(const char *rule)  { AddCut(fTestCuts, rule); }
    void AddTestCut(MFilter *f)        { Add(fTestCuts, (MTask*)(f)); }

    Int_t AddParameter(const char *rule);

    ClassDef(MJOptimizeBase, 0)//Base class for all optimizations and trainings
};

#endif
