#ifndef MARS_MFMagicCuts
#define MARS_MFMagicCuts

#ifndef MARS_MFilter
#include "MFilter.h"
#endif

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

class MParList;

class MHillas;
class MHillasSrc;
class MHillasExt;
class MParameterD;
class MPointingPos;
class MHMatrix;

class MFMagicCuts : public MFilter
{
public:
    // Possible kind of theta cuts
    enum ThetaCut_t {
        kNone  =BIT(0),
        kOn    =BIT(1),
        kOff   =BIT(2),
        kWobble=kOn|kOff
    };
    // Possible kind of hadronness cuts
    enum HadronnessCut_t {
        kNoCut =BIT(0),
        kArea  =BIT(1),
        kM3Long=BIT(2),
        kAll   =kArea|kM3Long
    };

private:
    // Elements for mapping. kLastElement must not be used and must be
    // the last on in the list. It is used as counter for fMap.
    enum {
        kESize, kEAlpha, kEAlphaAnti, kEArea, kEDist,
        kEM3Long, kEM3LongAnti, kEDistAnti, kEWdivL, kEZd,
        kLastElement
    };

    MHillas        *fHil;              //! Pointer to MHillas container
    MHillasSrc     *fHilSrc;           //! Pointer to MHillasSrc container
    MHillasSrc     *fHilAnti;          //! Pointer to MHillasSrc container called MHillasSrcAnti
    MHillasExt     *fHilExt;           //! Pointer to MHillasExt container
    MParameterD    *fThetaSq;          //! Pointer to MParameterD container called ThetaSq
    MParameterD    *fDisp;             //! Pointer to MParameterD container called Disp
    MPointingPos   *fPointing;         //! Pointer to MPointingPos container

    Float_t         fMm2Deg;            //! Conversion factor from mm to deg, from MGeomCam
    Bool_t          fResult;            //! Result of the filter evaluation

    Int_t           fMap[kLastElement]; //! Mapping table for fast optimization
    MHMatrix       *fMatrix;            //! Matrix thorugh which the mapped elements are accessed

    TArrayD         fVariables;         // Coefficients of cuts

    ThetaCut_t      fThetaCut;          // Which kind of theta cut should be evaluated
    HadronnessCut_t fHadronnessCut;     // Which kind of hadronness cut should be evaluated

    // MTask
    Int_t PreProcess(MParList *pList);
    Int_t Process();

    // MFilter
    Bool_t IsExpressionTrue() const { return fResult; }

    // MFMagicCuts
    Double_t GetVal(Int_t i) const;
    TString  GetParam(Int_t i) const;
    Double_t GetThetaSq(Double_t c, Double_t wl, Double_t d, Double_t a, MParameterD *par=0) const;

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

    // Getter
    Double_t GetThetaSqCut() const;

    // Setter
    void   SetThetaCut(ThetaCut_t c) { fThetaCut=c; }
    void   SetHadronnessCut(HadronnessCut_t c) { fHadronnessCut=c; }

    // MFMagicCuts
    void   InitMapping(MHMatrix *mat);
    void   StopMapping() { InitMapping(NULL); }

    Bool_t CoefficentsRead(const char *fname);
    Bool_t CoefficentsWrite(const char *fname) const;

    // MParContainer
    void   SetVariables(const TArrayD &arr);

    Int_t  ReadEnv(const TEnv &env, TString prefix, Bool_t print=kFALSE);

    // TObject
    void   Print(Option_t *o="") const;

    ClassDef(MFMagicCuts, 1) // A filter to evaluate the MagicCuts
};

#endif
