#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kk_dm_mng.h"
#include "kk_dm_msg.h"
#include "kk_tsl_api.h"
#include "kk_tsl_load.h"
#include "iot_export_linkkit.h"
#include "kk_product.h"


//const char DM_URI_SYS_PREFIX[]                        DM_READ_ONLY = "/sys/%s/%s/";
const char DM_URI_EXT_SESSION_PREFIX[]                DM_READ_ONLY = "/ext/session/%s/%s/";
const char DM_URI_EXT_NTP_PREFIX[]                    DM_READ_ONLY = "/ext/ntp/%s/%s/";
const char DM_URI_EXT_ERROR_PREFIX[]                  DM_READ_ONLY = "/ext/error/%s/%s";
const char DM_URI_REPLY_SUFFIX[]                      DM_READ_ONLY = "_reply";
const char DM_URI_OTA_DEVICE_INFORM[]                 DM_READ_ONLY = "/ota/device/inform/%s/%s";


/* From Cloud To Local Request And Response*/
const char DM_URI_THING_TOPO_ADD_NOTIFY[]             DM_READ_ONLY = "thing/topo/add/notify";
const char DM_URI_THING_TOPO_ADD_NOTIFY_REPLY[]       DM_READ_ONLY = "thing/topo/add/notify_reply";
const char DM_URI_THING_DELETE[]                      DM_READ_ONLY = "thing/delete";
const char DM_URI_THING_DELETE_REPLY[]                DM_READ_ONLY = "thing/delete_reply";
const char DM_URI_THING_DISABLE[]                     DM_READ_ONLY = "thing/disable";
const char DM_URI_THING_DISABLE_REPLY[]               DM_READ_ONLY = "thing/disable_reply";
const char DM_URI_THING_ENABLE[]                      DM_READ_ONLY = "thing/enable";
const char DM_URI_THING_ENABLE_REPLY[]                DM_READ_ONLY = "thing/enable_reply";
const char DM_URI_THING_GATEWAY_PERMIT[]              DM_READ_ONLY = "thing/gateway/permit";
const char DM_URI_THING_GATEWAY_PERMIT_REPLY[]        DM_READ_ONLY = "thing/gateway/permit_reply";

/* From Local To Cloud Request And Response*/
const char DM_URI_THING_SUB_REGISTER[]                DM_READ_ONLY = "thing/sub/register";
const char DM_URI_THING_SUB_REGISTER_REPLY[]          DM_READ_ONLY = "thing/sub/register_reply";
const char DM_URI_THING_SUB_UNREGISTER[]              DM_READ_ONLY = "thing/sub/unregister";
const char DM_URI_THING_SUB_UNREGISTER_REPLY[]        DM_READ_ONLY = "thing/sub/unregister_reply";
const char DM_URI_THING_TOPO_ADD[]                    DM_READ_ONLY = "thing/topo/add";
const char DM_URI_THING_TOPO_ADD_REPLY[]              DM_READ_ONLY = "thing/topo/add_reply";
const char DM_URI_THING_TOPO_DELETE[]                 DM_READ_ONLY = "thing/topo/delete";
const char DM_URI_THING_TOPO_DELETE_REPLY[]           DM_READ_ONLY = "thing/topo/delete_reply";
const char DM_URI_THING_TOPO_GET[]                    DM_READ_ONLY = "thing/topo/get";
const char DM_URI_THING_TOPO_GET_REPLY[]              DM_READ_ONLY = "thing/topo/get_reply";
const char DM_URI_THING_LIST_FOUND[]                  DM_READ_ONLY = "thing/list/found";
const char DM_URI_THING_LIST_FOUND_REPLY[]            DM_READ_ONLY = "thing/list/found_reply";
const char DM_URI_COMBINE_LOGIN[]                     DM_READ_ONLY = "combine/login";
const char DM_URI_COMBINE_LOGIN_REPLY[]               DM_READ_ONLY = "combine/login_reply";
const char DM_URI_COMBINE_LOGOUT[]                    DM_READ_ONLY = "combine/logout";
const char DM_URI_COMBINE_LOGOUT_REPLY[]              DM_READ_ONLY = "combine/logout_reply";


static dm_mgr_ctx g_dm_mgr = {0};
static dm_mgr_ctx *_dm_mgr_get_ctx(void)
{
    return &g_dm_mgr;
}

