#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"
#include "kk_log.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";
const char DM_URI_THING_EVENT_PROPERTY_POST_METHOD[]  DM_READ_ONLY = "thing.event.property.post";


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;
        }
    }

    ERROR_PRINT("Device Not Found, devid: %d", devid);
    return FAIL_RETURN;
}
static int _dm_mgr_search_dev_by_pkdn(_IN_ char deviceCode[DEVICE_CODE_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->deviceCode) == strlen(deviceCode)) &&
            (memcmp(search_node->deviceCode, deviceCode, strlen(deviceCode)) == 0)) {
            /* dm_log_debug("Device Found, Product Key: %s, Device Name: %s", product_key, device_name); */
            if (node) {
                *node = search_node;
            }
            return SUCCESS_RETURN;
        }
    }

    ERROR_PRINT("Device Not Found, Device Code: %s", deviceCode);
    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] = {0};
 	char s_IP[NETWORK_ADDR_LEN] = {0};
 	char s_mac[MAC_ADDR_LEN] = {0};
	char s_SN[SN_ADDR_LEN] = {0};
	int port = 0;

	/*******set version***********/
	HAL_GetVersion(version);
	res = kk_tsl_set_value(kk_tsl_set_property_value,devId,KK_TSL_VERSION_IDENTIFIER,NULL,version);
	if(res != SUCCESS_RETURN)
	{
		ERROR_PRINT("[%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_CCU_LANIP_IDENTIFIER,NULL,"0.0.0.0");
	if(res != SUCCESS_RETURN)
	{
		ERROR_PRINT("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	}
	res = kk_tsl_set_value(kk_tsl_set_property_value,devId,KK_TSL_CCU_WANIP_IDENTIFIER,NULL,"0.0.0.0");
	if(res != SUCCESS_RETURN)
	{
		ERROR_PRINT("[%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)
	{
		ERROR_PRINT("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	}	
	
	int wanState = 0;
	res = kk_tsl_set_value(kk_tsl_set_property_value,devId,KK_TSL_CCU_WANSTATE_IDENTIFIER,&wanState,NULL);
	if(res != SUCCESS_RETURN)
	{
		ERROR_PRINT("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	}		

	int IOTCloudState = 0;
	res = kk_tsl_set_value(kk_tsl_set_property_value,devId,KK_TSL_CCU_IOTCLOUD_IDENTIFIER,&IOTCloudState,NULL);
	if(res != SUCCESS_RETURN)
	{
		ERROR_PRINT("[%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)
	{
		ERROR_PRINT("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	}	
	return res;
}
int dm_mgr_device_create(_IN_ int dev_type,_IN_ char productCode[PRODUCT_CODE_MAXLEN], _IN_ char deviceCode[DEVICE_CODE_MAXLEN],
			_IN_ char mac[DEVICE_MAC_MAXLEN],_IN_ char fatherDeviceCode[DEVICE_CODE_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;
	

    if (deviceCode != NULL && strlen(deviceCode) >= DEVICE_CODE_MAXLEN) {
        return INVALID_PARAMETER;
    }

    res = _dm_mgr_search_dev_by_pkdn(deviceCode, &node);
    if (res == SUCCESS_RETURN) {
        if (devid) {
            *devid = node->devid;
        }
        return TSL_ALREADY_EXIST;
    }

    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_CCU)
    	node->devid = 0;
	else
		node->devid = _dm_mgr_next_devid();
    node->dev_type = dev_type;
    node->dev_shadow = NULL;
	if (productCode != NULL) {
    	memcpy(node->productCode, productCode, strlen(productCode));
	}
    if (deviceCode != NULL) {
        memcpy(node->deviceCode, deviceCode, strlen(deviceCode));
    }
    if (mac != NULL) {
        memcpy(node->mac, mac, strlen(mac));
    }	
    if (dev_type != KK_DM_DEVICE_CCU && fatherDeviceCode != NULL) {
        memcpy(node->fatherDeviceCode, fatherDeviceCode, strlen(fatherDeviceCode));
    }
	node->timestamp = HAL_UptimeMs();
    //node->dev_status = IOTX_DM_DEV_STATUS_AUTHORIZED;
	tsl_str = kk_load_json(productCode, dev_type);
	if(tsl_str != NULL)
	{
		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_CCU){
		//_dm_init_tsl_params(node->devid);
	}

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

    return SUCCESS_RETURN;
}
int dm_mgr_search_device_by_pkdn( _IN_ char deviceCode[DEVICE_CODE_MAXLEN],_OU_ int *devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

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

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

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

    return SUCCESS_RETURN;
}


                        
int dm_mgr_get_devicetype_by_devicecode(_IN_ char deviceCode[DEVICE_CODE_MAXLEN], _OU_ int* deviceType)
{
	dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
	dm_mgr_dev_node_t *node = NULL;

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

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


int dm_mgr_get_device_by_devicecode(_IN_ char deviceCode[DEVICE_CODE_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->deviceCode) == strlen(deviceCode)) &&
            (memcmp(search_node->deviceCode, deviceCode, strlen(deviceCode)) == 0)) {
            /* dm_log_debug("Device Found, Product Key: %s, Device Name: %s", product_key, device_name); */
            if (node) {
                *node = search_node;
            }
            return SUCCESS_RETURN;
        }
    }

    ERROR_PRINT("Device Not Found, deviceCode: %s\n", deviceCode);
    return FAIL_RETURN;
}
int dm_mgr_update_timestamp_by_devicecode(_IN_ char deviceCode[DEVICE_CODE_MAXLEN],uint64_t timestamp)
{
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    dm_mgr_dev_node_t *search_node = NULL;

	_dm_mgr_mutex_lock();
    list_for_each_entry(search_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) {
        if ((strlen(search_node->deviceCode) == strlen(deviceCode)) &&
            (memcmp(search_node->deviceCode, deviceCode, strlen(deviceCode)) == 0)) {
            /* dm_log_debug("Device Found, Product Key: %s, Device Name: %s", product_key, device_name); */
			search_node->timestamp = timestamp;
			_dm_mgr_mutex_unlock();
            return SUCCESS_RETURN;
        }
    }
	_dm_mgr_mutex_unlock();
    ERROR_PRINT("Device Not Found, deviceCode: %s\n", deviceCode);
    return FAIL_RETURN;
}
#define TEST_TIMEOUT     600000 // ten minutes
int dm_mgr_check_heartbeat_timeout(uint64_t timestamp)
{
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    dm_mgr_dev_node_t *search_node = NULL;

	_dm_mgr_mutex_lock();
    list_for_each_entry(search_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) {
		if(search_node->dev_type == KK_DM_DEVICE_CCU){
			continue;
		}
		if((timestamp - search_node->timestamp) >= TEST_TIMEOUT/*search_node->hb_timeout*/){
			
			if(search_node->isOffline == 0){
				INFO_PRINT("---------->dev timeout,send offline\n");
				search_node->isOffline = 1;
				iotx_dm_dev_offline(search_node->devid);
				kk_subDev_update_offline(search_node->isOffline,search_node->deviceCode);
			}
			
			//_dm_mgr_mutex_unlock();
			//return DEVICE_HEARTBEAT_TIMEOUT;
		}
		else{
			if(search_node->isOffline == 1){//need send online 
				INFO_PRINT("---------->dev online again,send online\n");
				search_node->isOffline = 0;
				iotx_dm_dev_online(search_node->devid);
				kk_subDev_update_offline(search_node->isOffline,search_node->deviceCode);
			}
		}
    }
	_dm_mgr_mutex_unlock();
    return SUCCESS_RETURN;
}

int dm_mgr_get_devId_by_devicecode(_IN_ char deviceCode[DEVICE_CODE_MAXLEN],_OU_ int *devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

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

    res = dm_mgr_get_device_by_devicecode(deviceCode, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

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

    return SUCCESS_RETURN;
}

static void _dm_mgr_destroy_devlist(void)
{
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    dm_mgr_dev_node_t *del_node = NULL;
    dm_mgr_dev_node_t *next_node = NULL;

    list_for_each_entry_safe(del_node, next_node, &ctx->dev_list, linked_list, dm_mgr_dev_node_t) {
        list_del(&del_node->linked_list);

        //dm_shw_destroy(&del_node->dev_shadow);

        free(del_node);
    }
}

int dm_mgr_init(void)
{
    int res = 0;
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();
    char productCode[PRODUCT_CODE_MAXLEN] = {0};
	char deviceCode[DEVICE_CODE_MAXLEN]= {0};
	char mac[DEVICE_MAC_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); 
	HAL_Get_mac(mac);
	res = dm_mgr_device_create(KK_DM_DEVICE_CCU,KK_DM_CCU_DEVICE_PRODUCT_CODE,"CCU_66666",mac,"",&devId);
	if (res != SUCCESS_RETURN) {
		goto ERROR;
	}
	else{
		_dm_init_tsl_params(devId);
	}

    return SUCCESS_RETURN;

ERROR:
    if (ctx->mutex) {
        kk_MutexDestroy(ctx->mutex);
    }
    memset(ctx, 0, sizeof(dm_mgr_ctx));
    return FAIL_RETURN;
}

int dm_mgr_deinit(void)
{
    dm_mgr_ctx *ctx = _dm_mgr_get_ctx();

    _dm_mgr_mutex_lock();
    _dm_mgr_destroy_devlist();
    _dm_mgr_mutex_unlock();

    if (ctx->mutex) {
        HAL_MutexDestroy(ctx->mutex);
    }

    return SUCCESS_RETURN;
}

const char DM_URI_THING_EVENT_POST[] = "/thing/event/%s/post";
const char DM_MSG_THING_UPSTREAM_REQUEST_PARAMS[] DM_READ_ONLY = "%s";
static int _dm_mgr_upstream_request_assemble(_IN_ int msgid, _IN_ int devid,
        _IN_ char *identify,
        _IN_ char *params, _IN_ int params_len, _IN_ char *method, _OU_ dm_msg_request_t *request)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
	int paramLen = 0;
	int msgTypeLen = 0;
	char *payload_param = NULL;
    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* dm_log_debug("Time Stamp: %s", timestamp); */
    paramLen = strlen(DM_MSG_THING_UPSTREAM_REQUEST_PARAMS) +
                    params_len + 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);

    request->msgid = msgid;
    request->devid = devid;
	msgTypeLen = strlen(DM_URI_THING_EVENT_POST) + strlen(identify) + 1;
    request->msgTypeStr = malloc(msgTypeLen);
	if(request->msgTypeStr == NULL){
		return MEMORY_NOT_ENOUGH;
	}
	memset(request->msgTypeStr,0x0,msgTypeLen);
	snprintf(request->msgTypeStr,msgTypeLen,DM_URI_THING_EVENT_POST,identify);
    memcpy(request->productCode, node->productCode, strlen(node->productCode));	
    memcpy(request->deviceCode, node->deviceCode, strlen(node->deviceCode));
    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, "property",
                                            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.msgTypeStr);	
	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;

    dm_msg_request_t request;

    if (devid < 0 || identifier == NULL || identifier_len <= 0 ||
        method == NULL || 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,identifier,
                                            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(request.msgTypeStr);
	free(request.params);
    return res;
}

const char DM_URI_THING_SERVICE_RESPONSE[] = "/thing/service/%.*s_reply";
static int _kk_mgr_upstream_response_assemble(_IN_ int devid, _IN_ char *msgid, _IN_ int msgid_len,
        _IN_ const char *identfy, _IN_ int code, _OU_ kk_msg_request_payload_t *request, _OU_ kk_msg_response_t *response)
{
    int res = 0;
	int msgTypeLen = 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;

	msgTypeLen = strlen(DM_URI_THING_SERVICE_RESPONSE) + strlen(identfy) + 1;

    response->msgTypeStr = malloc(msgTypeLen);
	if(response->msgTypeStr == NULL){
		return MEMORY_NOT_ENOUGH;
	}
	memset(response->msgTypeStr,0x0,msgTypeLen);
	snprintf(response->msgTypeStr,msgTypeLen,DM_URI_THING_SERVICE_RESPONSE,identfy);
    memcpy(response->productCode, node->productCode, strlen(node->productCode));	
    memcpy(response->deviceCode, node->deviceCode, strlen(node->deviceCode));
    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;
    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 */

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


    dm_msg_response(&request, &response, payload, payload_len, NULL);
	free(response.msgTypeStr);
    free(msgid_str);
    return SUCCESS_RETURN;
}

const char DM_URI_THING_SUB_REGISTER[] = "/thing/sub/register";
int dm_mgr_upstream_thing_sub_register(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_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) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }

	res = dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node);
    if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }
    memset(&request, 0, sizeof(dm_msg_request_t));
    request.msgTypeStr = DM_URI_THING_SUB_REGISTER;
	memcpy(request.productCode,gw_node->productCode,strlen(gw_node->productCode));	
	memcpy(request.deviceCode,gw_node->deviceCode,strlen(gw_node->deviceCode));		
    /* Get Params And Method */
    res = dm_msg_thing_sub_register( node->productCode,node->deviceCode, &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;
}

const char DM_URI_THING_SUB_UNREGISTER[] = "/thing/sub/unregister";
int dm_mgr_upstream_thing_sub_unregister(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_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;
    }
	res = dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node);
    if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.msgTypeStr = DM_URI_THING_SUB_UNREGISTER;
	memcpy(request.productCode,gw_node->productCode,strlen(gw_node->productCode));	
	memcpy(request.deviceCode,gw_node->deviceCode,strlen(gw_node->deviceCode));


    /* Get Params And Method */
    res = dm_msg_thing_sub_unregister(node->deviceCode, &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;
}

const char DM_URI_THING_TOPO_ADD[] = "/thing/topo/add";
int dm_mgr_upstream_thing_topo_add(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_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) {
        ERROR_PRINT("ERROR res:%d\n",res);
        return FAIL_RETURN;
    }
	res = dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node);
	
    if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.msgTypeStr = DM_URI_THING_TOPO_ADD;
	memcpy(request.productCode,gw_node->productCode,strlen(gw_node->productCode));	
	memcpy(request.deviceCode,gw_node->deviceCode,strlen(gw_node->deviceCode));
    

    /* Get Params And Method */
    res = dm_msg_thing_topo_add( node->productCode, node->deviceCode, node->mac,&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;
}

const char DM_URI_THING_TOPO_DELETE[] = "/thing/topo/delete";
int dm_mgr_upstream_thing_topo_delete(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_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;
    }
	
	res = dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node);
    if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.msgTypeStr = DM_URI_THING_TOPO_DELETE;
	memcpy(request.productCode,gw_node->productCode,strlen(gw_node->productCode));	
	memcpy(request.deviceCode,gw_node->deviceCode,strlen(gw_node->deviceCode));



    /* Get Params And Method */
    res = dm_msg_thing_topo_delete( node->deviceCode, &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;
}

const char DM_URI_THING_TOPO_GET[] = "/thing/topo/get";
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.msgTypeStr = DM_URI_THING_TOPO_GET;
    HAL_GetProduct_Code(request.deviceCode);


    res = _dm_mgr_search_dev_by_pkdn(request.deviceCode, &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;
}
const char DM_URI_THING_LIST_FOUND[] = "/thing/list/found";

int dm_mgr_upstream_thing_list_found(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_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;
    }
	res = dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node);
    if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.msgTypeStr = DM_URI_THING_LIST_FOUND;
	memcpy(request.productCode,gw_node->productCode,strlen(gw_node->productCode));	
	memcpy(request.deviceCode,gw_node->deviceCode,strlen(gw_node->deviceCode));


    /* Get Params And Method */
    res = dm_msg_thing_list_found( node->deviceCode, &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;
}
const char DM_URI_STATUS_ONLINE[] = "/thing/status/online";
int dm_mgr_upstream_status_online(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_node = NULL;		
    dm_msg_request_t request;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }
    memset(&request, 0, sizeof(dm_msg_request_t));

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
	if(strlen(node->fatherDeviceCode) > 0){
		res = dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node);
	    if (res != SUCCESS_RETURN) {
			ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	        return FAIL_RETURN;
	    }
		memcpy(request.productCode,gw_node->productCode,strlen(gw_node->productCode));	
		memcpy(request.deviceCode,gw_node->deviceCode,strlen(gw_node->deviceCode));
		
	}else{
		memcpy(request.productCode,node->productCode,strlen(node->productCode));	
		memcpy(request.deviceCode,node->deviceCode,strlen(node->deviceCode));
	}
	


    request.msgTypeStr = DM_URI_STATUS_ONLINE;


    /* Get Params And Method */
    res = dm_msg_status_online( node->productCode, node->deviceCode, &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;
}

const char DM_URI_STATUS_OFFLINE[] = "/thing/status/offline";
int dm_mgr_upstream_status_offline(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_node = NULL;		
    dm_msg_request_t request;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }
    memset(&request, 0, sizeof(dm_msg_request_t));

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
	if(strlen(node->fatherDeviceCode) > 0){
		res = dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node);
	    if (res != SUCCESS_RETURN) {
			ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	        return FAIL_RETURN;
	    }
		memcpy(request.productCode,gw_node->productCode,strlen(gw_node->productCode));	
		memcpy(request.deviceCode,gw_node->deviceCode,strlen(gw_node->deviceCode));
		
	}else{
		memcpy(request.productCode,node->productCode,strlen(node->productCode));	
		memcpy(request.deviceCode,node->deviceCode,strlen(node->deviceCode));
	}
	
    request.msgTypeStr = DM_URI_STATUS_OFFLINE;

    /* Get Params And Method */
    res = dm_msg_status_offline( node->productCode, node->deviceCode, &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;
}


const char DM_URI_COMBINE_LOGIN[] = "/thing/combine/login";
int dm_mgr_upstream_combine_login(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_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;
    }
	res = dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node);
    if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.msgTypeStr = DM_URI_COMBINE_LOGIN;
	memcpy(request.productCode,gw_node->productCode,strlen(gw_node->productCode));	
	memcpy(request.deviceCode,gw_node->deviceCode,strlen(gw_node->deviceCode));


    /* Get Params And Method */
    res = dm_msg_combine_login( node->productCode, node->deviceCode, &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;
}
const char DM_URI_COMBINE_LOGOUT[] = "/thing/combine/logout";
int dm_mgr_upstream_combine_logout(_IN_ int devid)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_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;
    }
	res = dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node);
    if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }

    memset(&request, 0, sizeof(dm_msg_request_t));
    request.msgTypeStr = DM_URI_COMBINE_LOGOUT;
	memcpy(request.productCode,gw_node->productCode,strlen(gw_node->productCode));	
	memcpy(request.deviceCode,gw_node->deviceCode,strlen(gw_node->deviceCode));


    /* Get Params And Method */
    res = dm_msg_combine_logout( node->deviceCode, &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;
}

