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

static int send_data_in_query_list(channel_t *channel)
{
    tag_list_node_t *tmp = NULL;
    tag_list_node_t *tag_list = NULL;
    dy_db_session_t *session = channel->db_session;
    int ret = 0;
    int i = 0;

    if (list_empty(&session->query_list))
    {
        return 0;
    }

    list_for_each_entry_safe(tag_list, tmp, &session->query_list, list)
    {
        tag_table_t *p = &tag_list->tag;
        char topic[TOPIC_MAX_LEN] = {0};

        ret = dy_mqtt_session_publish(channel->session, p->ext, p->tag_node, p->tag_len);
        if (ret == 0)
        {
            // 发布成功保留在链表里，用于更新数据库
            p->report = REPORTED;
        }
        else
        {
            list_del(&tag_list->list);
            free(tag_list->tag.tag_node);
            free(tag_list->tag.ext);
            free(tag_list);
        }
    }

    if (list_empty(&session->query_list))
    {
        // 全部上报失败，不需要更新数据库
        dy_syslog(LOG_WARNING, "all report failed");
        return 0;
    }
    else
    {
        list_move_tail_list(&session->query_list, &session->update_list);
        return 1;
    }
}

static int status_poll(cloud_mqtt_var_t *var)
{
    TIMER_CONFIRM(var->status_poll_timer);
    int i = 0;

    for (i = 0; i < var->daslink_channel_cnt; i++)
    {
        channel_t * channel = &var->daslink_channel[i];

        if(channel->connect_status == 0)
        {
        	
        }
    }

    return 0;
}

int data_report_poll(cloud_mqtt_var_t *var)
{
    TIMER_CONFIRM(var->report_timer);
    int i = 0;

    for (i = 0; i < var->daslink_channel_cnt; i++)
    {
        channel_t * channel = &var->daslink_channel[i];

        if (channel->resume == 0) continue;

        dy_db_session_select_not_repoted(channel->db_session, 100);
        send_data_in_query_list(channel);
        dy_db_session_update_reported(channel->db_session);
    }

    return 0;
}

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

    while (1)
    {
        SELECT_INIT();
        timeout.tv_usec = 0;
        timeout.tv_sec = 2;
        SELECT_ADD_FD(var->status_poll_timer);
        SELECT_ADD_FD(var->report_timer);
        ret = select(maxfd + 1, &rset, 0, 0, &timeout);
        if (ret < 0)
        {
            printf("errno %d\n", errno);
            if (errno == EINTR)
            {
                continue;
            }
            else
            {
                break;
            }
        }
        else if (ret > 0)
        {
            if (var->status_poll_timer > 0 && FD_ISSET(var->status_poll_timer, &rset))
            {
                FD_CLR(var->status_poll_timer, &rset);
                status_poll(var);
            }
            if (var->report_timer > 0 && FD_ISSET(var->report_timer, &rset))
            {
                FD_CLR(var->report_timer, &rset);
                data_report_poll(var);
            }
        }
    }
}

static void daslink_node_connect(cloud_mqtt_var_t *var)
{
	int i;

	for(i=0; i<var->nodes_cfg_table->node_cnt; i++)
    {
    	dy_syslog(LOG_DEBUG,"===sn %s var->nodes_cfg_table->node[i].device_secret %p===",var->nodes_cfg_table->node[i].sn,var->nodes_cfg_table->node[i].device_secret);
    	if(var->nodes_cfg_table->node[i].device_secret && strlen(var->nodes_cfg_table->node[i].device_secret))
		{
			dy_syslog(LOG_DEBUG,"===sn %s var->nodes_cfg_table->node[i].device_secret %s===",var->nodes_cfg_table->node[i].sn,var->nodes_cfg_table->node[i].device_secret);
			daslink_params_list_t* daslink_list = calloc(sizeof(daslink_params_list_t), 1);
			daslink_list->daslink_params.thing_id = calloc(64,1);
			daslink_list->daslink_params.device_id = calloc(64,1);
			daslink_list->daslink_params.device_secret = calloc(64,1);

			strncpy(daslink_list->daslink_params.device_id, var->nodes_cfg_table->node[i].sn, 64);
			strncpy(daslink_list->daslink_params.thing_id, var->nodes_cfg_table->node[i].product_key, 64);
			strncpy(daslink_list->daslink_params.device_secret, var->nodes_cfg_table->node[i].device_secret, 64);
			strncpy(daslink_list->port, port_enum2char(var->nodes_cfg_table->node[i].port), sizeof(daslink_list->port));
			
			dy_syslog(LOG_DEBUG,"===sn %s (%s %s %s)===\n",var->nodes_cfg_table->node[i].sn,daslink_list->daslink_params.device_id,daslink_list->daslink_params.device_secret,daslink_list->daslink_params.thing_id);
	        list_add_tail(&daslink_list->list,&var->node_list);
		}
    }
}


static int cloud_mqtt_init(cloud_mqtt_var_t *var)
{
    get_board_sn(var->sn_str);
    get_process_name(var->proc_name);
	INIT_LIST_HEAD(&var->node_list);
    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 (cloud_mqtt_load_cfg(var, CLOUD_DASLINK_CFG) < 0)
    {
        dy_syslog(LOG_ERR, "load config failed");
        return -1;
    }

    cloud_mqtt_internal_mqtt_init(var);
	daslink_node_connect(var);
	cloud_daslink_channel_create(var);

    var->status_poll_timer = my_timer_create();
    if (var->status_poll_timer <= 0)
    {
        dy_syslog(LOG_INFO, "[ERR] create status check timer fail, %d", var->status_poll_timer);
    }

    if (var->status_poll_timer > 0)
    {
        my_timer_set(var->status_poll_timer, 10, 10 * 1000);
    }

    var->report_timer = my_timer_create();
    if (var->report_timer <= 0)
    {
        dy_syslog(LOG_INFO, "[ERR] create status check timer fail, %d", var->report_timer);
    }

    if (var->report_timer > 0)
    {
        my_timer_set(var->report_timer, 10, 60 * 1000);
    }

    dy_syslog(LOG_INFO, "init done");

    return 0;
}

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

    openlog("cloud_mqtt", LOG_PID, LOG_DAEMON);

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

    cloud_mqtt_init(&var);
    cloud_mqtt_loop(&var);

    return 0;
}
