/* ======================================================================== *\
!
! *
! * 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): Sebastian Raducci, 12/2003 <mailto:raducci@fisica.uniud.it>
!
!   Copyright: MAGIC Software Development, 2000-2003
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//
// MArrivalTime
//
// Times are calculated using the TSpline5 Root Class
// 
/////////////////////////////////////////////////////////////////////////////
#include "MArrivalTime.h"

#include "MGeomCam.h"

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

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

ClassImp(MArrivalTime);

using namespace std;

// --------------------------------------------------------------------------
//
// Creates an object containing the arrival time for each pixel in the event
//
MArrivalTime::MArrivalTime(const char *name, const char *title)
{
    fName  = name  ? name  : "MArrivalTime";
    fTitle = title ? title : "Photons arrival times Information";
}

//
// Calculates the arrival time for each pixel 
// Possible Methods 
// Case 1: Spline5 (From TSpline5 Root Class)
// 
//

void MArrivalTime::Calc(const MRawEvtData &evt, const MGeomCam &geom)
{
    const Int_t n = geom.GetNumPixels();

    fData.Set(n);
    fData.Reset();

    MRawEvtPixelIter pixel((MRawEvtData*)&evt);
   
    while ( pixel.Next() )
    {
	const UInt_t idx = pixel.GetPixelId();

//If pixel has saturated and hasn't lo gains we return -1

        if (pixel.GetMaxHiGainSample() == 0xff)
        {   
            if (!pixel.HasLoGain())        
	    {
                fData[idx]=-1.0;
            }
            else //Calculate time using Lo Gains
            {
		Byte_t *ptr = pixel.GetLoGainSamples();

		Int_t nSlice = evt.GetNumLoGainSamples();
//Some casts are needed because TSpline5 constructor accepts only Double_t values
		Double_t ptr2[nSlice];
		for (Int_t i = 0; i < nSlice; i++)
		    ptr2[i]=(Double_t)ptr[i];
		TSpline5 *spline = new TSpline5("spline",(Double_t) 0,(Double_t)(nSlice - 1),ptr2,nSlice);
//Now find the maximum evaluating the spline function at every 1/10 time slice
		Double_t abscissa=0.0;
		Double_t maxAb=0.0;
		Double_t maxOrd=0.0;
		Double_t swap;
		while (abscissa <= nSlice - 1) 
		{
		    swap=spline->Eval(abscissa);
		    if (swap > maxOrd)
		    {
			maxOrd = swap;
			maxAb  = abscissa;
		    }
		    abscissa += 0.1;
		}
		fData[idx]=maxAb;
            }
	}
        else //Calculate time using Hi Gains
        {
	    Byte_t *ptr = pixel.GetHiGainSamples();

	    Int_t nSlice = evt.GetNumHiGainSamples();
//Some casts are needed because TSpline5 constructor accepts only Double_t values
	    Double_t  ptr2[nSlice];
	    for (Int_t i = 0; i < nSlice; i++)
		ptr2[i]=(Double_t)ptr[i];
	    TSpline5 *spline = new TSpline5("spline",(Double_t) 0,(Double_t)(nSlice - 1),ptr2,nSlice);
//Now find the maximum evaluating the spline function at every 1/10 time slice
	    Double_t abscissa=0.0;
	    Double_t maxAb=0.0;
	    Double_t maxOrd=0.0;
	    Double_t swap;
	    while (abscissa <= nSlice - 1) 
	    {
		swap=spline->Eval(abscissa);
		if (swap > maxOrd)
		{
		    maxOrd = swap;
		    maxAb  = abscissa;
		}
		abscissa += 0.1;
	    }
	    fData[idx]=maxAb;
        }
    }
}


// --------------------------------------------------------------------------
//
// Returns the arrival time value
//

Bool_t MArrivalTime::GetPixelContent(Double_t &val, Int_t idx, const MGeomCam &cam, Int_t type) const
{
    if (idx<0 || idx>=fData.GetSize())
        return kFALSE;

    val = fData[idx];
    return kTRUE;
}

void MArrivalTime::DrawPixelContent(Int_t num) const
{
    *fLog << warn << "MArrivalTime::DrawPixelContent - not available." << endl;
}