const char KK_URI_OTA_INFORM[] = "/ota/device/inform/%s/%s";
int dm_mgr_ota_report_version(_IN_ int devid, char *version)
{
    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.msgTypeStr = malloc(strlen(KK_URI_OTA_INFORM)+strlen(node->productCode)+strlen(node->deviceCode)+1);
	if(request.msgTypeStr == NULL){
		return MEMORY_NOT_ENOUGH;
	}
	sprintf(request.msgTypeStr,KK_URI_OTA_INFORM,node->productCode,node->deviceCode);
    memcpy(request.productCode, node->productCode, PRODUCT_CODE_MAXLEN);	
    memcpy(request.deviceCode, node->deviceCode, DEVICE_CODE_MAXLEN);

    /* Get Params And Method */
    res = dm_msg_ota_report_version(version, &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);
	free(request.msgTypeStr);

    return res;
}



int dm_mgr_subdev_create(int devtype,_IN_ char productCode[PRODUCT_CODE_MAXLEN], _IN_ char deviceCode[DEVICE_CODE_MAXLEN],
		_IN_ char mac[DEVICE_MAC_MAXLEN],_IN_ char fatherDeviceCode[DEVICE_CODE_MAXLEN], _OU_ int *devid){
    int res = 0;
    
    res = dm_mgr_device_create(devtype,productCode,deviceCode,mac,fatherDeviceCode, devid);
	if(TSL_ALREADY_EXIST == res)
	{
    	ERROR_PRINT("SUBDEV ALREADY EXIST!!!\n");
	}
    return res;
}

int dm_mgr_subdev_delete(_IN_ char deviceCode[DEVICE_CODE_MAXLEN])
{
	int res = 0;
	dm_mgr_dev_node_t *node = NULL;
	
	INFO_PRINT("dm_mgr_subdev_delete deviceCode:%s\n",deviceCode);
	res = kk_subDev_delete_by_dcode(deviceCode);//delete db data
    if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }

	res = dm_mgr_get_device_by_devicecode(deviceCode,&node);
    if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }

	if(node->dev_type == KK_DM_DEVICE_CCU){
		ERROR_PRINT("ERROR [%s][%d]\n",__FUNCTION__,__LINE__);
        return FAIL_RETURN;
	}

	list_del(&node->linked_list);

	if (node->dev_shadow) {
        kk_tsl_destroy(&node->dev_shadow);
    }

	free(node);
	node = NULL;
	return SUCCESS_RETURN;

}

