#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include "vint_common.h"

gw_port_e ports[] = {VINTF_MQTT, VINTF_TCP, MQTT_DTU_RS485, VINTF_NB};

void vint_in_subscribe_all(vint_var_t *var)
{
    ipc_session_t *session = var->session_int;
    char topic[TOPIC_MAX_LEN] = {0};
    int i;

    for (i = 0; i < ARRAY_SIZE(ports); i++)
    {
        snprintf(topic, TOPIC_MAX_LEN, "ipc/+/%s/device/+/data/%s", port_enum2char(ports[i]), TOPIC_SEND_RGLT_SIGNAL_RAW_DATA);
        ipc_session_subscribe(session, topic);
    }

	snprintf(topic, TOPIC_MAX_LEN, "ipc/+/%s/device/+/data/%s", "qSlisTS2f41N70hm", TOPIC_SEND_RGLT_SIGNAL_RAW_DATA);
    ipc_session_subscribe(session, topic);
}
static int ds_flush_timer(vint_var_t *var)
{
    time_t now = time(NULL);

    TIMER_CONFIRM(var->node_status_timer);
    if (now >= var->nodes_status_sync_date + 30)
    {
        static time_t lasttime = 0;
        var->nodes_status_sync_date = now;
        char *node_status = ds_print(var->ds);

        dy_syslog(LOG_INFO, "online_status_changed:%d strlen(node_status):%d, (now-lasttime):%d",
                  var->ds->online_status_changed, strlen(node_status), now - lasttime);
        if (node_status && strlen(node_status) > 20 &&
                (var->ds->online_status_changed || now > lasttime + 3600)) //在线状态变化上报，1小时也会上报
        {
            char topic[TOPIC_MAX_LEN];
            int ret = 0;

            snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/%s", var->sn_str, var->proc_name, TOPIC_EVT_NODESSTATUS);

            ret = ipc_session_publish(var->session_int, topic, node_status, strlen(node_status));
            if (ret == 0)
            {
                lasttime = now;
                var->ds->online_status_changed = false;
            }
            node_sta_backup(var->ds, VINT_NODE_STATUS_BAK_FILE);
        }
        if (node_status)
        {
            write_file_data(NODES_CACHE "/vint_status.json", node_status, strlen(node_status));
            free(node_status);
        }
    }
}

static int period_service_poll(vint_var_t *var)
{
    TIMER_CONFIRM(var->period_poll_timer);
    int ret = 0;
    static int all_started = 0;

    period_msg_t *msg = period_msg_next(var->period);
    if (msg && msg->started && msg->rs)
    {
        ret = vint_send_rglt_data(var, msg->rs);
        if (ret < 0)
        {
            dy_syslog(LOG_ERR, "parse real data structure failed");
        }
    }

    if (all_started == 0)
    {
        all_started = period_services_retrigger(var->session_int, var->period, var->nodes_cfg_table, var->template_table, ports, ARRAY_SIZE(ports));
    }
    return 0;
}

static void vint_loop(vint_var_t *var)
{
    int ret = -1, maxfd;
    fd_set rset;
    struct timeval timeout;

    while (1)
    {
        SELECT_INIT();
        timeout.tv_usec = 0;
        timeout.tv_sec = 20;
        SELECT_ADD_FD(var->node_status_timer);
        SELECT_ADD_FD(var->period_poll_timer);
        ret = select(maxfd + 1, &rset, 0, 0, &timeout);
        if (ret < 0)
        {
            int error = errno;
            printf("errno %d\n", error);
            if (error == EINTR)
            {
                continue;
            }
            else
            {
                break;
            }
        }
        else if (ret > 0)
        {
            if (var->node_status_timer > 0 && FD_ISSET(var->node_status_timer, &rset))
            {
                FD_CLR(var->node_status_timer, &rset);
                ds_flush_timer(var);
            }
            if (var->period_poll_timer > 0 && FD_ISSET(var->period_poll_timer, &rset))
            {
                FD_CLR(var->period_poll_timer, &rset);
                period_service_poll(var);
            }
        }
    }
}

static int vint_init(vint_var_t *var)
{
    int i = 0, j = 0;
    node_cfg_t *p_node = NULL;
    check_make_dir(NODES_CACHE);
    check_make_dir(NODES_CFG);
    get_board_sn(var->sn_str);
    get_process_name(var->proc_name);

    dy_syslog(LOG_INFO, "board SN:%s", var->sn_str);

    if (load_nodes_cfg(&var->nodes_cfg_table, NODES_CFG_PATH) == -1)
    {
        dy_syslog(LOG_ERR, "load nodes cfg fail");
    }
    if (load_templates_cfg(&var->template_table, TEMPLATES_CFG_PATH) == -1)
    {
        dy_syslog(LOG_ERR, "load template cfg fail");
    }
    for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
    {
        p_node = &var->nodes_cfg_table->node[i];
        p_node->template = pp_find_template(var->template_table, p_node->template_id);
    }
    dev_status_init(&var->ds, var->nodes_cfg_table, var->template_table, ports, ARRAY_SIZE(ports));
    node_sta_recovery(var->ds, VINT_NODE_STATUS_BAK_FILE);

    kv_array_init(&var->identifier_backup, 32);
    var->node_status_timer = my_timer_create();
    if (var->node_status_timer > 0)
    {
        my_timer_set(var->node_status_timer, 1, 5000);
    }
    var->period_poll_timer = my_timer_create();
    if (var->period_poll_timer > 0)
    {
        my_timer_set(var->period_poll_timer, 1, 1000);
    }

    vint_internal_client_init(var);
    vint_external_client_init(var, MQTT_VINTERFACE_CONFIG_PATH);
    period_msg_init(&var->period, 512);
    period_services_trigger(var->session_int, var->period, var->nodes_cfg_table, var->template_table, ports, ARRAY_SIZE(ports));
    dy_syslog(LOG_INFO, "init done");

    return 0;
}

int main(int argc, char *argv[])
{
    vint_var_t var = {0};

    memset(&var, 0, sizeof(var));

    vint_init(&var);
    vint_loop(&var);

    return 0;
}
