#ifndef MARS_MBadPixelsPix
#define MARS_MBadPixelsPix

#ifndef MARS_MParContainer
#include "MParContainer.h"
#endif

#ifndef ROOT_TArrayI
#include <TArrayI.h>
#endif

class MBadPixelsPix : public MParContainer
{
private:
    TArrayI fInfo;

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

    enum UnsuitableType_t {
        kUnsuitableRun    = BIT(1),
        kUnsuitableEvt    = BIT(2)
    };

    // All types are initialized to normal behaviour
    enum CalibrationType_t {
      kHiGainSaturation         = BIT(1),
      kLoGainSaturation         = BIT(2),
      kHiGainNotFitted          = BIT(3),
      kLoGainNotFitted          = BIT(4), 
      kChargeIsPedestal         = BIT(5),
      kChargeErrNotValid        = BIT(6),
      kChargeRelErrNotValid     = BIT(7),
      kChargeSigmaNotValid      = BIT(8),
      kConvHiLoNotValid         = BIT(9),      
      kHiGainOscillating        = BIT(10),
      kLoGainOscillating        = BIT(11),
      kMeanTimeInFirstBin       = BIT(12),
      kMeanTimeInLastBin        = BIT(13), 
      kBlindPixelMethodNotValid = BIT(14),
      kFFactorMethodNotValid    = BIT(15), 
      kPINDiodeMethodNotValid   = BIT(16),
      kCombinedMethodNotValid   = BIT(17)
    };
    
      
    static const Char_t fgRunMask; // All types which are not event wise determined

    void Reset();
    void Clear(Option_t *o="");
    void Copy(TObject &object) const
    {
        static_cast<MBadPixelsPix&>(object).fInfo = fInfo;
    }

    // Setter
    void   SetUnsuitableRun(UnsuitableType_t typ=kUnsuitableRun) { fInfo[0] |=  typ; }
    void   SetSuitableRun(UnsuitableType_t typ=kUnsuitableRun)   { fInfo[0] &= ~typ; }

    void   SetUnsuitableEvt(UnsuitableType_t typ=kUnsuitableEvt) { fInfo[0] |=  typ; }
    void   SetSuitableEvt(UnsuitableType_t typ=kUnsuitableEvt)   { fInfo[0] &= ~typ; }

    // Calibration
    void SetHiGainSaturation         ( CalibrationType_t typ=kHiGainSaturation         )
      { fInfo[1] |= typ; }
    void SetLoGainSaturation         ( CalibrationType_t typ=kLoGainSaturation         )
      { fInfo[1] |= typ; }
    void SetCombinedMethodNotValid   ( CalibrationType_t typ=kCombinedMethodNotValid   )
      { fInfo[1] |= typ; }
    void SetPINDiodeMethodNotValid   ( CalibrationType_t typ=kPINDiodeMethodNotValid   )
      { fInfo[1] |= typ; }
    void SetFFactorMethodNotValid    ( CalibrationType_t typ=kFFactorMethodNotValid    )
      { fInfo[1] |= typ; }
    void SetBlindPixelMethodNotValid ( CalibrationType_t typ=kBlindPixelMethodNotValid )
      { fInfo[1] |= typ; }
    void SetMeanTimeInLastBin        ( CalibrationType_t typ=kMeanTimeInLastBin        )
      { fInfo[1] |= typ; }
    void SetMeanTimeInFirstBin       ( CalibrationType_t typ=kMeanTimeInFirstBin       )
      { fInfo[1] |= typ; }
    void SetLoGainOscillating        ( CalibrationType_t typ=kLoGainOscillating        )
      { fInfo[1] |= typ; }
    void SetHiGainOscillating        ( CalibrationType_t typ=kHiGainOscillating        )
      { fInfo[1] |= typ; }
    void SetConvHiLoNotValid         ( CalibrationType_t typ=kConvHiLoNotValid         )
      { fInfo[1] |= typ; }
    void SetChargeSigmaNotValid      ( CalibrationType_t typ=kChargeSigmaNotValid      )
      { fInfo[1] |= typ; }
    void SetChargeRelErrNotValid     ( CalibrationType_t typ=kChargeRelErrNotValid     )
      { fInfo[1] |= typ; }
    void SetChargeErrNotValid        ( CalibrationType_t typ=kChargeErrNotValid        )
      { fInfo[1] |= typ; }
    void SetChargeIsPedestal         ( CalibrationType_t typ=kChargeIsPedestal         )
      { fInfo[1] |= typ; }
    void SetLoGainNotFitted          ( CalibrationType_t typ=kLoGainNotFitted          )
      { fInfo[1] |= typ; }
    void SetHiGainNotFitted          ( CalibrationType_t typ=kHiGainNotFitted          )
      { fInfo[1] |= typ; }

    // Getter
    Bool_t IsUnsuitableRun(UnsuitableType_t typ=kUnsuitableRun) const { return   fInfo[0]&typ; }
    Bool_t IsSuitableRun(UnsuitableType_t typ=kUnsuitableRun) const   { return !(fInfo[0]&typ); }

    Bool_t IsUnsuitableEvt(UnsuitableType_t typ=kUnsuitableEvt) const { return   fInfo[0]&typ; }
    Bool_t IsSuitableEvt(UnsuitableType_t typ=kUnsuitableEvt) const   { return !(fInfo[0]&typ); }

