/* ======================================================================== *\
!
! *
! * 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   02/2004 <mailto:markus@ifae.es>
!
!   Copyright: MAGIC Software Development, 2000-2004
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//                                                               
// MCalibrationQECam                                               
//                                                               
// Storage container for the calibrated Quantum Efficiency of the whole camera.
//
// For a complete description of the quantum efficiency calibration process, 
// see MCalibrationQEPix.
//
// Individual pixels have to be cast when retrieved e.g.:
// MCalibrationQEPix &avpix = (MCalibrationQEPix&)(*fQECam)[i]
// 
// Averaged values over one whole area index (e.g. inner or outer pixels for 
// the MAGIC camera), can be retrieved via: 
// MCalibrationQEPix &avpix = (MCalibrationQEPix&)fRelCam->GetAverageArea(i)
//
// Averaged values over one whole camera sector can be retrieved via: 
// MCalibrationQEPix &avpix = (MCalibrationQEPix&)fRelCam->GetAverageSector(i)
//
// The following "calibration" constants can be retrieved from each pixel:
// - GetQEBlindPixel ( const PulserColor_t color ): The mean quantum 
//   efficiency obtained with the calibration pulser color (e.g. kGREEN, kBLUE, kUV)
//   after the Blind Pixel Method
// - GetQEFFactor ( const PulserColor_t color ): The mean quantum 
//   efficiency obtained with the calibration pulser color (e.g. kGREEN, kBLUE, kUV)
//   after the F-Factor Method
// - GetQEPINDiode ( const PulserColor_t color ): The mean quantum 
//   efficiency obtained with the calibration pulser color (e.g. kGREEN, kBLUE, kUV)
//   after the PIN Diode Method
// - GetQECombined ( const PulserColor_t color ): The mean quantum 
//   efficiency obtained with the calibration pulser color (e.g. kGREEN, kBLUE, kUV)
//   after the combination of the three methods
//
// See also: MCalibrationQEPix, MCalibrationChargeCam, MCalibrationChargeCalc
//           MCalibrationChargeBlindPix, MCalibrationChargePINDiode, MCalibrationChargePix
//
//                                                                         
// The calculated values (types of GetPixelContent) are:
// 
// 0: Mean Quantum Efficiency of the color: kCT1
// 1: Error of the Mean Quantum Efficiency of the color: kCT1
// 2: Mean Quantum Efficiency of the color: kGREEN
// 3: Error of the Mean Quantum Efficiency of the color: kGreen
// 4: Mean Quantum Efficiency of the color: kBLUE
// 5: Error of the Mean Quantum Efficiency of the color: kBlue
// 6: Mean Quantum Efficiency of the color: kUV
// 7: Error of the Mean Quantum Efficiency of the color: kUV
//
/////////////////////////////////////////////////////////////////////////////
#include "MCalibrationQECam.h"
#include "MCalibrationCam.h"

#include <TClonesArray.h>

#include "MLog.h"
#include "MLogManip.h"

#include "MCalibrationQEPix.h"

ClassImp(MCalibrationQECam);

using namespace std;

const Float_t MCalibrationQECam::gkPlexiglassQE         = 0.96;
const Float_t MCalibrationQECam::gkPlexiglassQEErr      = 0.01;
// --------------------------------------------------------------------------
//
// Default constructor. 
//
// Creates a TClonesArray of MCalibrationQEPix containers, initialized to 1 entry, destinated 
// to hold one container per pixel. Later, a call to MCalibrationQECam::InitSize() 
// has to be performed (in MGeomApply). 
//
MCalibrationQECam::MCalibrationQECam(const char *name, const char *title)
    : fFlags(MCalibrationCam::gkNumPulserColors)
{
    fName  = name  ? name  : "MCalibrationQECam";
    fTitle = title ? title : "Storage container for the calibrated Quantrum Efficiency of the camera";

    fPixels           = new TClonesArray("MCalibrationQEPix",1);
    fAverageAreas     = new TClonesArray("MCalibrationQEPix",1);
    fAverageSectors   = new TClonesArray("MCalibrationQEPix",1);

    Clear();
}

// ------------------------------------------------------------------------
//
// Sets all bits to kFALSE
// 
// Calls:
// - MCalibrationCam::Clear()
//
void MCalibrationQECam::Clear(Option_t *o)
{

  SetBlindPixelMethodValid ( kFALSE, MCalibrationCam::kGREEN);
  SetFFactorMethodValid    ( kFALSE, MCalibrationCam::kGREEN);
  SetCombinedMethodValid   ( kFALSE, MCalibrationCam::kGREEN);
  SetPINDiodeMethodValid   ( kFALSE, MCalibrationCam::kGREEN);
  SetBlindPixelMethodValid ( kFALSE, MCalibrationCam::kBLUE);
  SetFFactorMethodValid    ( kFALSE, MCalibrationCam::kBLUE);
  SetCombinedMethodValid   ( kFALSE, MCalibrationCam::kBLUE);
  SetPINDiodeMethodValid   ( kFALSE, MCalibrationCam::kBLUE);
  SetBlindPixelMethodValid ( kFALSE, MCalibrationCam::kUV);
  SetFFactorMethodValid    ( kFALSE, MCalibrationCam::kUV);
  SetCombinedMethodValid   ( kFALSE, MCalibrationCam::kUV);
  SetPINDiodeMethodValid   ( kFALSE, MCalibrationCam::kUV);
  SetBlindPixelMethodValid ( kFALSE, MCalibrationCam::kCT1);
  SetFFactorMethodValid    ( kFALSE, MCalibrationCam::kCT1);
  SetCombinedMethodValid   ( kFALSE, MCalibrationCam::kCT1);
  SetPINDiodeMethodValid   ( kFALSE, MCalibrationCam::kCT1);

  MCalibrationCam::Clear();
}

// --------------------------------------------------------------------------
//
// Return -1 if gkPlexiglassQEErr is smaller than 0.
// Return -1 if gkPlexiglassQE    is 0.
// Return gkPlexiglassQEErr^2 / (gkPlexiglassQE^2 )
// 
Float_t MCalibrationQECam::GetPlexiglassQERelVar() const
{
  if (gkPlexiglassQEErr < 0.)
    return -1.;
  
  if (gkPlexiglassQE  == 0.)
    return -1.;
  
  return gkPlexiglassQEErr * gkPlexiglassQEErr / gkPlexiglassQE / gkPlexiglassQE ;
}


void MCalibrationQECam::SetBlindPixelMethodValid ( Bool_t b ) 
{
  SetBlindPixelMethodValid ( b, MCalibrationCam::kGREEN);
  SetBlindPixelMethodValid ( b, MCalibrationCam::kBLUE );
  SetBlindPixelMethodValid ( b, MCalibrationCam::kUV   );
  SetBlindPixelMethodValid ( b, MCalibrationCam::kCT1  );
}

void MCalibrationQECam::SetCombinedMethodValid ( Bool_t b ) 
{
  SetCombinedMethodValid ( b, MCalibrationCam::kGREEN);
  SetCombinedMethodValid ( b, MCalibrationCam::kBLUE );
  SetCombinedMethodValid ( b, MCalibrationCam::kUV   );
  SetCombinedMethodValid ( b, MCalibrationCam::kCT1  );
}

void MCalibrationQECam::SetFFactorMethodValid ( Bool_t b ) 
{
  SetFFactorMethodValid ( b, MCalibrationCam::kGREEN);
  SetFFactorMethodValid ( b, MCalibrationCam::kBLUE );
  SetFFactorMethodValid ( b, MCalibrationCam::kUV   );
  SetFFactorMethodValid ( b, MCalibrationCam::kCT1  );
}

void MCalibrationQECam::SetPINDiodeMethodValid ( Bool_t b ) 
{
  SetPINDiodeMethodValid ( b, MCalibrationCam::kGREEN);
  SetPINDiodeMethodValid ( b, MCalibrationCam::kBLUE );
  SetPINDiodeMethodValid ( b, MCalibrationCam::kUV   );
  SetPINDiodeMethodValid ( b, MCalibrationCam::kCT1  );
}

void MCalibrationQECam::SetBlindPixelMethodValid ( Bool_t b,  MCalibrationCam::PulserColor_t col ) 
{
  if (b) 
    SETBIT(fFlags[ MCalibrationCam::kGREEN ],kBlindPixelMethodValid);
  else
    CLRBIT(fFlags[ MCalibrationCam::kGREEN ],kBlindPixelMethodValid);    
}

void MCalibrationQECam::SetPINDiodeMethodValid ( Bool_t b,  MCalibrationCam::PulserColor_t col ) 
{
  if (b) 
    SETBIT(fFlags[ MCalibrationCam::kGREEN ],kPINDiodeMethodValid);
  else
    CLRBIT(fFlags[ MCalibrationCam::kGREEN ],kPINDiodeMethodValid);    
}

void MCalibrationQECam::SetFFactorMethodValid ( Bool_t b,  MCalibrationCam::PulserColor_t col ) 
{
  if (b) 
    SETBIT(fFlags[ MCalibrationCam::kGREEN ],kFFactorMethodValid);
  else
    CLRBIT(fFlags[ MCalibrationCam::kGREEN ],kFFactorMethodValid);    
}

void MCalibrationQECam::SetCombinedMethodValid ( Bool_t b,  MCalibrationCam::PulserColor_t col ) 
{
  if (b) 
    SETBIT(fFlags[ MCalibrationCam::kGREEN ],kCombinedMethodValid);
  else
    CLRBIT(fFlags[ MCalibrationCam::kGREEN ],kCombinedMethodValid);    
}

Bool_t MCalibrationQECam::IsBlindPixelMethodValid () const  
{
  if (IsBlindPixelMethodValid (MCalibrationCam::kGREEN))
    return kTRUE;
  if (IsBlindPixelMethodValid (MCalibrationCam::kBLUE ))
    return kTRUE;
  if (IsBlindPixelMethodValid (MCalibrationCam::kUV   ))
    return kTRUE;
  if (IsBlindPixelMethodValid (MCalibrationCam::kCT1  ))
    return kTRUE;

  return kFALSE;
}

Bool_t MCalibrationQECam::IsCombinedMethodValid () const
{
  if (IsCombinedMethodValid (MCalibrationCam::kGREEN))
    return kTRUE;
  if (IsCombinedMethodValid (MCalibrationCam::kBLUE ))
    return kTRUE;
  if (IsCombinedMethodValid (MCalibrationCam::kUV   ))
    return kTRUE;
  if (IsCombinedMethodValid (MCalibrationCam::kCT1  ))
    return kTRUE;

  return kFALSE;
}

Bool_t MCalibrationQECam::IsFFactorMethodValid () const
{
  if (IsFFactorMethodValid (MCalibrationCam::kGREEN))
    return kTRUE;
  if (IsFFactorMethodValid (MCalibrationCam::kBLUE ))
    return kTRUE;
  if (IsFFactorMethodValid (MCalibrationCam::kUV   ))
    return kTRUE;
  if (IsFFactorMethodValid (MCalibrationCam::kCT1  ))
    return kTRUE;

  return kFALSE;
}


Bool_t MCalibrationQECam::IsPINDiodeMethodValid () const
{
  if (IsPINDiodeMethodValid (MCalibrationCam::kGREEN))
    return kTRUE;
  if (IsPINDiodeMethodValid (MCalibrationCam::kBLUE ))
    return kTRUE;
  if (IsPINDiodeMethodValid (MCalibrationCam::kUV   ))
    return kTRUE;
  if (IsPINDiodeMethodValid (MCalibrationCam::kCT1  ))
    return kTRUE;

  return kFALSE;
}

Bool_t MCalibrationQECam::IsBlindPixelMethodValid (MCalibrationCam::PulserColor_t col)  const
{
  return TESTBIT(fFlags[ MCalibrationCam::kGREEN ],kBlindPixelMethodValid);
}

Bool_t MCalibrationQECam::IsCombinedMethodValid (MCalibrationCam::PulserColor_t col)  const
{
  return TESTBIT(fFlags[ MCalibrationCam::kGREEN ],kCombinedMethodValid);
}

Bool_t MCalibrationQECam::IsFFactorMethodValid (MCalibrationCam::PulserColor_t col)  const
{
  return TESTBIT(fFlags[ MCalibrationCam::kGREEN ],kFFactorMethodValid);
}

Bool_t MCalibrationQECam::IsPINDiodeMethodValid (MCalibrationCam::PulserColor_t col)  const
{
  return TESTBIT(fFlags[ MCalibrationCam::kGREEN ],kPINDiodeMethodValid);
}

// --------------------------------------------------------------------------
//
// Print first the well fitted pixels 
// and then the ones which are not FitValid
//
void MCalibrationQECam::Print(Option_t *o) const
{

  *fLog << all << GetDescriptor() << ":" << endl;
  int id = 0;
  
  TIter Next(fPixels);
  MCalibrationQEPix *pix;
  while ((pix=(MCalibrationQEPix*)Next()))
    {
      
      if (!pix->IsExcluded() && pix->IsValid()) 
	{
          id++;
	}
    }
  
  *fLog << all << id << " succesful pixels :-))" << endl;
  id = 0;
  
  *fLog << all << endl;
  *fLog << all << "Pixels with errors:" << endl;
  *fLog << all << endl;
  
  TIter Next2(fPixels);
    while ((pix=(MCalibrationQEPix*)Next2()))
      {
        
        if (!pix->IsExcluded() && !pix->IsValid())
          {
            id++;
          }
      }
    *fLog << all << id << " pixels with errors :-((" << endl;

    
  *fLog << all << endl;
  *fLog << all << "Excluded pixels:" << endl;
  *fLog << all << endl;
  
  id = 0;

  TIter Next4(fPixels);
  while ((pix=(MCalibrationQEPix*)Next4()))
  {
      if (pix->IsExcluded())
      {
	  *fLog << all << pix->GetPixId() << endl;
	  id++;
      }
  }
  *fLog << all << id << " Excluded pixels " << endl;
}

// --------------------------------------------------------------------
//                                                                         
// The calculated values (types) are:
// 
// 0: Mean Quantum Efficiency of the color: kCT1
// 1: Error of the Mean Quantum Efficiency of the color: kCT1
// 2: Mean Quantum Efficiency of the color: kGREEN
// 3: Error of the Mean Quantum Efficiency of the color: kGreen
// 4: Mean Quantum Efficiency of the color: kBLUE
// 5: Error of the Mean Quantum Efficiency of the color: kBlue
// 6: Mean Quantum Efficiency of the color: kUV
// 7: Error of the Mean Quantum Efficiency of the color: kUV
//
Bool_t MCalibrationQECam::GetPixelContent(Double_t &val, Int_t idx, const MGeomCam &cam, Int_t type) const
{

  if (idx > GetSize())
    return kFALSE;

  MCalibrationQEPix &pix = (MCalibrationQEPix&)(*this)[idx];

  if (pix.IsExcluded())
    return kFALSE;

  switch (type)
    {
    case 0:
      val = pix.GetQECascadesFFactor();
      break;
    case 1:
      val = pix.GetQECascadesFFactorErr();
      break;
    case 2:
      val = pix.GetQECascadesBlindPixel();
      break;
    case 3:
      val = pix.GetQECascadesBlindPixelErr();
      break;
    case 4:
      val = pix.GetQECascadesPINDiode();
      break;
    case 5:
      val = pix.GetQECascadesPINDiodeErr();
      break;
    case 6:
      val = pix.GetQECascadesCombined();
      break;
    case 7:
      val = pix.GetQECascadesCombinedErr();
      break;
    case 8:
      val = pix.GetQEFFactor(kCT1);
      break;
    case 9:
      val = pix.GetQEFFactorErr(kCT1);
      break;
    case 10:
      val = pix.GetQEFFactor(kGREEN);
      break;
    case 11:
      val = pix.GetQEFFactorErr(kGREEN);
      break;
    case 12:
      val = pix.GetQEFFactor(kBLUE);
      break;
    case 13:
      val = pix.GetQEFFactorErr(kBLUE);
      break;
    case 14:
      val = pix.GetQEFFactor(kUV);
      break;
    case 15:
      val = pix.GetQEFFactorErr(kUV);
      break;
    default:
      return kFALSE;
    }
  return val!=-1.;
}

// --------------------------------------------------------------------------
//
// Not yet implemented
//
void MCalibrationQECam::DrawPixelContent(Int_t idx) const
{
  return;
}









