#ifndef MARS_MAvalanchePhotoDiode
#define MARS_MAvalanchePhotoDiode

#ifndef ROOT_TH2
#include <TH2.h>
#endif

class APD : public TObject  // FIXME: Derive from TH2?
{
private:
    TH2F fHist;

    Float_t fCrosstalkProb;  // Probability that a converted photon creates another one in a neighboring cell
    Float_t fDeadTime;       // Deadtime of a single cell after a hit
    Float_t fRecoveryTime;   // Recoverytime after Deadtime (1-exp(-t/fRecoveryTime)

    Float_t fTime;           // A user settable time of the system

    Float_t HitCellImp(Int_t x, Int_t y, Float_t t=0);

public:
    APD(Int_t n, Float_t prob=0, Float_t dt=0, Float_t rt=0);

    Float_t HitCell(Int_t x, Int_t y, Float_t t=0);
    Float_t HitRandomCell(Float_t t=0);
    Float_t HitRandomCellRelative(Float_t t=0) { return HitRandomCell(fTime+t); }

    void FillEmpty(Float_t t=0);
    void FillRandom(Float_t rate, Float_t t=0);

    void Init(Float_t rate) { if (fTime<0) FillRandom(rate); else Relax(rate); }

    Int_t CountDeadCells(Float_t t=0) const;
    Int_t CountRecoveringCells(Float_t t=0) const;

    Float_t GetCellContent(Int_t x, Int_t y) const { return fHist.GetBinContent(x, y); }
    Int_t   GetNumCellsX() const { return fHist.GetNbinsX(); }

    Float_t GetCrosstalkProb() const { return fCrosstalkProb; }
    Float_t GetDeadTime() const { return fDeadTime; }
    Float_t GetRecoveryTime() const { return fRecoveryTime; }
    Float_t GetTime() const { return fTime; }

    Float_t GetRelaxationTime(Float_t threshold=0.001) const;

    Float_t GetLastHit() const { return fHist.GetMaximum(); }

    void SetTime(Float_t tm) { fTime=tm; }
    void IncreaseTime(Float_t dt) { fTime += dt; }

    Float_t Evolve(Double_t freq, Double_t dt);
    Float_t Relax(Double_t freq, Float_t threshold=0.001) { return Evolve(freq, GetRelaxationTime(threshold)); }

    void Draw(Option_t *o="") { fHist.Draw(o); }
    void DrawCopy(Option_t *o="") { fHist.DrawCopy(o); }

    ClassDef(APD, 1) // An object representing a Geigermode APD
};

#endif
