#include <TROOT.h>
#include <TApplication.h>

#include <TThread.h>

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

#include "MLogManip.h"

#include "MRawSocketRead.h"
#include "MGeomApply.h"
#include "MCerPhotAnal2.h"
#include "MFillH.h"
#include "MFRealTimePeriod.h"
#include "MOnlineDump2.h"
#include "MHTriggerLvl0.h"

#include "MStatusDisplay.h"

#include "MImgCleanStd.h"
#include "MHillasCalc.h"
#include "MHillasSrcCalc.h"

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

    //                1         2         3         4         5
    //       12345678901234567890123456789012345678901234567890
    gLog << "==================================================" << endl;
    gLog << "                    MONA V" << MARSVER << "                      " << endl;
    gLog << "              Magic Online Analysis               " << endl;
    gLog << "            Compiled on <" << __DATE__ << ">"       << endl;
    gLog << "               Using ROOT v" << ROOTVER             << endl;
    gLog << "==================================================" << endl;
    gLog << endl;
}

Bool_t Loop(MStatusDisplay *display)
{
    //
    // create the tasks which should be executed and add them to the list
    // in the case you don't need parameter containers, all of them can
    // be created by MRawFileRead::PreProcess
    //
    MRawSocketRead reader;

    //
    // create a (empty) list of parameters which can be used by the tasks
    // and an (empty) list of tasks which should be executed
    //
    MParList plist;

    MTaskList tasks;
    plist.AddToList(&tasks);
    tasks.AddToList(&reader);

    //MParList &plist = *(MParList*)ptr;
    //MTaskList &tasks = *(MTaskList*)plist.FindObject("MTaskList");

    MGeomApply geomapl;
    MCerPhotAnal2 ncalc;
    tasks.AddToList(&geomapl);
    tasks.AddToList(&ncalc);

    MFillH fill1("MHCamEvent", "MCerPhotEvt");
    MFillH fill2("MHEvent",    "MCerPhotEvt");

    MHTriggerLvl0 trigmap(128, "Above 128");
    MFillH fill3(&trigmap, "MRawEvtData");

    MFRealTimePeriod filter;
    fill2.SetFilter(&filter);

    fill1.SetName("MFillCamEvent");
    fill2.SetName("MFillEvent");
    fill3.SetName("MFillTriggerLvl0");

    tasks.AddToList(&fill2);
    tasks.AddToList(&filter);
    tasks.AddToList(&fill1);
    tasks.AddToList(&fill3);

    MOnlineDump2 dump;
    dump.SetFilter(&filter);
    tasks.AddToList(&dump);

    MImgCleanStd      clean;
    MHillasCalc       hcalc;
    MHillasSrcCalc    scalc; // !!Preliminary!! Will be removed later!
    MFillH hfill3("MHHillas", "MHillas");
    MFillH hfill6("MHHillasSrc","MHillasSrc");
    tasks.AddToList(&clean);
    tasks.AddToList(&hcalc);
    tasks.AddToList(&scalc);
    tasks.AddToList(&hfill3);
    tasks.AddToList(&hfill6);

    MEvtLoop magic;
    //plist.AddToList(&magic);
    magic.SetParList(&plist);

    magic.SetDisplay(display);

    if (!magic.Eventloop())
    {
        gLog << err << "Mona Eventloop error..." << endl;
        return kFALSE;
    }

    tasks.PrintStatistics();
    return kTRUE;
}

void *thread(void *ptr)
{
    // TThread::SetCancelAsynchronous();
    // TThread::SetCancelOn();
    MStatusDisplay *display=(MStatusDisplay*)ptr;
//    display->Lock();

    //
    // If a loop is stopped reinitialize a new loop until the
    // user requested to exit the program.
    //
    while (display->CheckStatus()!=MStatusDisplay::kFileExit)
        Loop(display);

    gLog << dbg << "Exit System Loop... " << flush;
    gSystem->ExitLoop();
    gLog << "done." << endl;

    return 0;
}

int main(int argc, char **argv)
{
    TROOT simple("mona", "Magic ONline Analysis");
    TApplication app("MonaApp", &argc, argv);

    StartUpMessage();

    //
    // Starting MStatusDisplay in the thread results in hangs
    // if the thread is terminated (by return)
    //
    MStatusDisplay d;
    d.Resize(740, 600);

    gLog << dbg << "Starting Thread..." << endl;
    TThread t(thread, &d);
    t.Run();

    gLog << dbg << "Starting System loop..." << endl;
    app.Run(kTRUE);
    gLog << dbg << "System loop stopped." << endl;

    return 0;
}
