/*
 * Copyright (C) 2020-2020 ikonke
 */

//#include "iotx_dm_internal.h"
#include "kk_tsl_common.h"
#include "klist.h"
#include "cJSON.h"
#include "kk_dm_msg.h"
#include "kk_dm_mng.h"
#include "kk_dm_api.h"
#include "kk_tsl_api.h"
#include "com_api.h"
#include "kk_log.h"
#include "kk_area_handle.h"


#define IOTX_LINKKIT_KEY_ID          "id"
#define IOTX_LINKKIT_KEY_CODE        "code"
#define IOTX_LINKKIT_KEY_DEVID       "devid"
#define IOTX_LINKKIT_KEY_SERVICEID   "serviceid"
#define IOTX_LINKKIT_KEY_PROPERTYID  "propertyid"
#define IOTX_LINKKIT_KEY_EVENTID     "eventid"
#define IOTX_LINKKIT_KEY_PAYLOAD     "payload"
#define IOTX_LINKKIT_KEY_CONFIG_ID   "configId"
#define IOTX_LINKKIT_KEY_CONFIG_SIZE "configSize"
#define IOTX_LINKKIT_KEY_GET_TYPE    "getType"
#define IOTX_LINKKIT_KEY_SIGN        "sign"
#define IOTX_LINKKIT_KEY_SIGN_METHOD "signMethod"
#define IOTX_LINKKIT_KEY_URL         "url"
#define IOTX_LINKKIT_KEY_VERSION     "version"
#define IOTX_LINKKIT_KEY_UTC         "utc"
#define IOTX_LINKKIT_KEY_RRPCID      "rrpcid"
#define IOTX_LINKKIT_KEY_CTX         "ctx"
#define IOTX_LINKKIT_KEY_TOPO        "topo"
#define IOTX_LINKKIT_KEY_PRODUCT_KEY "productKey"
#define IOTX_LINKKIT_KEY_TIME        "time"
#define IOTX_LINKKIT_KEY_DATA        "data"

#define IOTX_LINKKIT_SYNC_DEFAULT_TIMEOUT_MS 10000
#define dm_log_err          ERROR_PRINT
#define dm_log_debug        WARNING_PRINT
#define dm_log_info         INFO_PRINT





typedef struct {
    int msgid;
    void *semaphore;
    int code;
    struct list_head linked_list;
} iotx_linkkit_upstream_sync_callback_node_t;

typedef struct {
    void *mutex;
    void *upstream_mutex;
    int is_opened;
    int is_connected;
    struct list_head upstream_sync_callback_list;
} iotx_linkkit_ctx_t;

static iotx_linkkit_ctx_t g_iotx_linkkit_ctx = {0};

static iotx_linkkit_ctx_t *_iotx_linkkit_get_ctx(void)
{
    return &g_iotx_linkkit_ctx;
}

static void _iotx_linkkit_mutex_lock(void)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();
    if (ctx->mutex) {
        HAL_MutexLock(ctx->mutex);
    }
}

static void _iotx_linkkit_mutex_unlock(void)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();
    if (ctx->mutex) {
        HAL_MutexUnlock(ctx->mutex);
    }
}

static int _impl_copy(_IN_ void *input, _IN_ int input_len, _OU_ void **output, _IN_ int output_len)
{
    if (input == NULL || output == NULL || *output != NULL) {
        return INVALID_PARAMETER;
    }

    *output = malloc(output_len);
    if (*output == NULL) {
        return MEMORY_NOT_ENOUGH;
    }
    memset(*output, 0, output_len);
    memcpy(*output, input, input_len);

    return SUCCESS_RETURN;
}

#if 1
static void _iotx_linkkit_upstream_mutex_lock(void)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();
    if (ctx->upstream_mutex) {
        HAL_MutexLock(ctx->upstream_mutex);
    }
}

static void _iotx_linkkit_upstream_mutex_unlock(void)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();
    if (ctx->upstream_mutex) {
        HAL_MutexUnlock(ctx->upstream_mutex);
    }
}


static int _iotx_linkkit_upstream_sync_callback_list_insert(int msgid, void *semaphore,
        iotx_linkkit_upstream_sync_callback_node_t **node)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();
    iotx_linkkit_upstream_sync_callback_node_t *search_node = NULL;

    list_for_each_entry(search_node, &ctx->upstream_sync_callback_list, linked_list,
                        iotx_linkkit_upstream_sync_callback_node_t) {
        if (search_node->msgid == msgid) {
            WARNING_PRINT("Message Already Exist: %d", msgid);
            return FAIL_RETURN;
        }
    }

    search_node = malloc(sizeof(iotx_linkkit_upstream_sync_callback_node_t));
    if (search_node == NULL) {
        dm_log_debug("malloc error");
        return FAIL_RETURN;
    }
    memset(search_node, 0, sizeof(iotx_linkkit_upstream_sync_callback_node_t));
    search_node->msgid = msgid;
    search_node->semaphore = semaphore;
    INIT_LIST_HEAD(&search_node->linked_list);

    list_add(&search_node->linked_list, &ctx->upstream_sync_callback_list);
    INFO_PRINT("New Message, msgid: %d", msgid);

    *node = search_node;
    return SUCCESS_RETURN;
}

static int _iotx_linkkit_upstream_sync_callback_list_remove(int msgid)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();
    iotx_linkkit_upstream_sync_callback_node_t *search_node = NULL;

    list_for_each_entry(search_node, &ctx->upstream_sync_callback_list, linked_list,
                        iotx_linkkit_upstream_sync_callback_node_t) {
        if (search_node->msgid == msgid) {
            INFO_PRINT("Message Found: %d, Delete It \n", msgid);
            HAL_SemaphoreDestroy(search_node->semaphore);
            list_del(&search_node->linked_list);
            free(search_node);
            return SUCCESS_RETURN;
        }
    }

    return FAIL_RETURN;
}

int _iotx_linkkit_upstream_sync_callback_list_search(int msgid,
        iotx_linkkit_upstream_sync_callback_node_t **node)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();
    iotx_linkkit_upstream_sync_callback_node_t *search_node = NULL;

    if (node == NULL || *node != NULL) {
        dm_log_debug("invalid param");
        return FAIL_RETURN;
    }

    list_for_each_entry(search_node, &ctx->upstream_sync_callback_list, linked_list,
                        iotx_linkkit_upstream_sync_callback_node_t) {
        if (search_node->msgid == msgid) {
            dm_log_debug("Sync Message Found: %d", msgid);
            *node = search_node;
            return SUCCESS_RETURN;
        }
    }

    return FAIL_RETURN;
}

static void _iotx_linkkit_upstream_sync_callback_list_destroy(void)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();
    iotx_linkkit_upstream_sync_callback_node_t *search_node = NULL, *next_node = NULL;

    list_for_each_entry_safe(search_node, next_node, &ctx->upstream_sync_callback_list, linked_list,
                             iotx_linkkit_upstream_sync_callback_node_t) {
        list_del(&search_node->linked_list);
        HAL_SemaphoreDestroy(search_node->semaphore);
        free(search_node);
    }
}


static void _iotx_linkkit_upstream_callback_remove(int msgid, int code)
{
     INFO_PRINT("_iotx_linkkit_upstream_callback_remove : [%d] ,code= %d  \n",msgid, code );
    int res = 0;
    iotx_linkkit_upstream_sync_callback_node_t *sync_node = NULL;
    res = _iotx_linkkit_upstream_sync_callback_list_search(msgid, &sync_node);
    if (res == SUCCESS_RETURN) {
        sync_node->code = (code == IOTX_DM_ERR_CODE_SUCCESS) ? (SUCCESS_RETURN) : (FAIL_RETURN);
        INFO_PRINT("Sync Message %d Result: %d", msgid, sync_node->code);
        HAL_SemaphorePost(sync_node->semaphore);
    }
}
#endif

