#include <iostream>

#include <boost/bind.hpp>

#include "Dim.h"
#include "EventImp.h"
#include "WindowLog.h"
#include "Configuration.h"
#include "StateMachineDim.h"
#include "ReadlineColor.h"

using namespace std;

void SetupConfiguration(Configuration &conf)
{
    const string n = conf.GetName()+".log";

    po::options_description config("Program options");
    config.add_options()
        ("dns",       var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
        ("log,l",     var<string>(n), "Write log-file")
        ;

    conf.AddEnv("dns", "DIM_DNS_NODE");

    conf.AddOptions(config);
}

/*
 Extract usage clause(s) [if any] for SYNOPSIS.
 Translators: "Usage" and "or" here are patterns (regular expressions) which
 are used to match the usage synopsis in program output.  An example from cp
 (GNU coreutils) which contains both strings:
  Usage: cp [OPTION]... [-T] SOURCE DEST
    or:  cp [OPTION]... SOURCE... DIRECTORY
    or:  cp [OPTION]... -t DIRECTORY SOURCE...
 */
void PrintUsage()
{
    cout <<
        "The chatserv is a Dim-based chat server.\n"
        "\n"
        "It is a non-interactive program which acts as a relay of messages "
        "sent via a Dim command CHAT/MSG and which are redirected to the "
        "logging service CHAT/MESSAGE.\n"
        "\n"
        "Usage: chatserv [OPTIONS]\n"
        "  or:  chatserv [OPTIONS]\n";
    cout << endl;
}

void PrintHelp()
{
    /* Additional help text which is printed after the configuration
     options goes here */
}

class ChatServer : public StateMachineDim
{
private:
    int HandleMsg(const EventImp &evt)
    {
        Message(evt.GetString());
        return GetCurrentState();
    }
public:
    ChatServer(ostream &lout) : StateMachineDim(lout, "CHAT")
    {
        AddEvent("MSG", "C")
            (boost::bind(&ChatServer::HandleMsg, this, _1))
            ("|msg[string]:message to be distributed");
    }
};

int main(int argc, const char *argv[])
{
    Configuration conf(argv[0]);
    conf.SetPrintUsage(PrintUsage);
    SetupConfiguration(conf);

    po::variables_map vm;
    try
    {
        vm = conf.Parse(argc, argv);
    }
#if BOOST_VERSION > 104000
    catch (po::multiple_occurrences &e)
    {
        cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
        return -1;
    }
#endif
    catch (exception& e)
    {
        cerr << "Program options invalid due to: " << e.what() << endl;
        return -1;
    }

    if (conf.HasVersion() || conf.HasPrint())
        return -1;

    if (conf.HasHelp())
    {
        PrintHelp();
        return -1;
    }

    Dim::Setup(conf.Get<string>("dns"));

    WindowLog log;

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

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

    ChatServer serv(log);
    serv.Run(true);

    return 0;
}

// **************************************************************************
/** @example chatserv.cc

The program is stopped by CTRL-C

*/
// **************************************************************************
