/**
 * @file main.cpp
 * @brief StreamHub entry point.
 *
 * Usage:
 *   StreamHub.ex [-cfg <file.cfg>] [-port <N>] [-maxPoints <N>]
 *
 * If -cfg is not given a minimal in-memory configuration is used with defaults.
 * -port and -maxPoints override values from the config file.
 */

#include "StreamHub.h"
#include "ConfigurationDatabase.h"
#include "StandardParser.h"
#include "BasicFile.h"
#include "AdvancedErrorManagement.h"
#include "ErrorManagement.h"
#include "StreamString.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>

/* Simple stderr logger for MARTe2 REPORT_ERROR_STATIC messages */
static void StderrErrorProcessFunction(const MARTe::ErrorManagement::ErrorInformation &info,
                                       const MARTe::char8 * const errorDescription) {
    const char *level = "Info";
    MARTe::ErrorManagement::ErrorType et = info.header.errorType;
    if (et == MARTe::ErrorManagement::FatalError)   { level = "FatalError"; }
    else if (et == MARTe::ErrorManagement::Warning)       { level = "Warning"; }
    else if (et == MARTe::ErrorManagement::Information)   { level = "Information"; }
    else if (et == MARTe::ErrorManagement::Debug)         { level = "Debug"; }
    const char *fname = info.fileName;
    if (fname == static_cast<const char *>(0)) { fname = "?"; }
    /* strip path — just filename */
    for (const char *p = fname; *p != '\0'; p++) {
        if (*p == '/') { fname = p + 1; }
    }
    fprintf(stderr, "[StreamHub][%s - %s:%u]: %s\n",
            level, fname,
            static_cast<unsigned int>(info.header.lineNumber),
            errorDescription != static_cast<const char *>(0) ? errorDescription : "");
}

using MARTe::ConfigurationDatabase;
using MARTe::StandardParser;
using MARTe::StreamString;
using MARTe::uint32;
using MARTe::BasicFile;

/* Global flag set by SIGINT/SIGTERM handler */
static volatile int gStop = 0;
static StreamHub::StreamHub *gHub = static_cast<StreamHub::StreamHub *>(0);

static void SignalHandler(int /*sig*/) {
    gStop = 1;
    if (gHub != static_cast<StreamHub::StreamHub *>(0)) {
        gHub->Stop();
    }
}

int main(int argc, char **argv) {
    /* Install MARTe2 error handler so REPORT_ERROR_STATIC messages go to stderr */
    MARTe::ErrorManagement::SetErrorProcessFunction(&StderrErrorProcessFunction);

    const char *cfgFile   = static_cast<const char *>(0);
    uint32      portOverride     = 0u;
    uint32      maxPtsOverride   = 0u;

    /* Parse command line */
    for (int i = 1; i < argc; i++) {
        if ((strcmp(argv[i], "-cfg") == 0) && (i + 1 < argc)) {
            cfgFile = argv[++i];
        } else if ((strcmp(argv[i], "-port") == 0) && (i + 1 < argc)) {
            portOverride = static_cast<uint32>(atoi(argv[++i]));
        } else if ((strcmp(argv[i], "-maxPoints") == 0) && (i + 1 < argc)) {
            maxPtsOverride = static_cast<uint32>(atoi(argv[++i]));
        } else if ((strcmp(argv[i], "-h") == 0) ||
                   (strcmp(argv[i], "--help") == 0)) {
            printf("Usage: StreamHub.ex [-cfg file.cfg] [-port N] [-maxPoints N]\n");
            return 0;
        }
    }

    /* Build ConfigurationDatabase */
    ConfigurationDatabase cfg;

    if (cfgFile != static_cast<const char *>(0)) {
        /* Load from file via StandardParser */
        BasicFile f;
        if (!f.Open(cfgFile,
                    BasicFile::ACCESS_MODE_R | BasicFile::FLAG_CREAT)) {
            fprintf(stderr, "StreamHub: cannot open config file '%s'\n", cfgFile);
            return 1;
        }

        StreamString cfgContent;
        StreamString errStream;
        StandardParser parser(f, cfg, &errStream);
        if (!parser.Parse()) {
            fprintf(stderr, "StreamHub: config parse error: %s\n",
                    errStream.Buffer());
            f.Close();
            return 1;
        }
        f.Close();

        /* Navigate into +Hub node if present */
        if (cfg.MoveRelative("Hub")) {
            /* already inside */
        }
    }

    /* Apply command-line overrides */
    if (portOverride > 0u) {
        (void) cfg.Write("WSPort", portOverride);
    }
    if (maxPtsOverride > 0u) {
        (void) cfg.Write("MaxPoints", maxPtsOverride);
    }

    /* Install signal handlers */
    signal(SIGINT,  SignalHandler);
    signal(SIGTERM, SignalHandler);

    /* Allocate on the heap: StreamHub embeds 32 UDPSourceSession objects,
     * each ~4 MB (4 reassembly slots × 1 MiB + recv buffer), totalling
     * ~128 MB — far above the default 8 MB thread stack limit. */
    StreamHub::StreamHub *hub = new StreamHub::StreamHub();
    gHub = hub;

    if (!hub->Initialise(cfg)) {
        fprintf(stderr, "StreamHub: Initialise() failed.\n");
        delete hub;
        return 1;
    }

    (void) hub->Run();

    delete hub;
    printf("StreamHub: stopped.\n");
    return 0;
}
