#include "wrenchboard.h"
#include "clog.h"
#include "cfg.h"
#include "exceptions.h"
#include "input.h"
#include "wrenchboard_api.h"
#include "pgsql.h"

#include "wrenchboard_api_main.h"

#include <exception>
#include <iostream>
#include <libpq-fe.h>

#include <gelfcpp/decorator/StaticDecoratorSet.hpp>
#include <gelfcpp/decorator/Timestamp.hpp>
#include <gelfcpp/decorator/Host.hpp>

extern gelfcpp::output::GelfUDPOutput *graylog;
using Decorator = gelfcpp::decorator::StaticDecoratorSet<gelfcpp::decorator::CurrentTimestamp, gelfcpp::decorator::Host>;
extern Decorator decorator;

WrenchBoard::WrenchBoard() {
    
    // Read config
    CfgReadConfig();

    this->logFile = CfgReadLong("logger.file");
    // global_log_level = static_cast<TLogLevel>(CfgReadLong("logger.level"));
    const char *logLevel = CfgReadChar("logger.level");
    global_log_level = FILELog::FromString(logLevel);
    FILELog().SetReportingLevel(global_log_level);

    // Open log
    if (this->logFile == 1) {
        this->pFile = fopen(WRENCHBOARD_LOG, "a");
        Output2FILE::Stream() = pFile; 
    }

    const char *logHost = CfgReadChar("logger.host");
    long logPort = CfgReadLong("logger.port");

    // Instantiate remote logger (GELF)
    graylog = new gelfcpp::output::GelfUDPOutput(logHost, logPort);
    std::string msg = "Instantiate remote logger (GELF)";
    GELF_MESSAGE(*graylog)(decorator)
                (msg.c_str())
                ("pid", getpid())
                ("loglevel", logLevel);
    //*/
    FILE_LOG(logINFO) << "WRENCHBOARD is starting...";

    logfmt(logINFO, "Version from config: %s", CfgReadChar("version"));

    // Open database
    FILE_LOG(logDEBUG) << "Connecting to database...";
    FILE_LOG(logDEBUG) << "host=" << CfgReadChar("database.host") << ", name=" << CfgReadChar("database.name") << ", user=" << CfgReadChar("database.user") << ", pass=***hidden***, port=" << CfgReadLong("database.port");

    this->db = 0;
    try {
        this->db = pgsql_db_connect(
            CfgReadChar("database.host"),
            CfgReadChar("database.name"),
            CfgReadChar("database.user"),
            CfgReadChar("database.pass"),
            CfgReadLong("database.port") );
        FILE_LOG(logDEBUG) << "pgsql_db_connect() done!";
    } catch (const std::exception &e) { 
        FILE_LOG(logDEBUG) << "Exception: " << e.what(); 
    } catch (const std::string &e) { 
        FILE_LOG(logDEBUG) << "Exception: " << e; 
    } catch (const char *e) { 
        FILE_LOG(logDEBUG) << "Exception: " << e;
    } catch (...) {
        FILE_LOG(logDEBUG) << "Unknown Exception!";
    }
    FILE_LOG(logDEBUG) << "Database connection " << (this->db>0?"successful":"failed");
}

long WrenchBoard::wrenchboard_api(CVars in, CVars &out) {
    long retval = PHP_API_BAD_PARAM;
    try {
        retval = wrenchboard_api_main(in, out);
    } catch (bad_parameter) {
        out["status"] = "Incorrect input parameter";
    } catch (...) { 
        out["status"] = "Unhandled exception";
    }
    return retval;
}

const char* WrenchBoard::cfgReadChar(const char *parameter) {
    return CfgReadChar(parameter);
}

long WrenchBoard::cfgReadLong(const char *parameter) {
    return CfgReadLong(parameter);
}

void WrenchBoard::logMessage(const char *message) {
    FILE_LOG(logINFO) << message;

    const char* remote_addr = std::getenv( "REMOTE_ADDR" );
    const char* server_name = std::getenv( "SERVER_NAME" );
    // const char* http_cookie = std::getenv( "HTTP_COOKIE" );
    const char* query_string = std::getenv( "QUERY_STRING" );
    // const char* http_x_ff = std::getenv( "HTTP_X_FORWARDED_FOR" );

    GELF_MESSAGE(*graylog)(decorator)
                ("Environment variables")
                ("pid", getpid())
                ("loglevel", global_log_level)
                ("REMOTE_ADDR", remote_addr)
                ("SERVER_NAME", server_name)
                /* ("HTTP_COOKIE", http_cookie) */
                ("QUERY_STRING", query_string);
                // ("HTTP_X_FORWARDED_FOR", http_x_ff);
}
/*
            SET_ENV( "REMOTE_ADDR" );
            SET_ENV( "SERVER_NAME" );
            SET_ENV( "HTTP_COOKIE" );
            SET_ENV( "QUERY_STRING" );
            SET_ENV( "HTTP_X_FORWARDED_FOR" );
*/

WrenchBoard::~WrenchBoard() {
    FILE_LOG(logINFO) << "WRENCHBOARD is stopping...";
    if (db>0) {
        FILE_LOG(logDEBUG) << "Closing database connection";
        pgsql_close();
    }
    // Do we need it?
    if (this->logFile == 1) {
        if (this->pFile) {
            fclose(this->pFile);
        } // */
    }
    // clean-up GELF
    if (graylog) {
        delete graylog;
    }
}

