/* ======================================================================== *\
!
! *
! * 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): Josep Flix 04/2001 <mailto:jflix@ifae.es>
!   Author(s): Thomas Bretz 05/2001 <mailto:tbretz@uni-sw.gwdg.de>
!
!   Copyright: MAGIC Software Development, 2000-2001
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
//   MPedCalcPedRun                                                        //
//                                                                         //
//  Input Containers:                                                      //
//   MRawEvtData                                                           //
//                                                                         //
//  Output Containers:                                                     //
//   MPedestalCam                                                          //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

#include "MPedCalcPedRun.h"

#include "MParList.h"

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

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

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

#include "MGeomCamMagic.h"

ClassImp(MPedCalcPedRun);

using namespace std;

MPedCalcPedRun::MPedCalcPedRun(const char *name, const char *title)
{
    fName  = name  ? name  : "MPedCalcPedRun";
    fTitle = title ? title : "Task to calculate pedestals from pedestal runs raw data";

    AddToBranchList("fHiGainPixId");
    AddToBranchList("fHiGainFadcSamples");
    
    fCounter=0;
}

Int_t MPedCalcPedRun::PreProcess( MParList *pList )
{
    fRawEvt = (MRawEvtData*)pList->FindObject("MRawEvtData");
    if (!fRawEvt)
    {
        *fLog << dbginf << "MRawEvtData not found... aborting." << endl;
        return kFALSE;
    }

    fPedestals = (MPedestalCam*)pList->FindCreateObj("MPedestalCam");
    if (!fPedestals)
        return kFALSE;

    MGeomCamMagic magiccam;

    fSumx.Set(magiccam.GetNumPixels());
    fSumx2.Set(magiccam.GetNumPixels());
    
    for(UInt_t i=0;i<magiccam.GetNumPixels();i++)
    {
	fSumx.AddAt(0,i);
	fSumx2.AddAt(0,i);
    }

    return kTRUE;
}

Bool_t MPedCalcPedRun::ReInit(MParList *pList )   
{

    fRunheader = (MRawRunHeader*)pList->FindObject("MRawRunHeader");
    if (!fRunheader)
	{
        *fLog << warn << dbginf << 
        	"Warning - cannot check file type, MRawRunHeader not found." << endl;
	}
    else
        if (fRunheader->GetRunType() == kRTMonteCarlo)
        {
            return kTRUE;
        }

    fNumHiGainSamples =  fRunheader->GetNumSamplesHiGain();

    fPedestals->InitSize(fRunheader->GetNumPixel());

    return kTRUE;

}


Int_t MPedCalcPedRun::Process()
{

    MRawEvtPixelIter pixel(fRawEvt);

    while (pixel.Next())
    {
	Byte_t shift=(fNumHiGainSamples/2*2==fNumHiGainSamples) ? 0:1;
              Byte_t *ptr = pixel.GetHiGainSamples();
        const Byte_t *end = ptr + fRawEvt->GetNumHiGainSamples()-shift;

        const Float_t higainped = CalcHiGainMean(ptr, end);
        const Float_t higainrms = CalcHiGainRms(ptr, end, higainped);

        const UInt_t pixid = pixel.GetPixelId();
        MPedestalPix &pix = (*fPedestals)[pixid];
	
	// cumulate the sum of pedestals and of pedestal squares
	fSumx.AddAt(higainped+fSumx.At(pixid),pixid);
	fSumx2.AddAt(GetSumx2(ptr, end)+fSumx2.At(pixid),pixid);

	// set the value of the pedestal and rms computed from the processed event
        pix.Set(higainped, higainrms);
    }


    fCounter++;

    fPedestals->SetReadyToSave();

    return kTRUE;
}

Int_t MPedCalcPedRun::PostProcess()
{
// Compute pedestals and rms from the whole run

    MRawEvtPixelIter pixel(fRawEvt);

    while (pixel.Next())
    {
        const UInt_t pixid = pixel.GetPixelId();
        MPedestalPix &pix = (*fPedestals)[pixid];

	const Int_t N = fCounter;
	const Float_t sum = fSumx.At(pixid);
	const Float_t sum2 = fSumx2.At(pixid);
	const Float_t higainped = sum/N;
        const Float_t higainrms = sqrt(1./(N-1.)*(sum2-sum*sum/N));
        pix.Set(higainped,higainrms);

    }
    return kTRUE;

}


Float_t MPedCalcPedRun::CalcHiGainMean(Byte_t *ptr, const Byte_t *end) const
{
    Int_t sum=0;
    Byte_t EvenNumSamples=(fNumHiGainSamples/2*2==fNumHiGainSamples) ? fNumHiGainSamples:fNumHiGainSamples-1;

    do sum += *ptr;
    while (++ptr != end);
   
    return (Float_t)sum/EvenNumSamples;
}



Float_t MPedCalcPedRun::GetSumx2(Byte_t *ptr, const Byte_t *end) const
{
    Float_t square = 0;

    // Take an even number of time slices to avoid biases due to A/B effect
    Byte_t EvenNumSamples=(fNumHiGainSamples/2*2==fNumHiGainSamples) ? fNumHiGainSamples:fNumHiGainSamples-1;

    do
    {
        const Float_t val = (Float_t)(*ptr);

        square += val*val;
    } while (++ptr != end);

    return square/EvenNumSamples;
}


Float_t MPedCalcPedRun::CalcHiGainRms(Byte_t *ptr, const Byte_t *end, Float_t higainped) const
{
    Float_t rms = 0;
    Byte_t EvenNumSamples=(fNumHiGainSamples/2*2==fNumHiGainSamples) ? fNumHiGainSamples:fNumHiGainSamples-1;

    do
    {
        const Float_t diff = (Float_t)(*ptr)-higainped;

        rms += diff*diff;
    } while (++ptr != end);

    return sqrt(rms/EvenNumSamples);
}



/*
Float_t MPedCalcPedRun::CalcHiGainMeanErr(Float_t higainrms) const
{
    return higainrms/sqrt((float)fNumHiGainSamples);
}

Float_t MPedCalcPedRun::CalcHiGainRmsErr(Float_t higainrms) const
{
    return higainrms/sqrt(2.*fNumHiGainSamples);
}
*/
