#ifndef MARS_MRFEnergyEst
#define MARS_MRFEnergyEst

#ifndef MARS_MTask
#include "MTask.h"
#endif

#ifndef ROOT_TObjArray
#include <TObjArray.h>
#endif

#ifndef ROOT_TArrayD
#include <TArrayD.h>
#endif

class MDataArray;
class MParameterD;
class MHMatrix;

class MRFEnergyEst : public MTask
{
public:
    enum EstimationMode_t
    {
        kMean,
        kMaximum,
        kFit
    };

private:
    static const TString gsDefName;   //! Default Name
    static const TString gsDefTitle;  //! Default Title

    Bool_t       fDebug;      // Debugging of eventloop while training on/off

    TString      fFileName;   // File name to forest
    TObjArray    fEForests;   // List of forests

    MDataArray  *fData;       //! Used to store the MDataChains to get the event values
    MParameterD *fEnergyEst;  //! Used to storeestimated energy

    Int_t        fNumTrees;   //! Training parameters
    Int_t        fNumTry;     //! Training parameters
    Int_t        fNdSize;     //! Training parameters

    MHMatrix    *fTestMatrix; //! Test Matrix used in Process (together with MMatrixLoop)

    EstimationMode_t fEstimationMode;

private:
    // MTask
    Int_t PreProcess(MParList *plist);
    Int_t Process();

    // MRFEnergyEst
    Int_t ReadForests(MParList &plist);

    // MParContainer
    Int_t ReadEnv(const TEnv &env, TString prefix, Bool_t print);

    // Train Interface
    Int_t Train(const MHMatrix &n, const TArrayD &grid, Int_t ver=2);

public:
    MRFEnergyEst(const char *name=NULL, const char *title=NULL);
    ~MRFEnergyEst();

    // Setter for estimation
    void SetFileName(TString filename)          { fFileName = filename; }
    void SetEstimationMode(EstimationMode_t op) { fEstimationMode = op; }

    // Setter for training
    void SetNumTrees(UShort_t n=100) { fNumTrees = n; }
    void SetNdSize(UShort_t n=5)     { fNdSize   = n; }
    void SetNumTry(UShort_t n=0)     { fNumTry   = n; }
    void SetDebug(Bool_t b=kTRUE)    { fDebug = b; }

    // Train Interface
    Int_t TrainMultiRF(const MHMatrix &n, const TArrayD &grid)
    {
        return Train(n, grid, 0);
    }
    Int_t TrainSingleRF(const MHMatrix &n, const TArrayD &grid=TArrayD())
    {
        return Train(n, grid, grid.GetSize()==0 ? 2 : 1);
    }

    // Test Interface
    void  SetTestMatrix(MHMatrix *m=0) { fTestMatrix=m; }
    void  InitMapping(MHMatrix *m=0)   { fTestMatrix=m; }

    ClassDef(MRFEnergyEst, 0) // Task
};

#endif
