/* ======================================================================== *\
!
! *
! * 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
!
!
\* ======================================================================== */

//////////////////////////////////////////////////////////////////////////////
//
//  MHCalibrationChargePINDiode
//
//  Histogram class for the charge calibration of the PIN Diode. 
//  Stores and fits the charges, the RMS of the charges  and stores the 
//  location of the maximum FADC slice. Charges are taken from MExtractedSignalPINDiode.
//
//////////////////////////////////////////////////////////////////////////////
#include "MHCalibrationChargePINDiode.h"

#include <TH1.h>
#include <TF1.h>
#include <TPad.h>
#include <TVirtualPad.h>
#include <TCanvas.h>

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

#include "MParList.h"

#include "MExtractedSignalPINDiode.h"
#include "MCalibrationChargePINDiode.h"

ClassImp(MHCalibrationChargePINDiode);

using namespace std;

const Int_t   MHCalibrationChargePINDiode::fgChargeNbins     = 200;
const Axis_t  MHCalibrationChargePINDiode::fgChargeFirst     = -0.5;
const Axis_t  MHCalibrationChargePINDiode::fgChargeLast      = 199.5;
const Int_t   MHCalibrationChargePINDiode::fgRmsChargeNbins  = 100;
const Axis_t  MHCalibrationChargePINDiode::fgRmsChargeFirst  = 0.;
const Axis_t  MHCalibrationChargePINDiode::fgRmsChargeLast   = 100.;  
const Int_t   MHCalibrationChargePINDiode::fgAbsTimeNbins    = 30;
const Axis_t  MHCalibrationChargePINDiode::fgAbsTimeFirst    = -0.5;
const Axis_t  MHCalibrationChargePINDiode::fgAbsTimeLast     = 29.5;
// --------------------------------------------------------------------------
//
// Default Constructor. 
//
// Sets: 
// - the default number for MHGausEvents::fNbins (fgChargeNbins)
// - the default number for MHGausEvents::fFirst (fgChargeFirst)
// - the default number for MHGausEvents::fLast  (fgChargeLast)
// - the default number for fRmsChargeNbins      (fgRmsChargeNbins)
// - the default number for fRmsChargeFirst      (fgRmsChargeFirst)
// - the default number for fRmsChargeLast       (fgRmsChargeLast)
// - the default number for fAbsTimeNbins        (fgAbsTimeNbins)
// - the default number for fAbsTimeFirst        (fgAbsTimeFirst)
// - the default number for fAbsTimeLast         (fgAbsTimeLast)
//
// - the default name of the  fHGausHist      ("HCalibrationChargePINDiode")
// - the default title of the fHGausHist      ("Distribution of Summed FADC slices PIN Diode")
// - the default x-axis title for fHGausHist  ("Sum FADC Slices")
// - the default y-axis title for fHGausHist  ("Nr. of events")
// - the default name of the  fHAbsTime       ("HAbsTimePINDiode")
// - the default title of the fHAbsTime       ("Distribution of Absolute Arrival Times PIN Diode")
// - the default x-axis title for fHAbsTime   ("Absolute Arrival Time [FADC slice nr]")
// - the default y-axis title for fHAbsTime   ("Nr. of events")
// - the default name of the  fHRmsCharge     ("HRmsChargePINDiode")
// - the default title of the fHRmsCharge     ("Distribution of Variances of summed FADC slices PIN Diode")
// - the default x-axis title for fHRmsCharge ("RMS (sum) [FADC slices]")
// - the default y-axis title for fHRmsCharge ("Nr. of events")
// - the default directory of the fHRmsCharge (NULL)
// - the current style for fHRmsCharge (NULL)
//
// Initializes:
// - fHRmsCharge()
// - all pointers to NULL
//
// Calls:
// - Clear()
//
MHCalibrationChargePINDiode::MHCalibrationChargePINDiode(const char *name, const char *title)
    : fPINDiode(NULL), fHRmsCharge()
{

  fName  = name  ? name  : "MHCalibrationChargePINDiode";
  fTitle = title ? title : "Fill the FADC sums of the PINDiode events and perform the fits";
  
  SetNbins( fgChargeNbins );
  SetFirst( fgChargeFirst );
  SetLast ( fgChargeLast  );
  
  SetRmsChargeNbins();
  SetRmsChargeFirst();
  SetRmsChargeLast();
  
  SetAbsTimeNbins();
  SetAbsTimeFirst();
  SetAbsTimeLast();

  fHGausHist.SetName("HCalibrationChargePINDiode");
  fHGausHist.SetTitle("Distribution of Summed FADC slices PIN Diode");  
  fHGausHist.SetXTitle("Sum FADC Slices");
  fHGausHist.SetYTitle("Nr. of events");

  fHAbsTime.SetName("HAbsTimePINDiode");
  fHAbsTime.SetTitle("Distribution of Absolute Arrival Times PIN Diode");  
  fHAbsTime.SetXTitle("Absolute Arrival Time [FADC slice nr]");
  fHAbsTime.SetYTitle("Nr. of events");

  fHRmsCharge.SetName("HRmsChargePINDiode");
  fHRmsCharge.SetTitle("Distribution of Variances of summed FADC slices PIN Diode");  
  fHRmsCharge.SetXTitle("RMS (sum) [FADC slices]");
  fHRmsCharge.SetYTitle("Nr. of events");
  fHRmsCharge.UseCurrentStyle();
  fHRmsCharge.SetDirectory(NULL); 

  Clear();
}

