/* ======================================================================== *\
!
! *
! * 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): Thomas Bretz, 02/2004 <mailto:tbretz@astro.uni-wuerzburg.de>
!
!   Copyright: MAGIC Software Development, 2000-2004
!
!
\* ======================================================================== */

//////////////////////////////////////////////////////////////////////////////
//
//   MExtractSignal2
//
//  Calculate the signal as the fWindow time slices which have the highest
// integral contents.
//
// Calculation of arrival time not yet implemented
//
//////////////////////////////////////////////////////////////////////////////
#include "MExtractSignal2.h"

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

#include "MParList.h"

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

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

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

ClassImp(MExtractSignal2);

using namespace std;

const Byte_t MExtractSignal2::fgSaturationLimit = 254;
const Byte_t MExtractSignal2::fgFirst  =  2;
const Byte_t MExtractSignal2::fgLast   = 14;
const Byte_t MExtractSignal2::fgWindow =  8;

// --------------------------------------------------------------------------
//
// Default constructor. 
//
MExtractSignal2::MExtractSignal2(const char *name, const char *title)
  : fSaturationLimit(fgSaturationLimit)
{

    fName  = name  ? name  : "MExtractSignal2";
    fTitle = title ? title : "Task to extract the signal from the FADC slices";

    AddToBranchList("MRawEvtData.*");

    SetRange();
}

void MExtractSignal2::SetRange(Byte_t first, Byte_t last, Byte_t window)
{

    fNumHiGainSamples = last-first+1;
    fNumLoGainSamples = last-first+1;

    fHiGainFirst = first;
    fLoGainFirst = first;

    fWindow     = window & ~1;
    fWindowSqrt = TMath::Sqrt((Float_t)fWindow);

    if (fWindow==window)
        return;

    *fLog << warn << "MExtractSignal2::SetRange - Window size set to even " << fWindow << endl;
}

// --------------------------------------------------------------------------
//
// The PreProcess searches for the following input containers:
//  - MRawEvtData
//  - MPedestalCam
//
// The following output containers are also searched and created if
// they were not found:
//
//  - MExtractedSignalCam
//
Int_t MExtractSignal2::PreProcess(MParList *pList)
{
    fRawEvt = (MRawEvtData*)pList->FindObject(AddSerialNumber("MRawEvtData"));
    if (!fRawEvt)
    {
        *fLog << err << AddSerialNumber("MRawEvtData") << " not found... aborting." << endl;
        return kFALSE;
    }


    fSignals = (MExtractedSignalCam*)pList->FindCreateObj(AddSerialNumber("MExtractedSignalCam"));
    if (!fSignals)
        return kFALSE;

    fSignals->SetUsedFADCSlices(fHiGainFirst, fHiGainFirst+fNumHiGainSamples-1,
                                fLoGainFirst, fLoGainFirst+fNumLoGainSamples-1);

    fPedestals = (MPedestalCam*)pList->FindObject(AddSerialNumber("MPedestalCam"));
    if (!fPedestals)
    {
        *fLog << err << AddSerialNumber("MPedestalCam") << " not found... aborting" << endl;
        return kFALSE;
    }
    return kTRUE;
}

void MExtractSignal2::FindSignal(Byte_t *ptr, Byte_t size, Int_t &max, Int_t &sat) const
{
    const Byte_t *end = ptr + size;

    Int_t sum=0;

    //
    // Calculate the sum of the first fWindow slices
    //
    sat = 0;
    Byte_t *p = ptr;
    while (p<ptr+fWindow)
    {
        sum += *p;
        if (*p++ >= fSaturationLimit)
            sat++;
    }

    //
    // Check for saturation in all other slices
    //
    while (p<end)
        if (*p++ >= fSaturationLimit)
            sat++;

    //
    // Calculate the i-th sum as
    //    sum_i+1 = sum_i + slice[i+8] - slice[i]
    // This is fast and accurate (because we are using int's)
    //
    max=0;
    for (p=ptr; p+fWindow<end; p++)
    {
        sum += *(p+fWindow) - *p;
        if (sum>max)
            max = sum;
    }
}

// --------------------------------------------------------------------------
//
// Calculate the integral of the FADC of fWindow time slices which have the
// highest signal
//
Int_t MExtractSignal2::Process()
{
    MRawEvtPixelIter pixel(fRawEvt);
    fSignals->Clear();

    Int_t sat=0;
    while (pixel.Next())
    {
        //
        // Find signal in hi- and lo-gain
        //
        Int_t sumhi, sumlo, sathi, satlo;
        FindSignal(pixel.GetHiGainSamples()+fHiGainFirst, fNumHiGainSamples, sumhi, sathi);
        FindSignal(pixel.GetLoGainSamples()+fLoGainFirst, fNumLoGainSamples, sumlo, satlo);
        if (satlo)
            sat++;

        //
        // Take correspodning pedestal
        //
        const Int_t pixid = pixel.GetPixelId();

        const MPedestalPix  &ped = (*fPedestals)[pixid];
        MExtractedSignalPix &pix = (*fSignals)[pixid];

        const Float_t pedes  = ped.GetPedestal();
        const Float_t pedrms = ped.GetPedestalRms();

        //
        // Set extracted signal with pedestal substracted
        //
        pix.SetExtractedSignal(sumhi - pedes*fWindow, pedrms*fWindowSqrt,
                               sumlo - pedes*fWindow, pedrms*fWindowSqrt);

        pix.SetGainSaturation(sathi, sathi, satlo);
    } /* while (pixel.Next()) */

    //
    // Print a warning if evant has saturationg lo-gains
    //
    if (sat)
        *fLog << warn << "WARNING - Lo Gain saturated in " << sat << " pixels." << endl;

    fSignals->SetReadyToSave();

    return kTRUE;
}
