/* ======================================================================== *\
!
! *
! * 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
!
!
\* ======================================================================== */
/////////////////////////////////////////////////////////////////////////////
//                                                               
// MCalibrationIntensityCam                                               
//                                                               
// Base class for intensity calibration results 
//
// Contains TOrdCollections for the following objects:
// - fCams:  Array of classes derived from MCalibrationCam, one entry 
//           per calibration camera result. Has to be created
//
// See also: MCalibrationIntensityChargeCam, MCalibrationIntensityQECam,
//           MCalibrationIntensityRelTimeCam,
//           MCalibrationCam, MCalibrationPix, 
//           MCalibrationQECam, MCalibrationQEPix,
//           MHCalibrationChargePix, MHCalibrationChargeCam              
//           MCalibrationChargeBlindPix, MCalibrationChargePINDiode
//
//
/////////////////////////////////////////////////////////////////////////////
#include "MCalibrationIntensityCam.h"

#include <TOrdCollection.h>

#include "MGeomCam.h"

ClassImp(MCalibrationIntensityCam);

using namespace std;

// --------------------------------------------------------------------------
//
// Default constructor. 
//
// Set the following pointer to NULL:
// - fCams
//
MCalibrationIntensityCam::MCalibrationIntensityCam(const char *name, const char *title)
{

  fName  = name  ? name  : "MCalibrationIntensityCam";
  fTitle = title ? title : "Base container for the Intensity Calibration";

  fCams = new TOrdCollection;
  fCams->SetOwner();
  
}


// --------------------------------------------------------------------------
//
// Deletes the histograms if they exist
//
MCalibrationIntensityCam::~MCalibrationIntensityCam()
{
  if (fCams)
    delete fCams;
}

// --------------------------------------------------------------------------
//
// Add a new MCalibrationCam to fCams, give it the name "name" and initialize
// it with geom.
//
void MCalibrationIntensityCam::AddToList( const char* name, const MGeomCam &geom) 
{
  InitSize(GetSize()+1);
  GetCam()->SetName(name);
  GetCam()->Init(geom);
}



// --------------------------------------------------------------------------
//
// Copy 'constructor'
//
void MCalibrationIntensityCam::Copy(TObject& object) const
{
  
  MCalibrationIntensityCam &calib = (MCalibrationIntensityCam&)object;
  
  MParContainer::Copy(calib);
  
  calib.fOffsets = fOffsets;
  calib.fSlopes  = fSlopes;
  
  const UInt_t n = GetSize();
  if (n != 0)
    {
      calib.InitSize(n);
      for (UInt_t i=0; i<n; i++)
        GetCam(i)->Copy(*(calib.GetCam(i)));
    }
  
}

// -----------------------------------------------------
//
// Calls Clear() for all entries fCams
//
void MCalibrationIntensityCam::Clear(Option_t *o)
{

  fCams->ForEach(MCalibrationCam, Clear)(); 

  return;
}

// -----------------------------------------------------
//
// Calls Print(o) for all entries fCams
//
void MCalibrationIntensityCam::Print(Option_t *o) const
{
  fCams->ForEach(MCalibrationCam, Print)(o); 
}

// -----------------------------------------------------
//
// Not yet installed...
//
void MCalibrationIntensityCam::DrawHiLoFits()
{

  /*
  if (!fOffsets)
    fOffsets = new TH1D("pp","Offsets of the HiGain LoGain Fit",100,-600.,400.);
  if (!fSlopes)
    fSlopes  = new TH1D("mm","Slopes of the HiGain LoGain Fit",100,-2.,2.);
  if (!fOffvsSlope)
    fOffvsSlope = new TH2D("aa","Slopes vs Offsets of the HiGain LoGain Fit",100,-600.,400.,100,-2.,2.);
  
  TIter Next(fPixels);
  MCalibrationPix *pix;
  MHCalibrationPixel *hist;
  while ((pix=(MCalibrationPix*)Next()))
    {
      hist = pix->GetHist();
      hist->FitHiGainvsLoGain();
      fOffsets->Fill(hist->GetOffset(),1.);
      fSlopes->Fill(hist->GetSlope(),1.);
      fOffvsSlope->Fill(hist->GetOffset(),hist->GetSlope(),1.);
    }

   TCanvas *c1 = new TCanvas();

   c1->Divide(1,3);
   c1->cd(1);
   fOffsets->Draw();
   gPad->Modified();
   gPad->Update();

   c1->cd(2);
  fSlopes->Draw();
  gPad->Modified();
  gPad->Update();

  c1->cd(3);
  fOffvsSlope->Draw("col1");
  gPad->Modified();
  gPad->Update();
  */
}

// -------------------------------------------------------------------
//
// Initialize the objects inside the TOrdCollection using the 
// virtual function Add().
//
// InitSize can only increase the size, but not shrink. 
// 
// It can be called more than one time. New Containers are 
// added only from the current size to the argument i.
//
void MCalibrationIntensityCam::InitSize(const UInt_t i)
{

  const UInt_t save = GetSize();

  if (i==save)
    return;
  
  if (i>save)
    Add(save,i);
}

// -------------------------------------------------------------------
//
// Add MCalibrationCams in the ranges from - to. In order to initialize
// from MCalibrationCam derived containers, overwrite this function
//
void MCalibrationIntensityCam::Add(const UInt_t from, const UInt_t to)
{
  for (UInt_t i=from; i<to; i++)
    fCams->AddAt(new MCalibrationCam,i);
}

