#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 "ipdev_manager.h"

#define IP_DEVICE_APP_KEY "zKXqkp7pdUP6eQl2"

gw_port_e ports[] = {TCP_CLIENT};

static int ipdev_manager_msg_tag_data_ctrl(ipdev_manager_var_t *var, ipc_msg_t *mqtt_msg)
{
    pp_regulate_signal_t regulate_data;
    int ret = 0;
    int i = 0;

    ret = get_rglt_data_from_json(&regulate_data, mqtt_msg->payload);
    if (ret < 0 || regulate_data.len <= 0)
    {
        dy_syslog(LOG_ERR, "parse real data structure failed");
        return -1;
    }

out:
    free(regulate_data.data);

    return 0;
}

static int ipdev_manager_mqtt_handle_recv_msg(void *obj, ipc_msg_t *mqtt_msg)
{
    ipdev_manager_var_t *var = (ipdev_manager_var_t *)obj;
    dy_syslog(LOG_DEBUG, "received MQTT topic:%s payload length:%d", mqtt_msg->topic, mqtt_msg->payloadLen);
    if (strstr(mqtt_msg->topic, TOPIC_SEND_RGLT_SIGNAL_RAW_DATA))
    {
        //发送下行数据
        ipdev_manager_msg_tag_data_ctrl(var, mqtt_msg);
    }
}

static void ipdev_manager_subscribe_all(ipdev_manager_var_t *var)
{
	ipc_session_t *ipc_session = var->session;
    char topic[TOPIC_MAX_LEN] = {0};

    snprintf(topic, TOPIC_MAX_LEN, "ipc/+/%s/device/+/data/%s", IP_DEVICE_APP_KEY, TOPIC_SEND_RGLT_SIGNAL_RAW_DATA);
    ipc_session_subscribe(ipc_session, topic);
}

// 建立与内部broker之间的MQTT连接
static int ipdev_manager_mqtt_client_init(ipdev_manager_var_t *var)
{
    char clientId[MAX_CLIENT_ID_LEN] = {0};

    snprintf(clientId, MAX_CLIENT_ID_LEN, "INT_ipdev_manager_%s", var->sn_str);
    var->session = ipc_session_new(clientId, (void*)var, IPC_DEFAULT);
    if (var->session == NULL)
        return -1;

    ipc_session_set_callbacks(var->session, ipdev_manager_mqtt_handle_recv_msg, NULL);
    ipdev_manager_subscribe_all(var);
    ipc_session_start(var->session);
}

static int period_service_poll(ipdev_manager_var_t *var)
{
    TIMER_CONFIRM(var->period_poll_timer);
    
    time_t now = time(NULL);

    if (var->upgrading == 1)
    {
        return 0;
    }

    ip_device_config_t *ip_dev_cfg = NULL;
	list_for_each_entry(ip_dev_cfg, &var->config_list, list)
	{
		//检索周期服务
		if(now - ip_dev_cfg->last_push >= ip_dev_cfg->dev_cfg.server_period)
		{
			ip_dev_cfg->last_push = time(NULL);
			ipc_session_publish(var->session, ip_dev_cfg->dev_cfg.topic, ip_dev_cfg->dev_cfg.payload, strlen(ip_dev_cfg->dev_cfg.payload));
		}
	}
    return 0;
}

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

    while (1)
    {
        SELECT_INIT();
        SELECT_ADD_FD(var->period_poll_timer);

        timeout.tv_usec = 0;
        timeout.tv_sec = 5;

        ret = select(maxfd + 1, &rset, 0, 0, &timeout);
        if (ret < 0)
        {
            dy_syslog(LOG_INFO, "errno %d\n", errno);

            if (errno == EINTR)
            {
                continue;
            }
            else
            {
                break;
            }
        }
        else if (ret > 0)
        {
            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 ip_deveice_period_rs_triger(ipdev_manager_var_t *var)
{
    int i, j, k;

    for (i = 0; i < var->template_table->template_cnt; i++)
    {
        //解析周期命令
        for (j = 0; j < var->template_table->template[i].service_tab->serviceCnt; j++)
        {
            if (var->template_table->template[i].service_tab->service[j].server_period && !var->template_table->template[i].service_tab->service[j].direction)
            {
                //节点信息
                for (k = 0; k < var->nodes_cfg_table->node_cnt; k++)
                {
                    if (strcmp(var->nodes_cfg_table->node[k].app_key, IP_DEVICE_APP_KEY) == 0 &&
                        strcmp(var->nodes_cfg_table->node[k].template_id, var->template_table->template[i].template_id) == 0)
                    {
                        ip_device_config_t *ip_dev_cfg = calloc(1, sizeof(ip_device_config_t));

						strncpy(ip_dev_cfg->dev_cfg.sn, var->nodes_cfg_table->node[i].sn, sizeof(ip_dev_cfg->dev_cfg.sn));
						snprintf(ip_dev_cfg->dev_cfg.topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", var->sn_str, IP_DEVICE_APP_KEY, var->nodes_cfg_table->node[k].sn, TOPIC_EVT_SET_RGLT);
						ip_dev_cfg->dev_cfg.payload = service_rs_data(&var->template_table->template[i].service_tab->service[j], var->nodes_cfg_table->node[k].sn);
						ip_dev_cfg->last_push = 0;//time(NULL);
						ip_dev_cfg->dev_cfg.server_period = var->template_table->template[i].service_tab->service[j].server_period;
						//ipc_session_publish(var->session, ip_dev_cfg->dev_cfg.topic, ip_dev_cfg->dev_cfg.payload, strlen(ip_dev_cfg->dev_cfg.payload));
						
						dy_syslog(LOG_INFO,"==sn:%s identifier:%s==",ip_dev_cfg->dev_cfg.sn,var->template_table->template[i].service_tab->service[j].identifier);
						list_add_tail(&ip_dev_cfg->list, &var->config_list);
                    }
                }
            }
        }
    }
}

static int ipdev_manager_init(ipdev_manager_var_t *var)
{
	int i;
    get_board_sn(var->sn_str);
	INIT_LIST_HEAD(&var->config_list);
	dy_syslog(LOG_INFO,"==sn_str:%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");
    }

    var->period_poll_timer = my_timer_create();
    if (var->period_poll_timer > 0)
    {
        my_timer_set(var->period_poll_timer, 1, 5000);
    }

    ipdev_manager_mqtt_client_init(var);
	ip_deveice_period_rs_triger(var);
}

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

    openlog("ipdev_manager", LOG_PID, LOG_DAEMON);

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

    return 0;
}