#ifndef MARS_MRanForest
#define MARS_MRanForest

#ifndef MARS_MParContainer
#include "MParContainer.h"
#endif

#ifndef MARS_MRanTree
#include "MRanTree.h"
#endif

#ifndef MARS_MDataArray
#include "MDataArray.h"
#endif

#ifndef ROOT_TArrayI
#include <TArrayI.h>
#endif

#ifndef ROOT_TArrayF
#include <TArrayF.h>
#endif

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

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

#ifndef ROOT_TRandom
#include <TRandom.h>
#endif

class MHMatrix;
class MRanTree;
class TVector;
class TMatrix;

class MRanForest : public MParContainer
{
private:
    Int_t fNumTrees;
    Int_t fTreeNo;      //!

    MRanTree *fRanTree; //!
    TObjArray *fForest;

    // training data
    MHMatrix *fGammas;  //!
    MHMatrix *fHadrons; //!

    // true  and estimated hadronness
    TArrayI fHadTrue;   //!
    TArrayF fHadEst;    //!

    // data sorted according to parameters
    TArrayI fDataSort;  //!
    TArrayI fDataRang;  //!
    TArrayI fClassPop;  //!

    // weights
    Bool_t  fUsePriors; //!
    TArrayF fPrior;     //!
    TArrayF fWeight;    //!
    TArrayI fNTimesOutBag;//!

    // estimates for classification error of growing forest
    TArrayD fTreeHad;   //

    void InitHadEst(Int_t from, Int_t to, const TMatrix &m, TArrayI &jinbag);

protected:
    // create and modify (->due to bagging) fDataSort
    void CreateDataSort();
    void ModifyDataSort(TArrayI &datsortinbag, Int_t ninbag, const TArrayI &jinbag);

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

    // initialize forest
    void SetPriors(Float_t prior_had, Float_t prior_gam);
    void SetNumTrees(Int_t n);

    // tree growing
    //void   SetupForest();
    Bool_t SetupGrow(MHMatrix *mhad,MHMatrix *mgam);
    Bool_t GrowForest();
    void SetCurTree(MRanTree *rantree) { fRanTree=rantree; }
    Bool_t AddTree(MRanTree *rantree);

    // getter methods
    TObjArray  *GetForest()      { return fForest; }
    MRanTree   *GetCurTree()     { return fRanTree; }
    MRanTree   *GetTree(Int_t i) { return (MRanTree*)(fForest->At(i)); }
    MDataArray *GetRules() { return ((MRanTree*)(fForest->At(0)))->GetRules(); }


    Int_t      GetNumTrees() const { return fNumTrees; }
    Int_t      GetNumData()  const;
    Int_t      GetNumDim()   const;
    Double_t   GetTreeHad(Int_t i) const { return fTreeHad.At(i); }
 
    // use forest to calculate hadronness of event
    Double_t CalcHadroness(const TVector &event);

    Bool_t AsciiWrite(ostream &out) const;

    ClassDef(MRanForest, 1) // Storage container for tree structure
};

#endif