static void _dm_mgr_mutex_lock(void)
{
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    if (ctx->mutex) {
        kk_MutexLock(ctx->mutex);
    }
}

static void _dm_mgr_mutex_unlock(void)
{
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    if (ctx->mutex) {
        kk_MutexUnLock(ctx->mutex);
    }
}

int dm_mgr_search_dev_by_devid(_IN_ int devid, _OU_ dm_mgr_dev_node_t **node)
{
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    dm_mgr_dev_node_t *search_node = NULL;

    list_for_each_entry(search_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) {
        if (search_node->devid == devid) {
            /* dm_log_debug("Device Found, devid: %d", devid); */
            if (node) {
                *node = search_node;
            }
            return SUCCESS_RETURN;
        }
    }

    printf("Device Not Found, devid: %d", devid);
    return FAIL_RETURN;
}
static int _dm_mgr_search_dev_by_pkdn(_IN_ char product_key[PRODUCT_KEY_MAXLEN],
                                      _IN_ char device_name[DEVICE_NAME_MAXLEN], _OU_ dm_mgr_dev_node_t **node)
{
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    dm_mgr_dev_node_t *search_node = NULL;

    list_for_each_entry(search_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) {
        if ((strlen(search_node->product_key) == strlen(product_key)) &&
            (memcmp(search_node->product_key, product_key, strlen(product_key)) == 0) &&
            (strlen(search_node->device_name) == strlen(device_name)) &&
            (memcmp(search_node->device_name, device_name, strlen(device_name)) == 0)) {
            /* dm_log_debug("Device Found, Product Key: %s, Device Name: %s", product_key, device_name); */
            if (node) {
                *node = search_node;
            }
            return SUCCESS_RETURN;
        }
    }

    printf("Device Not Found, Product Key: %s, Device Name: %s", product_key, device_name);
    return FAIL_RETURN;
}
static int _dm_mgr_next_devid(void)
{
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();

    return ctx->global_devid++;
}
static int _dm_init_tsl_params(int devId)
{
	int res = 0;
 	char version[VERSION_MAXLEN];
 	char s_IP[NETWORK_ADDR_LEN];
 	char s_mac[MAC_ADDR_LEN];
	char s_SN[SN_ADDR_LEN];
	int port = 0;

	/*******set version***********/
	HAL_GetVersion(version);
	res = kk_tsl_set_value(kk_tsl_set_property_value,devId,KK_TSL_GATAWAY_VERSION_IDENTIFIER,NULL,version);
	if(res != SUCCESS_RETURN)
	{
		printf("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	}
	
	/*******set IP*************/
	HAL_Get_IP(s_IP,NULL);
	res = kk_tsl_set_value(kk_tsl_set_property_value,devId,KK_TSL_GATAWAY_IP_IDENTIFIER,NULL,s_IP);
	if(res != SUCCESS_RETURN)
	{
		printf("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	}

	/*******set MAC*************/
	HAL_Get_mac(s_mac);
	res = kk_tsl_set_value(kk_tsl_set_property_value,devId,KK_TSL_GATAWAY_MAC_IDENTIFIER,NULL,s_mac);
	if(res != SUCCESS_RETURN)
	{
		printf("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	}	
	
	/*******set port*************/
	port = HAL_Get_port();
	res = kk_tsl_set_value(kk_tsl_set_property_value,devId,KK_TSL_GATAWAY_PORT_IDENTIFIER,&port,NULL);
	if(res != SUCCESS_RETURN)
	{
		printf("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	}	
	
	/*******set sn*************/
	HAL_Get_SN(s_SN);
	res = kk_tsl_set_value(kk_tsl_set_property_value,devId,KK_TSL_GATAWAY_SN_IDENTIFIER,NULL,s_SN);
	if(res != SUCCESS_RETURN)
	{
		printf("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	}	
	return res;
}
int dm_mgr_device_create(_IN_ int dev_type, _IN_ char product_key[PRODUCT_KEY_MAXLEN],
                         _IN_ char device_name[DEVICE_NAME_MAXLEN], _IN_ char device_secret[DEVICE_SECRET_MAXLEN],_IN_ char device_mac[DEVICE_MAC_MAXLEN], _OU_ int *devid)
{
    int res = 0;
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    dm_mgr_dev_node_t *node = NULL;
	char *tsl_str = NULL;
	int idx = 0;
	char name[TSL_PATH_MAXLEN] = {0};
    if (product_key == NULL || device_name == NULL ||
        strlen(product_key) >= PRODUCT_KEY_MAXLEN ||
        strlen(device_name) >= DEVICE_NAME_MAXLEN) {
        return INVALID_PARAMETER;
    }

    if (device_secret != NULL && strlen(device_secret) >= DEVICE_SECRET_MAXLEN) {
        return INVALID_PARAMETER;
    }
    if (device_mac != NULL && strlen(device_mac) >= DEVICE_MAC_MAXLEN) {
        return INVALID_PARAMETER;
    }

    res = _dm_mgr_search_dev_by_pkdn(product_key, device_name, &node);
    if (res == SUCCESS_RETURN) {
        if (devid) {
            *devid = node->devid;
        }
        return FAIL_RETURN;
    }

    node = malloc(sizeof(dm_mgr_dev_node_t));
    if (node == NULL) {
        return MEMORY_NOT_ENOUGH;
    }
    memset(node, 0, sizeof(dm_mgr_dev_node_t));

	if(dev_type == KK_DM_DEVICE_GATEWAY)
    	node->devid = 0;
	else
		node->devid = _dm_mgr_next_devid();
    node->dev_type = dev_type;
    node->dev_shadow = NULL;
    memcpy(node->product_key, product_key, strlen(product_key));
    memcpy(node->device_name, device_name, strlen(device_name));
    if (device_secret != NULL) {
        memcpy(node->device_secret, device_secret, strlen(device_secret));
    }
    if (device_mac != NULL) {
        memcpy(node->device_mac, device_mac, strlen(device_mac));
    }

    //node->dev_status = IOTX_DM_DEV_STATUS_AUTHORIZED;
    memset(name,0x0,sizeof(name));
    kk_get_tsl_by_productKey(product_key,name);
	tsl_str = kk_load_json(name);
	res = kk_tsl_create(tsl_str,strlen(tsl_str),&node->dev_shadow);
	free(tsl_str);
	if(res != 0){
		return FAIL_RETURN;
	}
	
    INIT_LIST_HEAD(&node->linked_list);
    list_add_tail(&node->linked_list, &ctx->dev_list);
	
	if(dev_type == KK_DM_DEVICE_GATEWAY){
		_dm_init_tsl_params(node->devid);
	}

    if (devid) {
        *devid = node->devid;
    }

    return SUCCESS_RETURN;
}
int dm_mgr_search_device_by_pkdn(_IN_ char product_key[PRODUCT_KEY_MAXLEN], _IN_ char device_name[DEVICE_NAME_MAXLEN],
                                 _OU_ int *devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (product_key == NULL || device_name == NULL) {
        return INVALID_PARAMETER;
    }

    res = _dm_mgr_search_dev_by_pkdn(product_key, device_name, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    if (devid) {
        *devid = node->devid;
    }

    return SUCCESS_RETURN;
}

int dm_mgr_search_mac_by_topic(_IN_ char* topic,              _OU_ char mac[DEVICE_MAC_MAXLEN])
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    char product_key[PRODUCT_KEY_MAXLEN];
    char device_name[DEVICE_NAME_MAXLEN];

    if (topic == NULL) {
        return INVALID_PARAMETER;
    }
    
    res =kk_msg_uri_parse_pkdn((char *)topic, strlen(topic), 2 + KK_URI_OFFSET, 4 + KK_URI_OFFSET, product_key,
                                device_name);
     if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
  
    res = _dm_mgr_search_dev_by_pkdn(product_key, device_name, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    memcpy(mac, node->device_mac, DEVICE_MAC_MAXLEN);

    return SUCCESS_RETURN;
}
                               

 int dm_mgr_search_mac_by_pkdn(_IN_ char product_key[PRODUCT_KEY_MAXLEN], _IN_ char device_name[DEVICE_NAME_MAXLEN],
                                  _OU_ char mac[DEVICE_MAC_MAXLEN])
 {
     int res = 0;
     dm_mgr_dev_node_t *node = NULL;
 
     if (product_key == NULL || device_name == NULL) {
         return INVALID_PARAMETER;
     }
 
     res = _dm_mgr_search_dev_by_pkdn(product_key, device_name, &node);
     if (res != SUCCESS_RETURN) {
         return FAIL_RETURN;
     }

    memcpy(mac, node->device_mac, DEVICE_MAC_MAXLEN);

     return SUCCESS_RETURN;
 }


int dm_mgr_get_device_by_mac(_IN_ char device_mac[DEVICE_MAC_MAXLEN], _OU_ dm_mgr_dev_node_t **node)
{
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    dm_mgr_dev_node_t *search_node = NULL;

    list_for_each_entry(search_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) {
        if ((strlen(search_node->device_mac) == strlen(device_mac)) &&
            (memcmp(search_node->device_mac, device_mac, strlen(device_mac)) == 0)) {
            /* dm_log_debug("Device Found, Product Key: %s, Device Name: %s", product_key, device_name); */
            if (node) {
                *node = search_node;
            }
            return SUCCESS_RETURN;
        }
    }

    printf("Device Not Found, device_mac: %s\n", device_mac);
    return FAIL_RETURN;
}

int dm_mgr_get_devId_by_mac(_IN_ char device_mac[DEVICE_MAC_MAXLEN],_OU_ int *devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (device_mac == NULL) {
        return INVALID_PARAMETER;
    }

    res = dm_mgr_get_device_by_mac(device_mac, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    if (devid) {
        *devid = node->devid;
    }

    return SUCCESS_RETURN;
}

int dm_mgr_init(void)
{
    int res = 0;
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    char product_key[PRODUCT_KEY_MAXLEN] = {0};
    char device_name[DEVICE_NAME_MAXLEN] = {0};
	char device_secret[DEVICE_SECRET_MAXLEN]= {0};
	int devId = 0;
    memset(ctx, 0, sizeof(dm_mgr_ctx));
	
    /* Create Mutex */
    ctx->mutex = kk_MutexCreate();
    if (ctx->mutex == NULL) {
        goto ERROR;
    }
    /* Init Device Id*/
    ctx->global_devid = 1;

    /* Init Device List */
    INIT_LIST_HEAD(&ctx->dev_list);

    HAL_GetProduct_Type(product_key);
    HAL_GetProduct_Code(device_name);
    //memset(product_key,0x0,sizeof(product_key));
    //memset(device_name,0x0,sizeof(device_name));	
	//memcpy(product_key,"a1OYuSBt23u",strlen("a1OYuSBt23u"));
	//memcpy(device_name,"aIqEbWno8yDdsjCX15iq",strlen("aIqEbWno8yDdsjCX15iq"));
	
    //_dm_mgr_legacy_thing_created(IOTX_DM_LOCAL_NODE_DEVID);
	res = dm_mgr_device_create(KK_DM_DEVICE_GATEWAY,product_key,device_name,device_secret,"aabbccddeeff1120",&devId);
	if (res != SUCCESS_RETURN) {
		goto ERROR;
	}
    return SUCCESS_RETURN;

ERROR:
    if (ctx->mutex) {
        kk_MutexDestroy(ctx->mutex);
    }
    memset(ctx, 0, sizeof(dm_mgr_ctx));
    return FAIL_RETURN;
}
const char DM_MSG_THING_UPSTREAM_REQUEST_PARAMS[] DM_READ_ONLY =
          "{\"value\":%s,\"timestamp\":\"%s\"}";
static int _dm_mgr_upstream_request_assemble(_IN_ int msgid, _IN_ int devid, _IN_ const char *service_prefix,
        _IN_ const char *service_name,
        _IN_ char *params, _IN_ int params_len, _IN_ char *method, _OU_ dm_msg_request_t *request)
{
    int res = 0;
    char timestamp[DM_UTILS_UINT64_STRLEN] = {0};	
    dm_mgr_dev_node_t *node = NULL;
	int paramLen = 0;
	char *payload_param = NULL;
    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* TimeStamp */
    HAL_Snprintf(timestamp, DM_UTILS_UINT64_STRLEN, "%llu", (unsigned long long)HAL_UptimeMs());
    /* dm_log_debug("Time Stamp: %s", timestamp); */
    paramLen = strlen(DM_MSG_THING_UPSTREAM_REQUEST_PARAMS) +
                    params_len + strlen(timestamp) + 1;
    payload_param = malloc(paramLen);
    if (payload_param == NULL) {
      return MEMORY_NOT_ENOUGH;
    }

    memset(payload_param, 0, paramLen);
    HAL_Snprintf(payload_param, paramLen, DM_MSG_THING_UPSTREAM_REQUEST_PARAMS, params,timestamp);

    request->msgid = msgid;
    request->devid = devid;
    request->service_prefix = service_prefix;
    request->service_name = service_name;
    memcpy(request->product_key, node->product_key, strlen(node->product_key));
    memcpy(request->device_name, node->device_name, strlen(node->device_name));
    request->params = payload_param;
    request->params_len = paramLen;
    request->method = method;

    return SUCCESS_RETURN;
}
static unsigned int g_report_id = 1;

int iotx_report_id(void)
{
    return g_report_id++;
}

int dm_mgr_upstream_thing_property_post(_IN_ int devid, _IN_ char *payload, _IN_ int payload_len)
{
    int res = 0;
    dm_msg_request_t request;

    if (devid < 0 || payload == NULL || payload_len <= 0) {
        return INVALID_PARAMETER;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, DM_URI_THING_EVENT_PROPERTY_POST,
                                            payload, payload_len, DM_URI_THING_EVENT_PROPERTY_POST_METHOD, &request);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Callback */
    //request.callback = dm_client_thing_event_post_reply;

    /* Send Message To Cloud */
    res = dm_msg_request(&request);
	free(request.params);
    return res;
}
int dm_mgr_upstream_thing_event_post(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *method,
                                     _IN_ char *payload, _IN_ int payload_len)
{
    int res = 0, service_name_len = 0;
    char *service_name = NULL;
    dm_msg_request_t request;

    if (devid < 0 || identifier == NULL || identifier_len <= 0 ||
        method == NULL || payload == NULL || payload_len <= 0) {
        return INVALID_PARAMETER;
    }

    service_name_len = strlen(DM_URI_THING_EVENT_POST) + identifier_len + 1;
    service_name = malloc(service_name_len);
    if (service_name == NULL) {
        return MEMORY_NOT_ENOUGH;
    }
    memset(service_name, 0, service_name_len);
    snprintf(service_name, service_name_len, DM_URI_THING_EVENT_POST, identifier_len, identifier);

    memset(&request, 0, sizeof(dm_msg_request_t));
    res = _dm_mgr_upstream_request_assemble(iotx_report_id(), devid, DM_URI_SYS_PREFIX, service_name,
                                            payload, payload_len, method, &request);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Callback */
    //request.callback = dm_client_thing_event_post_reply;

    /* Send Message To Cloud */
    res = dm_msg_request(&request);
    free(service_name);

    return res;
}

static int _kk_mgr_upstream_response_assemble(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len,
        _IN_ const char *prefix,
        _IN_ const char *service_name, _IN_ int code, _OU_ kk_msg_request_payload_t *request, _OU_ kk_msg_response_t *response)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    request->id.value = msgid;
    request->id.value_length = msgid_len;

    response->service_prefix = DM_URI_SYS_PREFIX;
    response->service_name = service_name;
    memcpy(response->product_key, node->product_key, strlen(node->product_key));
    memcpy(response->device_name, node->device_name, strlen(node->device_name));
    response->code = code;

    return SUCCESS_RETURN;
}

int dm_mgr_deprecated_upstream_thing_service_response(_IN_ int devid, _IN_ int msgid, _IN_ iotx_dm_error_code_t code,
        _IN_ char *identifier, _IN_ int identifier_len, _IN_ char *payload, _IN_ int payload_len)
{
    int res = 0, service_name_len = 0;
    char *msgid_str = NULL, *service_name = NULL;
    kk_msg_request_payload_t request;
    kk_msg_response_t response;

    memset(&request, 0, sizeof(kk_msg_request_payload_t));
    memset(&response, 0, sizeof(kk_msg_response_t));

    if (devid < 0 || msgid < 0 || identifier == NULL || identifier_len <= 0 ||
        payload == NULL || payload_len <= 0) {
        return INVALID_PARAMETER;
    }

    /* Response Msg ID */
    res = kk_utils_itoa(msgid, &msgid_str);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
    request.id.value = msgid_str;
    request.id.value_length = strlen(msgid_str);

    /* Service Name */
    service_name_len = strlen(DM_URI_THING_SERVICE_RESPONSE) + identifier_len + 1;
    service_name = malloc(service_name_len);
    if (service_name == NULL) {
        free(msgid_str);
        return MEMORY_NOT_ENOUGH;
    }
    memset(service_name, 0, service_name_len);
    snprintf(service_name, service_name_len, DM_URI_THING_SERVICE_RESPONSE, identifier_len, identifier);

    res = _kk_mgr_upstream_response_assemble(devid, msgid_str, strlen(msgid_str), DM_URI_SYS_PREFIX, service_name, code,
            &request,
            &response);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    printf("Current Service Name: %s", service_name);
    dm_msg_response(&request, &response, payload, payload_len, NULL);

    free(msgid_str);
    free(service_name);
    return SUCCESS_RETURN;
}

int dm_mgr_upstream_thing_sub_register(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
    dm_msg_request_t request;
	
    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.service_prefix = DM_URI_SYS_PREFIX;
    request.service_name = DM_URI_THING_SUB_REGISTER;
    HAL_GetProduct_Type(request.product_key);
    HAL_GetProduct_Code(request.device_name);

    /* Get Params And Method */
    res = dm_msg_thing_sub_register(node->product_key, node->device_name, &request);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Get Msg ID */
    request.msgid = iotx_report_id();

    /* Get Dev ID */
    request.devid = devid;

    /* Callback */
    //request.callback = dm_client_thing_sub_register_reply;

    /* Send Message To Cloud */
    res = dm_msg_request(&request);
    if (res == SUCCESS_RETURN) {
        res = request.msgid;
    }
    free(request.params);

    return res;
}

int dm_mgr_upstream_thing_sub_unregister(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
    dm_msg_request_t request;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.service_prefix = DM_URI_SYS_PREFIX;
    request.service_name = DM_URI_THING_SUB_UNREGISTER;
    HAL_GetProduct_Type(request.product_key);
    HAL_GetProduct_Code(request.device_name);

    /* Get Params And Method */
    res = dm_msg_thing_sub_unregister(node->product_key, node->device_name, &request);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Get Msg ID */
    request.msgid = iotx_report_id();

    /* Get Dev ID */
    request.devid = devid;

    /* Callback */
    //request.callback = dm_client_thing_sub_unregister_reply;


    /* Send Message To Cloud */
    res = dm_msg_request(&request);

    if (res == SUCCESS_RETURN) {
        res = request.msgid;
    }
    free(request.params);

    return res;
}

int dm_mgr_upstream_thing_topo_add(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
    dm_msg_request_t request;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.service_prefix = DM_URI_SYS_PREFIX;
    request.service_name = DM_URI_THING_TOPO_ADD;
    HAL_GetProduct_Type(request.product_key);
    HAL_GetProduct_Code(request.device_name);

    /* Get Params And Method */
    res = dm_msg_thing_topo_add(node->product_key, node->device_name, node->device_secret, &request);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Get Msg ID */
    request.msgid = iotx_report_id();

    /* Get Dev ID */
    request.devid = devid;

    /* Callback */
    //request.callback = dm_client_thing_topo_add_reply;


    /* Send Message To Cloud */
    res = dm_msg_request(&request);

    if (res == SUCCESS_RETURN) {
        res = request.msgid;
    }
    free(request.params);

    return res;
}

int dm_mgr_upstream_thing_topo_delete(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
    dm_msg_request_t request;

    if (devid < 0) {
        return DM_INVALID_PARAMETER;
    }

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.service_prefix = DM_URI_SYS_PREFIX;
    request.service_name = DM_URI_THING_TOPO_DELETE;
    HAL_GetProduct_Type(request.product_key);
    HAL_GetProduct_Code(request.device_name);

    /* Get Params And Method */
    res = dm_msg_thing_topo_delete(node->product_key, node->device_name, &request);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Get Msg ID */
    request.msgid = iotx_report_id();

    /* Get Dev ID */
    request.devid = devid;

    /* Callback */
    //request.callback = dm_client_thing_topo_delete_reply;


    /* Send Message To Cloud */
    res = dm_msg_request(&request);

    if (res == SUCCESS_RETURN) {
        res = request.msgid;
    }
    free(request.params);

    return res;
}

int dm_mgr_upstream_thing_topo_get(void)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
    dm_msg_request_t request;

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.service_prefix = DM_URI_SYS_PREFIX;
    request.service_name = DM_URI_THING_TOPO_GET;
    HAL_GetProduct_Type(request.product_key);
    HAL_GetProduct_Code(request.device_name);

    res = _dm_mgr_search_dev_by_pkdn(request.product_key, request.device_name, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Get Params And Method */
    res = dm_msg_thing_topo_get(&request);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Get Msg ID */
    request.msgid = iotx_report_id();

    /* Get Dev ID */
    request.devid = node->devid;

    /* Callback */
    //request.callback = dm_client_thing_topo_get_reply;

    /* Send Message To Cloud */
    res = dm_msg_request(&request);
    if (res == SUCCESS_RETURN) {
        res = request.msgid;
    }
    free(request.params);

    return res;
}

int dm_mgr_upstream_thing_list_found(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
    dm_msg_request_t request;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.service_prefix = DM_URI_SYS_PREFIX;
    request.service_name = DM_URI_THING_LIST_FOUND;
    HAL_GetProduct_Type(request.product_key);
    HAL_GetProduct_Code(request.device_name);

    /* Get Params And Method */
    res = dm_msg_thing_list_found(node->product_key, node->device_name, &request);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Get Msg ID */
    request.msgid = iotx_report_id();

    /* Get Dev ID */
    request.devid = devid;

    /* Callback */
    //request.callback = dm_client_thing_list_found_reply;

    /* Send Message To Cloud */
    res = dm_msg_request(&request);
    if (res == SUCCESS_RETURN) {
        res = request.msgid;
    }
    free(request.params);

    return res;
}


int dm_mgr_upstream_combine_login(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
    dm_msg_request_t request;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.service_prefix = DM_URI_EXT_SESSION_PREFIX;
    request.service_name = DM_URI_COMBINE_LOGIN;
    HAL_GetProduct_Type(request.product_key);
    HAL_GetProduct_Code(request.device_name);

    /* Get Params And Method */
    res = dm_msg_combine_login(node->product_key, node->device_name, node->device_secret, &request);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Get Msg ID */
    request.msgid = iotx_report_id();

    /* Get Dev ID */
    request.devid = devid;

    /* Callback */
    //request.callback = dm_client_combine_login_reply;


    /* Send Message To Cloud */
    res = dm_msg_request(&request);

    if (res == SUCCESS_RETURN) {
        res = request.msgid;
    }
    free(request.params);

    return res;
}

int dm_mgr_upstream_combine_logout(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
    dm_msg_request_t request;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.service_prefix = DM_URI_EXT_SESSION_PREFIX;
    request.service_name = DM_URI_COMBINE_LOGOUT;
    HAL_GetProduct_Type(request.product_key);
    HAL_GetProduct_Code(request.device_name);

    /* Get Params And Method */
    res = dm_msg_combine_logout(node->product_key, node->device_name, &request);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* Get Msg ID */
    request.msgid = iotx_report_id();

    /* Get Dev ID */
    request.devid = devid;

    /* Callback */
    //request.callback = dm_client_combine_logout_reply;

    /* Send Message To Cloud */

    /* Send Message To Cloud */
    res = dm_msg_request(&request);

    if (res == SUCCESS_RETURN) {
        res = request.msgid;
    }
    free(request.params);

    return res;
}


int dm_mgr_subdev_create(_IN_ char product_key[PRODUCT_KEY_MAXLEN],
                         _IN_ char device_name[DEVICE_NAME_MAXLEN], _IN_ char device_secret[DEVICE_SECRET_MAXLEN],_IN_ char device_mac[DEVICE_MAC_MAXLEN], _OU_ int *devid){
    int res = 0;
    
    res = dm_mgr_device_create(KK_DM_DEVICE_SUBDEV,product_key,device_name,device_secret,device_mac, devid);
	if (res != SUCCESS_RETURN) {
        printf("subdev open Failed\n");
        return FAIL_RETURN;
    }

    return res;
}
