/* ======================================================================== *\
!
! *
! * 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, 06/2007 <mailto:tbretz@astro.uni-wuerzburg.de>
!   Author(s): Daniela Dorner, 11/2005 <mailto:dorner@astro.uni-wuerzburg.de>
!   Author(s): Daniel Hoehne, 06/2007 <mailto:hoehne@astro.uni-wuerzburg.de>
!
!   Copyright: MAGIC Software Development, 2000-2007
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//
// fillcamera.C
// ============
//
// This macro is used to read the camera-output files.
//
// 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 <iomanip>

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

#include <TFile.h>
#include <TTree.h>
#include <TBranch.h>

#include <TH1.h>

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

#include "MSQLServer.h"
#include "MSQLMagic.h"

#include "MMcRunHeader.hxx"
#include "MMcConfigRunHeader.h"
#include "MMcCorsikaRunHeader.h"
#include "MMcFadcHeader.hxx"
#include "MMcEvtBasic.h"
#include "MGeomCamMagic.h"
#include "MRawRunHeader.h"

#include <math.h>
#include <MBinning.h>

using namespace std;

int Process(MSQLMagic &serv, TString fname, Bool_t dummy)
{
    TFile file(fname, "READ");
    if (!file.IsOpen())
    {
        cout << "ERROR - Could not find file " << fname << endl;
        return 2;
    }

    //
    // Get tree RunHeaders from file
    //
    TTree *tree = dynamic_cast<TTree*>(file.Get("RunHeaders"));
    if (!tree)
    {
        cout << "ERROR - Tree RunHeaders not found in file " << fname << endl;
        return 2;
    }

    //
    // Get branch MMcCorsikaRunHeader from tree RunHeaders
    //
    TBranch *b1 = tree->GetBranch("MMcCorsikaRunHeader.");
    if (!b1)
    {
        cout << "ERROR - Branch MMcCorsikaRunHeader. not found in file " << fname << endl;
        return 2;
    }

    MMcCorsikaRunHeader *runheader1 = 0;
    b1->SetAddress(&runheader1);

    //
    // Get branch MMcConfigRunHeader from tree RunHeaders
    //
    TBranch *b2 = tree->GetBranch("MMcConfigRunHeader.");
    if (!b2)
    {
        cout << "ERROR - Branch MMcConfigRunHeader. not found in file " << fname << endl;
        return 2;
    }

    MMcConfigRunHeader *runheader2 = 0;
    b2->SetAddress(&runheader2);

    //
    // Get branch MMcRunHeader from tree RunHeaders
    //
    TBranch *b3 = tree->GetBranch("MMcRunHeader.");
    if (!b3)
    {
        cout << "ERROR - Branch MMcRunHeader. not found in file " << fname << endl;
        return 2;
    }

    MMcRunHeader *runheader3 = 0;
    b3->SetAddress(&runheader3);

    //
    // Get branch MMcFadcRunHeader from tree RunHeaders
    //
    TBranch *b4 = tree->GetBranch("MMcFadcHeader.");
    if (!b4)
    {
        cout << "ERROR - Branch MMcFadcHeader. not found in file " << fname << endl;
        return 2;
    }

    MMcFadcHeader *fadcheader = 0;
    b4->SetAddress(&fadcheader);

    //
    // Get branch MRawRunHearder from tree RunHeaders
    //
    TBranch *b5 = tree->GetBranch("MRawRunHeader.");
    if (!b5)
    {
        cout << "ERROR - Branch MRawRunHeader. not found in file " << fname << endl;
        return 2;
    }

    MRawRunHeader *rawheader = 0;
    b5->SetAddress(&rawheader);

    tree->GetEvent(0);

    //
    // Get tree Events from file
    //
    TTree *tree2 = dynamic_cast<TTree*>(file.Get("Events"));
    if (!tree2)
    {
        cout << "ERROR - Tree Events not found in file " << fname << endl;
        return 2;
    }

    //
    // Get branch MMcEvtBasic from tree Events
    //
    TBranch *b6 = tree2->GetBranch("MMcEvtBasic.");
    if (!b6)
    {
        cout << "ERROR - Branch MMcEvtBasic. not found in file " << fname << endl;
        return 2;
    }

    MMcEvtBasic *evtbasic = 0;
    b6->SetAddress(&evtbasic);

    tree2->GetEvent(0);

    Double_t misptx       = runheader2->GetMissPointingX();
    Double_t mispty       = runheader2->GetMissPointingY();
    Double_t pointspreadx = runheader2->GetPointSpreadX();
    Double_t tmin         = runheader3->GetShowerThetaMin();
    Double_t tmax         = runheader3->GetShowerThetaMax();
    UInt_t   reflvers     = runheader3->GetReflVersion();
    UInt_t   camvers      = runheader3->GetCamVersion();
    UInt_t   numsimshow   = runheader3->GetNumSimulatedShowers();
    UInt_t   numevents    = tree2->GetEntries();

    TString elow      = Form("%5.1f", runheader1->GetELowLim());
    TString eupp      = Form("%5.1f", runheader1->GetEUppLim());
    TString slope     = Form("%5.1f", runheader1->GetSlopeSpec());
    TString wobble    = Form("%5.0f", runheader1->GetWobbleMode());
    TString corsika1  = Form("%5.0f", runheader1->GetCorsikaVersion());
    TString psf       = Form("%5.1f", runheader2->GetPointSpread());
    TString psfx      = Form("%5.2f", pointspreadx);
    TString psfy      = Form("%5.2f", runheader2->GetPointSpreadY());
    TString psfadd    = Form("%5.2f", TMath::Hypot(runheader2->GetPointSpreadX(), runheader2->GetPointSpread()));
    TString mirrfrac  = Form("%5.2f", runheader2->GetMirrorFraction());
    TString misx      = Form("%5.2f", misptx);
    TString misy      = Form("%5.2f", mispty);
//    TString reflector = Form("%5.0f", runheader3->GetReflVersion());
    TString reflector = Form("%5.0i", reflvers);
    TString camera    = Form("%5.0i", camvers);
//    TString camera    = Form("%5.0f", runheader3->GetCamVersion());
    TString imax      = Form("%5.1f", runheader3->GetImpactMax());
    TString numphe    = Form("%5.1f", runheader3->GetNumPheFromDNSB());
    TString pmin      = Form("%5.1f", runheader3->GetShowerPhiMin());
    TString pmax      = Form("%5.1f", runheader3->GetShowerPhiMax());
    TString numss     = Form("%7.0i", numsimshow);
    TString thetamin  = Form("%5.1f", tmin);
    TString thetamax  = Form("%5.1f", tmax);
    TString ped       = Form("%5.1f", fadcheader->GetPedestal(1));
    TString low2high  = Form("%5.1f", fadcheader->GetLow2HighGain());
    TString amplfadc  = Form("%5.1f", fadcheader->GetAmplitud());
    TString amplfadco = Form("%5.1f", fadcheader->GetAmplitudOuter());
    TString enoise    = Form("%5.1f", fadcheader->GetElecNoise(1));
    TString dnoise    = Form("%5.1f", fadcheader->GetDigitalNoise(1));

    TH1I h("myhist", "", 1, -0.5, 0.5);
    tree2->Draw("MRawEvtData.GetNumPixels()>>myhist", "", "goff");
    h.SetDirectory(0);

    TString numtrig   = Form("%7.0i", TMath::Nint(h.GetBinContent(2)));
    TString numevt    = Form("%7.0i", numevents);
    TString partid    = Form("%5.0f", evtbasic->GetPartId());
    TString partname  = evtbasic->GetParticleName();

    // Bestimmung von fakewobble aus file
    // Kombination aus Wobble(0,1) und MissPoint
    TString wobblemod="Wobble";

    // Fake Wobble: als ObservationModeKEY 4 einfügen?
    if (wobblemod != 1)
        wobblemod = misptx == 0 && mispty == 0 ? "On" : "Fake Wobble";

    Float_t pointsfx=TMath::Floor(pointspreadx*10);
    pointsfx=TMath::Nint(pointsfx);
    TString pointsfuncx=Form("%5.1f",pointsfx);

    Float_t zBin=TMath::Nint((1-((TMath::Cos(tmin*TMath::Pi()/180)+TMath::Cos(tmax*TMath::Pi()/180))/2))*100);
    zBin=TMath::Nint(zBin);

    // folgende Werte werden aus dem Pfadnamen gewonnen
    // RunNumber
    TRegexp reg2("_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_");
    TString Run = fname(reg2);
    Int_t RunNum = atoi(Run.Data()+1);
    if (RunNum < 1 || RunNum > 99999)
    {
        cout << "ERROR - RunNumber wrong value" << endl;
        return 2;
    }

    // PointSpreadFunction
    TRegexp reg4("/[12][0-9]/");
    TString pointsf = fname(reg4);
    Int_t Point = atoi(pointsf.Data()+1);
    if (Point < 0 || Point > 99)
    {
        cout << "ERROR - PointSpreadFunction wrong value" << endl;
        return 2;
    }

    // zbin
    TRegexp reg1("/19[0-9][0-9]/");
    TString zbin = fname(reg1);
    Int_t ZBin  = atoi(zbin.Data()+3);
    if (ZBin < 0 || ZBin > 99)
    {
        cout << "ERROR - zbin wrong value" << endl;
        return 2;
    }

    // WobbleMode
    TRegexp reg3("/0[0-9]/");	/*extrahiert '/0X'   mit X= 1-8 */
    TString wm = fname(reg3);	/* weist WM den extrahierten Wert zu */
    Int_t wob = atoi(wm.Data()+1); /* schneidet fuehrenden '/' ab */


    // Umrechnung von WobbleModus Bezeichnung in 'wobble', 'nowobble', 'fakewobble'
    TString wobmode;	// dieser Wert wird in 'MCDB' Tabelle 'WobbleMode' eingetragen
    switch (wob)
    {
    case 1:
    case 3:
        wobmode = "Wobble";
        break;

    case 2:
    case 4:
    case 7:
    case 8:
        wobmode = "On";
        break;

    case 5:
    case 6:
        wobmode = "Fake Wobble";
        break;

    default:
        cout << "ERROR - ObservationMode wrong value" << endl;
        return 2;
    }


    cout << endl;
    cout << endl;

    cout << "--- From File ---" << endl;

    cout << endl;
    cout << "Energy Range    " << elow << " < E < " << eupp      << endl;
    cout << "SpectralIndex   " << slope     << endl;
    cout << "ObservationMode " << wobblemod << endl;
    cout << "CorsikaVer      " << corsika1  << endl;
    cout << "ReflVer         " << reflector << endl;
    cout << "CamVer          " << camera    << endl;
    cout << "ParticleId      " << partid    << endl;
    cout << "ParticleName    "  << partname  << endl;
    cout << "PointSpread     " << psf       << endl;
    cout << "PointSpreadXY   " << psfx      << " /" << psfy << endl;
    cout << "AdditionPSF     " << psfadd << endl;
    cout << "MispointingXY   " << misx << " /" << misy <<endl;
    cout << "NumSimShowers   " << numss     << endl;
    cout << "ImpactMax       " << imax      << endl;
    cout << "NumEvents       " << numevt    << endl;
    cout << "NumTriggers     " << numtrig   << endl;
    cout << "NumPheFromDNSB  " << numphe    << endl;
    cout << "Pedestal        " << ped       << endl;
    cout << "Low2HighGain    " << low2high  << endl;
    cout << "AmplitudeFADC   " << amplfadc  << endl;
    cout << "AmplFADCOuter   " << amplfadco << endl;
    cout << "ElecNoise       " << enoise    << endl;
    cout << "DigiNoise       " << dnoise    << endl;
    cout << "PhiMin          " << pmin      << endl;
    cout << "PhiMax          " << pmax      << endl;
    cout << "ThetaMin        " << thetamin  << endl;
    cout << "ThetaMax        " << thetamax  << endl;
    cout << "Zenith range    " << tmin << " to " << tmax << endl;
    cout << "MirrorFraction  " << mirrfrac << endl;
    cout << endl;

    cout << endl;
    cout << "--- key's from mcdb tables ---" << endl;
    cout << endl;

    Int_t corsikakey = serv.QueryKeyOfName("CorsikaVersion", corsika1.Data());
    Int_t reflectorkey = serv.QueryKeyOfName("ReflectorVersion", reflector.Data());
    Int_t camerakey = serv.QueryKeyOfName("CameraVersion", camera.Data());
    Int_t observationkey = serv.QueryKeyOfName("ObservationMode", wobblemod.Data());
    Int_t particlekey = serv.QueryKeyOfName("MCParticle", partname.Data());

    cout << "corsikakey: " << corsikakey << endl;
    cout << "reflectorkey: " << reflectorkey << endl;
    cout << "camerakey: " << camerakey << endl;
    cout << "observationkey: " << observationkey << endl;
    cout << "particlekey: " << particlekey << endl;

    cout << endl;
    cout << endl;
    cout << "--- From File ---" << endl;
    cout << endl;
    cout << "WobbleMode      " << wobblemod << endl;
    cout << "PSF             " << pointsfuncx << endl;
    cout << "zBin            " << zBin << endl;
    cout << endl;
    cout << "--- From FileName ---" << endl;
    cout << endl;
    cout << "WobbleMode      " << wobmode   << endl;
    cout << "RunNum          " << RunNum    << endl;
    cout << "PSF             " << Point     << endl;
    cout << "ZBin            " << ZBin      << endl;
    cout << "WobbleMode(dir) " << wob       << endl;
    cout << endl;


    if (wobblemod!=wobmode)
    {
        cout << "Error, WobbleMode in file and filename are not the same" << endl;
        return 2;
    }
    if (pointsfx!=Point)
    {
        cout << "Error, PSF in file and filename are not the same" << endl;
        return 2;
    }
    if (zBin!=ZBin)
    {
        cout << "Error, ZBin in file and filename are not the same" << endl;
        return 2;
    }

    TString vars =
        Form("fELowLim=%s, fEUppLim=%s, fSlopeSpec=%s, "
             "fImpactMax=%s, fNumSimulatedShowers=%d, fNumEvents=%d, "
             "fNumPheFromDNSB=%s, fZBin=%d, fThetaMin=%s, "
             "fThetaMax=%s, fPointSpread=%s, fPointSpreadX=%s, "
             "fPointSpreadY=%s, fPedesMean=%s, fLow2HighGain=%s, ",
             elow.Data(), eupp.Data(), slope.Data(), imax.Data(),
             numsimshow, numevents, numphe.Data(),
             zBin, thetamin.Data(), thetamax.Data(), psf.Data(),
             psfx.Data(), psfy.Data(), ped.Data(), low2high.Data());
    vars +=
        Form("fAmplFadc=%s, fAmplFadcOuter=%s, fElectricNoise=%s, "
             "fDigitalNoise=%s, fRunNumber=%d, fMisspointingX=%s, "
             "fMissPointingY=%s, fCorsikaVersionKEY =%d, "
             "fReflectorVersionKEY=%d, fCameraVersionKEY=%d, "
             "fObservationModeKEY=%d, fMCParticleKEY=%d, "
             "fSequenceFirst=0, fNumTriggers=%s ",
             amplfadc.Data(), amplfadco.Data(), enoise.Data(),
             dnoise.Data(), RunNum, misx.Data(), misy.Data(), corsikakey,
             reflectorkey, camerakey, observationkey, particlekey, numtrig.Data());

    // Comming soon (-1: dummy, 0: failed, 1: succeeded)
    // return serv.InsertUpdate("MCRunData", "fRunNumber", RunData()+1, vars);

    if (!serv.ExistStr("fRunNumber", "MCRunData", Run.Data()+1))
        if (!serv.Insert("MCRunData", vars)==kFALSE)
            return 2;
    else
        if (!serv.Update("MCRunData", vars, Form("fRunNumber=%d", Run))==kFALSE)
            return 2;

    return 1;
}

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

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

    serv.SetIsDummy(dummy);

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

    return Process(serv, fname, dummy);
}
