#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "dy_common.h"
#include "period_service.h"
#include "dy_pp.h"
#include "dy_ipc.h"

period_msg_t *period_msg_next(period_service_t *period_service)
{
    if (period_service->size == 0)
    {
        return NULL;
    }
    long long now = get_time_stamp_ms();
    int count = 0;
    while (1)
    {
        count++;
        if (count > period_service->size)
            break;

        period_service->index++;
        if (period_service->index >= period_service->size)
            period_service->index = 0;

        period_msg_t *arg = &period_service->arg[period_service->index];
        if (strlen(arg->key) == 0 || arg->started == 0 || arg->rs == NULL)
            continue;

        if (arg->last_poll == 0 || now >= arg->last_poll + arg->interval)
        {
            arg->last_poll = now;
            return arg;
        }
    }
    return NULL;
}

void period_msg_init(period_service_t **period_service, int size)
{
    *period_service = malloc(sizeof(period_service_t) + size * sizeof(period_msg_t));
    memset(*period_service, 0, sizeof(period_service_t) + size * sizeof(period_msg_t));

    (*period_service)->max_size = size;
}

int period_msg_add(period_service_t *period_service, period_msg_t *new)
{
    int i = 0;
    int index = -1;
    int first_index = -1;

    if (period_service && period_service->max_size <= 0)
    {
        dy_syslog(LOG_WARNING, "period service have not initialized");
        return -1;
    }

    if (new == NULL || strlen(new->key) == 0)
    {
        dy_syslog(LOG_WARNING, "wrong new period msg");
        return -1;
    }

    for (i = 0; i < period_service->max_size; i++)
    {
        period_msg_t *msg = &period_service->arg[i];
        if (strlen(msg->key) == 0 && first_index == -1)
        {
            first_index = i;
        }
        if (strcmp(new->key, msg->key) == 0)
        {
            // find existed
            index = i;
            break;
        }
    }

    if (index == -1)
    {
        // if not exist, choose the first empty
        index = first_index;
        period_service->size++;
        strcpy(period_service->arg[index].key, new->key);
    }

    if (index == -1)
    {
        // not exist and full
        dy_syslog(LOG_WARNING, "Period service full");
        return -1;
    }

    // insert new msg into index
    // free old memory
    if (period_service->arg[index].rs)
    {
        free(period_service->arg[index].rs->data);
        free(period_service->arg[index].rs);
    }

    if (new->rs)
        dy_syslog_hex(LOG_DEBUG, new->rs->data, new->rs->len, "period data");
    // update period_service
    period_service->arg[index].interval = new->interval;
    period_service->arg[index].last_poll = new->last_poll;
    period_service->arg[index].started = new->started;
    period_service->arg[index].rs = new->rs;

    return 0;
}

int period_msg_started(period_service_t *period_service, char *key)
{
    int i = 0;

    for (i = 0; i < period_service->max_size; i++)
    {
        period_msg_t *msg = &period_service->arg[i];
        if (strcmp(msg->key, key) == 0)
        {
            return msg->started;
        }
    }

    return 0;
}

