/* ======================================================================== *\
!
! *
! * This file is part of MARS, the MAGIC Analysis and Reconstruction
! * Software. It is distributed to you in the hope that it can be a useful
! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
! * It is distributed WITHOUT ANY WARRANTY.
! *
! * Permission to use, copy, modify and distribute this software and its
! * documentation for any purpose is hereby granted without fee,
! * provided that the above copyright notice appear in all copies and
! * that both that copyright notice and this permission notice appear
! * in supporting documentation. It is provided "as is" without express
! * or implied warranty.
! *
!
!
!   Author(s): Markus Gaug   11/2003 <mailto:markus@ifae.es>
!
!   Copyright: MAGIC Software Development, 2000-2004
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//                                                               
// MCalibrationCam                                               
//                                                               
// Base class for Camera Calibration results. 
//
// Contains TClonesArrays for the following objects:
// - fPixels:         Array of classes derived from MCalibrationPix, one entry 
//                    per pixel. Has to be created
// - fAverageAreas:   Array of classes derived from MCalibrationPix, one entry
//                    per pixel AREA. Has to be created
// - fAverageSectors: Array of classes derived from MCalibrationPix, one entry
//                    per camera SECTOR. Has to be created
//
// - fAverageBadAreas: Array of classes derived from MBadPixelsPix, one entry
//                     per pixel AREA. Is created automatically. 
// - fAverageBadSectors: Array of classes derived from MBadPixelsPix, one entry
//                    per camera SECTOR. Is created automatically.
//
// All TClonesArrays have to enlarged by the corresponding calls to (e.g. in MGeomApply): 
// - InitSize()
// - InitAverageAreas()
// - InitAverageSectors() 
//
/////////////////////////////////////////////////////////////////////////////
#include "MCalibrationCam.h"

#include <TClonesArray.h>

#include "MGeomCam.h"
#include "MGeomPix.h"

#include "MBadPixelsCam.h"
#include "MBadPixelsPix.h"

#include "MCalibrationPix.h"

ClassImp(MCalibrationCam);

using namespace std;

const Int_t MCalibrationCam::gkNumPulserColors = 4;
// --------------------------------------------------------------------------
//
// Default constructor. 
//
// Set the following pointer to NULL:
// - fPixels
// - fAverageAreas
// - fAverageSectors
//
// Initializes:
// - fPulserColor to kNONE 
// - fNumHiGainFADCSlices to 0.
// - fNumLoGainFADCSlices to 0.
//
// Creates a TClonesArray of MBadPixelsPix containers for the TClonesArray's: 
// - fAverageBadAreas
// - fAverageBadSectors
// all initialized to 1 entry
//
// Later, a call to InitAverageAreas() and InitAverageSectors() (or Init()) 
// has to be performed in order to get the dimension correctly.
//
MCalibrationCam::MCalibrationCam(const char *name, const char *title)
    : fPulserColor(kNONE), 
      fPixels(NULL), fAverageAreas(NULL), fAverageSectors(NULL),
      fAverageBadAreas(NULL), fAverageBadSectors(NULL)
{

  fNumHiGainFADCSlices.Set(1);
  fNumLoGainFADCSlices.Set(1);
}

// --------------------------------------------------------------------------
//
// Deletes the following TClonesArray's of MCalibrationPix containers (if exist):
// - fPixels
// - fAverageAreas
// - fAverageSectors
//  
// Deletes the following TClonesArray's of MBadPixelsPix containers (if exist):
// - fAverageBadAreas
// - fAverageBadSectors
//
MCalibrationCam::~MCalibrationCam()
{

  //
  // delete fPixels should delete all Objects stored inside
  //
  if (fPixels)
    delete fPixels;

  if (fAverageAreas)
    delete fAverageAreas;

  if (fAverageSectors)
    delete fAverageSectors;

  if (fAverageBadAreas)
    delete fAverageBadAreas;

  if (fAverageBadSectors)
    delete fAverageBadSectors;
  
}

// --------------------------------------
//
// Calls the ForEach macro for the TClonesArray fPixels with the argument Clear()
// 
// Loops over the fAverageAreas, calling the function Clear() for 
// every entry in:
// - fAverageAreas
// - fAverageBadAreas
// 
// Loops over the fAverageSectors, calling the function Clear() for 
// every entry in:
// - fAverageSectors
// - fAverageBadSectors
// 
void MCalibrationCam::Clear(Option_t *o)
{

  {  fPixels        ->ForEach(TObject, Clear)();  }
  {  fAverageAreas  ->ForEach(TObject, Clear)();  }
  {  fAverageSectors->ForEach(TObject, Clear)();  }
  
  return;
}

// --------------------------------------------------------------------------
//
// Copy 'constructor'
//
void MCalibrationCam::Copy(TObject& object) const
{
  
  MCalibrationCam &calib = (MCalibrationCam&)object;
  
  MParContainer::Copy(calib);
  
  calib.fPulserColor          = fPulserColor;
  
  const Int_t n3 = GetSize();
  if (n3 != 0)
    {
      calib.InitSize(n3);
      for (int i=0; i<n3; i++)
        (*this)[i].Copy(calib[i]);
    }
  
  const Int_t n4 = GetAverageAreas();
  if (n4 != 0)
    {
      calib.InitAverageAreas(n4);
      for (int i=0; i<n4; i++)
        {
          GetAverageArea   (i).Copy(calib.GetAverageArea(i));
          GetAverageBadArea(i).Copy(calib.GetAverageBadArea(i));
          calib.fNumUnsuitable      [i] = fNumUnsuitable[i];
          calib.fNumUnreliable      [i] = fNumUnreliable[i];
          calib.fNumHiGainFADCSlices[i] = fNumHiGainFADCSlices[i];
          calib.fNumLoGainFADCSlices[i] = fNumLoGainFADCSlices[i];
        }
    }
  
  const Int_t n5 = GetAverageSectors();
  if (n5 != 0)
    {
      calib.InitAverageSectors(n5);
      for (int i=0; i<n5; i++)
        {
          GetAverageSector   (i).Copy(calib.GetAverageSector(i));
          GetAverageBadSector(i).Copy(calib.GetAverageBadSector(i));
        }
    }
}

// -------------------------------------------------------------------
//
// Calls TClonesArray::ExpandCreate() for fPixels
//
void MCalibrationCam::InitSize(const UInt_t i)
{
  fPixels->ExpandCreate(i);
}

// -------------------------------------------------------------------
//
// Calls TClonesArray::ExpandCreate() for:
// - fAverageAreas
// - fAverageBadAreas
//
void MCalibrationCam::InitAverageAreas(const UInt_t i)
{
  fAverageAreas->ExpandCreate(i);
  fAverageBadAreas->ExpandCreate(i);

  for (UInt_t j=0; j<i; j++)
    GetAverageArea(j).SetPixId(j);
  
  fNumUnsuitable.Set(i);
  fNumUnreliable.Set(i);
  fNumHiGainFADCSlices.Set(i);
  fNumLoGainFADCSlices.Set(i);
}

// -------------------------------------------------------------------
//
// Calls TClonesArray::ExpandCreate() for:
// - fAverageSectors
// - fAverageBadSectors
//
void MCalibrationCam::InitAverageSectors(const UInt_t i)
{
  fAverageSectors->ExpandCreate(i);
  fAverageBadSectors->ExpandCreate(i);

  for (UInt_t j=0; j<i; j++)
    GetAverageSector(j).SetPixId(j);

}

// -------------------------------------------------------------------
//
// Calls:
// - InitSize()
// - InitAverageAreas()
// - InitAverageSectors()
//
void MCalibrationCam::Init(const MGeomCam &geom)
{
  InitSize          (geom.GetNumPixels() );
  InitAverageAreas  (geom.GetNumAreas()  );
  InitAverageSectors(geom.GetNumSectors());
}

// --------------------------------------------------------------------------
//
// Returns the number of un-suitable pixels per area index and -1 if 
// the area index exceeds the initialized array.
//
const Int_t MCalibrationCam::GetNumUnsuitable( const Int_t  aidx ) const
{
  if (aidx < 0)
    {
      Int_t num = 0;
      for (Int_t i=0;i<fNumUnsuitable.GetSize();i++)
        num += fNumUnsuitable[i];
      return num;
    }
  
  return aidx > fNumUnsuitable.GetSize() ? -1 : fNumUnsuitable[aidx]; 
}

// --------------------------------------------------------------------------
//
// Returns the number of un-reliable pixels per area index and -1 if 
// the area index exceeds the initialized array.
//
const Int_t MCalibrationCam::GetNumUnreliable( const Int_t  aidx ) const
{
  if (aidx < 0)
    {
      Int_t num = 0;
      for (Int_t i=0;i<fNumUnreliable.GetSize();i++)
        num += fNumUnreliable[i];
      return num;
    }

  return aidx > fNumUnreliable.GetSize() ? -1 : fNumUnreliable[aidx]; 
}

// --------------------------------------------------------------------------
//
// Returns the mean number of High-Gain FADC slices per area index and -1 if 
// the area index exceeds the initialized array.
//
const Float_t MCalibrationCam::GetNumHiGainFADCSlices( const Int_t  aidx ) const
{
  if (aidx < 0)
    return -1;

  return aidx > fNumHiGainFADCSlices.GetSize() ? -1 : fNumHiGainFADCSlices[aidx]; 
}

// --------------------------------------------------------------------------
//
// Returns the mean number of Low-Gain FADC slices per area index and -1 if 
// the area index exceeds the initialized array.
//
const Float_t MCalibrationCam::GetNumLoGainFADCSlices( const Int_t  aidx ) const
{
  if (aidx < 0)
    return -1;

  return aidx > fNumLoGainFADCSlices.GetSize() ? -1 : fNumLoGainFADCSlices[aidx]; 
}



// --------------------------------------------------------------------------
//
// Returns the current size of the TClonesArray fAverageAreas
// independently if the MCalibrationPix is filled with values or not.
//
const Int_t MCalibrationCam::GetAverageAreas() const
{
  return fAverageAreas->GetEntriesFast();
}

// --------------------------------------------------------------------------
//
// Returns the current size of the TClonesArray fAverageSectors
// independently if the MCalibrationPix is filled with values or not.
//
const Int_t MCalibrationCam::GetAverageSectors() const
{
  return fAverageSectors->GetEntriesFast();
}


// --------------------------------------------------------------------------
//
// Get i-th pixel (pixel number)
//
MCalibrationPix &MCalibrationCam::operator[](UInt_t i)
{
  return *static_cast<MCalibrationPix*>(fPixels->UncheckedAt(i));
}

// --------------------------------------------------------------------------
//
// Get i-th pixel (pixel number)
//
const MCalibrationPix &MCalibrationCam::operator[](UInt_t i) const
{
  return *static_cast<MCalibrationPix*>(fPixels->UncheckedAt(i));
}

// --------------------------------------------------------------------------
//
// Returns the current size of the TClonesArray fPixels 
// independently if the MCalibrationPix is filled with values or not.
//
const Int_t MCalibrationCam::GetSize() const
{
  return fPixels->GetEntriesFast();
}

// --------------------------------------------------------------------------
//
// Get i-th average pixel (area number)
//
MCalibrationPix &MCalibrationCam::GetAverageArea(const UInt_t i)
{
  return *static_cast<MCalibrationPix*>(fAverageAreas->UncheckedAt(i));
}

// --------------------------------------------------------------------------
//
// Get i-th average pixel (area number)
//
const MCalibrationPix &MCalibrationCam::GetAverageArea(const UInt_t i) const 
{
  return *static_cast<MCalibrationPix*>(fAverageAreas->UncheckedAt(i));
}

// --------------------------------------------------------------------------
//
// Get i-th average pixel (sector number)
//
MCalibrationPix &MCalibrationCam::GetAverageSector(const UInt_t i)
{
  return *static_cast<MCalibrationPix*>(fAverageSectors->UncheckedAt(i));
}

// --------------------------------------------------------------------------
//
// Get i-th average pixel (sector number)
//
const MCalibrationPix &MCalibrationCam::GetAverageSector(const UInt_t i) const 
{
  return *static_cast<MCalibrationPix*>(fAverageSectors->UncheckedAt(i));
}

// --------------------------------------------------------------------------
//
// Get i-th average pixel (area number)
//
MBadPixelsPix &MCalibrationCam::GetAverageBadArea(const UInt_t i)
{
  return *static_cast<MBadPixelsPix*>(fAverageBadAreas->UncheckedAt(i));
}

// --------------------------------------------------------------------------
//
// Get i-th average pixel (area number)
//
const MBadPixelsPix &MCalibrationCam::GetAverageBadArea(const UInt_t i) const 
{
  return *static_cast<MBadPixelsPix*>(fAverageBadAreas->UncheckedAt(i));
}

// --------------------------------------------------------------------------
//
// Get i-th average pixel (sector number)
//
MBadPixelsPix &MCalibrationCam::GetAverageBadSector(const UInt_t i)
{
  return *static_cast<MBadPixelsPix*>(fAverageBadSectors->UncheckedAt(i));
}

// --------------------------------------------------------------------------
//
// Get i-th average pixel (sector number)
//
const MBadPixelsPix &MCalibrationCam::GetAverageBadSector(const UInt_t i) const 
{
  return *static_cast<MBadPixelsPix*>(fAverageBadSectors->UncheckedAt(i));
}



// --------------------------------------------------------------------------
//
// Dummy needed for compilation with MCamEvent
//
Bool_t MCalibrationCam::GetPixelContent(Double_t &val, Int_t idx, const MGeomCam &cam, Int_t type) const
{
  return kTRUE;
}



// --------------------------------------------------------------------------
//
// Calls MCalibrationPix::DrawClone()
//
void MCalibrationCam::DrawPixelContent(Int_t idx) const
{
  (*this)[idx].DrawClone();
}

void MCalibrationCam::SetNumHiGainFADCSlices( const Float_t i, const Int_t aidx)
{
  if (aidx < 0)
    return;

  if (aidx < fNumHiGainFADCSlices.GetSize())
    fNumHiGainFADCSlices[aidx] = i;  
}

void MCalibrationCam::SetNumLoGainFADCSlices( const Float_t i, const Int_t aidx)
{
  if (aidx < 0)
    return;
  if (aidx < fNumLoGainFADCSlices.GetSize())
    fNumLoGainFADCSlices[aidx] = i; 
}

void MCalibrationCam::SetNumUnsuitable( const UInt_t i, const Int_t aidx)
{
  if (aidx < 0)
    return;

  if (aidx < fNumUnsuitable.GetSize())
    fNumUnsuitable[aidx] = i;  
}

void MCalibrationCam::SetNumUnreliable( const UInt_t i, const Int_t aidx)
{
  if (aidx < 0)
    return;
  if (aidx < fNumUnreliable.GetSize())
    fNumUnreliable[aidx] = i; 
}
