/* ======================================================================== *\
!
! *
! * This file is part of CheObs, the Modular 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 appears 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,  1/2009 <mailto:tbretz@astro.uni-wuerzburg.de>
!
!   Copyright: CheObs Software Development, 2000-2009
!
!
\* ======================================================================== */

//////////////////////////////////////////////////////////////////////////////
//
//  MSimCalibrationSignal
//
// This task is a MRead task which produces events instead of reading them
// from a file. To be more precise, calibration events are produced.
// (Note, that pedestal events are also a kind of calibration events).
//
// Whether pedestal or calibration events are produced is defined by
// the RunType stored in MRawRunheader. The number of pixels which are
// "enlightened" are determined from a MGeomCam.
//
//
//  Input Containers:
//   fNameGeomCam [MGeomCam]
//   MRawRunHeader
//   IntendedPulsePos [MParameterD]
//
//  Output Containers:
//   [MPhotonEvent]
//   [TriggerPos [MParameterD]]
//   MPhotonStatistics
//   MRawEvtHeader
//
//////////////////////////////////////////////////////////////////////////////
#include "MSimCalibrationSignal.h"

#include <TRandom.h>

#include "MParList.h"
#include "MTaskList.h"

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

#include "MParameters.h"

#include "MGeomCam.h"

#include "MRawRunHeader.h"
#include "MRawEvtHeader.h"

#include "MPhotonEvent.h"
#include "MPhotonData.h"

ClassImp(MSimCalibrationSignal);

using namespace std;

// --------------------------------------------------------------------------
//
//  Default Constructor.
//
MSimCalibrationSignal::MSimCalibrationSignal(const char* name, const char *title)
    : fParList(0), fGeom(0), fPulsePos(0), fTrigger(0), fRunHeader(0), fEvtHeader(0),
    fEvt(0), fStat(0),  fNumEntries(1000)
{
    fName  = name  ? name  : "MRead";//"MSimCalibrationSignal";
    fTitle = title ? title : "Task to create a fake signal (derives from MRead)";
}

// --------------------------------------------------------------------------
//
//  Check for the needed parameter containers.
//
Int_t MSimCalibrationSignal::PreProcess(MParList *pList)
{
    fGeom = (MGeomCam*)pList->FindObject(fNameGeomCam, "MGeomCam");
    if (!fGeom)
    {
        *fLog << inf << fNameGeomCam << " [MGeomCam] not found..." << endl;

        fGeom = (MGeomCam*)pList->FindCreateObj(fNameGeomCam);
        if (!fGeom)
            return kFALSE;
    }

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

    fEvt = (MPhotonEvent*)pList->FindCreateObj("MPhotonEvent");
    if (!fEvt)
        return kFALSE;

    fTrigger = (MParameterD*)pList->FindCreateObj("MParameterD", "TriggerPos");
    if (!fTrigger)
        return kFALSE;

    fStat = (MPhotonStatistics*)pList->FindCreateObj("MPhotonStatistics");
    if (!fStat)
        return kFALSE;

    fEvtHeader = (MRawEvtHeader*)pList->FindCreateObj("MRawEvtHeader");
    if (!fEvtHeader)
        return kFALSE;

    fPulsePos = (MParameterD*)pList->FindObject("IntendedPulsePos", "MParameterD");
    if (!fPulsePos)
    {
        *fLog << err << "IntendedPulsePos [MParameterD] not found... aborting." << endl;
        return kFALSE;
    }

    //
    // Search for MTaskList
    //
    fParList = pList;

    //
    // A new file has been opened and new headers have been read.
    //  --> ReInit tasklist
    //
    return kTRUE;
}

// --------------------------------------------------------------------------
//
// ReInit the task-list if this is the first "event from this fake file"
//
Bool_t MSimCalibrationSignal::CallReInit()
{
    if (GetNumExecutions()>0)
        return kTRUE;

    MTask *tlist = (MTask*)fParList->FindObject("MTaskList");
    if (!tlist)
    {
        *fLog << err << dbginf << "MTaskList not found... abort." << endl;
        return kFALSE;
    }

    return tlist->ReInit(fParList);
}

// --------------------------------------------------------------------------
//
// Produce the events.
//
Int_t MSimCalibrationSignal::Process()
{
    if (GetNumExecutions()>fNumEntries)
        return kFALSE;

    if (!CallReInit())
        return kERROR;

    Int_t cnt = 0;
    if (fRunHeader->IsCalibrationRun())
    {
        for (UInt_t idx=0; idx<fGeom->GetNumPixels(); idx++)
        {
            // FIXME: Where to get this number from?
            for (int i=0; i<5; i++)
            {
                MPhotonData &ph = fEvt->Add(cnt++);

                const Float_t tm = gRandom->Gaus(0, 1);

                ph.SetPrimary(MMcEvtBasic::kArtificial);
                ph.SetTag(idx);
                ph.SetWeight();
                ph.SetTime(tm);
            }
        }
    }

    fEvt->Shrink(cnt);
    fEvt->Sort(kTRUE);

    // ------------ FIMXE: Move somewhere else? -------------
    // -------------------- MSimGeomCam ---------------------

    const Double_t freq = fRunHeader->GetFreqSampling()/1000.;

    // Length (ns), Pulse position (Units ns)
    const Float_t ns = fRunHeader->GetNumSamplesHiGain()*freq;
    const Float_t pp = fPulsePos->GetVal();

    const Float_t first = cnt>0 ? fEvt->GetFirst()->GetTime() : 0;
    const Float_t last  = cnt>0 ? fEvt->GetLast()->GetTime()  : ns;

    fStat->SetTime(first-pp, last+(ns-pp));
    fStat->SetMaxIndex(fGeom->GetNumPixels()-1);
    fStat->SetReadyToSave();

    // FIXME: Jitter! (Own class?)
    fTrigger->SetVal(pp*freq);

    // FIXME: Set from somewhere else? (see also MSimTrigger)
    fEvtHeader->SetDAQEvtNumber(GetNumExecutions());
    fEvtHeader->SetReadyToSave();

    return kTRUE;

}
