#ifndef MARS_MExtractPedestal
#define MARS_MExtractPedestal

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

#ifndef MARS_MArrayD
#include <MArrayD.h>
#endif

#ifndef MARS_MArrayI
#include <MArrayI.h>
#endif

class MGeomCam;
class MPedestalCam;
class MRawEvtData;
class MRawRunHeader;
class MRawEvtHeader;
class MExtractTimeAndCharge;

class MExtractPedestal : public MTask
{
private:
  static const TString  fgNamePedestalCam;  //! "MPedestalCam"

  TString fNamePedestalCamIn;        // Name of the incoming 'MPedestalCam' container
  TString fNamePedestalCamOut;       // Name of the outgoing 'MPedestalCam' container
  TString fNamePedestalCamInter;     // Name of the intermediate 'MPedestalCam' container  

  Bool_t  fRandomCalculation;        // Is pedestalextraction by extractor random?
  
protected:
  
  Bool_t  fIntermediateStorage;      // Is pedestal stored every event?

  MGeomCam      *fGeom;              //! Camera geometry
  MPedestalCam  *fPedestalsIn;       //! Pedestals of all pixels in the camera (incoming)
  MPedestalCam  *fPedestalsInter;    //! Pedestals of all pixels in the camera (intermediate)
  MPedestalCam  *fPedestalsOut;      //! Pedestals of all pixels in the camera (outgoing)
  MRawEvtData   *fRawEvt;            //! Raw event data (time slices)
  MRawRunHeader *fRunHeader;         //! RunHeader information
  MRawEvtHeader *fEvtHeader;         //! EvtHeader information
  MExtractTimeAndCharge *fExtractor; //  Possible Extractor
  
  UShort_t fExtractWinFirst;         // First FADC slice to extract pedestal from
  UShort_t fExtractWinSize;          // Number of slices to calculate the pedestal from
  UShort_t fExtractWinLast;          // Last FADC slice to extract pedestal from 
                                     
  UInt_t  fNumEventsDump;            // Number of event after which MPedestalCam gets updated
  UInt_t  fNumAreasDump;             // Number of events after which averaged areas gets updated
  UInt_t  fNumSectorsDump;           // Number of events after which averaged sectors gets updated
 
  Bool_t  fPedestalUpdate;           // Flag if the pedestal shall be updated after every fNumEventsDump

  MArrayD fSumx;                     // sum of values
  MArrayD fSumx2;                    // sum of squared values
  MArrayD fSumAB0;                   // sum of ABFlag=0 slices
  MArrayD fSumAB1;                   // sum of ABFlag=1 slices
  MArrayD fAreaSumx;                 // averaged sum of values per area idx
  MArrayD fAreaSumx2;                // averaged sum of squared values per area idx
  MArrayD fAreaSumAB0;               // averaged sum of ABFlag=0 slices per area idx
  MArrayD fAreaSumAB1;               // averaged sum of ABFlag=1 slices per area idx
  MArrayI fAreaFilled;               // number of valid entries with area idx
  MArrayI fAreaValid;                // number of valid pixels  within area idx
  MArrayD fSectorSumx;               // averaged sum of values per sector
  MArrayD fSectorSumx2;              // averaged sum of squared values per sector
  MArrayD fSectorSumAB0;             // averaged sum of ABFlag=0 slices per sector
  MArrayD fSectorSumAB1;             // averaged sum of ABFlag=1 slices per sector 
  MArrayI fSectorFilled;             // number of valid entries with sector idx
  MArrayI fSectorValid;              // number of valid pixels within sector idx

  // MTask virtual functions
  Int_t  PreProcess(MParList *pList);
  Int_t  Process();
  Int_t  PostProcess();
  Bool_t ReInit(MParList *pList);
  Int_t  ReadEnv(const TEnv &env, TString prefix, Bool_t print);

  // Interface to be overwritten by a new class
  virtual void  ResetArrays();
  virtual Int_t Calc() = 0;

  // Helper functions
  void CalcPixResults   (const UInt_t nevts, const UInt_t pixid);
  void CalcAreaResults  (const UInt_t nevts, const UInt_t napix, const UInt_t aidx);
  void CalcSectorResults(const UInt_t nevts, const UInt_t nspix, const UInt_t sector);

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

  void Clear(const Option_t *o="");
  void Print(const Option_t *o="") const;

  Bool_t SetExtractWindow(UShort_t first, UShort_t size);

  void SetNumEventsDump (UInt_t dumpevents=500)  { fNumEventsDump  = dumpevents; }
  void SetNumAreasDump  (UInt_t dumpevents=500)  { fNumAreasDump   = dumpevents; }
  void SetNumSectorsDump(UInt_t dumpevents=500)  { fNumSectorsDump = dumpevents; }
  void SetNumDump       (UInt_t n=500) { fNumEventsDump=n; fNumAreasDump=n; fNumSectorsDump=n; }

  // names
  void SetNamePedestalCamIn   (const char *name=fgNamePedestalCam.Data()) { fNamePedestalCamIn    = name; }
  void SetNamePedestalCamInter(const char *name=fgNamePedestalCam.Data()) { fNamePedestalCamInter = name; }  
  void SetNamePedestalCamOut  (const char *name=fgNamePedestalCam.Data()) { fNamePedestalCamOut   = name; }

  // pointers
  void SetExtractor     ( MExtractTimeAndCharge *e) { fExtractor      = e; }
  void SetPedestalsIn   ( MPedestalCam *pedcam    ) { fPedestalsIn    = pedcam; }
  void SetPedestalsInter( MPedestalCam *pedcam    ) { fPedestalsInter = pedcam; }
  void SetPedestalsOut  ( MPedestalCam *pedcam    ) { fPedestalsOut   = pedcam; }

  // flags
  void SetIntermediateStorage (Bool_t b=kTRUE) { fIntermediateStorage = b; }
  void SetPedestalUpdate      (Bool_t b=kTRUE) { fPedestalUpdate      = b; }
  void SetRandomCalculation   (Bool_t b=kTRUE) { fRandomCalculation   = b; }

  ClassDef(MExtractPedestal, 0)   // Base class for pedestal extractors
};

#endif
