#pragma once

#ifndef _WMC_BASEAPPLICATION_H_INCLUDED_
#define _WMC_BASEAPPLICATION_H_INCLUDED_

#include <Poco/Util/Application.h>
#include <Poco/Util/Option.h>
#include <Poco/Util/OptionSet.h>
#include <Poco/Util/HelpFormatter.h>
#include <Poco/Util/AbstractConfiguration.h>
#include <Poco/LoggingFactory.h>
#include <Poco/Formatter.h>
#include <Poco/Instantiator.h>
#include <iostream>
#include <vector>
#include <string>
#include <sstream>


#include "wmconsole/legacy/util/pattern_formatter.h"

using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;
using Poco::Util::AbstractConfiguration;
using Poco::Util::OptionCallback;
using Poco::LoggingFactory;
using Poco::Formatter;
using Poco::Instantiator;

namespace NWebmaster {

static const char *const OP_HELP = "help";
static const char *const OP_CONFIG_FILE = "config-file";

class WMCBaseApplication : public Poco::Util::Application {
public:

    WMCBaseApplication() : fShowHelp(false) {
        LoggingFactory::defaultFactory().registerFormatterClass(
            "WMCPatternFormatter",
            new Instantiator<WMCPatternFormatter, Formatter>);
    }

    ~WMCBaseApplication() override {}

    void print_keys() const {
        std::vector<std::string> keys;
        config().keys(keys);
        for (std::vector<std::string>::const_iterator iter = keys.begin(); iter != keys.end(); ++iter) {
            std::stringstream buf;
            buf << *iter << " = " << config().getString(*iter, "");
            logger().information(buf.str());
        }
    }

protected:

    void initialize(Application &self) override {
        loadConfiguration();
        Application::initialize(self);
    }


    void defineOptions(OptionSet &options) override {
        Application::defineOptions(options);

        options.addOption(
            Option("help", "h", "Display help information on command line arguments\n")
            .required(false)
            .repeatable(false)
            .callback(OptionCallback<WMCBaseApplication>(this, &WMCBaseApplication::handleHelp)));

        options.addOption(
            Option(OP_CONFIG_FILE, "f", "Load configuration data from a file\n")
            .required(false)
            .repeatable(true)
            .argument("file")
            .callback(OptionCallback<WMCBaseApplication>(this, &WMCBaseApplication::handleConfig)));
    }


    void handleHelp(const std::string & /*name*/, const std::string & /*value*/) {
        fShowHelp = true;
        displayHelp();
        stopOptionsProcessing();
    }

    void handleConfig(const std::string & /*name*/, const std::string &value) {
        loadConfiguration(value);
    }

    virtual void displayHelp() {
        HelpFormatter helpFormatter(options());
        helpFormatter.setCommand(commandName());
        helpFormatter.setHeader( helpHeader() );
        helpFormatter.setUsage("OPTIONS");
        helpFormatter.format(std::cout);
    }

    virtual std::string helpHeader() const {
        return "";
    }

    int main(const std::vector<std::string> &args) override {
        int result = Application::EXIT_OK;

        if (!fShowHelp) {
            logger().information("Started");
            result = doMain(args);
            logger().information("Finished");
        }

        return result;
    }

protected:
    virtual int doMain(const std::vector<std::string> &args) = 0;

private:
    bool fShowHelp;
};

} // namespace NWebmaster

#endif // _WMC_BASEAPPLICATION_H_INCLUDED_