#ifdef LOG_REPORT_TO_CLOUD
    int  report_sample = 0;
#endif
#ifdef ALCS_ENABLED
    extern void dm_server_free_context(_IN_ void *ctx);
#endif
static int s_CloudStatus = 0;
static int s_CloudStatusRecv = 0;

int kk_get_cloudstatus(void){
	return s_CloudStatus;
}
int kk_get_cloud_recv_status(void){
	return s_CloudStatusRecv;
}

int kk_topo_delete_handle(cJSON *payload)
{
	if(payload == NULL){
		return FAIL_RETURN;
	}
	cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR); 
	cJSON *state = cJSON_GetObjectItem(paramStr, MSG_TOPO_CHANGE_TYPE_STR);
	if(state != NULL && state->valueint == 1){
		cJSON *deviceArray = cJSON_GetObjectItem(paramStr, MSG_TOPO_CHANGE_DEVICES_STR);
		if(deviceArray == NULL){
			return FAIL_RETURN;
		}
		cJSON * item = deviceArray->child;
		while(item != NULL){
			char *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR)->valuestring;
			dm_mgr_subdev_delete(deviceCode);
			item = item->next;
		}

	}
	return SUCCESS_RETURN;
	

}
static int kk_service_addRoom_handle(const char *deviceCode, cJSON *params)
{
	dm_mgr_dev_node_t *node = NULL;
	char roomId[32] = {0};
	int res = 0;
	int idx = 0,idxIpt = 0;
	int start  = 0,serverNum = 0;
	kk_tsl_service_t *serviceItem = NULL;
	kk_tsl_data_t* pinputData = NULL;
	cJSON *currentItem  =NULL;
	if(deviceCode == NULL||params == NULL){
		return INVALID_PARAMETER;
	}
    res = dm_mgr_get_device_by_devicecode(deviceCode, &node);
    if (res < SUCCESS_RETURN) {
		ERROR_PRINT("dm_mgr_get_device_by_devicecode failed\n");
        return res;
    }
	cJSON *roomInfoStr = cJSON_GetObjectItem(params, MSG_AREA_ADDROOM_ROOMNAME);	
	if(roomInfoStr == NULL){
		return FAIL_RETURN;
	}
	kk_room_add(roomInfoStr->valuestring,roomId);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_AREA_ADDROOM_NOTIFICATION_ROOMID,NULL,roomId);	
	return SUCCESS_RETURN;
	
}
static int kk_service_deleteRoom_handle(cJSON *params)
{
	if(params == NULL){
		return INVALID_PARAMETER;
	}

	cJSON *roomInfoStr = cJSON_GetObjectItem(params, MSG_AREA_ROOM_ROOMID);	
	if(roomInfoStr == NULL){
		return FAIL_RETURN;
	}
	kk_room_delete(roomInfoStr->valuestring);
	return SUCCESS_RETURN;
	
}
static int kk_service_addDeviceToRoom_handle(cJSON *params)
{
	char epNumStr[10] = {0};
	if(params == NULL){
		return INVALID_PARAMETER;
	}

	cJSON *roomId = cJSON_GetObjectItem(params, MSG_AREA_ROOM_ROOMID);	
	if(roomId == NULL){
		return FAIL_RETURN;
	}
	cJSON *deviceCode = cJSON_GetObjectItem(params, MSG_DEVICE_CODE_STR);	
	if(deviceCode == NULL){
		return FAIL_RETURN;
	}	
	cJSON *epNum = cJSON_GetObjectItem(params, MSG_AREA_ROOM_EPNUM);	
	if(epNum == NULL){
		strcpy(epNumStr,"1");
	}else{
		strcpy(epNumStr,epNum->valuestring);
	}		
	kk_room_dev_add(roomId->valuestring,deviceCode->valuestring,epNumStr);
	return SUCCESS_RETURN;
}
static int kk_service_removeDeviceFromRoom_handle(cJSON *params)
{
	char epNumStr[10] = {0};

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

	cJSON *deviceCode = cJSON_GetObjectItem(params, MSG_DEVICE_CODE_STR);	
	if(deviceCode == NULL){
		return FAIL_RETURN;
	}	
	cJSON *epNum = cJSON_GetObjectItem(params, MSG_AREA_ROOM_EPNUM);	
	if(epNum == NULL){
		strcpy(epNumStr,"1");
	}else{
		strcpy(epNumStr,epNum->valuestring);
	}			
	kk_room_dev_remove(deviceCode->valuestring,epNumStr);
	return SUCCESS_RETURN;
}
static int kk_service_execute_action(cJSON *action,dm_mgr_dev_node_t *node)
{
	int idx = 0;
	kk_tsl_data_t *pCurrentItem = NULL;
	cJSON *pCurrentData = NULL;
	if(node == NULL){
		return INVALID_PARAMETER;
	}
	void *param = cJSON_Print(action);
	kk_msg_execute_property_set(node->productCode,node->deviceCode,param,node->fatherDeviceCode);
	
#if 0	
	for(idx = 0; idx < shadow->property_number; idx++){
		pCurrentItem = shadow->properties + idx;
		if(pCurrentItem != NULL){
			cJSON *pCurrentData = cJSON_GetObjectItem(action, pCurrentItem->identifier);
			if(pCurrentData != NULL){

			}
		}
	}
#endif	
	free(param);
	return SUCCESS_RETURN;


}
static int kk_service_executeRoom_handle(cJSON *params)
{
	int res = 0;
	kk_dev_list_t *pList = NULL;
	dm_mgr_dev_node_t *search_node = NULL;	

	if(params == NULL){
		return INVALID_PARAMETER;
	}
	cJSON *roomId = cJSON_GetObjectItem(params, MSG_AREA_ROOM_ROOMID);	
	if(roomId == NULL){
		return FAIL_RETURN;
	}

	cJSON *productCodeStr = cJSON_GetObjectItem(params, MSG_PRODUCT_TYPE_STR);	
	if(productCodeStr == NULL){
		return FAIL_RETURN;
	}	

	pList = kk_get_room_deviceCode(roomId->valuestring);
	if(pList != NULL){
		while(pList != NULL){
			res = dm_mgr_get_device_by_devicecode(pList->deviceCode,&search_node);
			if (res != SUCCESS_RETURN) {
				pList = pList->next;
		        continue;
		    }
			if(strcmp(search_node->productCode,productCodeStr->valuestring) == 0){
				cJSON *action = cJSON_GetObjectItem(params, MSG_AREA_ROOM_ACTION);
				if(action != NULL){
					kk_service_execute_action(action,search_node);
					
				}
			}
			pList = pList->next;
		}
	}
	kk_free_room_dev_list();
	return SUCCESS_RETURN;
}
static int kk_service_setLocalTimer_handle(cJSON *params,const char *deviceCode)
{
	int res = 0;
	kk_dev_list_t *pList = NULL;
	dm_mgr_dev_node_t *search_node = NULL;	
	char *timer = NULL,*targets = NULL;
	int isEnable  = 0, isValid = 0, zoneOffset = 0;
	int size = 0	;

	if(params == NULL || deviceCode == NULL){
		return INVALID_PARAMETER;
	}
	res = dm_mgr_get_device_by_devicecode(deviceCode,&search_node);	
    if (res < SUCCESS_RETURN) {
		ERROR_PRINT("dm_mgr_get_device_by_devicecode failed\n");
        return res;
    }

	size = kk_service_get_array_size(search_node->dev_shadow);
	
	cJSON *LocalTimerArray = cJSON_GetObjectItem(params, MSG_TIMER_SETLOCALTIMER_LOCALTIMER);	
	if(LocalTimerArray == NULL){
		return FAIL_RETURN;
	}
	cJSON * item = LocalTimerArray->child;
	while(item != NULL){

		timer = cJSON_GetObjectItem(item,MSG_TIMER_SETLOCALTIMER_TIMER)->valuestring;
	    isEnable = cJSON_GetObjectItem(item,MSG_TIMER_SETLOCALTIMER_ENABLE)->valueint;
		isValid = cJSON_GetObjectItem(item,MSG_TIMER_SETLOCALTIMER_ISVALID)->valueint;
		zoneOffset = cJSON_GetObjectItem(item,MSG_TIMER_SETLOCALTIMER_ZONEOFFSET)->valueint;
		targets = cJSON_GetObjectItem(item,MSG_TIMER_SETLOCALTIMER_TARGETS)->valuestring;
		kk_service_localtimer_set(search_node->dev_shadow,timer,isEnable,isValid,zoneOffset,targets,size);
		item = item->next;
	}
	return SUCCESS_RETURN;
}
static int kk_service_getLocalTimer_handle(const char *deviceCode)
{
	if(deviceCode == NULL){
		return INVALID_PARAMETER;
	}
	dm_msg_thing_service_post(deviceCode,MSG_TIMER_GETLOCALTIMER_GETLOCALTIMER);

	return SUCCESS_RETURN;
}