    Bool_t IsOK() const  { return fInfo[0]==0; }
    Bool_t IsBad() const { return fInfo[0]!=0; }

    Bool_t IsHiGainSaturation         () const
      { return !((fInfo[1] | ~kHiGainSaturation)         == ~kHiGainSaturation );         }
    Bool_t IsLoGainSaturation         () const
      { return !((fInfo[1] | ~kLoGainSaturation)         == ~kLoGainSaturation );         }
    Bool_t IsCombinedMethodNotValid   () const
      { return !((fInfo[1] | ~kCombinedMethodNotValid)   == ~kCombinedMethodNotValid );   }
    Bool_t IsPINDiodeMethodNotValid   () const
      { return !((fInfo[1] | ~kPINDiodeMethodNotValid)   == ~kPINDiodeMethodNotValid );   }
    Bool_t IsFFactorMethodNotValid    () const
      { return !((fInfo[1] | ~kFFactorMethodNotValid)    == ~kFFactorMethodNotValid );    }
    Bool_t IsBlindPixelMethodNotValid () const
      { return !((fInfo[1] | ~kBlindPixelMethodNotValid) == ~kBlindPixelMethodNotValid ); }
    Bool_t IsMeanTimeInLastBin        () const
      { return !((fInfo[1] | ~kMeanTimeInLastBin)        == ~kMeanTimeInLastBin );        }
    Bool_t IsMeanTimeInFirstBin       () const
      { return !((fInfo[1] | ~kMeanTimeInFirstBin)       == ~kMeanTimeInFirstBin );       }
    Bool_t IsLoGainOscillating        () const
      { return !((fInfo[1] | ~kLoGainOscillating)        == ~kLoGainOscillating );        }
    Bool_t IsHiGainOscillating        () const
      { return !((fInfo[1] | ~kHiGainOscillating)        == ~kHiGainOscillating );        }
    Bool_t IsConvHiLoNotValid         () const
      { return !((fInfo[1] | ~kConvHiLoNotValid)         == ~kConvHiLoNotValid );         }
    Bool_t IsChargeSigmaNotValid      () const
      { return !((fInfo[1] | ~kChargeSigmaNotValid)      == ~kChargeSigmaNotValid );      }
    Bool_t IsChargeRelErrNotValid     () const
      { return !((fInfo[1] | ~kChargeRelErrNotValid)     == ~kChargeRelErrNotValid );     }
    Bool_t IsChargeErrNotValid        () const
      { return !((fInfo[1] | ~kChargeErrNotValid)        == ~kChargeErrNotValid );        }
    Bool_t IsChargeIsPedestal         () const
      { return !((fInfo[1] | ~kChargeIsPedestal)         == ~kChargeIsPedestal );         }
    Bool_t IsLoGainNotFitted          () const
      { return !((fInfo[1] | ~kLoGainNotFitted)          == ~kLoGainNotFitted );          }
    Bool_t IsHiGainNotFitted          () const
      { return !((fInfo[1] | ~kHiGainNotFitted)          == ~kHiGainNotFitted );          }

    Bool_t IsLoGainBad() const { return IsLoGainSaturation()
                                   || IsConvHiLoNotValid()
                                   || IsLoGainOscillating() ;}    
    Bool_t IsHiGainBad() const { return ( IsHiGainSaturation() && IsConvHiLoNotValid() 
                                          || IsHiGainOscillating() ); }
    Bool_t IsCalibrationSignalOK() const  { return !( IsChargeIsPedestal()
                                                      || IsChargeErrNotValid()
                                                      || IsChargeRelErrNotValid()
                                                      || IsChargeSigmaNotValid()
                                                      || IsMeanTimeInFirstBin()
                                                      || IsMeanTimeInLastBin() );  }
    Bool_t IsCalibrationFitOK() const    { return !( (IsHiGainSaturation() && IsHiGainNotFitted())
                                                     || ( IsLoGainSaturation() && IsLoGainNotFitted()) ); }
    Bool_t IsCalibrationOscillating() const  { return ( !IsHiGainSaturation() && IsHiGainOscillating()) 
                                                 || ( IsHiGainSaturation() && IsLoGainOscillating()) ; }
    Bool_t IsCalibrationResultOK() const  {  return IsCalibrationSignalOK()
                                               && !(IsCalibrationOscillating())
                                               && IsCalibrationFitOK()
                                               && ( (!IsHiGainSaturation() && !IsHiGainBad())
                                                    || (IsHiGainSaturation() && !IsLoGainBad()) ) ;}
    Bool_t IsCalibrationFFactorMethodOK() const  { return IsCalibrationResultOK()
                                                     && !IsFFactorMethodNotValid() ; }
    Bool_t IsCalibrationBlindPixelMethodOK() const  { return IsCalibrationResultOK()
                                                        && !IsBlindPixelMethodNotValid(); }
    Bool_t IsCalibrationPINDiodeMethodOK() const  { return IsCalibrationResultOK()
                                                      && !IsPINDiodeMethodNotValid() ; }
    Bool_t IsCalibrationCombinedMethodOK() const  { return IsCalibrationResultOK()
                                                      && !IsCombinedMethodNotValid(); }

    void Merge(const MBadPixelsPix &pix);

    const TArrayI &GetInfo() const { return fInfo; }

    ClassDef(MBadPixelsPix, 1)	// Storage Container for bad pixel information of a single pixel
};

#endif

