/* ======================================================================== *\
!
! *
! * 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, 08/2004 <mailto:tbretz@astro.uni-wuerzburg.de>
!   Author(s): Daniela Dorner, 08/2004 <mailto:dorner@astro.uni-wuerzburg.de>
!
!   Copyright: MAGIC Software Development, 2000-2004
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//
// fillcalib.C
// ===========
//
// This macro is used to read the calibartion-/callisto-output files.
// These files are automatically called calib00000.root.
//
// From this file the MBadPixelsCam and the MGeomCam is extracted. If
// the geometry isn't found MGeomCamMagic is used as a default.
//
// Usage:
//   .x fillcalib.C("/data/MAGIC/Period014/calib00000.root", kTRUE)
//
// The second argument is the 'dummy-mode'. If it is kTRUE dummy-mode is
// switched on and nothing will be written into the database. This is usefull
// for tests.
//
// The corresponding sequence number is extracted from the filename...
// FIXME: MSeqeuence should be stored in the calib-file?
//
// The macro can also be run without ACLiC but this is a lot slower...
//
// Remark: Running it from the commandline looks like this:
//   root -q -l -b fillcalib.C+\(\"filename\"\,kFALSE\) 2>&1 | tee fillcalib.log
//
// Make sure, that database and password are corretly set in a resource
// file called sql.rc and the resource file is found.
//
// Returns 0 in case of failure and 1 in case of success.
//
/////////////////////////////////////////////////////////////////////////////
#include <iostream>

#include <TEnv.h>
#include <TRegexp.h>

#include <TH1.h>

#include <TFile.h>
#include <TSQLResult.h>
#include <TSQLRow.h>

#include "MSQLServer.h"

#include "MStatusArray.h"
#include "MHCamera.h"
#include "MGeomCamMagic.h"
#include "MBadPixelsCam.h"

using namespace std;

// --------------------------------------------------------------------------
//
// Checks whether an entry is already existing
//
Bool_t ExistStr(MSQLServer &serv, const char *column, const char *table, Int_t test)
{
    TString query(Form("SELECT %s FROM %s WHERE %s='%d'", column, table, column, test));
    TSQLResult *res = serv.Query(query);
    if (!res)
        return kFALSE;

    TSQLRow *row;

    Bool_t rc = kFALSE;
    while ((row=res->Next()))
    {
        if ((*row)[0])
        {
            rc = kTRUE;
            break;
        }
    }

    delete res;

    return rc;
}

int Process(MSQLServer &serv, TString fname, Bool_t dummy)
{
    MBadPixelsCam badpix;

    TFile file(fname, "READ");
    if (!file.IsOpen())
    {
        cout << "ERROR - Could not find file " << fname << endl;
        return 0;
    }

    if (badpix.Read("MBadPixelsCam")<=0)
    {
        cout << "ERROR - Reading of MBadPixelsCam failed." << endl;
        return 0;
    }

    MGeomCamMagic def;

    MGeomCam *geom = (MGeomCam*)file.Get("MGeomCam");
    if (!geom)
    {
        cout << "WARNING - Reading of MGeomCam failed... using default <MGeomCamMagic>" << endl;
        geom = &def;
    }

    cout << "Camera Geometry: " << geom->ClassName() << endl;

    const Short_t unsin  = badpix.GetNumUnsuitable(MBadPixelsPix::kUnsuitableRun, geom, 0);
    const Short_t unsout = badpix.GetNumUnsuitable(MBadPixelsPix::kUnsuitableRun, geom, 1);

    const Short_t unrin  = badpix.GetNumUnsuitable(MBadPixelsPix::kUnreliableRun, geom, 0);
    const Short_t unrout = badpix.GetNumUnsuitable(MBadPixelsPix::kUnreliableRun, geom, 1);

    const Short_t isoin  = badpix.GetNumIsolated(*geom, 0);
    const Short_t isoout = badpix.GetNumIsolated(*geom, 1);

    const Short_t clumax = badpix.GetNumMaxCluster(*geom);

    if (unsin<0 || unsout<0 || unrin<0 || unrout<0 || isoin<0 || isoout<0 || clumax<0)
        return 0;

    //     MHCamera hist(geom);
    //     hist.SetCamContent(badpix, 1);
    //     hist.DrawCopy();
    //     hist.SetCamContent(badpix, 3);
    //     hist.DrawCopy();

    //Getting values from the status display
    MStatusArray arr;
    if (arr.Read()<=0)
        return 0;

    TH1 *h;

    //getting the mean and rms from the arrival time (inner cam)
    h = (TH1*)arr.FindObjectInCanvas("HRelTimeHiGainArea0", "TH1F", "Time");
    if (!h)
    {
        cout << "WARNING - Could not find histogram HRelTimeHiGainArea0." << endl;
        return 0;
    }

    Float_t meani = h->GetMean();
    Float_t rmsi  = h->GetRMS();
    meani = TMath::Nint(meani*10)/10.;
    rmsi  = TMath::Nint(rmsi*10)/10.;
    TString meaninner = Form("%5.1f", meani);
    TString rmsinner  = Form("%5.1f", rmsi);


    //getting the mean and rms from the arrival time (outer cam)
    h = (TH1*)arr.FindObjectInCanvas("HRelTimeHiGainArea1", "TH1F", "Time");
    if (!h)
    {
        cout << "WARNING - Could not find histogram HRelTimeHiGainArea1." << endl;
        return 0;
    }

    Float_t meano = h->GetMean();
    Float_t rmso  = h->GetRMS();
    meano = TMath::Nint(meano*10)/10.;
    rmso  = TMath::Nint(rmso*10)/10.;
    TString meanouter = Form("%5.1f", meano);
    TString rmsouter  = Form("%5.1f", rmso);


    //Getting conversion factors
    MHCamera *c = (MHCamera*)arr.FindObjectInCanvas("TotalConvPhe", "MHCamera", "Conversion");
    if (!c)
    {
        cout << "WARNING - Could not find MHCamera TotalConv." << endl;
        return 0;
    }

    TArrayI inner(1), outer(1);
    inner[0] = 0;
    outer[0] = 1;

    Int_t s0[] = { 1, 2, 3, 4, 5, 6 };

    Stat_t meanconvi = c->GetMeanSectors(TArrayI(6, s0), inner);
    Stat_t meanconvo = c->GetMeanSectors(TArrayI(6, s0), outer);
    meanconvi = TMath::Nint(meanconvi*1000)/1000.;
    meanconvo = TMath::Nint(meanconvo*1000)/1000.;
    TString meanconvinner=Form("%6.3f", meanconvi);
    TString meanconvouter=Form("%6.3f", meanconvo);


    //Getting sequ# from filename
    TString sequence = fname(TRegexp("calib[0-9]+[.]root$"));
    if (sequence.IsNull())
    {
        cout << "WARNING - Could get sequence# from filename: " << fname << endl;
        return 0;
    }

    Int_t seq = atoi(sequence.Data()+5);


    cout << "Sequence #" << seq << endl;
    cout << "  Unsuitable: (i/o) " << Form("%3d %3d", (int)unsin, (int)unsout) << endl; // Unbrauchbar
    cout << "  Unreliable: (i/o) " << Form("%3d %3d", (int)unrin, (int)unrout) << endl; // Unzuverlaessig
    cout << "  Isolated:   (i/o) " << Form("%3d %3d", (int)isoin, (int)isoout) << endl; // Isolated (unbrauchbar)
    cout << "  Max.Cluster:      " << Form("%3d", (int)clumax)                 << endl; // Max Cluster
    cout << "  Arr Time inner:    " << meaninner << " +- " << rmsinner  << endl;
    cout << "  Arr Time outer:    " << meanouter << " +- " << rmsouter  << endl;
    cout << "  Mean Conv inner:   " << meanconvinner << endl;
    cout << "  Mean Conv outer:   " << meanconvouter << endl;

    TString query;
    if (!ExistStr(serv, "fSequenceFirst", "Calibration", seq))
    {
        query = Form("INSERT Calibration SET"
                     " fSequenceFirst=%d,"
                     " fUnsuitableInner=%d, "
                     " fUnsuitableOuter=%d, "
                     " fUnreliableInner=%d, "
                     " fUnreliableOuter=%d, "
                     " fIsolatedInner=%d, "
                     " fIsolatedOuter=%d, "
                     " fIsolatedMaxCluster=%d, "
                     " fArrTimeMeanInner=%s, "
                     " fArrTimeRmsInner=%s, "
                     " fArrTimeMeanOuter=%s, "
                     " fArrTimeRmsOuter=%s, "
                     " fConvFactorInner=%s, "
                     " fConvFactorOuter=%s ",
                     seq, (int)unsin, (int)unsout, (int)unrin,
                     (int)unrout, (int)isoin, (int)isoout,
                     (int)clumax,
                     meaninner.Data(), rmsinner.Data(),
                     meanouter.Data(), rmsouter.Data(),
                     meanconvinner.Data(), meanconvouter.Data());
    }
    else
    {
        query = Form("UPDATE Calibration SET"
                     " fUnsuitableInner=%d, "
                     " fUnsuitableOuter=%d, "
                     " fUnreliableInner=%d, "
                     " fUnreliableOuter=%d, "
                     " fIsolatedInner=%d, "
                     " fIsolatedOuter=%d, "
                     " fIsolatedMaxCluster=%d, "
                     " fArrTimeMeanInner=%s, "
                     " fArrTimeRmsInner=%s, "
                     " fArrTimeMeanOuter=%s, "
                     " fArrTimeRmsOuter=%s, "
                     " fConvFactorInner=%s, "
                     " fConvFactorOuter=%s "
                     " WHERE fSequenceFirst=%d ",
                     (int)unsin, (int)unsout, (int)unrin,(int)unrout,
                     (int)isoin, (int)isoout, (int)clumax,
                     meaninner.Data(), rmsinner.Data(),
                     meanouter.Data(), rmsouter.Data(),
                     meanconvinner.Data(), meanconvouter.Data(),
                     seq);
    }

    if (dummy)
        return 0;

    TSQLResult *res = serv.Query(query);
    if (!res)
    {
        cout << "ERROR - Query failed: " << query << endl;
        return 0;
    }
    delete res;

    return 1;
}

int fillcalib(TString fname, Bool_t dummy=kTRUE)
{
    TEnv env("sql.rc");

    MSQLServer serv(env);
    if (!serv.IsConnected())
    {
        cout << "ERROR - Connection to database failed." << endl;
        return 0;
    }

    cout << "fillcalib" << endl;
    cout << "---------" << endl;
    cout << endl;
    cout << "Connected to " << serv.GetName() << endl;
    cout << "File: " << fname << endl;
    cout << endl;

    return Process(serv, fname, dummy);
}