static int kk_service_setCountDown_handle(cJSON *params,const char *deviceCode)
{
	int res = 0;
	kk_dev_list_t *pList = NULL;
	dm_mgr_dev_node_t *search_node = NULL;	
	char *targets = NULL;
	int isEnable  = 0, isValid = 0, delaytimer = 0,current = 0;
	int size = 0	;

	if(params == NULL || deviceCode == NULL){
		return INVALID_PARAMETER;
	}
	res = dm_mgr_get_device_by_devicecode(deviceCode,&search_node);	
    if (res < SUCCESS_RETURN) {
		ERROR_PRINT("dm_mgr_get_device_by_devicecode failed\n");
        return res;
    }

	size = kk_service_get_array_size(search_node->dev_shadow);

	cJSON *LocalTimerArray = cJSON_GetObjectItem(params, MSG_TIMER_SETCOUNTDOWN_COUNTDOWN);	
	if(LocalTimerArray == NULL){
		return FAIL_RETURN;
	}
	cJSON * item = LocalTimerArray->child;
	while(item != NULL){
		delaytimer = cJSON_GetObjectItem(item,MSG_TIMER_SETCOUNTDOWN_DELAYTIME)->valueint;
	    current = cJSON_GetObjectItem(item,MSG_TIMER_SETCOUNTDOWN_CURRENTTIME)->valueint;
		isValid = cJSON_GetObjectItem(item,MSG_TIMER_SETLOCALTIMER_ISVALID)->valueint;
		isEnable = cJSON_GetObjectItem(item,MSG_TIMER_SETLOCALTIMER_ENABLE)->valueint;
		targets = cJSON_GetObjectItem(item,MSG_TIMER_SETLOCALTIMER_TARGETS)->valuestring;
		kk_service_setCountDown_set(search_node->dev_shadow,delaytimer,current,isEnable,isValid,targets,size);
		item = item->next;
	}
	return SUCCESS_RETURN;
}

static int kk_service_getCountDown_handle(const char *deviceCode)
{
	if(deviceCode == NULL){
		return INVALID_PARAMETER;
	}
	dm_msg_thing_service_post(deviceCode,MSG_TIMER_SETCOUNTDOWN_GETCOUNTDOWN);

	return SUCCESS_RETURN;
}

static int kk_service_getLockKeylist_handle(const char *deviceCode)
{
	if(deviceCode == NULL){
		return INVALID_PARAMETER;
	}

	return SUCCESS_RETURN;
}

static int kk_service_addKey_handle(const char *deviceCode,cJSON *param)
{
	char keyId[32] = {0};
	int res = 0;
	dm_mgr_dev_node_t *node = NULL;	
	if(deviceCode == NULL || param == NULL){
		return INVALID_PARAMETER;
	}
    res = dm_mgr_get_device_by_devicecode(deviceCode, &node);
    if (res < SUCCESS_RETURN) {
		ERROR_PRINT("dm_mgr_get_device_by_devicecode failed\n");
        return res;
    }

	cJSON *KeyType = cJSON_GetObjectItem(param,MSG_KEYADD_KEYTYPE);
	if(KeyType == NULL) return FAIL_RETURN;
	cJSON *KeyRole = cJSON_GetObjectItem(param,MSG_KEYADD_KEYROLE);	
	if(KeyRole == NULL) return FAIL_RETURN;
	cJSON *IsValid = cJSON_GetObjectItem(param,MSG_KEYADD_KEYISVALID);	
	if(IsValid == NULL) return FAIL_RETURN;
	cJSON *KeyName = cJSON_GetObjectItem(param,MSG_KEYADD_KEYNAME);
	if(KeyName == NULL) return FAIL_RETURN;;
	cJSON *KeyEffectiveTime = cJSON_GetObjectItem(param,MSG_KEYADD_KEYEFFECTIVE); 
	if(KeyEffectiveTime == NULL) return FAIL_RETURN;;
	cJSON *KeyExpiryTime = cJSON_GetObjectItem(param,MSG_KEYADD_KEYEXPIRE);
	if(KeyExpiryTime == NULL) return FAIL_RETURN;;
	HAL_GetTime_s(keyId);
	kk_property_update_lockkeys(deviceCode,keyId,KeyType->valueint,KeyRole->valueint,IsValid->valueint,
				KeyName->valuestring,KeyEffectiveTime->valueint,KeyExpiryTime->valueint);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYADD_NOTIFICATION_KEYID,NULL,keyId);		
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYADD_NOTIFICATION_KEYTYPE,&KeyType->valueint,NULL);	
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYADD_NOTIFICATION_KEYROLE,&KeyRole->valueint,NULL);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYADD_NOTIFICATION_KEYISVALID,&IsValid->valueint,NULL);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYADD_NOTIFICATION_KEYNAME,NULL,KeyName->valuestring);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYADD_NOTIFICATION_KEYEFFECTIVE,&IsValid->valueint,NULL);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYADD_NOTIFICATION_KEYEXPIRE,&IsValid->valueint,NULL);
	dm_msg_thing_event_post(deviceCode,MSG_KEYADD_NOTIFICATION);

	return SUCCESS_RETURN;
}

static int kk_service_modifyKey_handle(const char *deviceCode,cJSON *param)
{
	int res = 0;
	dm_mgr_dev_node_t *node = NULL;	
	if(deviceCode == NULL || param == NULL){
		return INVALID_PARAMETER;
	}
    res = dm_mgr_get_device_by_devicecode(deviceCode, &node);
    if (res < SUCCESS_RETURN) {
		ERROR_PRINT("dm_mgr_get_device_by_devicecode failed\n");
        return res;
    }
	cJSON *keyId = cJSON_GetObjectItem(param,MSG_KEYADD_KEYID);	
	if(keyId == NULL) return FAIL_RETURN;
	cJSON *KeyType = cJSON_GetObjectItem(param,MSG_KEYADD_KEYTYPE);
	if(KeyType == NULL) return FAIL_RETURN;
	cJSON *KeyRole = cJSON_GetObjectItem(param,MSG_KEYADD_KEYROLE);	
	if(KeyRole == NULL) return FAIL_RETURN;
	cJSON *IsValid = cJSON_GetObjectItem(param,MSG_KEYADD_KEYISVALID);	
	if(IsValid == NULL) return FAIL_RETURN;
	cJSON *KeyName = cJSON_GetObjectItem(param,MSG_KEYADD_KEYNAME);
	if(KeyName == NULL) return FAIL_RETURN;;
	cJSON *KeyEffectiveTime = cJSON_GetObjectItem(param,MSG_KEYADD_KEYEFFECTIVE); 
	if(KeyEffectiveTime == NULL) return FAIL_RETURN;;
	cJSON *KeyExpiryTime = cJSON_GetObjectItem(param,MSG_KEYADD_KEYEXPIRE);
	if(KeyExpiryTime == NULL) return FAIL_RETURN;;

	kk_property_update_lockkeys(deviceCode,keyId->valuestring,KeyType->valueint,KeyRole->valueint,IsValid->valueint,
				KeyName->valuestring,KeyEffectiveTime->valueint,KeyExpiryTime->valueint);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYMODIFY_NOTIFICATION_KEYID,NULL,keyId->valuestring);		
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYMODIFY_NOTIFICATION_KEYTYPE,&KeyType->valueint,NULL);	
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYMODIFY_NOTIFICATION_KEYROLE,&KeyRole->valueint,NULL);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYMODIFY_NOTIFICATION_KEYISVALID,&IsValid->valueint,NULL);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYMODIFY_NOTIFICATION_KEYNAME,NULL,KeyName->valuestring);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYMODIFY_NOTIFICATION_KEYEFFECTIVE,&IsValid->valueint,NULL);
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYMODIFY_NOTIFICATION_KEYEXPIRE,&IsValid->valueint,NULL);
	dm_msg_thing_event_post(deviceCode,MSG_KEYMODIFY_NOTIFICATION);

	return SUCCESS_RETURN;
}

