/*
 * Copyright (C) 2022 EXOLIGENT (www.exoligent.com)
 * Author: Maxime Coroyer <maxime.coroyer@exoligent.com>
 *
 * Description:
 * UA pong example (loopback subcriber value to publisher)
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>     // memset()
#include <stdint.h>     // uint8_t, ...
#include <fcntl.h>      // open()
#include <unistd.h>     // read()
#include <libgen.h>     // basename
#include <inttypes.h>   // PRIx64+
#include <signal.h>     // signal
#include <time.h>       // nanosleep, timespec

#include "test.h"

char *app_name = NULL;
int running = 0;
struct tst_session sess;

static void help();
void handle_signal(int sig);
int app_task();
extern void dev_show_all();

int main(int argc, char *argv[])
{
    int ret = 0;
    int value = 0;

#if defined (_WIN32) || defined (_WIN64)
    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
    enable_console_colorization();
#endif

    app_name = basename(argv[0]);

    /* Try to process all command line arguments */
    while ((value = getopt(argc, argv, "hv")) != -1) {
        switch (value) {
            case 'h':
                help();
                return EXIT_SUCCESS;
            case 'v':
                printf("%s %s\n", app_name, APP_VERSION);
                return EXIT_SUCCESS;
            case '?':
            default:
                help();
                return EXIT_FAILURE;
        }
    }

    signal(SIGINT, handle_signal);
    signal(SIGTERM, handle_signal);
    signal(SIGQUIT, handle_signal);

    memset(&sess, 0, sizeof(struct tst_session));

    /* init settings here */
    opc_init(&sess);

    /* opcua starting ... */
    if (opc_pub_start(&sess) < 0)
        goto end;

    /* main loop */
    /* TODO: wait a signal */
    _usleep(2000); //--!!
    _print(app, info,
        "[ok] app is active. press Ctrl + C to exit.\n");

    app_task();
    ret = 0;

end:
    ret |= opc_pub_stop(&sess);
    if (ret)
        _print(opc, err, "[failed] opcua publisher stop\n");
    else
        _print(opc, info, "[ok] opcua publisher stop\n");

    if (!ret)
        _print(app, info, "[ok] app is stopped\n");

    return ret;
}

int app_task()
{
    int err = 0;
    struct timespec rqtp = {0};
    struct timespec rmtp = {0};

    rqtp.tv_sec = 0;
    rqtp.tv_nsec = 500000000; /* 500ms */

    running = 1;
    while (running) {
        err = nanosleep(&rqtp, &rmtp);
    }
    printf("\n");

    return err;
}

/**
 * \brief Callback function for handling signals.
 * \param sig identifier of signal
 */
void handle_signal(int sig)
{
    if ((sig == SIGINT) ||
        (sig == SIGTERM) ||
        (sig == SIGQUIT)) {

        switch (sig) {
            case SIGINT:  _print(app, evt, "SIGINT signal received\n"); break;
            case SIGTERM: _print(app, evt, "SIGTERM signal received\n"); break;
            case SIGQUIT: _print(app, evt, "SIGQUIT signal received\n"); break;
            default: break;
        }
        running = 0;
        /* reset signal handling to default behavior */
        signal(sig, SIG_DFL);
    } else
        _print(app, warn, "signal received but not supported (sig=%d)\n", sig);
}

/**
 * \brief Print help for this application
 */
static void help()
{
    printf("\n");
    printf("Usage: %s [OPTION]...\n\n", app_name);
    printf("UA pong application.\n\n");
    printf("Options:\n");
    printf("    -h   show this help and exit\n");
    printf("    -v   show version and exit\n");
    printf("\n");
    printf("Examples: \n");
    printf("    %s\n", app_name);
    printf("\n");
}