/* ======================================================================== *\
!
! *
! * 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, 09/2004 <mailto:markus@ifae.es>
!         
!   Copyright: MAGIC Software Development, 2000-2004
!
!
\* ======================================================================== */
//////////////////////////////////////////////////////////////////////////////
//
//  MCalibColorSteer
//
//  Steers the occurrance of different calibration colours in one calibration 
//  run. 
// 
//  Input Containers:
//   MCalibrationPattern
//   MParList
//   MCalibrationIntensityChargeCam
//   MCalibrationIntensityRelTimeCam
//   MBadPixelsIntensityCam 
//
//  Output Containers:
//   MCalibrationIntensityChargeCam
//   MCalibrationIntensityRelTimeCam
//   MBadPixelsIntensityCam 
//
//////////////////////////////////////////////////////////////////////////////
#include "MCalibColorSteer.h"

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

#include "MParList.h"
#include "MTaskList.h"

#include "MHCalibrationCam.h"
#include "MCalibrationChargeCam.h"
#include "MCalibrationBlindCam.h"

#include "MCalibrationIntensityChargeCam.h"
#include "MCalibrationIntensityBlindCam.h"
#include "MCalibrationIntensityQECam.h"
#include "MCalibrationIntensityRelTimeCam.h"

#include "MBadPixelsIntensityCam.h"

#include "MCalibrationChargeCam.h"
#include "MCalibrationChargeCalc.h"
#include "MCalibrationRelTimeCalc.h"

#include "MRawRunHeader.h"
#include "MCalibrationPattern.h"

#include "MGeomCam.h"

ClassImp(MCalibColorSteer);

using namespace std;

// --------------------------------------------------------------------------
//
//  Default constructor. 
//
MCalibColorSteer::MCalibColorSteer(const char *name, const char *title)
    : fCalibPattern(NULL), fGeom(NULL), fParList(NULL), 
      fIntensCharge(NULL), fIntensRelTime(NULL), fIntensBad(NULL),
      fBad(NULL), fChargeCalc(NULL), fRelTimeCalc(NULL)
{

  fName  = name  ? name  : "MCalibColorSteer";
  fTitle = title ? title : "Task to steer the processing of different colours in the calibration events";

}