static int kk_service_deleteKey_handle(const char *deviceCode,cJSON *param)
{
	int res = 0;
	dm_mgr_dev_node_t *node = NULL;	
	if(deviceCode == NULL || param == NULL){
		return INVALID_PARAMETER;
	}
    res = dm_mgr_get_device_by_devicecode(deviceCode, &node);
    if (res < SUCCESS_RETURN) {
		ERROR_PRINT("dm_mgr_get_device_by_devicecode failed\n");
        return res;
    }
	cJSON *KeyType = cJSON_GetObjectItem(param,MSG_KEYADD_KEYTYPE);
	if(KeyType == NULL) return FAIL_RETURN;
	cJSON *KeyRole = cJSON_GetObjectItem(param,MSG_KEYADD_KEYROLE);	
	if(KeyRole == NULL) return FAIL_RETURN;
	cJSON *keyId = cJSON_GetObjectItem(param,MSG_KEYADD_KEYID);	
	if(keyId == NULL) return FAIL_RETURN;
	kk_property_delete_lockkeys(deviceCode,keyId->valuestring);
	
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYDELETE_NOTIFICATION_KEYID,NULL,keyId->valuestring);		
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYDELETE_NOTIFICATION_KEYTYPE,&KeyType->valueint,NULL);	
	kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,MSG_KEYDELETE_NOTIFICATION_KEYROLE,&KeyRole->valueint,NULL);
	dm_msg_thing_event_post(deviceCode,MSG_KEYDELETE_NOTIFICATION);

	return SUCCESS_RETURN;
}

static int kk_service_addScene_handle(cJSON *param,cJSON *msgId)
{
	int res = 0;
	char sceneId[32] = {0};
	kk_tsl_t *pSceneShadow = NULL;
	if(param == NULL || msgId == NULL){
		return INVALID_PARAMETER;
	}

	res = kk_scene_parse_addscene(param,sceneId,0);
	if(res == SUCCESS_RETURN){
		pSceneShadow = kk_scene_shadow();
		if(pSceneShadow != NULL){
			kk_tsl_set_value(kk_tsl_set_event_output_value,pSceneShadow,MSG_SCENE_ADDNOTIFICATION_SCENEID,NULL,sceneId);
			dm_msg_scene_event_post(MSG_SCENE_ADDNOTIFICATION,pSceneShadow,msgId->valuestring);		
		}
	}
	return res;
}
static int kk_service_updateScene_handle(cJSON *param,cJSON *msgId)
{
	int res = 0;
	kk_tsl_t *pSceneShadow = NULL;
	if(param == NULL || msgId == NULL){
		return INVALID_PARAMETER;
	}	
	cJSON *sceneId = cJSON_GetObjectItem(param,MSG_SCENE_SCENEID);
	if(sceneId == NULL) return FAIL_RETURN;		
	res = kk_scene_parse_updatescene(param,sceneId->valuestring);
	if(res == SUCCESS_RETURN){
		pSceneShadow = kk_scene_shadow();
		if(pSceneShadow != NULL){
			kk_tsl_set_value(kk_tsl_set_event_output_value,pSceneShadow,MSG_SCENE_UPDATENOTIFICATION_SCENEID,NULL,sceneId->valuestring);
			dm_msg_scene_event_post(MSG_SCENE_UPDATENOTIFICATION,pSceneShadow,msgId->valuestring);		
		}
	}

	return res;
}

static int kk_service_deleteScene_handle(cJSON *param,cJSON *msgId)
{
	int res = 0;
	kk_tsl_t *pSceneShadow = NULL;
	char sceneIdBuf[16] = {0};
	if(param == NULL || msgId == NULL){
		return INVALID_PARAMETER;
	}
	cJSON *sceneId = cJSON_GetObjectItem(param,MSG_SCENE_SCENEID);
	if(sceneId == NULL) return FAIL_RETURN;		
	if(sceneId->valuestring == NULL){
		sprintf(sceneIdBuf,"%d",sceneId->valueint);
		res = kk_scene_parse_deletescene(sceneIdBuf);
	}
	else{
		res = kk_scene_parse_deletescene(sceneId->valuestring);
	}
	if(res == SUCCESS_RETURN){
		pSceneShadow = kk_scene_shadow();
		if(pSceneShadow != NULL){
			if(strlen(sceneIdBuf) > 0){
				kk_tsl_set_value(kk_tsl_set_event_output_value,pSceneShadow,MSG_SCENE_DELETENOTIFICATION_SCENEID,NULL,sceneIdBuf);
			}
			else{
				kk_tsl_set_value(kk_tsl_set_event_output_value,pSceneShadow,MSG_SCENE_DELETENOTIFICATION_SCENEID,NULL,sceneId->valuestring);
			}
			dm_msg_scene_event_post(MSG_SCENE_DELETENOTIFICATION,pSceneShadow,msgId->valuestring);		
		}
	}
	return res;
}
static int kk_service_executeScene_handle(cJSON *param,cJSON *msgId)
{
	int res = 0;

	if(param == NULL || msgId == NULL){
		return INVALID_PARAMETER;
	}
	cJSON *sceneId = cJSON_GetObjectItem(param,MSG_SCENE_SCENEID);
	if(sceneId == NULL) return FAIL_RETURN;		

	res = kk_scene_execute_scene(sceneId->valuestring,msgId->valuestring);

	return res;
}

