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

//////////////////////////////////////////////////////////////////////////////
//
//   MExtractTimeAndCharge
//
//   Base class for the signal extractors which extract the arrival time 
//   and the signal at the same time. Uses the functions 
//   FindTimeAndChargeHiGain() and FindTimeAndChargeLoGain() to extract the signal and 
//   substract the pedestal value.
//
//   The following variables have to be set by the derived class and 
//   do not have defaults:
//   - fNumHiGainSamples
//   - fNumLoGainSamples
//   - fSqrtHiGainSamples
//   - fSqrtLoGainSamples
//
// Input Containers:
//   MRawEvtData
//   MRawRunHeader
//   MPedestalCam
//
// Output Containers:
//   MArrivalTimeCam
//   MExtractedSignalCam
//
//////////////////////////////////////////////////////////////////////////////
#include "MExtractTimeAndCharge.h"

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

#include "MParList.h"

#include "MRawEvtData.h"
#include "MRawEvtPixelIter.h"
#include "MRawRunHeader.h"

#include "MPedestalCam.h"
#include "MPedestalPix.h"

#include "MArrivalTimeCam.h"
#include "MArrivalTimePix.h"

#include "MExtractedSignalCam.h"
#include "MExtractedSignalPix.h"

ClassImp(MExtractTimeAndCharge);

using namespace std;

const Float_t MExtractTimeAndCharge::fgLoGainStartShift = -2.8; 

// --------------------------------------------------------------------------
//
// Default constructor. 
//
// Sets: 
// - fLoGainStartShift to fgLoGainStartShift+fgOffsetLoGain
//
MExtractTimeAndCharge::MExtractTimeAndCharge(const char *name, const char *title)
{
    fName  = name  ? name  : "MExtractTimeAndCharge";
    fTitle = title ? title : "Base class for signal and time extractors";

    SetLoGainStartShift();
}

// --------------------------------------------------------------------------
//
// The PreProcess searches for the following input containers:
//  - MRawEvtData
//  - MRawRunHeader
//  - MPedestalCam
//
// The following output containers are also searched and created if
// they were not found:
//
//  - MExtractedSignalCam
//  - MArrivalTimeCam    
//
Int_t MExtractTimeAndCharge::PreProcess(MParList *pList)
{

  if (!MExtractTime::PreProcess(pList))
    return kFALSE;
  
  fSignals = (MExtractedSignalCam*)pList->FindCreateObj("MExtractedSignalCam",AddSerialNumber(fNameSignalCam));
  if (!fSignals)
    {
      *fLog << err << fNameSignalCam.Data() << " could not be found nor created... aborting" << endl;
      return kFALSE;
    }
  
  return kTRUE;
}

// --------------------------------------------------------------------------
//
// The ReInit calls:
// -  MExtractor::ReInit()
//
// Call: 
// - MArrivalTimeCam::SetUsedFADCSlices(fHiGainFirst, fHiGainLast, fNumHiGainSamples,
//                                      fLoGainFirst, fLoGainLast, fNumLoGainSamples);
//
Bool_t MExtractTimeAndCharge::ReInit(MParList *pList)
{
    if (!MExtractTime::ReInit(pList))
        return kFALSE;

    fSignals->SetUsedFADCSlices(fHiGainFirst, fHiGainLast+fHiLoLast, fNumHiGainSamples,
                                fLoGainFirst, fLoGainLast, fNumLoGainSamples);

    *fLog << dec << endl;
    *fLog << inf << "Taking " << fNumHiGainSamples
        << " HiGain samples from slice " << (Int_t)fHiGainFirst
        << " to " << (Int_t)(fHiGainLast+fHiLoLast) << " incl" << endl;
    *fLog << inf << "Taking " << fNumLoGainSamples
        << " LoGain samples from slice " << (Int_t)fLoGainFirst
        << " to " << (Int_t)fLoGainLast << " incl" << endl;

    return kTRUE;
}

void MExtractTimeAndCharge::FindTimeAndChargeHiGain(Byte_t *firstused, Byte_t *logain, Float_t &sum, Float_t &dsum, 
                                                    Float_t &time, Float_t &dtime,
                                                    Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag)
{
  return;
}