// -----------------------------------------------------------------------------------
//
// The following container are searched for and execution aborted if not in MParList:
//  - MCalibrationPattern
//  - MTaskList
//
Int_t MCalibColorSteer::PreProcess(MParList *pList)
{

  fCalibPattern = (MCalibrationPattern*)pList->FindObject("MCalibrationPattern");
  if (!fCalibPattern)
    {
      *fLog << err << "MCalibrationPattern not found... abort." << endl;
      return kFALSE;
    }

  fRunHeader = (MRawRunHeader*)pList->FindObject("MRawRunHeader");
  if (!fRunHeader)
    {
      *fLog << err << "MRawRunHeader not found... abort." << endl;
      return kFALSE;
    }

  fGeom = (MGeomCam*)pList->FindObject("MGeomCam");
  if (!fGeom)
    {
      *fLog << err << "MGeomCam not found... abort." << endl;
      return kFALSE;
    }

  fParList = pList;
  if (!fParList)
    {
      *fLog << err << "MParList not found... abort." << endl;
      return kFALSE;
    }

  MTaskList *tlist = (MTaskList*)pList->FindObject("MTaskList");
  if (!tlist)
    {
      *fLog << err << "MTaskList not found... abort." << endl;
      return kFALSE;
    }

  // 
  // Look for the MBadPixels Intensity Cam
  //
  fIntensBad = (MBadPixelsIntensityCam*)pList->FindCreateObj("MBadPixelsIntensityCam");
  if (fIntensBad)
    *fLog << inf << "Found MBadPixelsIntensityCam ... " << flush;
  else
    return kFALSE;
  
  // 
  // Look for the MBadPixels Intensity Cam
  //
  fBad = (MBadPixelsCam*)pList->FindObject("MBadPixelsCam");
  if (fBad)
    {
      *fLog << inf << "Found also MBadPixelsCam ... " << flush;
      fIntensBad->GetCam()->Merge(*fBad);
    }
  else
    return kFALSE;
  
  // 
  // Look for the MCalibrationIntensityBlindCam
  //
  fIntensBlind = (MCalibrationIntensityBlindCam*)pList->FindCreateObj("MCalibrationIntensityBlindCam");

  if (fIntensBlind)
    *fLog << inf << "Found MCalibrationIntensityBlindCam ... " << flush;
  else
    return kFALSE;
  
  // 
  // Look for the MFillH name "FillChargeCam". In case yes, initialize the 
  // corresponding IntensityCam
  //
  if (pList->FindObject(AddSerialNumber("MHCalibrationChargeCam")))
  {

    fIntensCharge = (MCalibrationIntensityChargeCam*)pList->FindCreateObj("MCalibrationIntensityChargeCam");
    fIntensQE     = (MCalibrationIntensityQECam*)    pList->FindCreateObj("MCalibrationIntensityQECam");

    fChargeCalc   = (MCalibrationChargeCalc*)tlist->FindObject("MCalibrationChargeCalc");

    *fLog << inf << "Found MHCalibrationChargeCam ... " << flush;

    if (!fIntensCharge)
      {
        *fLog << err << "Could not find nor create MCalibrationIntensityChargeCam abort... " << endl;
        return kFALSE;
      }
    
    if (!fIntensQE)
      {
        *fLog << err << "Could not find nor create MCalibrationIntensityQECam abort... " << endl;
        return kFALSE;
      }
    
    if (!fChargeCalc)
      {
        *fLog << err << "Could not find MCalibrationChargeCalc abort... " << endl;
        return kFALSE;
      }
  }
      
  // 
  // Look for the MFillH name "FillRelTimeCam". In case yes, initialize the 
  // corresponding IntensityCam
  //
  if (pList->FindObject(AddSerialNumber("MHCalibrationRelTimeCam")))
  {

    fIntensRelTime = (MCalibrationIntensityRelTimeCam*)pList->FindCreateObj("MCalibrationIntensityRelTimeCam");
    fRelTimeCalc   = (MCalibrationRelTimeCalc*)tlist->FindObject(AddSerialNumber("MCalibrationRelTimeCalc"));

    *fLog << inf << "Found MHCalibrationRelTimeCam ... " << flush;

    if (!fIntensRelTime)
      {
        *fLog << err << "Could not find nor create MCalibrationIntensityRelTimeCam abort... " << endl;
        return kFALSE;
      }

    if (!fRelTimeCalc)
      {
        *fLog << err << "Could not find MCalibrationRelTimeCalc abort... " << endl;
        return kFALSE;
      }
  }
  
  fColor = MCalibrationCam::kNONE;
  fStrength = 0.;
      
  return kTRUE;
}

// --------------------------------------------------------------------------
//
// Reads the pattern from MCalibrationPattern and initializes new containers in the 
// Intensity Cams, if the pattern has changed. Executes Finalize of the 
// MCalibration*Calc classes in that case.
//
Int_t MCalibColorSteer::Process()
{

  const MCalibrationCam::PulserColor_t col = fCalibPattern->GetPulserColor();
  const Float_t strength                   = fCalibPattern->GetPulserStrength();

  if (fColor ==MCalibrationCam::kNONE)
    {
      fColor = col;
      fStrength = strength;
      return kTRUE;
    }

  const Float_t strdiff = TMath::Abs(fStrength-strength);

  if (col  == MCalibrationCam::kNONE || (col == fColor && strdiff < 0.05))
    return kTRUE;

  *fLog << inf << GetDescriptor() << " : Color - old=" << fColor << flush;
  fColor = col;
  *fLog << " / new=" << fColor << endl;

  *fLog << inf << GetDescriptor() << " : Strength - old=" << fStrength << flush;
  fStrength = strength;
  *fLog << " / new=" << fStrength << endl;

  //
  // Finalize Possible calibration histogram classes...
  //
  *fLog << inf << GetDescriptor() << " : Finalize calibration histograms..." << flush;
  if (Finalize("MHCalibrationChargeCam"))      *fLog << "MHCalibrationChargeCam...";
  if (Finalize("MHCalibrationChargeBlindCam")) *fLog << "MHCalibrationChargeBlindCam...";
  if (Finalize("MHCalibrationRelTimeCam"))     *fLog << "MHCalibrationRelTimeCam...";
  if (Finalize("MHCalibrationTestCam"))        *fLog << "MHCalibrationChargeCam...";
  if (Finalize("MHCalibrationTestTimeCam"))    *fLog << "MHCalibrationChargeCam...";

  //
  // Finalize possible calibration calculation tasks
  //
  *fLog << endl;
  *fLog << inf << GetDescriptor() << " : Finalize calibration calculations..." << flush;
  if (fChargeCalc)
    fChargeCalc->Finalize();
  if (fRelTimeCalc)
    fRelTimeCalc->Finalize();

  ReInitialize();

  return kTRUE;
}