static void _iotx_linkkit_event_callback(iotx_dm_event_types_t type, char *data)
{
    char *out;
    int res = 0;
    cJSON *json;
    cJSON *info_root;
    cJSON *payload,*typeJson;
	char *payload_Str = NULL;
	cJSON *deviceCode = NULL;
    json=cJSON_Parse(data);
	if (json == NULL) {
        WARNING_PRINT("Error before: [%s]\n","cJSON_Parse");
		return;
    }
    info_root = cJSON_GetObjectItem(json, MSG_INFO_STR);
	if(info_root == NULL) return;
	typeJson = cJSON_GetObjectItem(info_root, MSG_TYPE_STR);
	if(typeJson == NULL) return;	
	payload = cJSON_GetObjectItem(json, MSG_PAYLOAD_STR);
	if(payload == NULL) return;
	payload_Str = cJSON_Print(payload);
	deviceCode = cJSON_GetObjectItem(info_root, MSG_DEVICE_CODE_STR);
	if(deviceCode == NULL) return;

    if (strstr(typeJson->valuestring,KK_REGISTER_TOPIC_REPLY)){
        INFO_PRINT(" topic:register_reply  \n");
        dm_msg_response_payload_t response;
        res = dm_msg_response_parse((char *)payload_Str, strlen(payload->valuestring)+1, &response);
        if (res != SUCCESS_RETURN) {
            goto directReturn;
        }
          
        _iotx_linkkit_upstream_mutex_lock();
        _iotx_linkkit_upstream_callback_remove(atoi(response.id.value), response.code.value_int);
        _iotx_linkkit_upstream_mutex_unlock();

   }else if (strstr(typeJson->valuestring,KK_ADD_TOPIC_REPLY)){
        INFO_PRINT(" topic:add_reply  \n");
        dm_msg_response_payload_t response;
        res = dm_msg_response_parse((char *)payload_Str, strlen(payload->valuestring)+1, &response);
        if (res != SUCCESS_RETURN) {
            goto directReturn;
        }
          
        _iotx_linkkit_upstream_mutex_lock();
        _iotx_linkkit_upstream_callback_remove(atoi(response.id.value), response.code.value_int);
        _iotx_linkkit_upstream_mutex_unlock();
        
   }else if (strstr(typeJson->valuestring,KK_LOGIN_TOPIC_REPLY)){
        INFO_PRINT(" topic:login_reply  \n");
        dm_msg_response_payload_t response;
        res = dm_msg_response_parse((char *)payload_Str, strlen(payload->valuestring)+1, &response);
        if (res != SUCCESS_RETURN) {
            goto directReturn;
        }
          
        _iotx_linkkit_upstream_mutex_lock();
        _iotx_linkkit_upstream_callback_remove(atoi(response.id.value), response.code.value_int);
        _iotx_linkkit_upstream_mutex_unlock();
   }else if (strstr(typeJson->valuestring,KK_THING_SERVICE_PROPERTY_SET)){
        INFO_PRINT("property set \n");	
        dm_msg_thing_property_set_reply(deviceCode->valuestring,payload_Str, strlen(payload_Str), NULL);
   }else if (strstr(typeJson->valuestring,KK_THING_CLOUDSTATE_MSG)){
        INFO_PRINT("cloud state notify \n");
		s_CloudStatusRecv = 1;
		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
		cJSON *state = cJSON_GetObjectItem(paramStr, MSG_IOTClOUDSTATE_STR);
		s_CloudStatus = atoi(state->valuestring);

		dm_mgr_dev_node_t *node = NULL;
		dm_mgr_search_dev_by_devid(KK_DM_DEVICE_CCU_DEVICEID,&node);
		res = kk_tsl_set_value(kk_tsl_set_property_value,node->dev_shadow,KK_TSL_CCU_WANSTATE_IDENTIFIER,&s_CloudStatus,NULL);
		if(res != SUCCESS_RETURN)
		{
			ERROR_PRINT("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
		}	

		res = kk_tsl_set_value(kk_tsl_set_property_value,node->dev_shadow,KK_TSL_CCU_IOTCLOUD_IDENTIFIER,&s_CloudStatus,NULL);
		if(res != SUCCESS_RETURN)
		{
			ERROR_PRINT("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
		}		

		kk_property_db_update("CCU_66666");

		if(s_CloudStatus){
			node->isOffline = KK_DEV_ONLINE;

			iotx_dm_dev_online(KK_DM_DEVICE_CCU_DEVICEID);//first online,report the online status
			usleep(200000);
			dm_msg_ccu_property_post(node);
		}

   }else if (strstr(typeJson->valuestring,KK_THING_OTA_DEVICE_UPGRADE)){
        INFO_PRINT("ota upgrade... \n");
        kk_dm_ota_send(data, strlen(data)+1);
        
   }else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_REBOOT) == 0){
   		INFO_PRINT(" reboot called!!!\n");	
		dm_msg_thing_event_post(deviceCode->valuestring,MSG_REBOOT_REBOOTNOTIFICATION);
		sleep(3);
		HAL_Reboot();
   }
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_ADDROOM) == 0){
		INFO_PRINT(" add room!!!\n");
		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
		kk_service_addRoom_handle(deviceCode->valuestring,paramStr);
		dm_msg_thing_event_post(deviceCode->valuestring,MSG_AREA_ADDROOM_NOTIFICATION);
   }
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_DELETEROOM) == 0){
   	    INFO_PRINT(" delete room  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
   		kk_service_deleteRoom_handle(paramStr);

   }
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_ADDDEVICETOROOM) == 0){
   	    INFO_PRINT(" adddevicetoroom  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
   		kk_service_addDeviceToRoom_handle(paramStr);
   }  
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_REMOVEDEVICEFROMROOM) == 0){
   		INFO_PRINT(" removedevicefromroom  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
   		kk_service_removeDeviceFromRoom_handle(paramStr);
   }   
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_EXECUTEROOM) == 0){
   	    INFO_PRINT(" executeroom  \n");
	    cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR); 
	    kk_service_executeRoom_handle(paramStr);

   }
#if 0   
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_SETLOCALTIMER) == 0){
   		INFO_PRINT(" setlocaltimer  \n");
		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
		
		kk_service_setLocalTimer_handle(paramStr,deviceCode->valuestring);
   }
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_GETLOCALTIMER) == 0){
   		INFO_PRINT(" getlocaltimer  \n");
		kk_service_getLocalTimer_handle(deviceCode->valuestring);
   }   
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_SETCOUNTDOWN) == 0){
   		INFO_PRINT(" set count down  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
		kk_service_setCountDown_handle(paramStr,deviceCode->valuestring);
   }   
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_GETCOUNTDOWN) == 0){
   		INFO_PRINT(" get count down  \n");
		kk_service_getCountDown_handle(deviceCode->valuestring);
   }  
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_GETKEYLIST) == 0){
   		INFO_PRINT(" get key list  \n");
		kk_service_getLockKeylist_handle(deviceCode->valuestring);
   }  
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_ADDKEY) == 0){
   		INFO_PRINT(" add key  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
		kk_service_addKey_handle(deviceCode->valuestring,paramStr);

   }   
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_MODIFYKEY) == 0){
   		INFO_PRINT(" modify key  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
		kk_service_modifyKey_handle(deviceCode->valuestring,paramStr);

   }     
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_DELETEKEY) == 0){
   		INFO_PRINT(" delete key  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
		kk_service_deleteKey_handle(deviceCode->valuestring,paramStr);

   }    
#endif   
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_ADDSCENC) == 0){
   		INFO_PRINT(" add scene  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
     	cJSON *msgId = cJSON_GetObjectItem(payload, MSG_SCENE_MSGID);	 
		kk_service_addScene_handle(paramStr,msgId);
   }    
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_UPDATESCENC) == 0){
   		INFO_PRINT(" update scene  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
   		cJSON *msgId = cJSON_GetObjectItem(payload, MSG_SCENE_MSGID);
		kk_service_updateScene_handle(paramStr,msgId);
   }    
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_DELETESCENC) == 0){
   		INFO_PRINT("delete scene  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
   		cJSON *msgId = cJSON_GetObjectItem(payload, MSG_SCENE_MSGID);
		kk_service_deleteScene_handle(paramStr,msgId);
   }   
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_EXECUTESCENE) == 0){
   		INFO_PRINT("execute scene  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
   		cJSON *msgId = cJSON_GetObjectItem(payload, MSG_SCENE_MSGID);
		kk_service_executeScene_handle(paramStr,msgId);
   }  
   else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_NEGATIVE) == 0){
   		INFO_PRINT("negative service  \n");
   		cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);	
   		if(paramStr != NULL){
			cJSON *identifierStr = cJSON_GetObjectItem(paramStr, MSG_SCENE_NEGATICE);
			if(identifierStr != NULL){
				int value_ = 0;
				dm_mgr_dev_node_t *node = NULL;	
				kk_property_db_get_value(deviceCode->valuestring,identifierStr->valuestring, &value_);
				value_ = !value_;
				res = dm_mgr_get_device_by_devicecode(deviceCode->valuestring, &node);
				if (res != SUCCESS_RETURN) {
					goto directReturn;
				}
				cJSON *root_ =cJSON_CreateObject();
				cJSON_AddNumberToObject(root_,identifierStr->valuestring,value_);
				char *out_=cJSON_Print(root_);
				kk_msg_execute_property_set(node->productCode,node->deviceCode,out_,node->fatherDeviceCode);
				cJSON_Delete(root_); 
				free(out_);
			}
			
		}
   }     
   else{
        INFO_PRINT("Error msgtype!!! \n");
        
   }
   