// --------------------------------------------------------------------------
//
// Initializes Binning of the following histograms:
// - fHGausHist.SetBins(fNbins,fFirst,fLast);
// - fHAbsTime.SetBins(fAbsTimeNbins,fAbsTimeFirst,fAbsTimeLast);
// - fHRmsCharge.SetBins(fRmsChargeNbins,fRmsChargeFirst,fRmsChargeLast);
//
Bool_t MHCalibrationChargePINDiode::SetupFill(const MParList *pList) 
{

  MHGausEvents::InitBins();

  fHAbsTime.SetBins(fAbsTimeNbins,fAbsTimeFirst,fAbsTimeLast);
  fHRmsCharge.SetBins(fRmsChargeNbins,fRmsChargeFirst,fRmsChargeLast);

  return kTRUE;

}

// --------------------------------------------------------------------------
//
// Gets or creates the pointers to:
// - MCalibrationChargePINDiode
//
Bool_t MHCalibrationChargePINDiode::ReInit(MParList *pList)
{
  
  fPINDiode = (MCalibrationChargePINDiode*)pList->FindCreateObj("MCalibrationChargePINDiode");
  if (!fPINDiode)
  {
      *fLog << err << "MCalibrationChargePINDiode not found... aborting " << endl;
      return kFALSE;
  }

  return kTRUE;
}

// --------------------------------------------------------------------------
//
// Retrieves from MExtractedSignalPINDiode:
// - Number of used FADC samples via MExtractedSignalPINDiode::GetNumFADCSamples()
// - Extracted signal via            MExtractedSignalPINDiode::GetExtractedSignal()
// - Signal Rms                      MExtractedSignalPINDiode::GetExtractedRms()
// - Arrival Time                    MExtractedSignalPINDiode::GetExtractedTime()
//
// Fills the following histograms:
// - MHGausEvents::FillHistAndArray(signal)
// - MHCalibrationChargePix::FillAbsTime(time);
// - FillRmsCharge(rms);
//
Bool_t MHCalibrationChargePINDiode::Fill(const MParContainer *par, const Stat_t w)
{

  MExtractedSignalPINDiode *extractor = (MExtractedSignalPINDiode*)par;
  
  if (!extractor)
    {
      *fLog << err << "No argument in MExtractedSignalPINDiode::Fill... abort." << endl;
      return kFALSE;
    }
  
  Float_t slices = (Float_t)extractor->GetNumFADCSamples();
  
  if (slices == 0.)
    {
      *fLog << err << "Number of used signal slices in MExtractedSignalPINDiode is zero  ... abort." 
            << endl;
      return kFALSE;
    }
  
  const Float_t signal = (float)extractor->GetExtractedSignal();
  const Float_t time   = extractor->GetExtractedTime();
  const Float_t rms    = extractor->GetExtractedRms();

  FillHistAndArray(signal);
  FillAbsTime(time);
  FillRmsCharge(rms);

  return kTRUE;
}

