/*
 * Copyright (C) 2022 EXOLIGENT (www.exoligent.com)
 * Author: Maxime Coroyer <maxime.coroyer@exoligent.com>
 */

#include <json-c/json.h>
#include <stdlib.h>     // strtol()
#include <string.h>     // strcpy(), strcmp()

#include "gw.h"

int gw_cfg_parse(const char *json_path, struct gateway *gw)
{
    struct json_object *root, *mbus, *fip;
    FILE *fp = fopen(json_path, "r");
    char buffer[8192];

    fread(buffer, 8192, 1, fp);
    fclose(fp);

    root = json_tokener_parse(buffer);
    json_object_object_get_ex(root, "modbus", &mbus);
    json_object_object_get_ex(root, "fip", &fip);

    /* modbus settings */
    {
        struct json_object *mode, *ip, *port;
        json_object_object_get_ex(mbus, "mode", &mode);
        json_object_object_get_ex(mbus, "ip", &ip);
        json_object_object_get_ex(mbus, "port", &port);

        //printf("mode          : %s\n", json_object_get_string(mode));
        //printf("ip            : %s\n", json_object_get_string(ip));
        //printf("port          : %d\n", json_object_get_int(port));

        if (sizeof(gw->mbus.ip_str) > strlen(json_object_get_string(ip)))
            strcpy(gw->mbus.ip_str, json_object_get_string(ip));

        gw->mbus.port = json_object_get_int(port);
    }

    /* fip settings */
    {
        struct json_object *addr, *seg, *frm_type, *bitrate;
        struct json_object *tr_us, *ts_us, *vars, *var;
        int i, vars_cnt;
        json_object_object_get_ex(fip, "address", &addr);
        json_object_object_get_ex(fip, "segment", &seg);
        json_object_object_get_ex(fip, "frame_type", &frm_type);
        json_object_object_get_ex(fip, "bitrate", &bitrate);
        json_object_object_get_ex(fip, "turn_around_us", &tr_us);
        json_object_object_get_ex(fip, "silence_us", &ts_us);
        json_object_object_get_ex(fip, "vars", &vars);
        vars_cnt = json_object_array_length(vars);

        //printf("address       : %d\n", json_object_get_int(addr));
        //printf("segment       : %d\n", json_object_get_int(seg));
        //printf("frame_type    : %s\n", json_object_get_string(frm_type));
        //printf("bitrate       : %s\n", json_object_get_string(bitrate));
        //printf("turn_around_us: %d\n", json_object_get_int(tr_us));
        //printf("silence_us    : %d\n", json_object_get_int(ts_us));
        //printf("vars_cnt      : %d\n", vars_cnt);

        gw->fip.addr = (uint8_t) json_object_get_int(addr);
        gw->fip.seg = (uint8_t) json_object_get_int(seg);

        if (!strcmp("worldfip", json_object_get_string(frm_type)))
            gw->fip.frm_type = PWRFIP_FRM_WORLDFIP;
        else if (!strcmp("fip", json_object_get_string(frm_type)))
            gw->fip.frm_type = PWRFIP_FRM_FIP;
        else
            gw->fip.frm_type = _PWRFIP_FRM_TYPE_UNKNOWN;

        if (!strcmp("31.25kbps", json_object_get_string(bitrate)))
            gw->fip.bitrate = PWRFIP_BITRATE_31K25;
        else if (!strcmp("1mbps", json_object_get_string(bitrate)))
            gw->fip.bitrate = PWRFIP_BITRATE_1M;
        else if (!strcmp("2.5mbps", json_object_get_string(bitrate)))
            gw->fip.bitrate = PWRFIP_BITRATE_2M5;
        else if (!strcmp("5mbps", json_object_get_string(bitrate)))
            gw->fip.bitrate = PWRFIP_BITRATE_5M;
        else if (!strcmp("12.5mbps", json_object_get_string(bitrate)))
            gw->fip.bitrate = PWRFIP_BITRATE_12M5;
        else if (!strcmp("25mbps", json_object_get_string(bitrate)))
            gw->fip.bitrate = PWRFIP_BITRATE_25M;
        else
            gw->fip.bitrate = _PWRFIP_BITRATE_UNKNOWN;

        gw->fip.tr_ustime = (uint32_t) json_object_get_int(tr_us);
        if (!gw->fip.tr_ustime && gw->fip.bitrate) {
            int idx = gw->fip.bitrate - 1;
            gw->fip.tr_ustime = tr_ustime[idx];

        }
        gw->fip.ts_ustime = (uint32_t) json_object_get_int(ts_us);
        if (!gw->fip.ts_ustime && gw->fip.bitrate) {
            int idx = gw->fip.bitrate - 1;
            gw->fip.ts_ustime = ts_ustime[idx];
        }

        for (i = 0; i < vars_cnt; i++) {
            struct json_object *type, *id, *bsz, *evt, *refresh, *refresh_us;
            struct json_object *prompt, *prompt_us;

            var = json_object_array_get_idx(vars, i);
            json_object_object_get_ex(var, "type", &type);
            json_object_object_get_ex(var, "id", &id);
            json_object_object_get_ex(var, "payload_bsz", &bsz);
            json_object_object_get_ex(var, "refreshment", &refresh);
            json_object_object_get_ex(var, "refresh_us", &refresh_us);
            json_object_object_get_ex(var, "promptness", &prompt);
            json_object_object_get_ex(var, "prompt_us", &prompt_us);
            json_object_object_get_ex(var, "event", &evt);

            //printf("[%03d]\n", i + 1);
            //printf("  type        : %s\n", json_object_get_string(type));
            //printf("  id          : 0x%04x\n",
            //    (uint16_t) strtol(json_object_get_string(id), NULL, 0));
            //printf("  payload_bsz : %d\n", json_object_get_int(bsz));
            //printf("  refreshment : %s\n", json_object_get_string(refresh));
            //printf("  refresh_us  : %d\n", json_object_get_int(refresh_us));
            //printf("  promptness  : %s\n", json_object_get_string(prompt));
            //printf("  prompt_us   : %d\n", json_object_get_int(prompt_us));
            //printf("  event       : %s\n", json_object_get_string(evt));

            if (i >= FIP_VAR_COUNT_MAX)
                continue;

            if (!strcmp("prod", json_object_get_string(type)))
                gw->fip.cfg_varlist[i].type = PWRFIP_VAR_TYPE_PROD;
            else if (!strcmp("cons", json_object_get_string(type)))
                gw->fip.cfg_varlist[i].type = PWRFIP_VAR_TYPE_CONS;
            else
                gw->fip.cfg_varlist[i].type = PWRFIP_VAR_TYPE_SYNC;

            gw->fip.cfg_varlist[i].id = \
                (uint16_t) strtol(json_object_get_string(id), NULL, 0);

            switch (gw->fip.cfg_varlist[i].type)
            {
            case PWRFIP_VAR_TYPE_PROD:
                gw->fip.cfg_varlist[i].prod.payload_bsz = json_object_get_int(bsz);
                /* refreshment ? */
                if (!strcmp("yes", json_object_get_string(refresh))) {
                    gw->fip.cfg_varlist[i].prod.flags |= PWRFIP_VAR_FLAGS_REFRESH;
                    gw->fip.cfg_varlist[i].prod.refreshment_ustime = \
                        json_object_get_int(refresh_us);
                }
                /* is an event attached ? */ 
                if (!strcmp("yes", json_object_get_string(evt))) {
                    gw->fip.cfg_varlist[i].prod.evt_type = \
                        PWRFIP_EVT_TYPE_PERMANENT_ID;
                    gw->fip.cfg_varlist[i].pwrfip_var_handler = \
                        fip_id_sync_handler;
                }
            break;
            case PWRFIP_VAR_TYPE_CONS:
                gw->fip.cfg_varlist[i].cons.payload_bsz = json_object_get_int(bsz);
                gw->fip.cfg_varlist[i].cons.flags |= PWRFIP_VAR_FLAGS_CHK_PDU_LEN;
                /* refreshment ? */
                if (!strcmp("yes", json_object_get_string(refresh))) {
                    gw->fip.cfg_varlist[i].cons.flags |= PWRFIP_VAR_FLAGS_REFRESH;
                }
                /* promptness ? */
                if (!strcmp("yes", json_object_get_string(prompt))) {
                    gw->fip.cfg_varlist[i].cons.flags |= PWRFIP_VAR_FLAGS_PROMPT;
                    gw->fip.cfg_varlist[i].cons.promptness_ustime = \
                        json_object_get_int(prompt_us);
                }
                /* is an event attached ? */
                if (!strcmp("yes", json_object_get_string(evt))) {
                    gw->fip.cfg_varlist[i].cons.evt_type = \
                        PWRFIP_EVT_TYPE_PERMANENT_ID;
                    gw->fip.cfg_varlist[i].pwrfip_var_handler = \
                        fip_id_sync_handler;
                }
            break;
            default:
                gw->fip.cfg_varlist[i].pwrfip_var_handler = \
                    fip_id_sync_handler;
            break;
            }
            gw->fip.cfg_varcnt++;
        }
    }

    /* release root object */
    json_object_put(root);
    return 0;
}