directReturn:
   free(payload_Str);
   cJSON_Delete(json);    
}

int kk_init_dmproc(){
    int res = 0;
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();

    res = iotx_dm_open();
    if (res != SUCCESS_RETURN) {
        dm_log_err("DM iotx_dm_open Failed");

        return FAIL_RETURN;
    }

    res = iotx_dm_connect(_iotx_linkkit_event_callback);
    if (res != SUCCESS_RETURN) {
        dm_log_err("DM Start Failed");
        //ctx->is_connected = 0;
        return FAIL_RETURN;
    }
    
    if (ctx->is_opened) {
        return FAIL_RETURN;
    }
    ctx->is_opened = 1;


    /* Create Mutex */
    ctx->mutex = HAL_MutexCreate();
    if (ctx->mutex == NULL) {
        dm_log_err("Not Enough Memory");
        ctx->is_opened = 0;
        return FAIL_RETURN;
    }


    ctx->upstream_mutex = HAL_MutexCreate();
    if (ctx->upstream_mutex == NULL) {
        HAL_MutexDestroy(ctx->mutex);
        dm_log_err("Not Enough Memory");
        ctx->is_opened = 0;
        return FAIL_RETURN;
    }


    INIT_LIST_HEAD(&ctx->upstream_sync_callback_list);

    return SUCCESS_RETURN;
}

int _iotx_linkkit_slave_connect(int devid)
{
    int res = 0, msgid = 0, code = 0;
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();
    iotx_linkkit_upstream_sync_callback_node_t *node = NULL;
    void *semaphore = NULL;



    if (devid <= 0) {
        dm_log_err("devid invalid");
        return FAIL_RETURN;
    }



    /* Subdev Add Topo */
    res = kk_dm_subdev_topo_add(devid);
    if (res < SUCCESS_RETURN) {
        _iotx_linkkit_mutex_unlock();
        return FAIL_RETURN;
    }


    return SUCCESS_RETURN;
}

static int _iotx_linkkit_subdev_delete_topo(int devid)
{
    int res = 0, msgid = 0, code = 0;
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();
    iotx_linkkit_upstream_sync_callback_node_t *node = NULL;
    void *semaphore = NULL;

    if (ctx->is_connected == 0) {
        dm_log_err("master isn't start");
        return FAIL_RETURN;
    }

    if (devid <= 0) {
        dm_log_err("devid invalid");
        return FAIL_RETURN;
    }

    /* Subdev Delete Topo */
    res = iotx_dm_subdev_topo_del(devid);
    if (res < SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
    msgid = res;

    semaphore = HAL_SemaphoreCreate();
    if (semaphore == NULL) {
        return FAIL_RETURN;
    }

    _iotx_linkkit_upstream_mutex_lock();
    res = _iotx_linkkit_upstream_sync_callback_list_insert(msgid, semaphore, &node);
    if (res != SUCCESS_RETURN) {
        HAL_SemaphoreDestroy(semaphore);
        _iotx_linkkit_upstream_mutex_unlock();
        return FAIL_RETURN;
    }
    _iotx_linkkit_upstream_mutex_unlock();

    res = HAL_SemaphoreWait(semaphore, IOTX_LINKKIT_SYNC_DEFAULT_TIMEOUT_MS);
    if (res < SUCCESS_RETURN) {
        _iotx_linkkit_upstream_mutex_lock();
        _iotx_linkkit_upstream_sync_callback_list_remove(msgid);
        _iotx_linkkit_upstream_mutex_unlock();
        return FAIL_RETURN;
    }

    _iotx_linkkit_upstream_mutex_lock();
    code = node->code;
    _iotx_linkkit_upstream_sync_callback_list_remove(msgid);
    if (code != SUCCESS_RETURN) {
        _iotx_linkkit_upstream_mutex_unlock();
        return FAIL_RETURN;
    }
    _iotx_linkkit_upstream_mutex_unlock();

    return SUCCESS_RETURN;
}

static int _iotx_linkkit_master_close(void)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();

    _iotx_linkkit_mutex_lock();
    if (ctx->is_opened == 0) {
        _iotx_linkkit_mutex_unlock();
        return FAIL_RETURN;
    }
    ctx->is_opened = 0;

    //iotx_dm_close();
#if 1//DEVICE_MODEL_GATEWAY
    _iotx_linkkit_upstream_sync_callback_list_destroy();
    HAL_MutexDestroy(ctx->upstream_mutex);
#endif
    _iotx_linkkit_mutex_unlock();
    HAL_MutexDestroy(ctx->mutex);
    memset(ctx, 0, sizeof(iotx_linkkit_ctx_t));

    return SUCCESS_RETURN;
}

#if 1//DEVICE_MODEL_GATEWAY
static int _iotx_linkkit_slave_close(int devid)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();

    _iotx_linkkit_mutex_lock();
    if (ctx->is_opened == 0) {
        _iotx_linkkit_mutex_unlock();
        return FAIL_RETURN;
    }

    /* Release Subdev Resources */
    //iotx_dm_subdev_destroy(devid);

    _iotx_linkkit_mutex_unlock();

    return SUCCESS_RETURN;
}
#endif

/*int IOT_Linkkit_Open(iotx_linkkit_dev_type_t dev_type, iotx_linkkit_dev_meta_info_t *meta_info)
{
    int res = 0;

    if (dev_type < 0 || dev_type >= IOTX_LINKKIT_DEV_TYPE_MAX || meta_info == NULL) {
        dm_log_err("Invalid Parameter");
        return FAIL_RETURN;
    }

    switch (dev_type) {
        case IOTX_LINKKIT_DEV_TYPE_MASTER: {
            res = _iotx_linkkit_master_open(meta_info);
            if (res == SUCCESS_RETURN) {
                res = IOTX_DM_LOCAL_NODE_DEVID;
            }
        }
        break;
        case IOTX_LINKKIT_DEV_TYPE_SLAVE: {
#if 1//DEVICE_MODEL_GATEWAY
            res = _iotx_linkkit_slave_open(meta_info);
#else
            res = FAIL_RETURN;
#endif
        }
        break;
        default: {
            dm_log_err("Unknown Device Type");
            res = FAIL_RETURN;
        }
        break;
    }

    return res;
}*/

/*int IOT_Linkkit_Connect(int devid)
{
    int res = 0;
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();

    if (devid < 0) {
        dm_log_err("Invalid Parameter");
        return FAIL_RETURN;
    }

    if (ctx->is_opened == 0) {

        return FAIL_RETURN;
    }

    _iotx_linkkit_mutex_lock();

    if (devid == IOTX_DM_LOCAL_NODE_DEVID) {
        res = _iotx_linkkit_master_connect();
    } else {
        res = _iotx_linkkit_slave_connect(devid);

    }
    _iotx_linkkit_mutex_unlock();

    return res;
}*/