// --------------------------------------------------------------------------
//
// Searches for name in the MParList and calls, if existing: 
// - MHCalibrationCam::Finalize()
// - MHCalibrationCam::ResetHists()
//
Bool_t MCalibColorSteer::Finalize(const char* name)
{

  MHCalibrationCam *hist = (MHCalibrationCam*)fParList->FindObject(name);
  if (!hist)
      return kFALSE;

  hist->Finalize();
  hist->ResetHists();
  hist->SetColor( fCalibPattern->GetPulserColor());
  return kTRUE;
}

// --------------------------------------------------------------------------
//
// Re-Intitializes new containers inside the Intensity Cams. 
// From now on, a call to the IntensityCam functions returns pointers 
// to the newly created Containers.
//
Bool_t MCalibColorSteer::ReInitialize()
{

  *fLog << endl;

  TString namep = GetNamePattern();

  if (fIntensBad)
    {
      fIntensBad->AddToList(Form("MBadPixelsCam%s",namep.Data()),*fGeom);
      *fLog << inf << "New MBadPixelsCam with " << namep << endl;
      fIntensBad->GetCam()->Merge(*fBad);
      *fLog << inf << "Merged new MBadPixelsCam with first of list" << endl;
    }
  if (fIntensCharge)
    {
      MCalibrationChargeCam *oldcam = (MCalibrationChargeCam*)fIntensCharge->GetCam();
      fIntensCharge->AddToList(Form("MCalibrationChargeCam%s",namep.Data()),*fGeom);
      MCalibrationChargeCam *cam    = (MCalibrationChargeCam*)fIntensCharge->GetCam();
      cam->SetPulserColor(fCalibPattern->GetPulserColor());
      if (!cam->CopyHiLoConversionFactors(*oldcam))
        return kFALSE;
      *fLog << inf << "New MCalibrationChargeCam with name: " << cam->GetName() << endl;
    }
  if (fIntensQE)
    {
      fIntensQE->AddToList(Form("MCalibrationQECam%s",namep.Data()),*fGeom);
      *fLog << inf << "New MCalibrationQECam with: " << namep << endl;
    }

  if (fIntensBlind)
    {
      fIntensBlind->AddToList(Form("MCalibrationBlindCam%s",namep.Data()),*fGeom);
      MCalibrationCam *cam = fIntensBlind->GetCam();
      cam->SetPulserColor(fCalibPattern->GetPulserColor());
      *fLog << inf << "New MCalibrationBlindCam with name: " << cam->GetName() << endl;
    }

  if (fIntensRelTime)
    {
      fIntensRelTime->AddToList(Form("MCalibrationRelTimeCam%s",namep.Data()),*fGeom);
      MCalibrationCam *cam = fIntensRelTime->GetCam();
      cam->SetPulserColor(fCalibPattern->GetPulserColor());
      *fLog << inf << "New MCalibrationRelTimeCam with name: " << cam->GetName() << endl;
    }

  return kTRUE;

}

TString MCalibColorSteer::GetNamePattern()
{

  const Float_t strength = fCalibPattern->GetPulserStrength();
  const MCalibrationCam::PulserColor_t col = fCalibPattern->GetPulserColor();

  TString result = Form("%2.1f",strength);
  
  switch (col)
    {
    case MCalibrationCam::kCT1:
      result += "CT1";
      break;
    case MCalibrationCam::kGREEN:
      result += "GREEN";
      break;
    case MCalibrationCam::kBLUE:
      result += "BLUE";
      break;
    case MCalibrationCam::kUV:
      result += "UV";
      break;
    default:
      break;
    }
  return result;
}