void MExtractTimeAndCharge::FindTimeAndChargeLoGain(Byte_t *firstused, Float_t &sum, Float_t &dsum, 
                                                    Float_t &time, Float_t &dtime,
                                                    Byte_t &sat, const MPedestalPix &ped, const Bool_t abflag)
{
  return;
}


// --------------------------------------------------------------------------
//
// Calculate the integral of the FADC time slices and store them as a new
// pixel in the MArrivalTimeCam container.
// Calculate the integral of the FADC time slices and store them as a new
// pixel in the MExtractedSignalCam container. 
// The functions FindTimeAndChargeHiGain() and FindTimeAndChargeLoGain are 
// supposed to extract the signal themselves.
//
Int_t MExtractTimeAndCharge::Process()
{

  MRawEvtPixelIter pixel(fRawEvt);
  fArrTime->Clear();
  fSignals->Clear();

  while (pixel.Next())
    {
      //
      // Find signal in hi- and lo-gain
      //
      Float_t sumhi =0., deltasumhi =0.;
      Float_t timehi=0., deltatimehi=0.;
      Byte_t sathi=0;

      const Int_t pixid = pixel.GetPixelId();
      const MPedestalPix  &ped = (*fPedestals)[pixid];
      const Bool_t higainabflag = pixel.HasABFlag();

      FindTimeAndChargeHiGain(pixel.GetHiGainSamples()+fHiGainFirst, pixel.GetLoGainSamples(), 
                              sumhi, deltasumhi, 
                              timehi, deltatimehi, 
                              sathi, ped, higainabflag);
      
      Float_t sumlo =0., deltasumlo =0.;
      Float_t timelo=0., deltatimelo=0.;
      Byte_t satlo=0;
      
      //
      // Adapt the low-gain extraction range from the obtained high-gain time
      //
      if (pixel.HasLoGain())
        {
          fLoGainFirstSave = fLoGainFirst;
          fLoGainFirst     = (Int_t)(timehi+fLoGainStartShift);
          fLoGainFirst     = fLoGainFirst < fLoGainFirstSave ? fLoGainFirstSave : fLoGainFirst;
          
          if ( fLoGainFirst < fLoGainLast )
            {
              const Bool_t logainabflag = (higainabflag + pixel.GetNumHiGainSamples()) & 0x1;
              FindTimeAndChargeLoGain(pixel.GetLoGainSamples()+fLoGainFirst, 
                                      sumlo, deltasumlo, 
                                      timelo, deltatimelo, 
                                      satlo, ped, logainabflag);
            }
          
          fLoGainFirst     = fLoGainFirstSave;
        }
      
      MExtractedSignalPix &pix = (*fSignals)[pixid];
      MArrivalTimePix     &tix = (*fArrTime)[pixid];      

      pix.SetExtractedSignal(sumhi, deltasumhi,sumlo, deltasumlo);
      pix.SetGainSaturation(sathi, sathi, satlo);
      
      tix.SetArrivalTime(timehi, deltatimehi, timelo-fOffsetLoGain, deltatimelo);
      tix.SetGainSaturation(sathi, sathi, satlo);
 
    } /* while (pixel.Next()) */

  fArrTime->SetReadyToSave();
  fSignals->SetReadyToSave();

  return kTRUE;
}

// --------------------------------------------------------------------------
//
// In addition to the resources of the base-class MExtractor:
//   MJPedestal.MExtractor.LoGainStartShift: -2.8
//
Int_t MExtractTimeAndCharge::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
{
    Bool_t rc = kFALSE;

    if (IsEnvDefined(env, prefix, "LoGainStartShift", print))
    {
        fLoGainStartShift = GetEnvValue(env, prefix, "LoGainStartShift", fLoGainStartShift);
        rc = kTRUE;
    }


    return MExtractTime::ReadEnv(env, prefix, print) ? kTRUE : rc;
}

void MExtractTimeAndCharge::Print(Option_t *o) const
{
    *fLog << all;
    if (IsA()==MExtractTimeAndCharge::Class())
        *fLog << GetDescriptor() << ":" << endl;

    *fLog << " LoGainStartShift: " << fLoGainStartShift << endl;
    MExtractTime::Print(o);
}
