/////////////////////////////////////////////////////////////////////////////
//
//  MRawEvtData
//
//  Storage container to store the raw FADC values.
//
//  MArrayS fHiGainPixId
//  ---------------------
//  Array of Pixel Numbers for their high voltage channel in the order the
//  FADC values are stored in fHiGainFadcSamples
//
//  MArrayB fHiGainFadcSaples
//  -------------------------
//  FADC samples (hi gain) of all pixels
//
//  MArrayS fLoGainPixId
//  --------------------
//  see fHiGainPixId
//
//  MArrayB fLoGainFadcSamples
//  --------------------------
//  see fHiGainFadcSaples
//
/////////////////////////////////////////////////////////////////////////////

#include "MRawEvtData.h"

#include <iomanip.h>

#include <fstream.h>

#include <TH1.h>
#include <TGraph.h>
#include <TArrayC.h>

#include "MLog.h"
#include "MArrayS.h"
#include "MArrayB.h"
#include "MRawRunHeader.h"

ClassImp(MRawEvtData)

MRawEvtData::MRawEvtData(const char *name, const char *title)
{
    *fName  = name  ? name  : "MRawEvtData";
    *fTitle = title ? title : "Raw Event Data Information";

    InitArrays();
}

MRawEvtData::~MRawEvtData()
{
    DeleteArrays();
}

void MRawEvtData::Clear(Option_t *)
{
    //
    // reset all arrays
    //

    /*
     FIXME:
     Is Reset (set all entries to zero) what you want to do
     or Set(0) (delete the array)
     */
    fHiGainPixId->Reset();
    fLoGainPixId->Reset();
    fHiGainFadcSamples->Reset();
    fLoGainFadcSamples->Reset();
}

Byte_t MRawEvtData::GetNumHiGainSamples() const
{
    return fHiGainPixId->GetSize() ? fHiGainFadcSamples->GetSize()/fHiGainPixId->GetSize() : 0;
}

Byte_t MRawEvtData::GetNumLoGainSamples() const
{
    return fLoGainPixId->GetSize() ? fLoGainFadcSamples->GetSize()/fLoGainPixId->GetSize() : 0;
}

Byte_t MRawEvtData::GetNumPixels() const
{
    return fHiGainPixId->GetSize();
}


void MRawEvtData::Print(Option_t *opt)
{
    //
    // print fadc inforation to screen
    // Possible Options:
    // - DEC: Print values decimal instead of hexadecimal (default)
    //
    const Byte_t nHiSamp = GetNumHiGainSamples();
    const Byte_t nLoSamp = GetNumLoGainSamples();

    const UShort_t nHiPix = fHiGainPixId->GetSize();;
    const UShort_t nLoPix = fLoGainPixId->GetSize();;

    fLog->unsetf(ios::showbase);

    *fLog << dec;
    *fLog << "HiGain: " << nHiPix << " Pixels with " << (Int_t)nHiSamp << " Samples" << endl;
    *fLog << "LoGain: " << nLoPix << " Pixels with " << (Int_t)nLoSamp << " Samples";;

    TString str(opt);
    Int_t manip = str.Contains("dec", TString::kIgnoreCase);

    Int_t l=0;
    for (int i=0; i<nHiPix; i++)
    {
        *fLog << endl;
        *fLog << " " << setfill(' ') << setw(3) << dec << i << ": ";
        *fLog << (manip?dec:hex) << flush;

        if (!manip)
            *fLog << setfill('0');

        for (int j=0; j<nHiSamp; j++)
        {
            *fLog << setw(manip?3:2);
            *fLog << ((UShort_t)(*fHiGainFadcSamples)[j+i*nHiSamp]&0xff);
            if (manip)
                *fLog << ' ';
            *fLog << flush;
        }

        if (!(l<nLoPix && (*fLoGainPixId)[l]==(*fHiGainPixId)[i]))
            continue;

        if (manip)
            *fLog << "/ ";

        for (int j=0; j<nLoSamp; j++)
        {
            *fLog << setw(manip?3:2);
            *fLog << ((UShort_t)(*fLoGainFadcSamples)[j+i*nLoSamp]&0xff);
            if (manip)
                *fLog << ' ';
            *fLog << flush;
        }
        l++;
    }
    *fLog << endl;
}

void MRawEvtData::Draw(Option_t *opt)
{
  // ----- AppendPad(opt);
   
  TString str(opt);
  
  UInt_t num = 0;
  
  if (str.BeginsWith("GRAPH", TString::kIgnoreCase))
  {
      if (str.Length()>5)
          sscanf(&str[5], "%d", &num);

      if (num>=GetNumPixels())
          num= GetNumPixels();

      *fLog << "Drawing Graph of Pixel " << num << endl;

      const Int_t n = GetNumHiGainSamples();

      Float_t *x = new Float_t[n];
      Float_t *y = new Float_t[n];

      for (int i=0; i<n; i++)
      {
          x[i] = i;
          y[i] = (*fHiGainFadcSamples)[i + num*GetNumHiGainSamples()];
      }

      TGraph *graph = new TGraph(n, x, y);
      graph->SetMaximum (256) ;
      graph->SetMinimum (0) ;

      graph->Draw("AC*");

      return;
  }

  if (str.BeginsWith("HIST", TString::kIgnoreCase))
  {
      *fLog << "Length: " << str.Length() << endl;

      if (str.Length()>4)
          sscanf(&str[4], "%d", &num);

      if (num>=GetNumPixels())
          num= GetNumPixels();

      *fLog << "Drawing Histogram of Pixel " << num << endl;

      const Int_t n = GetNumHiGainSamples();

      char *name = new char[16];

      sprintf(name, "Pixel No.%d", (*fHiGainPixId)[num]);

      TH1F *hist = new TH1F(name, "Hi Gain Samples FADC", n, 0, n);

      for (int i=0; i<n; i++)
          hist->Fill(0.5+i, (*fHiGainFadcSamples)[i + num*GetNumHiGainSamples()]);

      hist->Draw();

      return;
  }

  *fLog << "MRawEvtData::Draw: Warning: You must specify either 'GRAPH' or 'HIST'" << endl;
}

