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

static int load_mqtt_cfg(cloud_mqtt_var_t *var, char *data, char *uplink_type)
{
    cJSON *root = NULL;
    cJSON *mqtts = NULL;
    cJSON *mqtt = NULL;
    int mqtt_cnt = 0;
    int i = 0, j = 0;
    char tmp[128] = {0};
    int ret = 0;
    char *new_data = NULL;
   
    root = cJSON_Parse(data);
    if (!root)
    {
        dy_syslog(LOG_ERR, "parse cfg file error");
        ret = -1;
        goto out;
    }

    mqtts = cJSON_GetObjectItem(root, uplink_type);
    if (!mqtts)
    {
        dy_syslog(LOG_ERR, "get MQTT failed");
        ret = -1;
        goto out;
    }

    mqtt_cnt = cJSON_GetArraySize(mqtts);
    if (mqtt_cnt == 0)
    {
        ret = 0;
        dy_syslog(LOG_INFO, "No MQTT UPLINK Channel");
        goto out;
    }

    if (mqtt_cnt > 8)
    {
        dy_syslog(LOG_WARNING, "exceed the max support channel count:%d, max:%d", mqtt_cnt, MAX_UPLINK_CHANNEL_CNT);
        mqtt_cnt = MAX_UPLINK_CHANNEL_CNT;
    }
	var->iec104_channel_cnt = mqtt_cnt;

    for (i = 0; i < mqtt_cnt; i++)
    {
	    char 	clientId[MAX_CLIENT_ID_LEN];	///<clientId
	    channel_t *channel = NULL;

		channel = &var->iec104_channel[i];
        mqtt = cJSON_GetArrayItem(mqtts, i);
        if (cJSON_GetObjectItem(mqtt, "client_id") != NULL)
        {
            GET_JSON_VALUE_STRING(mqtt, "client_id", clientId);
        }
        if (strlen(clientId) == 0)
        {
            snprintf(clientId, MAX_CLIENT_ID_LEN, "%s_UP_%d", var->sn_str, i);
        }

       mqtt_session_t* session = mqtt_session_new(clientId, (void*)channel);
        if (session == NULL)
        {
            dy_syslog(LOG_ERR, "malloc error");
            return -1;
        }
        channel->session = session;

        GET_JSON_VALUE_STRING(mqtt, "host", channel->addr);
        GET_JSON_VALUE_INT(mqtt, "port", channel->port);
        GET_JSON_VALUE_STRING(mqtt, "user", channel->user);
        GET_JSON_VALUE_STRING(mqtt, "pass", channel->pass);
        GET_JSON_VALUE_INT(mqtt, "resume", channel->resume);
		GET_JSON_VALUE_INT(mqtt, "asdu_addr", channel->asdu_addr);

		char cafile_url[128] = {0}, certfile_url[128] = {0}, keyfile_url[128] = {0};
		GET_JSON_VALUE_STRING(mqtt, "cafile", cafile_url);
		GET_JSON_VALUE_STRING(mqtt, "certfile", certfile_url);
		GET_JSON_VALUE_STRING(mqtt, "keyfile", keyfile_url);		
		
        mqtt_session_set_address(session, channel->addr, channel->port, channel->user, channel->pass);
        mqtt_session_set_opts(session, DEFAULT_QOS, KEEPALIVEINTERVAL);

        if (cJSON_GetObjectItem(mqtt, "heart_beat") != NULL)
        {
            cJSON *hb = cJSON_GetObjectItem(mqtt, "heart_beat");
            GET_JSON_VALUE_INT(hb, "interval", channel->heart_beat.interval);
            GET_JSON_VALUE_DY_STRING(hb, "pub_topic", channel->heart_beat.pub_topic);
            GET_JSON_VALUE_DY_STRING(hb, "sub_topic", channel->heart_beat.sub_topic);
            if (cJSON_GetObjectItem(hb, "pub_payload") != NULL)
            {
                GET_JSON_VALUE_DY_STRING(hb, "pub_payload", channel->heart_beat.payload);
            }
        }
        if (cJSON_GetObjectItem(mqtt, "login") != NULL)
        {
            cJSON *login = cJSON_GetObjectItem(mqtt, "login");
            GET_JSON_VALUE_INT(login, "interval", channel->login.interval);
            GET_JSON_VALUE_DY_STRING(login, "pub_topic", channel->login.pub_topic);
            GET_JSON_VALUE_DY_STRING(login, "sub_topic", channel->login.sub_topic);
            if (cJSON_GetObjectItem(login, "pub_payload") != NULL)
            {
                GET_JSON_VALUE_DY_STRING(login, "pub_payload", channel->login.payload);
            }
        }

        if (cJSON_GetObjectItem(mqtt, "topic_maps") != NULL)
        {
            cJSON *maps = cJSON_GetObjectItem(mqtt, "topic_maps");
            topic_maps_t *topic_maps = &channel->topic_maps;
            if (cJSON_GetObjectItem(maps, "uplink") != NULL)
            {
                cJSON *uplinks = cJSON_GetObjectItem(maps, "uplink");
                int cnt = cJSON_GetArraySize(uplinks);
                if (cnt > 0)
                {
                    topic_maps->uplink_cnt = cnt;
                    topic_maps->uplink = calloc(cnt, sizeof(topic_pair_t));
                    if (topic_maps->uplink == NULL)
                    {
                        dy_syslog(LOG_WARNING, "calloc failed, cnt:%d", cnt);
                        continue;
                    }
                    for (j = 0; j < cnt; j++)
                    {
                        cJSON *uplink = cJSON_GetArrayItem(uplinks, j);
                        GET_JSON_VALUE_DY_STRING(uplink, "internal", topic_maps->uplink[j].internal_topic);
                        GET_JSON_VALUE_DY_STRING(uplink, "external", topic_maps->uplink[j].external_topic);
                    }
                }
            }
            if (cJSON_GetObjectItem(maps, "downlink") != NULL)
            {
                cJSON *downlinks = cJSON_GetObjectItem(maps, "downlink");
                int cnt = cJSON_GetArraySize(downlinks);
                if (cnt > 0)
                {
                    topic_maps->downlink_cnt = cnt;
                    topic_maps->downlink = calloc(cnt, sizeof(topic_pair_t));
                    if (topic_maps->downlink == NULL)
                    {
                        dy_syslog(LOG_WARNING, "calloc failed, cnt:%d", cnt);
                        continue;
                    }
                    for (j = 0; j < cnt; j++)
                    {
                        cJSON *downlink = cJSON_GetArrayItem(downlinks, j);
                        GET_JSON_VALUE_DY_STRING(downlink, "internal", topic_maps->downlink[j].internal_topic);
                        GET_JSON_VALUE_DY_STRING(downlink, "external", topic_maps->downlink[j].external_topic);
                    }
                }
            }
        }
    }

    #if 0
    printf("Total channel number:%d\n", var->channel_cnt);
    for (i = 0; i < var->channel_cnt; i++)
    {
        printf("The %d channel\n", i);
        channel_t *channel = &var->channel[i];

        printf("MQTT host:%s\n", channel->session.client.addr);
        printf("UPLINK topic maps\n");
        for (j = 0; j < channel->topic_maps.uplink_cnt; j++)
        {
            printf("%s  ===>  %s\n", channel->topic_maps.uplink[j].internal_topic, channel->topic_maps.uplink[j].external_topic);
        }

        for (j = 0; j < channel->topic_maps.downlink_cnt; j++)
        {
            printf("%s  <===  %s\n", channel->topic_maps.downlink[j].internal_topic, channel->topic_maps.downlink[j].external_topic);
        }
    }
    #endif

out:
    cJSON_Delete(root);

    return ret;
}


int cloud_mqtt_load_cfg(cloud_mqtt_var_t *var, const char *cfg_file)
{
    char *data = NULL;
	char *new_data = NULL;
    int ret = 0;

    if (var == NULL || cfg_file == NULL)
    {
        dy_syslog(LOG_ERR, "p_nodes_cfg:%p cfg_file:%p", var, cfg_file);
        return -1;
    }

    data = read_file_data(cfg_file);
    if (data == NULL)
    {
        dy_syslog(LOG_ERR, "read cfg file %s error", cfg_file);
        ret = -1;
        goto out;
    }
    printf("raw_data:\n%s\n", data);
	new_data = calloc(strlen(var->sn_str) / strlen("[GW_SN]") + 1, strlen(data));
    replace_sub_str(data, "[GW_SN]", var->sn_str, new_data);
    free(data);
    data = new_data;
    printf("replaced data:\n%s\n", data);
	
	ret = load_mqtt_cfg(var, data, "iec104");
    if (ret != 0)
    {
        dy_syslog(LOG_WARNING, "Ignore iec104 config miss");
        ret = 0;
    }

out:
    if (data != NULL)
    {
        free(data);
    }

    return ret;
}
