#ifndef MARS_MJPedestal
#define MARS_MJPedestal

#ifndef MARS_MJob
#include "MJob.h"
#endif
#ifndef MARS_MPedestalCam
#include "MPedestalCam.h"
#endif
#ifndef MARS_MBadPixelsCam
#include "MBadPixelsCam.h"
#endif

class TCanvas;
class MParList;
class MRunIter;
class MHCamera;
class TH1D;
class MExtractor;
class MExtractPedestal;
class MEvtLoop;

class MJPedestal : public MJob
{
private:
    static const Double_t fgPedestalMin;                 //! Minimum Axis value for pedestal datacheck display
    static const Double_t fgPedestalMax;                 //! Maximum Axis value for pedestal datacheck display
    static const Double_t fgPedRmsMin;                   //! Minimum Axis value for ped. RMS datacheck display
    static const Double_t fgPedRmsMax;                   //! Maximum Axis value for ped. RMS datacheck display

    static const Float_t  fgRefPedClosedLids;            //! Reference line pedestal for closed lids run
    static const Float_t  fgRefPedExtraGalactic;         //! Reference line pedestal for extragalactic source
    static const Float_t  fgRefPedGalactic;              //! Reference line pedestal for galactic source

    static const Float_t  fgRefPedRmsClosedLidsInner;    //! Ref. line ped. RMS for closed lids run - inner pixels
    static const Float_t  fgRefPedRmsExtraGalacticInner; //! Ref. line ped. RMS for extragalactic source - inner pixels
    static const Float_t  fgRefPedRmsGalacticInner;      //! Ref. line ped. RMS for galactic source - inner pixels

    static const Float_t  fgRefPedRmsClosedLidsOuter;    //! Ref. line ped. RMS for closed lids run - outer pixels
    static const Float_t  fgRefPedRmsExtraGalacticOuter; //! Ref. line ped. RMS for extragalactic source - outer pixels
    static const Float_t  fgRefPedRmsGalacticOuter;      //! Ref. line ped. RMS for galactic source - outer pixels

    MRunIter   *fRuns;                                   // Used pedestal runs
    MExtractor *fExtractor;                              // Signal extractor, used to find the nr. of used FADC slices

    MPedestalCam  fPedestalCamIn;                        // Handed over pedestal results
    MPedestalCam  fPedestalCamOut;                       // Created pedestal results
    MBadPixelsCam fBadPixels;                            // Bad Pixels

    enum Display_t { kDataCheckDisplay, kNormalDisplay}; // Possible Display types
    Display_t fDisplayType;                              // Chosen Display type

    enum Storage_t { kNoStorage };                       // Possible flags for the storage of results
    Byte_t fStorage;                                     // Bit-field for chosen storage type

    Bool_t fDataCheck;                                   // Flag if the data check is run on raw data

    enum Extract_t { kUseData, kUsePedRun, kUseHists };  // Possible flags for the extraction of the pedestal
    Extract_t fExtractType;                              // Chosen extractor type

    enum Extraction { kFundamental, kWithExtractorRndm, kWithExtractor };
    Int_t fExtractionType;                         // Flag if the extractor is used to calculate the pedestals

    MExtractor *ReadCalibration() const;
    Bool_t ReadPedestalCam();
    Bool_t WriteResult();
    //Bool_t WriteEventloop(MEvtLoop &evtloop) const;

    void   DisplayResult(MParList &plist);
    void   DisplayReferenceLines(MHCamera *cam, const Int_t what) const;
    void   DisplayOutliers(TH1D *hist) const;
    void   FixDataCheckHist(TH1D *hist) const;

    Bool_t IsNoStorage() const { return TESTBIT(fStorage, kNoStorage); }

    Bool_t CheckEnvLocal();

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

    MPedestalCam &GetPedestalCam()            { return fPedestalCamOut; }
    const MBadPixelsCam &GetBadPixels() const { return fBadPixels;   }

    const char*  GetOutputFile() const;

    const Bool_t IsDataCheck() const { return fDataCheck; }
    const Bool_t IsUseData() const { return fExtractType == kUseData; }

    Bool_t Process    ();
    Bool_t ProcessFile();

    void SetBadPixels(const MBadPixelsCam &bad) { bad.Copy(fBadPixels); }
    void SetPedestals(const MPedestalCam  &ped) { ped.Copy(fPedestalCamIn); }
    void SetExtractor(MExtractor* ext);
    void SetInput(MRunIter  *iter)              { fRuns      = iter;    }
    void SetUseData()                           { fExtractType = kUseData;   }
    void SetUseHists()                          { fExtractType = kUseHists;  }
    void SetUsePedRun()                         { fExtractType = kUsePedRun; }
    void SetDataCheck(const Bool_t b=kTRUE)     { fDataCheck = b; b ? SetDataCheckDisplay() : SetNormalDisplay(); }
    void SetDataCheckDisplay()                  { fDisplayType = kDataCheckDisplay; }
    void SetNormalDisplay()                     { fDisplayType = kNormalDisplay;    }

    void SetExtractionFundamental()       { fExtractionType=kFundamental;       /*fPedestalCamOut.SetName("MPedestalFundamental");*/   }
    void SetExtractionWithExtractorRndm() { fExtractionType=kWithExtractorRndm; /*fPedestalCamOut.SetName("MPedestalExtractorRndm");*/ }
    void SetExtractionWithExtractor()     { fExtractionType=kWithExtractor;     /*fPedestalCamOut.SetName("MPedestalExtractor");*/     }

    MExtractor *GetExtractor() const { return fExtractor; }

    // Storage
    void SetNoStorage(const Bool_t b=kTRUE)     { b ? SETBIT(fStorage, kNoStorage) : CLRBIT(fStorage,kNoStorage); }
    void SetNormalStorage()                     { CLRBIT(fStorage, kNoStorage); }

    ClassDef(MJPedestal, 0) // Tool to create a pedestal file (MPedestalCam)
};

#endif
