#ifndef MARS_MExtractTimeAndChargeDigitalFilter
#define MARS_MExtractTimeAndChargeDigitalFilter

#ifndef MARS_MExtractTimeAndCharge
#include "MExtractTimeAndCharge.h"
#endif

#ifndef MARS_MArrayF
#include "MArrayF.h"
#endif

#ifndef MARS_MArrayI
#include "MArrayI.h"
#endif

class TH1F;
class TH2F;
class MPedestalPix;
class MCalibrationPattern;

class MExtractTimeAndChargeDigitalFilter : public MExtractTimeAndCharge
{
private:
  static const Byte_t fgHiGainFirst;             //! Default for fHiGainFirst       (now set to: 0)
  static const Byte_t fgHiGainLast;              //! Default for fHiGainLast        (now set to:14)
  static const Byte_t fgLoGainFirst;             //! Default for fLoGainFirst       (now set to: 3)
  static const Byte_t fgLoGainLast;              //! Default for fLoGainLast        (now set to:14)
  static const Int_t  fgWindowSizeHiGain;        //! Default for fWindowSizeHiGain  (now set to: 6)
  static const Int_t  fgWindowSizeLoGain;        //! Default for fWindowSizeLoGain  (now set to: 6)
  static const Int_t  fgBinningResolutionHiGain; //! Default for fBinningResolutionHiGain (now set to: 10)
  static const Int_t  fgBinningResolutionLoGain; //! Default for fBinningResolutionLoGain (now set to: 10)
  static const Int_t  fgSignalStartBinHiGain;    //! Default for fSignalStartBinHiGain (now set to: 4)
  static const Int_t  fgSignalStartBinLoGain;    //! Default for fSignalStartBinLoGain (now set to: 4)
  static const TString fgNameWeightsFile;        //! "cosmics_weights.dat"
  static const Float_t fgOffsetLoGain;           //! Default for fOffsetLoGain (now set to 1.7)
  static const Float_t fgLoGainStartShift;       //! Default for fLoGainStartShift (now set to -1.8)

  MCalibrationPattern  *fCalibPattern;          //! Calibration DM pattern
  
  MArrayF fHiGainSignal;                        //! Need fast access to the signals in a float way
  MArrayF fLoGainSignal;                        //! Store them in separate arrays

  MArrayI fArrBinningResHiGain;                 //! helping arrays to hold binningres * i 
  MArrayI fArrBinningResLoGain;                 //! helping arrays to hold binningres * i 
  MArrayI fArrBinningResHalfHiGain;             //! helping arrays to hold binningres * i + binningreshalf
  MArrayI fArrBinningResHalfLoGain;             //! helping arrays to hold binningres * i + binningreshalf
  
  Float_t fTimeShiftHiGain;                     //  Time shift from when on to apply the filter
  Float_t fTimeShiftLoGain;                     //  Time shift from when on to apply the filter
  
  Int_t   fSignalStartBinHiGain;                //! Start bin from when on to apply weights
  Int_t   fSignalStartBinLoGain;                //! Start bin from when on to apply weights

  Int_t   fBinningResolutionHiGain;             //  Number of weights per bin High-Gain
  Int_t   fBinningResolutionHalfHiGain;         //  Half Number of weights per bin High-Gain
  Int_t   fBinningResolutionLoGain;             //  Number of weights per bin Low-Gain
  Int_t   fBinningResolutionHalfLoGain;         //  Half Number of weights per bin Low-Gain
  
  MArrayF fAmpWeightsHiGain;                    //! Amplitude weights High-Gain (from weights file)
  MArrayF fTimeWeightsHiGain;                   //! Time weights High-Gain (from weights file)
  MArrayF fAmpWeightsLoGain;                    //! Amplitude weights Low-Gain (from weights file)
  MArrayF fTimeWeightsLoGain;                   //! Time weights Low-Gain (from weights file)

  TString fNameWeightsFile;                     // Name of the weights file
  Bool_t  fAutomaticWeights;                    // Flag whether weight should be determined automatically
  TString fNameWeightsFileSet;                  //! Flag if weights have alreayd been set
  Int_t   fRandomIter;                          //! Counter used to randomize weights for noise calculation

  // MExtractTimeAndChargeDigitalFilter
  void    CalcBinningResArrays();
  Bool_t  ReadAutomaticWeightsFile();

  // MExtractTimeAndCharge
  Bool_t InitArrays();

  // MTask
  Int_t PreProcess(MParList *pList);

protected:
  // MParContainer
  Int_t ReadEnv(const TEnv &env, TString prefix, Bool_t print);

public:
  MExtractTimeAndChargeDigitalFilter(const char *name=NULL, const char *title=NULL);
  ~MExtractTimeAndChargeDigitalFilter() { }

  Bool_t ReadWeightsFile(TString filename);
  
  Bool_t WriteWeightsFile(TString filename,
                          TH1F *shapehi, TH2F *autocorrhi,
                          TH1F *shapelo=NULL, TH2F *autocorrlo=NULL );


  void SetNameWeightsFile(TString s="") { fNameWeightsFile = s; fNameWeightsFileSet=""; }
  void EnableAutomaticWeights(Bool_t b=kTRUE) { fAutomaticWeights = b; }

  void SetBinningResolution(const Int_t rh=fgBinningResolutionHiGain, const Int_t rl=fgBinningResolutionLoGain)  {
    fBinningResolutionHiGain     = rh & ~1;
    fBinningResolutionHalfHiGain = fBinningResolutionHiGain/2;
    fBinningResolutionLoGain     = rl & ~1;
    fBinningResolutionHalfLoGain = fBinningResolutionLoGain/2;
  }
  
  void SetSignalStartBin( const Int_t sh=fgSignalStartBinHiGain, const Int_t sl=fgSignalStartBinLoGain) {
    fSignalStartBinHiGain = sh;
    fSignalStartBinLoGain = sl; 
  }

  void SetWindowSize( Int_t windowh=fgWindowSizeHiGain, Int_t windowl=fgWindowSizeLoGain);

  const char* GetNameWeightsFile() const  { return fNameWeightsFile.Data(); }

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

  void FindTimeAndChargeHiGain(Byte_t *firstused, Byte_t *logain, Float_t &sum, Float_t &dsum,
                               Float_t &time, Float_t &dtime,
                               Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag);
  void FindTimeAndChargeLoGain(Byte_t *firstused, Float_t &sum,  Float_t &dsum,
                               Float_t &time, Float_t &dtime,
                               Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag);
  
  ClassDef(MExtractTimeAndChargeDigitalFilter, 2)   // Hendrik's digital filter
};

#endif
