#include <TSystem.h>

#include "MParList.h"
#include "MTaskList.h"
#include "MEvtLoop.h"
/*'
#include "MLog.h"
 */
#include "MLogManip.h"

#include "MArgs.h"

#include "MArray.h"
#include "MReadMarsFile.h"
#include "MGeomApply.h"
#include "MMcPedestalCopy.h"
#include "MMcPedestalNSBAdd.h"
#include "MCerPhotCalc.h"
#include "MBlindPixelCalc.h"
#include "MSigmabarCalc.h"
#include "MImgCleanStd.h"
#include "MHillasCalc.h"
#include "MHillasSrcCalc.h"
#include "MWriteRootFile.h"

using namespace std;

//////////////////////////////////////////////////////////////////////////////
//
// This is an easy implementation of the Star process
// (as compilable prog)
//
//////////////////////////////////////////////////////////////////////////////

static void StartUpMessage()
{
    gLog << all << endl;

    //                1         2         3         4         5
    //       12345678901234567890123456789012345678901234567890
    gLog << "==================================================" << endl;
    gLog << "                 STAR - MARS V" << MARSVER          << endl;
    gLog << "   MARS - STandard Analysis and Reconstruction"     << endl;
    gLog << "            Compiled on <" << __DATE__ << ">"       << endl;
    gLog << "               Using ROOT v" << ROOTVER             << endl;
    gLog << "==================================================" << endl;
    gLog << endl;
}

static void Usage()
{
    gLog << all << endl;
    gLog << "Sorry the usage is:" << endl;
    gLog << "   star [-a0] [-vn] [-cn] inputfile[.root] outputfile[.root]" << endl << endl;
    gLog << "     input file: Merpped or MC root file." << endl;
    gLog << "     ouput file: Star-file (image parameter file)" << endl;
    gLog << "     -a0: Do not use Ansii codes." << endl;
    gLog << "     -cn: Compression level n=1..9 [default=2]" << endl;
    gLog << "     -vn: Verbosity level n [default=2]" << endl;
    gLog << "     -u1: Update File (instead of Recreate)" << endl;
    gLog << "     -tn: Telescope Serial Number n [default=0]" << endl << endl;
    gLog << " -> Further setup is not possible at the moment, please use" << endl;
    gLog << "    the star.C root macro instead. Using an input card will" << endl;
    gLog << "    be implemented in the future." << endl << endl;
}

int main(const int argc, char **argv)
{
    StartUpMessage();

    //
    // Evaluate arguments
    //
    MArgs arg(argc, argv);

    //
    // Set verbosity to highest level.
    //
    gLog.SetDebugLevel(arg.HasOption("-v") ? arg.GetIntAndRemove("-v") : 2);

    if (arg.HasOption("-a") && arg.GetIntAndRemove("-a")==0)
        gLog.SetNoColors();

    const int  kComprlvl = arg.HasOption("-c") ? arg.GetIntAndRemove("-c") : 1;
    const int  kTelIndex = arg.HasOption("-t") ? arg.GetIntAndRemove("-t") : 0;
    const bool kUpdate   = arg.HasOption("-u") && arg.GetIntAndRemove("-u")==1;

    //
    // check for the right usage of the program
    //
    if (arg.GetNumArguments()!=2)
    {
        Usage();
        return -1;
    }

    //
    // This is to make argv[i] more readable inside the code
    //
    TString kNamein  = arg.GetArgumentStr(0);
    TString kNameout = arg.GetArgumentStr(1);

    if (!kNamein.EndsWith(".root"))
        kNamein += ".root";

    if (!kNameout.EndsWith(".root"))
        kNameout += ".root";

    //
    // Initialize Non-GUI (batch) mode
    //
    gROOT->SetBatch();

    //
    // check whether the given files are OK.
    //
    if (gSystem->AccessPathName(kNamein, kFileExists))
    {
        gLog << err << "Sorry, the input file '" << kNamein << "' doesn't exist." << endl;
        return -1;
    }

    if (!gSystem->AccessPathName(kNameout, kFileExists))
    {
        if (kUpdate)
            gLog << warn << "Warning: File doesn't '" << kNameout << "' exist... recreating." << endl;
    }

    if (kUpdate || gSystem->AccessPathName(kNameout, kFileExists))
        if (!gSystem->AccessPathName(kNameout, kWritePermission))
        {
            gLog << err << "Sorry, you don't have write permission for '" << kNameout << "'." << endl;
            return -1;
        }

    MArray::Class()->IgnoreTObjectStreamer();
    MParContainer::Class()->IgnoreTObjectStreamer();

    //
    // Create a empty Parameter List and an empty Task List
    // The tasklist is identified in the eventloop by its name
    //
    MParList plist;

    MTaskList tlist;
    plist.AddToList(&tlist);

    //
    // Now setup the tasks and tasklist:
    // ---------------------------------
    //
    MReadMarsFile read("Events", kNamein);
    read.DisableAutoScheme();

    MGeomApply        apply;
    MMcPedestalCopy   pcopy;
    MMcPedestalNSBAdd pnsb;
    MCerPhotCalc      ncalc;
    MBlindPixelCalc   blind;
    MSigmabarCalc     sgcal;
    MImgCleanStd      clean;
    MHillasCalc       hcalc;
    MHillasSrcCalc    scalc; // !!Preliminary!! Will be removed later!
    MWriteRootFile    write(kNameout, kUpdate?"UPDATE":"RECREATE", "Star output", kComprlvl);

    tlist.AddToList(&read);
    tlist.AddToList(&apply);
    tlist.AddToList(&pcopy);
    tlist.AddToList(&pnsb);
    tlist.AddToList(&ncalc);
    tlist.AddToList(&blind);
    tlist.AddToList(&sgcal);
    tlist.AddToList(&clean);
    tlist.AddToList(&hcalc);
    tlist.AddToList(&scalc);
    tlist.AddToList(&write);

    //
    // Set the serial number for all tasks in the current tasklist
    //
    tlist.SetSerialNumber(kTelIndex);

    //
    // Setup tasks
    //
    blind.SetUseInterpolation();

    write.AddContainer(write.AddSerialNumber("MMcEvt"),       "Events");
    write.AddContainer(write.AddSerialNumber("MSigmabar"),    "Events");
    write.AddContainer(write.AddSerialNumber("MHillas"),      "Events");
    write.AddContainer(write.AddSerialNumber("MHillasExt"),   "Events");
    write.AddContainer(write.AddSerialNumber("MHillasSrc"),   "Events");
    write.AddContainer(write.AddSerialNumber("MNewImagePar"), "Events");
    write.AddContainer(write.AddSerialNumber("MSrcPosCam"),   "RunHeaders");
    if (!kUpdate)
    {
        write.AddContainer("MRawRunHeader", "RunHeaders");
        write.AddContainer("MMcRunHeader",  "RunHeaders");
    }

    //
    // Create and set up the eventloop
    //
    MEvtLoop evtloop;
    evtloop.SetParList(&plist);

    //
    // Execute your analysis
    //
    if (!evtloop.Eventloop())
    {
        gLog << err << "ERROR: Star eventloop failed!" << endl;
        return -1;
    }

    // tlist.PrintStatistics();

    gLog << all << "Star finished successfull!" << endl;
    return 0;
}
