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

/////////////////////////////////////////////////////////////////////////////
//
//  MPedCalUpdate
//
//  This task reads files stored by MJ* storing pedestals (F2) and
//  calibration constants (F1) while an eventloop is running.
//
//  The update is done according to the run-number. The information
//  which ped/cal files corresponds to which run-number is stored in
//  an ascii file. In a next step this ascii file can be created
//  automatically (hopefully from the Database)
//
/////////////////////////////////////////////////////////////////////////////
#include "MPedCalUpdate.h"

#include <fstream>
#include <TFile.h>

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

#include "MParList.h"

#include "MRawRunHeader.h"
#include "MPedPhotCam.h"
#include "MCalibrationChargeCam.h"
#include "MBadPixelsCam.h"

ClassImp(MPedCalUpdate);

using namespace std;

static const TString gsDefName  = "MPedCalUpdate";
static const TString gsDefTitle = "";

// --------------------------------------------------------------------------
//
// Default constructor.
//
MPedCalUpdate::MPedCalUpdate(const char *fname, const char *name, const char *title)
    : fPedPhot(0), fCalCam(0), fFileName(fname)
{
    fName  = name  ? name  : gsDefName.Data();
    fTitle = title ? title : gsDefTitle.Data();

    fLast=0;
}

Bool_t MPedCalUpdate::ReadPed(const char *fname)
{
    TFile file(fname, "READ");
    if (fPedPhot->Read()<=0)
    {
        *fLog << err << "Unable to read MPedPhotCam from " << fname << endl;
        return kFALSE;
    }

    if (file.FindKey("MBadPixelsCam"))
    {
        MBadPixelsCam bad;
        if (bad.Read()<=0)
        {
            *fLog << err << "Unable to read MBadPixelsCam from " << fname << endl;
            return kFALSE;
        }
        fBadPix->Merge(bad);
    }
    return kTRUE;
}

Bool_t MPedCalUpdate::ReadCal(const char *fname)
{
    TFile file(fname, "READ");
    if (fCalCam->Read()<=0)
    {
        *fLog << err << "Unable to read MCalibrationChargeCam from " << fname << endl;
        return kFALSE;
    }

    if (file.FindKey("MBadPixelsCam"))
    {
        MBadPixelsCam bad;
        if (bad.Read()<=0)
        {
            *fLog << "Unable to read MBadPixelsCam from " << fname << endl;
            return kFALSE;
        }
        fBadPix->Merge(bad);
    }
    return kTRUE;
}

Bool_t MPedCalUpdate::ReadPC(TString &line)
{
    const Int_t f = line.First(' ');
    if (f<0)
    {
        *fLog << err << "Entry for pedestal file not found!" << endl;
        return kFALSE;
    }

    const Int_t l = line.Last(' ')+1;
    if (l<0)
    {
        *fLog << err << "Entry for calibration file not found!" << endl;
        return kFALSE;
    }

    const TString fname1 = line(0, f);
    const TString fname2 = line(l, line.Length());

    TString mid(line(f, l-f));
    mid=mid.Strip(TString::kBoth);
    if (!mid.IsNull())
    {
        *fLog << err << "Found three filenames '" << fname1 << "' '" << mid << "' '" << fname2 << "'" << endl;
        return kFALSE;
    }

    if (!ReadPed(fname1))
        return kFALSE;

    if (!ReadCal(fname2))
        return kFALSE;

    return kTRUE;
}

// --------------------------------------------------------------------------
//
//
Bool_t MPedCalUpdate::ReInit(MParList *pList)
{
    MRawRunHeader *header = (MRawRunHeader*)pList->FindObject("MRawRunHeader");
    if (!header)
    {
        *fLog << err << "MRawRunHeader not found... aborting." << endl;
        return kFALSE;
    }
    fPedPhot = (MPedPhotCam*)pList->FindCreateObj("MPedPhotCam");
    if (!fPedPhot)
        return kFALSE;
    fBadPix = (MBadPixelsCam*)pList->FindCreateObj("MBadPixelsCam");
    if (!fBadPix)
        return kFALSE;
    fCalCam = (MCalibrationChargeCam*)pList->FindCreateObj("MCalibrationChargeCam");
    if (!fCalCam)
        return kFALSE;

    const Int_t run = header->GetRunNumber();

    ifstream fin(fFileName);
    if (!fin)
    {
        *fLog << err << "Cannot open file: " << fFileName << endl;
        return kFALSE;
    }

    Int_t last = 0;

    TString readline;

    while (1)
    {
        // Read line from file
        TString line;
        line.ReadLine(fin);
        if (!fin && !readline.IsNull() && fLast!=last)
        {
            *fLog << dbg << "Reading line " << readline << endl;
            fLast = last;
            return ReadPC(readline);
        }

        if (!fin)
            break;

        line = line.Strip(TString::kBoth);

        // Interprete line
        Int_t len, num;
        if (sscanf(line.Data(), "%d %n", &num, &len)!=1)
            continue;

        // Check whether entries are in increasing order
        if (num<=last)
        {
            *fLog << err << "Runs must be in increasing order..." << endl;
            return kFALSE;
        }
        last = num;

        // Check if a new set of files must be read
        if (num<=run)
        {
            readline=line;
            readline.Remove(0, len);
            continue;
        }

        // This is the case if the correct files were already read
        if (fLast==num)
            return kTRUE;

        // Read files given in new line
        *fLog << dbg << "Reading line " << readline << endl;
        fLast = num;
        return ReadPC(readline);
    }

    return kTRUE;
}