// -------------------------------------------------------------------
//
// If size is still 0, Intialize a first Cam.
// Calls Init(geom) for all fCams
//
void MCalibrationIntensityCam::Init(const MGeomCam &geom)
{
  if (GetSize() == 0)
    InitSize(1);

  fCams->ForEach(MCalibrationCam,Init)(geom);
}


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

// --------------------------------------------------------------------------
//
// Get i-th pixel from current camera
//
MCalibrationPix &MCalibrationIntensityCam::operator[](UInt_t i)
{
  return (*GetCam())[i];
}

// --------------------------------------------------------------------------
//
// Get i-th pixel from current camera
//
const MCalibrationPix &MCalibrationIntensityCam::operator[](UInt_t i) const 
{
  return (*GetCam())[i];
}


// --------------------------------------------------------------------------
//
// Returns the current size of the TOrdCollection fAverageAreas of the current camera.
//
const Int_t MCalibrationIntensityCam::GetAverageAreas() const
{
  return GetCam()->GetAverageAreas();
}

// --------------------------------------------------------------------------
//
// Get i-th High Gain pixel Area from the current camera
//
MCalibrationPix  &MCalibrationIntensityCam::GetAverageArea(UInt_t i)
{
  return GetCam()->GetAverageArea(i);
}

// --------------------------------------------------------------------------
//
// Get i-th High Gain pixel Area from the current camera
//
const MCalibrationPix  &MCalibrationIntensityCam::GetAverageArea(UInt_t i) const
{
  return GetCam()->GetAverageArea(i);
}

// --------------------------------------------------------------------------
//
// Get i-th High Gain pixel Area from the current camera
//
MBadPixelsPix  &MCalibrationIntensityCam::GetAverageBadArea(UInt_t i)
{
  return GetCam()->GetAverageBadArea(i);
}

// --------------------------------------------------------------------------
//
// Get i-th High Gain pixel Area from the current camera
//
const MBadPixelsPix  &MCalibrationIntensityCam::GetAverageBadArea(UInt_t i) const
{
  return GetCam()->GetAverageBadArea(i);
}

// --------------------------------------------------------------------------
//
// Returns the current size of the TOrdCollection fAverageSectors or the current camera
//
const Int_t MCalibrationIntensityCam::GetAverageSectors() const
{
  return GetCam()->GetAverageSectors();
}

// --------------------------------------------------------------------------
//
// Get i-th High Gain Sector from the current camera
//
MCalibrationPix  &MCalibrationIntensityCam::GetAverageSector(UInt_t i)
{
  return GetCam()->GetAverageSector(i);
}

// --------------------------------------------------------------------------
//
// Get i-th High Gain Sector from the current camera
//
const MCalibrationPix  &MCalibrationIntensityCam::GetAverageSector(UInt_t i) const
{
  return GetCam()->GetAverageSector(i);
}

// --------------------------------------------------------------------------
//
// Get i-th High Gain Sector from the current camera
//
MBadPixelsPix  &MCalibrationIntensityCam::GetAverageBadSector(UInt_t i)
{
  return GetCam()->GetAverageBadSector(i);
}

// --------------------------------------------------------------------------
//
// Get i-th High Gain Sector from the current camera
//
const MBadPixelsPix  &MCalibrationIntensityCam::GetAverageBadSector(UInt_t i) const
{
  return GetCam()->GetAverageBadSector(i);
}


// --------------------------------------------------------------------------
//
// Get i-th camera 
//
MCalibrationCam *MCalibrationIntensityCam::GetCam(Int_t i)
{
  return static_cast<MCalibrationCam*>(i==-1 ? fCams->Last() : fCams->At(i));
}

// --------------------------------------------------------------------------
//
// Get i-th camera 
//
const MCalibrationCam *MCalibrationIntensityCam::GetCam(Int_t i) const 
{
  return static_cast<MCalibrationCam*>(i==-1 ? fCams->Last() : fCams->At(i));
}

// --------------------------------------------------------------------------
//
// Get camera with name 'name' 
//
MCalibrationCam *MCalibrationIntensityCam::GetCam(const char *name )
{
  return static_cast<MCalibrationCam*>(fCams->FindObject(name));
}

// --------------------------------------------------------------------------
//
// Get camera with name 'name' 
//
const MCalibrationCam *MCalibrationIntensityCam::GetCam(const char *name ) const 
{
  return static_cast<MCalibrationCam*>(fCams->FindObject(name));
}

// --------------------------------------------------------------------------
//
// Calls GetPixelContent for the current entry in fCams
//
Bool_t MCalibrationIntensityCam::GetPixelContent(Double_t &val, Int_t idx, const MGeomCam &cam, Int_t type) const
{
  return GetCam()->GetPixelContent(val,idx,cam,type);
}

// --------------------------------------------------------------------------
//
// Calls DrawPixelContent for the current entry in fCams
//
void MCalibrationIntensityCam::DrawPixelContent( Int_t num ) const
{
  return GetCam()->DrawPixelContent(num);
}

Int_t MCalibrationIntensityCam::CountNumEntries(const MCalibrationCam::PulserColor_t col) const 
{
  
  Int_t size = 0;

  if (col == MCalibrationCam::kNONE)
    return GetSize();
  else
    for (Int_t i=0;i<GetSize();i++)
      {
        const MCalibrationCam *cam = GetCam(i);
        if (cam->GetPulserColor() == col)
          size++;
      }

  return size;
}