int period_services_retrigger(ipc_session_t *session, period_service_t *period, nodes_cfg_table_t *nodes_cfg_table, template_table_t *template_table, gw_port_e *ports, int cnt)
{
    int i, j, k, l;
    int all_triggered = 1;

    GET_SN_PROC

    for (i = 0; i < template_table->template_cnt; i++)
    {
        for (j = 0; j < template_table->template[i].service_tab->serviceCnt; j++)
        {
            if (template_table->template[i].service_tab->service[j].server_period && !template_table->template[i].service_tab->service[j].direction)
            {
                for (k = 0; k < nodes_cfg_table->node_cnt; k++)
                {
                    node_cfg_t *node = &nodes_cfg_table->node[k];
                    if (strlen(node->app_key) != 0) continue;
                    for (l = 0; l < cnt; l++)
                    {
                        if (node->port == ports[l])
                        {
                            if (strcmp(node->template_id, template_table->template[i].template_id) == 0)
                            {
                                if (period != NULL)
                                {
                                    char key[128] = {0};
                                    int triggered = 0;

                                    snprintf(key, 128, "%s_%s", node->sn, template_table->template[i].service_tab->service[j].identifier);
                                    triggered = period_msg_started(period, key);
                                    if (triggered == 0)
                                    {
                                        char *data = service_rs_data(&template_table->template[i].service_tab->service[j], node->sn);
                                        char topic[TOPIC_MAX_LEN] = {0};
                                        snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", sn, port_enum2char(node->port), node->sn, TOPIC_EVT_SET_RGLT);
                                        ipc_session_publish(session, topic, (unsigned char *) data, (int) strlen(data));
                                        free(data);
                                        all_triggered = 0;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return all_triggered;
}

int period_services_trigger(ipc_session_t *session, period_service_t *period, nodes_cfg_table_t *nodes_cfg_table, template_table_t *template_table, gw_port_e *ports, int cnt)
{
    int i, j, k, l;
    GET_SN_PROC

    for (i = 0; i < template_table->template_cnt; i++)
    {
        for (j = 0; j < template_table->template[i].service_tab->serviceCnt; j++)
        {
            if (template_table->template[i].service_tab->service[j].server_period && !template_table->template[i].service_tab->service[j].direction)
            {
                for (k = 0; k < nodes_cfg_table->node_cnt; k++)
                {
                    node_cfg_t *node = &nodes_cfg_table->node[k];
                    if (strlen(node->app_key) != 0) continue;
                    for (l = 0; l < cnt; l++)
                    {
                        if (node->port == ports[l])
                        {
                            if (strcmp(node->template_id, template_table->template[i].template_id) == 0)
                            {
                                char *data = service_rs_data(&template_table->template[i].service_tab->service[j], node->sn);
                                char topic[TOPIC_MAX_LEN] = {0};
                                if (period != NULL)
                                {
                                    period_msg_t period_msg = {0};
                                    snprintf(period_msg.key, 128, "%s_%s", node->sn, template_table->template[i].service_tab->service[j].identifier);
                                    period_msg_add(period, &period_msg);
                                }

                                snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", sn, port_enum2char(node->port), node->sn, TOPIC_EVT_SET_RGLT);
                                ipc_session_publish(session, topic, (unsigned char *) data, (int) strlen(data));
                                free(data);
                            }
                        }
                    }
                }
            }
        }
    }

    return 0;
}

int period_services_retrigger_by_appkey(ipc_session_t *session, period_service_t *period, nodes_cfg_table_t *nodes_cfg_table, template_table_t *template_table, char *appkey)
{
    int i, j, k;
    int all_triggered = 1;

    GET_SN_PROC

    for (i = 0; i < template_table->template_cnt; i++)
    {
        for (j = 0; j < template_table->template[i].service_tab->serviceCnt; j++)
        {
            if (template_table->template[i].service_tab->service[j].server_period && !template_table->template[i].service_tab->service[j].direction)
            {
                for (k = 0; k < nodes_cfg_table->node_cnt; k++)
                {
                    node_cfg_t *node = &nodes_cfg_table->node[k];
                    if (strcmp(node->app_key, appkey) == 0)
                    {
                        if (strcmp(node->template_id, template_table->template[i].template_id) == 0)
                        {
                            if (period != NULL)
                            {
                                char key[128] = {0};
                                int triggered = 0;

                                snprintf(key, 128, "%s_%s", node->sn, template_table->template[i].service_tab->service[j].identifier);
                                triggered = period_msg_started(period, key);
                                if (triggered == 0)
                                {
                                    char *data = service_rs_data(&template_table->template[i].service_tab->service[j], node->sn);
                                    char topic[TOPIC_MAX_LEN] = {0};
                                    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", sn, appkey, node->sn, TOPIC_EVT_SET_RGLT);
                                    ipc_session_publish(session, topic, (unsigned char *) data, (int) strlen(data));
                                    free(data);
                                    all_triggered = 0;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return all_triggered;
}

int period_services_trigger_by_appkey(ipc_session_t *session, period_service_t *period, nodes_cfg_table_t *nodes_cfg_table, template_table_t *template_table, char *appkey)
{
    int i, j, k;
    GET_SN_PROC

    for (i = 0; i < template_table->template_cnt; i++)
    {
        for (j = 0; j < template_table->template[i].service_tab->serviceCnt; j++)
        {
            if (template_table->template[i].service_tab->service[j].server_period && !template_table->template[i].service_tab->service[j].direction)
            {
                for (k = 0; k < nodes_cfg_table->node_cnt; k++)
                {
                    node_cfg_t *node = &nodes_cfg_table->node[k];
                    if (strcmp(node->app_key, appkey) == 0)
                    {
                        if (strcmp(node->template_id, template_table->template[i].template_id) == 0)
                        {
                            char *data = service_rs_data(&template_table->template[i].service_tab->service[j], node->sn);
                            char topic[TOPIC_MAX_LEN] = {0};
                            if (period != NULL)
                            {
                                period_msg_t period_msg = {0};
                                snprintf(period_msg.key, 128, "%s_%s", node->sn, template_table->template[i].service_tab->service[j].identifier);
                                period_msg_add(period, &period_msg);
                            }

                            snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", sn, appkey, node->sn, TOPIC_EVT_SET_RGLT);
                            ipc_session_publish(session, topic, (unsigned char *) data, (int) strlen(data));
                            free(data);
                        }
                    }
                }
            }
        }
    }

    return 0;
}
