#ifndef FACT_MAIN
#define FACT_MAIN

#if BOOST_VERSION < 104400
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
#undef BOOST_HAS_RVALUE_REFS
#endif
#endif
#include <boost/thread.hpp>

#include "LocalControl.h"

void MainThread(StateMachineImp *io_service, bool dummy)
{
    // This is necessary so that the StateMachien Thread can signal the
    // Readline to exit
    io_service->Run(dummy);
    Readline::Stop();
}

/*
template<class S>
int RunDim(Configuration &conf)
{
    WindowLog wout;

    ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);

    //log.SetWindow(stdscr);
    if (conf.Has("log"))
        if (!wout.OpenLogFile(conf.Get<string>("log")))
            wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;

    // Start io_service.Run to use the StateMachineImp::Run() loop
    // Start io_service.run to only use the commandHandler command detaching
    AutoScheduler<S> io_service(wout);
    if (!io_service.EvalConfiguration(conf))
        return -1;

    io_service.Run();

    return 0;
}
*/

template<class T, class S>
int Main(const Configuration &conf, bool dummy=false)
{
    static T shell(conf.GetName().c_str(),
                   conf.Has("console") ? conf.Get<int>("console")!=1 : 0);

    WindowLog &win  = shell.GetStreamIn();
    WindowLog &wout = shell.GetStreamOut();

    if (conf.Has("log"))
        if (!wout.OpenLogFile(conf.Get<string>("log")))
            win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;


    S io_service(wout);

    const Time now;
    io_service.Write(now, "/--------------------------- Program ----------------------------");
    io_service.Write(now, "| Program:  "PACKAGE_STRING" ("+conf.GetName()+")");
    io_service.Write(now, "| Compiled: "__DATE__" "__TIME__);
    io_service.Write(now, "| Revision: "REVISION);
    io_service.Write(now, "| Contact:  "PACKAGE_BUGREPORT);
    io_service.Write(now, "| URL:      "PACKAGE_URL);
    io_service.Write(now, "| Start:    "+now.GetAsStr("%c"));
    io_service.Write(now, "\\--------------------------- Options ----------------------------");
    const multimap<string,string> map = conf.GetOptions();
    for (multimap<string,string>::const_iterator it=map.begin(); it!=map.end(); it++)
        io_service.Write(now, ": "+it->first+(it->second.empty()?"":" = ")+it->second);
    io_service.Write(now, "\\----------------------- Evaluating options ---------------------");

    const int rc = io_service.EvalConfiguration(conf);
    io_service.Message("======================== Starting main loop =====================");
    if (rc>=0)
        return rc;

    shell.SetReceiver(io_service);

//    boost::thread t(boost::bind(&AutoScheduler<S>::Run, &io_service));
    boost::thread t(boost::bind(MainThread, &io_service, dummy));

    const vector<string> v1 = conf.Vec<string>("cmd");
    for (vector<string>::const_iterator it=v1.begin(); it!=v1.end(); it++)
        shell.ProcessLine(*it);

    const vector<string> v2 = conf.Vec<string>("exec");
    for (vector<string>::const_iterator it=v2.begin(); it!=v2.end(); it++)
        shell.Execute(*it);

    if (conf.Get<bool>("quit"))
        shell.Stop();

    shell.Run();                 // Run the shell
    io_service.Stop();           // Signal Loop-thread to stop
    // io_service.Close();       // Obsolete, done by the destructor
    // wout << "join: " << t.timed_join(boost::posix_time::milliseconds(0)) << endl;

    // Wait until the StateMachine has finished its thread
    // before returning and destroying the dim objects which might
    // still be in use.
    t.join();

    return 0;
}

#endif