void MRawEvtData::DeletePixels()
{
    //
    // Deletes all arrays describing the pixel Id and Samples in pixels
    //
    DeleteArrays();
    InitArrays();
}

void MRawEvtData::DeleteArrays()
{
    delete fHiGainPixId;
    delete fLoGainPixId;
    delete fHiGainFadcSamples;
    delete fLoGainFadcSamples;
}

void MRawEvtData::InitArrays()
{
    fHiGainPixId       = new MArrayS(0); //UShort_t[0];
    fLoGainPixId       = new MArrayS(0); //new UShort_t[0];
    fHiGainFadcSamples = new MArrayB(0); //new Byte_t[0];
    fLoGainFadcSamples = new MArrayB(0); //new Byte_t[0];
}

void MRawEvtData::AddPixel(UShort_t nOfPixel, TArrayC *data, Bool_t lflag)
{
    //
    //  This is to fill the data of one pixel to the MRawEvtHeader Class.
    //  The parameters are the pixelnumber and the FADC_SLICES values of ADCs
    //  Add to lo gains if lflag = 1
    //

    MArrayS *arrpix = lflag ? fLoGainPixId       : fHiGainPixId;
    MArrayB *arrsam = lflag ? fLoGainFadcSamples : fHiGainFadcSamples;

    //
    // check whether we got the right number of new samples
    // if there are no samples already stored: this is the new number of samples
    //
    const Byte_t ns    = data->GetSize();
    const Byte_t nSamp = lflag ? GetNumLoGainSamples() : GetNumHiGainSamples();
    if (nSamp && ns!=nSamp)
    {
        *fLog << "RawEvtData::FillPixel: Error, number of samples in ";
        *fLog << "TArrayC doesn't match actual number" << endl;
        return;
    }

    //
    // enhance pixel array by one
    //
    arrpix->Set(arrpix->GetSize()+1);

    //
    // add the number of the new pixel to the array as last entry
    //
    arrpix->AddAt(nOfPixel, arrpix->GetSize()-1);

    //
    // enhance the array by the number of new samples
    //
    arrsam->Set(arrsam->GetSize()+ns);

    //
    // add the new slices as last entries to array
    //
    arrsam->AddAt((Byte_t*)data->GetArray(), arrsam->GetSize()-ns, ns);
}

/*
void MRawEvtData::AddPixelLo(UShort_t nOfPixel, TArrayC *data, int nr, int pos)
{
    //
    // add the number of the new pixel to the array as last entry
    //
    fLoGainPixId->AddAt(nOfPixel, nr);

    //
    // add the new slices as last entries to array
    //
    fLoGainFadcSamples->AddAt((Byte_t*)data->GetArray(), pos,  data->GetSize());
}

void MRawEvtData::AddPixelHi(UShort_t nOfPixel, TArrayC *data, int nr, int pos)
{
    // check whether we got the right number of new samples
    // if there are no samples already stored: this is the new number of samples
    //
    const Byte_t ns = data->GetSize();

    //
    // add the number of the new pixel to the array as last entry
    //
    fHiGainPixId->AddAt(nOfPixel, nr);

    //
    // add the new slices as last entries to array
    //
    fHiGainFadcSamples->AddAt((Byte_t*)data->GetArray(), arrsam->GetSize()-ns, ns);
}
*/
void MRawEvtData::ReadEvt(ifstream &fin)
{
    //
    // Fills members with information from a magic binary file.
    //   WARNING: you have to use Init() before you can do this
    //
    const UShort_t nlo = fRunHeader->GetNumSamplesLoGain();
    const UShort_t nhi = fRunHeader->GetNumSamplesHiGain();

    TArrayC lo(nlo);
    TArrayC hi(nhi);

    const UShort_t npic = fRunHeader->GetNumPixInCrate();

    for (int i=0; i<npic; i++)
    {
        //
        // get the spiral pixel number from the run header
        //
        const UShort_t npix = fRunHeader->GetPixAssignment(i);

        fin.read((Byte_t*)hi.GetArray(), nhi);
        AddPixel(npix, &hi, kFALSE);

        // FIXME: Not implemented in the raw files yet
        //if (IsLoGainOn(i, j))
        //{
        fin.read((Byte_t*)lo.GetArray(), nlo);
        AddPixel(npix, &lo, kTRUE);
        //}
    }
}