// --------------------------------------------------------------------------
//
// Returns kTRUE, if empty
//
// Performs the following fits:
// - MHGausEvents::FitGaus()
// - FitRmsCharge()
//
// Creates the fourier spectrum (MHGausEvents::CreateFourierSpectrum() 
// and sets bit MCalibrationChargePINDiode::SetOscillating( MHGausEvents::IsFourierSpectrumOK() )
// Retrieves the results of the following fits and stores them in MCalibrationChargePINDiode:
// - Mean Charge and Error 
// - Sigma Charge and Error
// - Fit Probability
// - Abs Time Mean
// - Abs Time Rms
// - Rms Charge Mean and Error
// - Rms Charge Sigma and Error
// 
Bool_t MHCalibrationChargePINDiode::Finalize() 
{
  
  if (IsGausFitOK() || IsEmpty())
    return kTRUE;
    
  FitGaus();
  FitRmsCharge();

  CreateFourierSpectrum();
  fPINDiode->SetOscillating  ( !IsFourierSpectrumOK() );

  fPINDiode->SetMean     (  fMean     );
  fPINDiode->SetMeanVar  (  fMeanErr  * fMeanErr );
  fPINDiode->SetSigma    (  fSigma    );
  fPINDiode->SetSigmaVar (  fSigmaErr * fMeanErr );
  fPINDiode->SetProb     (  fProb     );

  fPINDiode->SetAbsTimeMean(    GetAbsTimeMean() );
  fPINDiode->SetAbsTimeRms(     GetAbsTimeRms()  );

  fPINDiode->SetRmsChargeMean(     GetRmsChargeMean()        );
  fPINDiode->SetRmsChargeMeanErr(  GetRmsChargeMeanErr()     );
  fPINDiode->SetRmsChargeSigma(    GetRmsChargeSigma()       );
  fPINDiode->SetRmsChargeSigmaErr( GetRmsChargeSigmaErr()    );

  return kTRUE;
}

// --------------------------------------------------------------------------
//
// Fills fHRmsCharge with q
// Returns kFALSE, if overflow or underflow occurred, else kTRUE
//
Bool_t MHCalibrationChargePINDiode::FillRmsCharge(const Float_t q)
{
  return fHRmsCharge.Fill(q) > -1;
}

// -----------------------------------------------------------
//
// Fits -- not yet implemented
//
Bool_t MHCalibrationChargePINDiode::FitRmsCharge(Option_t *option)
{
  return 1;
}


// -------------------------------------------------------------------------
//
// Draw the histogram
//
// The following options can be chosen:
//
// "": displays the fHGausHist with fits and fHRmsCharge
// "all": executes additionally MHGausEvents::Draw(), with option "fourierevents"
//
void MHCalibrationChargePINDiode::Draw(const Option_t *opt)
{

  TString option(opt);
  option.ToLower();
  
  Int_t win = 1;

  TVirtualPad *oldpad = gPad ? gPad : MH::MakeDefCanvas(this,900, 600);
  TVirtualPad *pad    = NULL;

  oldpad->SetBorderMode(0);
    
  if (option.Contains("all"))
  {
      option.ReplaceAll("all","");
      oldpad->Divide(2,1);
      win = 2;
      oldpad->cd(1);
      TVirtualPad *newpad = gPad;
      pad = newpad;
      pad->Divide(1,2);
      pad->cd(1);
  }
  else
  {
      pad = oldpad;
      pad->Divide(1,2);
      pad->cd(1);
  }

  if (!IsEmpty())
      gPad->SetLogy();

  gPad->SetTicks();

  fHGausHist.Draw(opt); 
  if (fFGausFit)
  {
      fFGausFit->SetLineColor(IsGausFitOK() ? kGreen : kRed);
      fFGausFit->Draw("same");
  }

  pad->cd(2);
  fHRmsCharge.Draw(opt);

  oldpad->cd(2);
  MHGausEvents::Draw("fourierevents");
}




