#ifndef MARS_MPhotonEvent
#define MARS_MPhotonEvent

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

#ifndef ROOT_TClonesArray
#include <TClonesArray.h>
#endif

#include <iosfwd>

class MPhotonData;
class MCorsikaRunHeader;

class MyClonesArray : public TClonesArray
{
public:
    TObject **FirstRef() { return fCont; }

    void FastRemove(Int_t idx1, Int_t idx2)
    {
        // Remove object at index idx.

        //if (!BoundsOk("RemoveAt", idx1)) return 0;
        //if (!BoundsOk("RemoveAt", idx2)) return 0;

        Long_t dtoronly = TObject::GetDtorOnly();

        idx1 -= fLowerBound;
        idx2 -= fLowerBound;

        for (TObject **obj=fCont+idx1; obj<=fCont+idx2; obj++)
        {
            if (!*obj)
                continue;

            if ((*obj)->TestBit(kNotDeleted)) {
                // Tell custom operator delete() not to delete space when
                // object fCont[i] is deleted. Only destructors are called
                // for this object.
                TObject::SetDtorOnly(*obj);
                delete *obj;
            }

            *obj = 0;
            // recalculate array size
        }
        TObject::SetDtorOnly((void*)dtoronly);

        if (idx1<=fLast && fLast<=idx2)
        {
            do {
                fLast--;
            } while (fLast >= 0 && fCont[fLast] == 0);
        }

        Changed();
    }

    void SetSorted() { fSorted = kTRUE; }
};

class MPhotonEvent : public MParContainer
{
private:
    TClonesArray fData;

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

    // TObjArray, FIXME: This could be improved if checking for IsSortable is omitted
    void Sort(Bool_t force=kFALSE) { if (force) fData.UnSort(); fData.Sort(); }
    Bool_t IsSorted() const { return fData.IsSorted(); }


    // Getter/Setter
    Int_t GetNumPhotons() const { return fData.GetEntriesFast(); }
    Int_t GetNumExternal() const;

    TClonesArray &GetArray() { return fData; }
    const TClonesArray &GetArray() const { return fData; }

    MPhotonData &Add(Int_t n);
    MPhotonData &Add();

    MPhotonData *GetFirst() const;
    MPhotonData *GetLast() const;

    MPhotonData &operator[](UInt_t idx);
    const MPhotonData &operator[](UInt_t idx) const;

    Int_t Shrink(Int_t n)
    {
        // The number of object written by the streamer is defined by
        // GetEntriesFast(), i.e. this number must be shrinked to
        // the real array size. We use RemoveAt instead of ExpandCreate
        // because RemoveAt doesn't free memory. Thus in the next
        // iteration it can be reused and doesn't need to be reallocated.
        // Do not change this. It is optimized for execution speed
        //        for (int i=fData.GetSize()-1; i>=n; i--)
        //          fData.RemoveAt(i);
        const Bool_t sorted = fData.IsSorted();

        MyClonesArray &loc = static_cast<MyClonesArray&>(fData);

        loc.FastRemove(n, fData.GetSize()-1);

        // If it was sorted before it is also sorted now.
        if (sorted)
            loc.SetSorted();

        return fData.GetEntriesFast();
    }

    // I/O
    Int_t ReadCorsikaEvt(istream &fin);
    Int_t ReadRflEvt(istream &fin);

    // TObject
    void Paint(Option_t *o="");
    void Print(Option_t * = NULL) const;
    //void Clear(Option_t * = NULL);

    ClassDef(MPhotonEvent, 1) //Container to store the raw Event Data
};

// FIXME: Should we merge this into MPhotonEvent?
class MPhotonStatistics : public MParContainer
{
private:
    Float_t fTimeFirst;
    Float_t fTimeLast;

//    Float_t fOffset;
//    Float_t fWindow;

    Int_t fMaxIndex;

public:
    MPhotonStatistics(const char *name=NULL, const char *title=NULL) : fMaxIndex(-1)
    {
        fName  = name  ? name  : "MPhotonStatistics";
        fTitle = title ? title : "Corsika Event Data Information";
    }

    void SetTime(Float_t first, Float_t last) { fTimeFirst=first; fTimeLast=last; }
    void SetMaxIndex(UInt_t idx) { fMaxIndex=idx; }

//    Float_t GetRawTimeFirst() const { return fTimeFirst; }
//    Float_t GetRawTimeLast() const { return fTimeLast; }

    Float_t GetTimeFirst() const { return fTimeFirst; }
    Float_t GetTimeLast() const { return fTimeLast; }

    Int_t GetMaxIndex() const { return fMaxIndex; }

//    Bool_t IsValid() const { return fTimeLast>=fTimeFirst; }

    ClassDef(MPhotonStatistics, 1)
};
#endif
