#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  

  Bool_t  fRandomCalculation;  // Is pedestalextraction by extractor random?

protected:
  
  MGeomCam      *fGeom;         //! Camera geometry
  MPedestalCam  *fPedestalsIn;  //! Pedestals of all pixels in the camera
  MPedestalCam  *fPedestalsOut; //! Pedestals of all pixels in the camera
  MRawEvtData   *fRawEvt;       //! Raw event data (time slices)
  MRawRunHeader *fRunHeader;    //! RunHeader information
  MRawEvtHeader *fEvtHeader;    //! EvtHeader information
  MExtractTimeAndCharge *fExtractor; // Possible Extractor used
  
  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; }
  void SetPedestalUpdate (Bool_t pedupdate=kTRUE) { fPedestalUpdate = pedupdate;  }

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

  void SetPedestalsIn(MPedestalCam *pedcam) { fPedestalsIn = pedcam; }
  void SetPedestalsOut(MPedestalCam *pedcam) { fPedestalsOut = pedcam; }

  void SetExtractor(MExtractTimeAndCharge *e) { fExtractor = e; }
  void SetRandomCalculation(Bool_t b=kTRUE) { fRandomCalculation = b; }

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

#endif