void IOT_Linkkit_Yield(int timeout_ms)
{
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();

    if (timeout_ms <= 0) {
        dm_log_err("Invalid Parameter");
        return;
    }

    //if (ctx->is_opened == 0 || ctx->is_connected == 0) {
    //    return;
    //}

    //iotx_dm_yield(timeout_ms);
    iotx_dm_dispatch();

#if 1//DEVICE_MODEL_GATEWAY
    HAL_SleepMs(timeout_ms);
#endif
}

int IOT_Linkkit_Close(int devid)
{
    int res = 0;

    if (devid < 0) {
        dm_log_err("Invalid Parameter");
        return FAIL_RETURN;
    }

    if (devid == IOTX_DM_LOCAL_NODE_DEVID) {
        res = _iotx_linkkit_master_close();
#ifdef DEV_BIND_ENABLED
        awss_bind_deinit();
#endif
    } else {
#if 1//DEVICE_MODEL_GATEWAY
        res = _iotx_linkkit_slave_close(devid);
#else
        res = FAIL_RETURN;
#endif
    }

    return res;
}

#if 1//DEVICE_MODEL_GATEWAY
static int _iotx_linkkit_subdev_login(int devid)
{
    int res = 0, msgid = 0, code = 0;
    iotx_linkkit_upstream_sync_callback_node_t *node = NULL;
    void *semaphore = NULL;
    void *callback = NULL;

    res = iotx_dm_dev_online(devid);//iotx_dm_subdev_login(devid);
    if (res < SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

#ifdef MSG_NEED_RESP
    msgid = res;
    semaphore = HAL_SemaphoreCreate();
    if (semaphore == NULL) {
        return FAIL_RETURN;
    }

    _iotx_linkkit_upstream_mutex_lock();
    res = _iotx_linkkit_upstream_sync_callback_list_insert(msgid, semaphore, &node);
    if (res != SUCCESS_RETURN) {
        HAL_SemaphoreDestroy(semaphore);
        _iotx_linkkit_upstream_mutex_unlock();
        return FAIL_RETURN;
    }
    _iotx_linkkit_upstream_mutex_unlock();

    res = HAL_SemaphoreWait(semaphore, IOTX_LINKKIT_SYNC_DEFAULT_TIMEOUT_MS);
    if (res < SUCCESS_RETURN) {
        _iotx_linkkit_upstream_mutex_lock();
        _iotx_linkkit_upstream_sync_callback_list_remove(msgid);
        _iotx_linkkit_upstream_mutex_unlock();
        return FAIL_RETURN;
    }

    _iotx_linkkit_upstream_mutex_lock();
    code = node->code;
    _iotx_linkkit_upstream_sync_callback_list_remove(msgid);
    if (code != SUCCESS_RETURN) {
        _iotx_linkkit_upstream_mutex_unlock();
        return FAIL_RETURN;
    }
    _iotx_linkkit_upstream_mutex_unlock();
#endif
     
    res = iotx_dm_subscribe(devid);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /*iotx_dm_send_aos_active(devid);
    callback = iotx_event_callback(ITE_INITIALIZE_COMPLETED);
    if (callback) {
        ((int (*)(const int))callback)(devid);
    }*/

    return res;
}

static int _iotx_linkkit_subdev_logout(int devid)
{
    int res = 0, msgid = 0, code = 0;
    iotx_linkkit_upstream_sync_callback_node_t *node = NULL;
    void *semaphore = NULL;

    res = iotx_dm_subdev_logout(devid);
    if (res < SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    msgid = res;
    semaphore = HAL_SemaphoreCreate();
    if (semaphore == NULL) {
        return FAIL_RETURN;
    }

    _iotx_linkkit_upstream_mutex_lock();
    res = _iotx_linkkit_upstream_sync_callback_list_insert(msgid, semaphore, &node);
    if (res != SUCCESS_RETURN) {
        HAL_SemaphoreDestroy(semaphore);
        _iotx_linkkit_upstream_mutex_unlock();
        return FAIL_RETURN;
    }
    _iotx_linkkit_upstream_mutex_unlock();

    res = HAL_SemaphoreWait(semaphore, IOTX_LINKKIT_SYNC_DEFAULT_TIMEOUT_MS);
    if (res < SUCCESS_RETURN) {
        _iotx_linkkit_upstream_mutex_lock();
        _iotx_linkkit_upstream_sync_callback_list_remove(msgid);
        _iotx_linkkit_upstream_mutex_unlock();
        return FAIL_RETURN;
    }

    _iotx_linkkit_upstream_mutex_lock();
    code = node->code;
    _iotx_linkkit_upstream_sync_callback_list_remove(msgid);
    if (code != SUCCESS_RETURN) {
        _iotx_linkkit_upstream_mutex_unlock();
        return FAIL_RETURN;
    }
    _iotx_linkkit_upstream_mutex_unlock();

    return res;
}
#endif

/*int IOT_Linkkit_Report(int devid, iotx_linkkit_msg_type_t msg_type, unsigned char *payload, int payload_len)
{
    int res = 0;
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();

    if (devid < 0 || msg_type < 0 || msg_type >= IOTX_LINKKIT_MSG_MAX) {
        dm_log_err("Invalid Parameter");
        return FAIL_RETURN;
    }

    if (ctx->is_opened == 0 || ctx->is_connected == 0) {
        return FAIL_RETURN;
    }

    _iotx_linkkit_mutex_lock();
    switch (msg_type) {
#if !defined(DEVICE_MODEL_RAWDATA_SOLO)
        case ITM_MSG_POST_PROPERTY: {
            if (payload == NULL || payload_len <= 0) {
                dm_log_err("Invalid Parameter");
                _iotx_linkkit_mutex_unlock();
                return FAIL_RETURN;
            }
            res = iotx_dm_post_property(devid, (char *)payload, payload_len);
#ifdef LOG_REPORT_TO_CLOUD
            if (1 == report_sample) {
                send_permance_info(NULL, 0, "4", 1);
            }
#endif
        }
        break;
#ifdef DEVICE_MODEL_SHADOW
        case ITM_MSG_PROPERTY_DESIRED_GET: {
            if (payload == NULL || payload_len <= 0) {
                dm_log_err("Invalid Parameter");
                _iotx_linkkit_mutex_unlock();
                return FAIL_RETURN;
            }
            res = iotx_dm_property_desired_get(devid, (char *)payload, payload_len);
        }
        break;
        case ITM_MSG_PROPERTY_DESIRED_DELETE: {
            if (payload == NULL || payload_len <= 0) {
                dm_log_err("Invalid Parameter");
                _iotx_linkkit_mutex_unlock();
                return FAIL_RETURN;
            }
            res = iotx_dm_property_desired_delete(devid, (char *)payload, payload_len);
        }
        break;
#endif
        case ITM_MSG_DEVICEINFO_UPDATE: {
            if (payload == NULL || payload_len <= 0) {
                dm_log_err("Invalid Parameter");
                _iotx_linkkit_mutex_unlock();
                return FAIL_RETURN;
            }
            res = iotx_dm_deviceinfo_update(devid, (char *)payload, payload_len);
        }
        break;
        case ITM_MSG_DEVICEINFO_DELETE: {
            if (payload == NULL || payload_len <= 0) {
                dm_log_err("Invalid Parameter");
                _iotx_linkkit_mutex_unlock();
                return FAIL_RETURN;
            }
            res = iotx_dm_deviceinfo_delete(devid, (char *)payload, payload_len);
        }
        break;
#endif
        case ITM_MSG_POST_RAW_DATA: {
            if (payload == NULL || payload_len <= 0) {
                dm_log_err("Invalid Parameter");
                _iotx_linkkit_mutex_unlock();
                return FAIL_RETURN;
            }
            res = iotx_dm_post_rawdata(devid, (char *)payload, payload_len);
        }
        break;
        case ITM_MSG_LOGIN: {
#if 1//DEVICE_MODEL_GATEWAY
            res = _iotx_linkkit_subdev_login(devid);
            if (res != SUCCESS_RETURN) {
                _iotx_linkkit_mutex_unlock();
                return FAIL_RETURN;
            }
#else
            res = FAIL_RETURN;
#endif
        }
        break;
        case ITM_MSG_LOGOUT: {
#if 1//DEVICE_MODEL_GATEWAY
            res = _iotx_linkkit_subdev_logout(devid);
            if (res != SUCCESS_RETURN) {
                _iotx_linkkit_mutex_unlock();
                return FAIL_RETURN;
            }
#else
            res = FAIL_RETURN;
#endif
        }
        break;
        case ITM_MSG_DELETE_TOPO: {
#if 1//DEVICE_MODEL_GATEWAY
            res = _iotx_linkkit_subdev_delete_topo(devid);
            if (res != SUCCESS_RETURN) {
                _iotx_linkkit_mutex_unlock();
                return FAIL_RETURN;
            }
#else
            res = FAIL_RETURN;
#endif
        }
        break;
#if 1//DEVICE_MODEL_GATEWAY
#ifdef DEVICE_MODEL_SUBDEV_OTA
        case ITM_MSG_REPORT_SUBDEV_FIRMWARE_VERSION: {
            res = iotx_dm_send_firmware_version(devid, (const char *)payload);
        }
        break;
#endif
#endif
        default: {
            dm_log_err("Unknown Message Type");
            res = FAIL_RETURN;
        }
        break;
    }
    _iotx_linkkit_mutex_unlock();
    return res;
}

int IOT_Linkkit_Query(int devid, iotx_linkkit_msg_type_t msg_type, unsigned char *payload, int payload_len)
{
    int res = 0;
#if 1
iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();

    if (devid < 0 || msg_type < 0 || msg_type >= IOTX_LINKKIT_MSG_MAX) {
        dm_log_err("Invalid Parameter");
        return FAIL_RETURN;
    }

    if (ctx->is_opened == 0 || ctx->is_connected == 0) {
        return FAIL_RETURN;
    }

    _iotx_linkkit_mutex_lock();
    switch (msg_type) {
#if !defined(DEVICE_MODEL_RAWDATA_SOLO)
        case ITM_MSG_QUERY_TIMESTAMP: {
            res = iotx_dm_qurey_ntp();
        }
        break;
#endif
        case ITM_MSG_QUERY_TOPOLIST: {
#if 1//DEVICE_MODEL_GATEWAY
            res = iotx_dm_query_topo_list();
#else
            res = FAIL_RETURN;
#endif
        }
        break;
        case ITM_MSG_QUERY_FOTA_DATA: {
            res = iotx_dm_fota_perform_sync((char *)payload, payload_len);
        }
        break;
        case ITM_MSG_QUERY_COTA_DATA: {
            res = iotx_dm_cota_perform_sync((char *)payload, payload_len);
        }
        break;
        case ITM_MSG_REQUEST_COTA: {
            res = iotx_dm_cota_get_config("product", "file", "");
        }
        break;
        case ITM_MSG_REQUEST_FOTA_IMAGE: {
            res = iotx_dm_fota_request_image((const char *)payload, payload_len);
        }
        break;
        default: {
            dm_log_err("Unknown Message Type");
            res = FAIL_RETURN;
        }
        break;
    }
    _iotx_linkkit_mutex_unlock();
    return res;
}

int IOT_Linkkit_TriggerEvent(int devid, char *eventid, int eventid_len, char *payload, int payload_len)
{
#if !defined(DEVICE_MODEL_RAWDATA_SOLO)
    int res = 0;
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();

    if (devid < 0 || eventid == NULL || eventid_len <= 0 || payload == NULL || payload_len <= 0) {
        dm_log_err("Invalid Parameter");
        return FAIL_RETURN;
    }

    if (ctx->is_opened == 0 || ctx->is_connected == 0) {
        return FAIL_RETURN;
    }

    _iotx_linkkit_mutex_lock();
    res = iotx_dm_post_event(devid, eventid, eventid_len, payload, payload_len);
    _iotx_linkkit_mutex_unlock();

    return res;
#else
    return -1;
#endif
#endif
    return -1;

}*/

#if 0//DEVICE_MODEL_GATEWAY
int iot_linkkit_subdev_query_id(char product_key[IOTX_PRODUCT_KEY_LEN + 1], char device_name[IOTX_DEVICE_NAME_LEN + 1])
{
    int res = -1;
    iotx_linkkit_ctx_t *ctx = _iotx_linkkit_get_ctx();

    if (ctx->is_opened == 0) {
        return res;
    }

    iotx_dm_subdev_query(product_key, device_name, &res);
    return res;
}
#endif /* #ifdef DEVICE_MODEL_GATEWAY */


int kk_mid_subdev_add(int devType, char productCode[PRODUCT_CODE_MAXLEN], char deviceCode[DEVICE_CODE_MAXLEN],char mac[DEVICE_MAC_MAXLEN],char fatherDeviceCode[DEVICE_CODE_MAXLEN]){
    int res = 0;
    int devid = 0;
	int heartbeat = 0;
    dm_mgr_dev_node_t *node = NULL;	
    res = dm_mgr_subdev_create(devType,productCode,deviceCode,mac,fatherDeviceCode,KK_DEV_ONLINE,&devid,&heartbeat);
	if (res != SUCCESS_RETURN && TSL_ALREADY_EXIST != res) {
        ERROR_PRINT("subdev create Failed\n");
        return FAIL_RETURN;
    }

    if (TSL_ALREADY_EXIST == res){
        //todo
    }else{
        res = kk_subDev_insert_db(devType,productCode,deviceCode,fatherDeviceCode,mac,"1.1.0",heartbeat);
        if (res != SUCCESS_RETURN) {
            return FAIL_RETURN;
        }
		res = dm_mgr_get_device_by_devicecode(deviceCode, &node);
		if (res != SUCCESS_RETURN) {
			return FAIL_RETURN;
		}
		kk_subDev_update_productType(node->productType,deviceCode);
    }

	_iotx_linkkit_mutex_lock();
    res = _iotx_linkkit_slave_connect(devid);
    if (res != SUCCESS_RETURN) {

        _iotx_linkkit_mutex_unlock();
        return FAIL_RETURN;
    }

    res = _iotx_linkkit_subdev_login(devid);
    if (res != SUCCESS_RETURN) {
        _iotx_linkkit_mutex_unlock();
        return FAIL_RETURN;
    }

	_iotx_linkkit_mutex_unlock();
    return SUCCESS_RETURN;
}

int kk_mid_subdev_batch_add( char productCode[PRODUCT_CODE_MAXLEN], char deviceCode[DEVICE_CODE_MAXLEN],char mac[DEVICE_MAC_MAXLEN],char fatherDeviceCode[DEVICE_CODE_MAXLEN]){
    int res = 0;
    int devid = 0;
	int heartbeat = 0;
    res = dm_mgr_subdev_create(KK_DM_DEVICE_SUBDEV,productCode,deviceCode,mac,fatherDeviceCode,KK_DEV_ONLINE,&devid,&heartbeat);
	if (res != SUCCESS_RETURN && TSL_ALREADY_EXIST != res) {
        ERROR_PRINT("subdev create Failed\n");
        return FAIL_RETURN;
    }

    if (TSL_ALREADY_EXIST == res){
        //todo
    }else{
        res = kk_subDev_insert_db(KK_DM_DEVICE_SUBDEV,productCode,deviceCode,fatherDeviceCode,mac,"1.1.0",heartbeat);
        if (res != SUCCESS_RETURN) {
            return FAIL_RETURN;
        }
    }

    res = _iotx_linkkit_subdev_login(devid);
    if (res != SUCCESS_RETURN) {

        return FAIL_RETURN;
    }
	_iotx_linkkit_mutex_unlock();
    return SUCCESS_RETURN;

}


