#include <stdio.h>
#include "kk_tsl_api.h"
#include "kk_tsl_load.h"
#include "kk_dm_mng.h"
#include "kk_dm_msg.h"
#include "kk_log.h"


typedef enum {
    KK_MSG_PROPERTY_SET,
    KK_MSG_SERVICE_SET
} kk_msg_set_type_t;

typedef int (*dm_get_shadow_data)(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data);
typedef int (*dm_set_shadow_data)(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
                                  _IN_ int value_len);
static int _kk_msg_set_object(kk_msg_set_type_t type, int devid, char *key, lite_cjson_t *root);

static int _kk_msg_get_property_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (key == NULL || key_len <= 0) {
        return INVALID_PARAMETER;
    }

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

    res = kk_tsl_get_property_data(node->dev_shadow, key, key_len, data);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}
#if 1
int kk_msg_get_event_output_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (key == NULL || key_len <= 0) {
        return INVALID_PARAMETER;
    }

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

    res = dm_tsl_get_event_output_data(node->dev_shadow, key, key_len, data);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}

int kk_msg_set_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
        _IN_ int value_len)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (key == NULL || key_len <= 0 || value == NULL) {
        return INVALID_PARAMETER;
    }

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

    res = dm_tls_set_event_output_value(node->dev_shadow, key, key_len, value, value_len);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}
#endif

static int _kk_msg_get_service_input_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (key == NULL || key_len <= 0) {
        return INVALID_PARAMETER;
    }

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

    res = dm_tsl_get_service_input_output_data(KK_TSL_DATA_TARGET_SERVICE_INPUT_DATA, node->dev_shadow, key, key_len, data);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}
static int _kk_msg_get_service_output_data(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _OU_ void **data)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (key == NULL || key_len <= 0) {
        return INVALID_PARAMETER;
    }

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

    res = dm_tsl_get_service_input_output_data(KK_TSL_DATA_TARGET_SERVICE_OUTPUT_DATA, node->dev_shadow, key, key_len,
            data);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}

static int _kk_msg_set_service_input_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
        _IN_ int value_len)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (key == NULL || key_len <= 0 || value == NULL) {
        return INVALID_PARAMETER;
    }

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
    res = dm_tsl_set_service_input_output_value(KK_TSL_DATA_TARGET_SERVICE_INPUT_DATA, node->dev_shadow, key, key_len,
            value, value_len);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}
static int _kk_msg_set_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
        _IN_ int value_len)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (key == NULL || key_len <= 0 || value == NULL) {
        return INVALID_PARAMETER;
    }

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

    res = dm_tsl_set_service_input_output_value(KK_TSL_DATA_TARGET_SERVICE_OUTPUT_DATA, node->dev_shadow, key, key_len,
            value, value_len);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}



static int _kk_msg_set_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
        _IN_ int value_len)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (key == NULL || key_len <= 0 || value == NULL) {
        return INVALID_PARAMETER;
    }

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

    res = dm_tsl_set_property_value(node->dev_shadow, key, key_len, value, value_len);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}

int _kk_tsl_set_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
		_IN_ char *value_str)
{
	int res = 0;
	void *data = NULL;
	kk_tsl_data_type_e type;

	if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
		return INVALID_PARAMETER;
	}

	res = _kk_msg_get_property_data(devid, key, key_len, &data);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}

	res = kk_tsl_get_data_type(data, &type);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}

	switch (type) {
		case KK_TSL_DATA_TYPE_INT:
		case KK_TSL_DATA_TYPE_ENUM:
		case KK_TSL_DATA_TYPE_BOOL: {
			int value_int = (value == NULL) ? (atoi(value_str)) : (*(int *)value);
			res = _kk_msg_set_property_value(devid, key, key_len, &value_int, sizeof(int));
		}
		break;
		case KK_TSL_DATA_TYPE_FLOAT: {
			float value_float = (value == NULL) ? (atof(value_str)) : (*(float *)value);
			res = _kk_msg_set_property_value(devid, key, key_len, &value_float, sizeof(float));
		}
		break;
		case KK_TSL_DATA_TYPE_DOUBLE: {
			double value_double = (value == NULL) ? (atof(value_str)) : (*(double *)value);
			res = _kk_msg_set_property_value(devid, key, key_len, &value_double, sizeof(double));
		}
		break;
		case KK_TSL_DATA_TYPE_TEXT:
		case KK_TSL_DATA_TYPE_DATE: {			
			char *value_string = (value == NULL) ? (value_str) : (value);
			res = _kk_msg_set_property_value(devid, key, key_len, value_string, strlen(value_string));
		}
		break;
		default: {
			res =  FAIL_RETURN;
		}
		break;
	}

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

static int _kk_msg_set_numberOrStr(kk_msg_set_type_t type, int devid, char *key, lite_cjson_t *root)
{
    int res = 0;
    void *data = NULL;
    kk_tsl_data_type_e data_type;
    dm_get_shadow_data get_shadow_data_func = (type == KK_MSG_PROPERTY_SET) ? (_kk_msg_get_property_data) :
            (_kk_msg_get_service_input_data);
    dm_set_shadow_data set_shadow_data_func = (type == KK_MSG_PROPERTY_SET) ? (_kk_msg_set_property_value) :
            (_kk_msg_set_service_input_value);

    /* dm_log_debug("Current Key: %s", key); */

    res = get_shadow_data_func(devid, key, strlen(key), &data);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    res = kk_tsl_get_data_type(data, &data_type);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* dm_log_debug("Current Type: %d", data_type); */
    switch (data_type) {
        case KK_TSL_DATA_TYPE_INT:
        case KK_TSL_DATA_TYPE_ENUM:
        case KK_TSL_DATA_TYPE_BOOL: {
            if (root->type == cJSON_String && root->value_length > 0){
                root->value_int = atoi(root->value);
            }
            res = set_shadow_data_func(devid, key, strlen(key), &root->value_int, 0);
        }
        break;
        case KK_TSL_DATA_TYPE_FLOAT: {
            float value_float = (float)root->value_double;
            res = set_shadow_data_func(devid, key, strlen(key), &value_float, 0);
        }
        break;
        case KK_TSL_DATA_TYPE_DOUBLE: {
            res = set_shadow_data_func(devid, key, strlen(key), &root->value_double, 0);
        }
        break;
        case KK_TSL_DATA_TYPE_TEXT:
        case KK_TSL_DATA_TYPE_DATE: {
            res = set_shadow_data_func(devid, key, strlen(key), root->value, root->value_length);
        }
        break;		
        default:
            ERROR_PRINT("Unkonwn Number Type");
            break;
    }

    return res;
}

static int _kk_msg_set_array(kk_msg_set_type_t type, int devid, char *key, lite_cjson_t *root)
{
    int res = 0, index = 0;
    lite_cjson_t lite_item_value;
    char *ascii_index = NULL;
    char *new_key = NULL;
    int new_key_len = 0;

    for (index = 0; index < root->size; index++) {

        res = lite_cjson_array_item(root, index, &lite_item_value);
        if (res != SUCCESS_RETURN) {
            continue;
        }

        /* dm_log_debug("Current Value: %.*s", lite_item_value.value_length, lite_item_value.value); */

        res = kk_utils_itoa(index, &ascii_index);
        if (res != SUCCESS_RETURN) {
            continue;
        }

        /*  Original Key              '['         Index         ']'*/
        new_key_len = ((key == NULL) ? (0) : (strlen(key) + 1)) + 1 + strlen(ascii_index) + 1 + 1;
        new_key = malloc(new_key_len);
        if (new_key == NULL) {
            free(ascii_index);
            return MEMORY_NOT_ENOUGH;
        }
        memset(new_key, 0, new_key_len);
        if (key) {
            memcpy(new_key, key, strlen(key));
        }
        new_key[strlen(new_key)] = '[';
        memcpy(new_key + strlen(new_key), ascii_index, strlen(ascii_index));
        new_key[strlen(new_key)] = ']';
        /* dm_log_debug("New Key: %s", new_key); */
        free(ascii_index);

        if (lite_cjson_is_object(&lite_item_value)) {
            res = _kk_msg_set_object(type, devid, new_key, &lite_item_value);
        }
        if (lite_cjson_is_array(&lite_item_value)) {
            res = _kk_msg_set_array(type, devid, new_key, &lite_item_value);
        }
        if (lite_cjson_is_number(&lite_item_value)) {
            res = _kk_msg_set_numberOrStr(type, devid, new_key, &lite_item_value);
        }
        if (lite_cjson_is_string(&lite_item_value)) {
            res = _kk_msg_set_numberOrStr(type, devid, new_key, &lite_item_value);
        }

        free(new_key);
        if (res != SUCCESS_RETURN) {
            return FAIL_RETURN;
        }
    }

    return SUCCESS_RETURN;
}

static int _kk_msg_set_object(kk_msg_set_type_t type, int devid, char *key, lite_cjson_t *root)
{
    int res = 0, index = 0;
    lite_cjson_t lite_item_key;
    lite_cjson_t lite_item_value;
    char *new_key = NULL;
    int new_key_len = 0;

    for (index = 0; index < root->size; index++) {
        res = lite_cjson_object_item_by_index(root, index, &lite_item_key, &lite_item_value);
        if (res != SUCCESS_RETURN) {
            continue;
        }

        /* dm_log_debug("Current Key: %.*s, Value: %.*s",
                     lite_item_key.value_length, lite_item_key.value,
                     lite_item_value.value_length, lite_item_value.value); */
        //new_key_len = lite_item_key.value_length + 1;
        new_key_len = ((key == NULL) ? (0) : (strlen(key) + 1)) + lite_item_key.value_length + 1;
        /* dm_log_debug("new_key_len: %d", new_key_len); */
        new_key = malloc(new_key_len);
        if (new_key == NULL) {
            return MEMORY_NOT_ENOUGH;
        }
        memset(new_key, 0, new_key_len);
        if (key) {
            memcpy(new_key, key, strlen(key));
            new_key[strlen(new_key)] = KK_MSG_KEY_DELIMITER;
        }
        memcpy(new_key + strlen(new_key), lite_item_key.value, lite_item_key.value_length);
        /* dm_log_debug("New Key: %s", new_key); */

        if (lite_cjson_is_object(&lite_item_value)) {
            res = _kk_msg_set_object(type, devid, new_key, &lite_item_value);
        }
        if (lite_cjson_is_array(&lite_item_value)) {
            res = _kk_msg_set_array(type, devid, new_key, &lite_item_value);
        }
        if (lite_cjson_is_number(&lite_item_value)) {
            res = _kk_msg_set_numberOrStr(type, devid, new_key, &lite_item_value);
        }
        if (lite_cjson_is_string(&lite_item_value)) {
            res = _kk_msg_set_numberOrStr(type, devid, new_key, &lite_item_value);
        }

        free(new_key);
        if (res != SUCCESS_RETURN) {
            return FAIL_RETURN;
        }
    }
    return SUCCESS_RETURN;
}

int _kk_msg_property_set(int devid, kk_msg_request_payload_t *request)
{
    int res = 0, message_len = 0;
    char *message = NULL;
    lite_cjson_t lite;

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

    /* Parse Root */
    memset(&lite, 0, sizeof(lite_cjson_t));
    res = lite_cjson_parse(request->params.value, request->params.value_length, &lite);
    if (res != SUCCESS_RETURN || (!lite_cjson_is_object(&lite) && !lite_cjson_is_array(&lite))) {
        return JSON_PARSE_FAILED;
    }
    /* dm_log_info("Property Set, Size: %d", lite.size); */

    if (lite_cjson_is_object(&lite)) {
        res = _kk_msg_set_object(KK_MSG_PROPERTY_SET, devid, NULL, &lite);
    }

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

#if 0
    message_len = strlen(DM_MSG_PROPERTY_SET_FMT) + DM_UTILS_UINT32_STRLEN + request->params.value_length + 1;
    message = DM_malloc(message_len);
    if (message == NULL) {
        return DM_MEMORY_NOT_ENOUGH;
    }
    memset(message, 0, message_len);
    HAL_Snprintf(message, message_len, DM_MSG_PROPERTY_SET_FMT, devid, request->params.value_length, request->params.value);

    res = _dm_msg_send_to_user(IOTX_DM_EVENT_PROPERTY_SET, message);
    if (res != SUCCESS_RETURN) {
        DM_free(message);
    }
#endif

    return SUCCESS_RETURN;
}

static int _kk_msg_request_parse(_IN_ char *payload, _IN_ int payload_len, _OU_ kk_msg_request_payload_t *request)
{
    lite_cjson_t lite;

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

    if (lite_cjson_parse(payload, payload_len, &lite) != SUCCESS_RETURN ||
        lite_cjson_object_item(&lite, KK_MSG_KEY_ID, strlen(KK_MSG_KEY_ID), &request->id) != SUCCESS_RETURN ||
        lite_cjson_object_item(&lite, KK_MSG_KEY_VERSION, strlen(KK_MSG_KEY_VERSION),
                                  &request->version) != SUCCESS_RETURN ||
        lite_cjson_object_item(&lite, KK_MSG_KEY_METHOD, strlen(KK_MSG_KEY_METHOD),
                                  &request->method) != SUCCESS_RETURN ||
        lite_cjson_object_item(&lite, KK_MSG_KEY_PARAMS, strlen(KK_MSG_KEY_PARAMS),
                                  &request->params) != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    INFO_PRINT("Current Request Message ID: %.*s", request->id.value_length, request->id.value);
    INFO_PRINT("Current Request Message Version: %.*s", request->version.value_length, request->version.value);
    INFO_PRINT("Current Request Message Method: %.*s", request->method.value_length, request->method.value);
    INFO_PRINT("Current Request Message Params: %.*s", request->params.value_length, request->params.value);

    return SUCCESS_RETURN;
}

static int _kk_set_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
        _IN_ char *value_str)
{
    int res = 0;
    void *data = NULL;
    kk_tsl_data_type_e type;
    dm_mgr_dev_node_t *node = NULL;	

    if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
        return INVALID_PARAMETER;
    }

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

    res = dm_tsl_get_event_output_data(node->dev_shadow, key, key_len, &data);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    res = kk_tsl_get_data_type(data, &type);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    switch (type) {
        case KK_TSL_DATA_TYPE_INT:
        case KK_TSL_DATA_TYPE_ENUM:
        case KK_TSL_DATA_TYPE_BOOL: {
            int value_int = (value == NULL) ? (atoi(value_str)) : (*(int *)value);
            res = dm_tls_set_event_output_value(node->dev_shadow, key, key_len, &value_int, sizeof(int));
        }
        break;
        case KK_TSL_DATA_TYPE_FLOAT: {
            float value_float = (value == NULL) ? (atof(value_str)) : (*(float *)value);
            res = dm_tls_set_event_output_value(node->dev_shadow, key, key_len, &value_float, sizeof(float));
        }
        break;
        case KK_TSL_DATA_TYPE_DOUBLE: {
            double value_double = (value == NULL) ? (atof(value_str)) : (*(double *)value);
            res = dm_tls_set_event_output_value(node->dev_shadow, key, key_len, &value_double, sizeof(double));
        }
        break;
        case KK_TSL_DATA_TYPE_TEXT:
        case KK_TSL_DATA_TYPE_DATE: {
            char *value_string = (value == NULL) ? (value_str) : (value);
            res = dm_tls_set_event_output_value(node->dev_shadow, key, key_len, value_string, strlen(value_string));
        }
        break;
        default: {
            res =  FAIL_RETURN;
        }
        break;
    }

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

static int _kk_set_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len,
        _IN_ void *value,
        _IN_ char *value_str)
{
    int res = 0;
    void *data = NULL;
    kk_tsl_data_type_e type;

    if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
        return INVALID_PARAMETER;
    }

    res = _kk_msg_get_service_output_data(devid, key, key_len, &data);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    res = kk_tsl_get_data_type(data, &type);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    switch (type) {
        case KK_TSL_DATA_TYPE_INT:
        case KK_TSL_DATA_TYPE_ENUM:
        case KK_TSL_DATA_TYPE_BOOL: {
            int value_int = (value == NULL) ? (atoi(value_str)) : (*(int *)value);
            res = _kk_msg_set_service_output_value(devid, key, key_len, &value_int, sizeof(int));
        }
        break;
        case KK_TSL_DATA_TYPE_FLOAT: {
            float value_float = (value == NULL) ? (atof(value_str)) : (*(float *)value);
            res = _kk_msg_set_service_output_value(devid, key, key_len, &value_float, sizeof(float));
        }
        break;
        case KK_TSL_DATA_TYPE_DOUBLE: {
            double value_double = (value == NULL) ? (atof(value_str)) : (*(double *)value);
            res = _kk_msg_set_service_output_value(devid, key, key_len, &value_double, sizeof(double));
        }
        break;
        case KK_TSL_DATA_TYPE_TEXT:
        case KK_TSL_DATA_TYPE_DATE: {
            char *value_string = (value == NULL) ? (value_str) : (value);
            res = _kk_msg_set_service_output_value(devid, key, key_len, value_string, strlen(value_string));
        }
        break;
        default: {
            res =  FAIL_RETURN;
        }
        break;
    }

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

/***********************************************************/

typedef struct {
    void *mutex;
	int is_started;
} kk_tsl_api_ctx_t;

static kk_tsl_api_ctx_t s_kk_tsl_api_ctx = {0};
static kk_tsl_api_ctx_t *_kk_tsl_api_get_ctx(void)
{
    return &s_kk_tsl_api_ctx;
}

static void _kk_tsl_api_lock(void)
{
    kk_tsl_api_ctx_t *ctx = _kk_tsl_api_get_ctx();
    if (ctx->mutex) {
        kk_MutexLock(ctx->mutex);
    }
}

static void _kk_tsl_api_unlock(void)
{
    kk_tsl_api_ctx_t *ctx = _kk_tsl_api_get_ctx();
    if (ctx->mutex) {
        kk_MutexUnLock(ctx->mutex);
    }
}
int kk_tsl_api_init(void)
{
    kk_tsl_api_ctx_t *ctx = _kk_tsl_api_get_ctx();
    memset(ctx, 0, sizeof(kk_tsl_api_ctx_t));

    /* Create Mutex */
    ctx->mutex = kk_MutexCreate();
	ctx->is_started = 1;
    if (ctx->mutex == NULL) {
        return FAIL_RETURN;
    }
	return SUCCESS_RETURN;
}

static int _kk_tsl_get_property_value_byId(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (key == NULL || key_len <= 0 || value == NULL) {
        return INVALID_PARAMETER;
    }

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

    res = kk_tsl_get_property_value_ex(node->dev_shadow, key, key_len, value);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}

static int _kk_tsl_get_property_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
        _IN_ char **value_str)
{
    int res = 0;
    void *data = NULL;
    kk_tsl_data_type_e type;

    if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
        return INVALID_PARAMETER;
    }

    res = _kk_msg_get_property_data(devid, key, key_len, &data);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    res = kk_tsl_get_data_type(data, &type);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    switch (type) {
        case KK_TSL_DATA_TYPE_INT:
        case KK_TSL_DATA_TYPE_ENUM:
        case KK_TSL_DATA_TYPE_BOOL: {
            int value_int = 0;
            res = _kk_tsl_get_property_value_byId(devid, key, key_len, (void *)&value_int);
            if (res == SUCCESS_RETURN) {
                if (value) {
                    *(int *)value = value_int;
                }
                if (value_str) {
                    res = kk_utils_itoa_direct(value_int, value_str);
                }
            }
        }
        break;
        case KK_TSL_DATA_TYPE_FLOAT: {
            float value_float = 0;
            res = _kk_tsl_get_property_value_byId(devid, key, key_len, (void *)&value_float);
            if (res == SUCCESS_RETURN) {
                if (value) {
                    *(float *)value = value_float;
                }
                if (value_str) {
                    res = kk_utils_ftoa_direct(value_float, value_str);
                }
            }
        }
        break;
        case KK_TSL_DATA_TYPE_DOUBLE: {
            double value_double = 0;
            res = _kk_tsl_get_property_value_byId(devid, key, key_len, (void *)&value_double);
            if (res == SUCCESS_RETURN) {
                if (value) {
                    *(double *)value = value_double;
                }
                if (value_str) {
                    res = kk_utils_ftoa_direct(value_double, value_str);
                }
            }
        }
        break;
        case KK_TSL_DATA_TYPE_TEXT:
        case KK_TSL_DATA_TYPE_DATE: {
            char *value_string = NULL;
            res = _kk_tsl_get_property_value_byId(devid, key, key_len, (void *)&value_string);
            if (res == SUCCESS_RETURN) {
                if (value) {
                    memcpy(value, value_string, strlen(value_string));
                }
                if (value_str) {
                    *value_str = value_string;
                } else {
                    free(value_string);
                }
            }
        }
        break;
        default: {
            res =  FAIL_RETURN;
        }
        break;
    }

    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
    return SUCCESS_RETURN;
}
		
static int _kk_tsl_get_event_output_value_byId(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (key == NULL || key_len <= 0 || value == NULL) {
        return INVALID_PARAMETER;
    }

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

    res = kk_tsl_get_event_oput_value(node->dev_shadow, key, key_len, value);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}
static int _kk_tsl_get_event_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
		_IN_ char **value_str)
{
	int res = 0;
	void *data = NULL;
	kk_tsl_data_type_e type;

	if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
		return INVALID_PARAMETER;
	}

	res = kk_msg_get_event_output_data(devid, key, key_len, &data);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}
	
	res = kk_tsl_get_data_type(data, &type);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}

	switch (type) {
		case KK_TSL_DATA_TYPE_INT:
		case KK_TSL_DATA_TYPE_ENUM:
		case KK_TSL_DATA_TYPE_BOOL: {
			int value_int = 0;
			res = _kk_tsl_get_event_output_value_byId(devid, key, key_len, (void *)&value_int);
			if (res == SUCCESS_RETURN) {
				if (value) {
					*(int *)value = value_int;
				}
				if (value_str) {
					res = kk_utils_itoa_direct(value_int, value_str);
				}
			}
		}
		break;
		case KK_TSL_DATA_TYPE_FLOAT: {
			float value_float = 0;
			res = _kk_tsl_get_event_output_value_byId(devid, key, key_len, (void *)&value_float);
			if (res == SUCCESS_RETURN) {
				if (value) {
					*(float *)value = value_float;
				}
				if (value_str) {
					res = kk_utils_ftoa_direct(value_float, value_str);
				}
			}
		}
		break;
		case KK_TSL_DATA_TYPE_DOUBLE: {
			double value_double = 0;
			res = _kk_tsl_get_event_output_value_byId(devid, key, key_len, (void *)&value_double);
			if (res == SUCCESS_RETURN) {
				if (value) {
					*(double *)value = value_double;
				}
				if (value_str) {
					res = kk_utils_ftoa_direct(value_double, value_str);
				}
			}
		}
		break;
		case KK_TSL_DATA_TYPE_TEXT:
		case KK_TSL_DATA_TYPE_DATE: {
			char *value_string = NULL;
			res = _kk_tsl_get_event_output_value_byId(devid, key, key_len, (void *)&value_string);
			if (res == SUCCESS_RETURN) {
				if (value) {
					memcpy(value, value_string, strlen(value_string));
				}
				if (value_str) {
					*value_str = value_string;
				} else {
					free(value_string);
				}
			}
		}
		break;
		default: {
			res =  FAIL_RETURN;
		}
		break;
	}

	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}
	return SUCCESS_RETURN;
}
		
static int _kk_tsl_get_service_input_value_byId(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value)
{
	int res = 0;
	dm_mgr_dev_node_t *node = NULL;

	if (key == NULL || key_len <= 0 || value == NULL) {
		return INVALID_PARAMETER;
	}

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

	res = kk_tsl_get_service_input_output_value(KK_TSL_DATA_TARGET_SERVICE_INPUT_DATA, node->dev_shadow, key, key_len,
			value);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}

	return SUCCESS_RETURN;
}
static int _kk_tsl_get_service_input_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len,
		_IN_ void *value,
		_IN_ char **value_str)
{
	int res = 0;
	void *data = NULL;
	kk_tsl_data_type_e type;

	if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
		return INVALID_PARAMETER;
	}

	res = _kk_msg_get_service_input_data(devid, key, key_len, &data);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}

	res = (data, &type);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}

	switch (type) {
		case KK_TSL_DATA_TYPE_INT:
		case KK_TSL_DATA_TYPE_ENUM:
		case KK_TSL_DATA_TYPE_BOOL: {
			int value_int = 0;
			res = _kk_tsl_get_service_input_value_byId(devid, key, key_len, (void *)&value_int);
			if (res == SUCCESS_RETURN) {
				if (value) {
					*(int *)value = value_int;
				}
				if (value_str) {
					res = kk_utils_itoa_direct(value_int, value_str);
				}
			}
		}
		break;
		case KK_TSL_DATA_TYPE_FLOAT: {
			float value_float = 0;
			res = _kk_tsl_get_service_input_value_byId(devid, key, key_len, (void *)&value_float);
			if (res == SUCCESS_RETURN) {
				if (value) {
					*(float *)value = value_float;
				}
				if (value_str) {
					res = kk_utils_ftoa_direct(value_float, value_str);
				}
			}
		}
		break;
		case KK_TSL_DATA_TYPE_DOUBLE: {
			double value_double = 0;
			res = _kk_tsl_get_service_input_value_byId(devid, key, key_len, (void *)&value_double);
			if (res == SUCCESS_RETURN) {
				if (value) {
					*(double *)value = value_double;
				}
				if (value_str) {
					res = kk_utils_ftoa_direct(value_double, value_str);
				}
			}
		}
		break;
		case KK_TSL_DATA_TYPE_TEXT:
		case KK_TSL_DATA_TYPE_DATE: {
			char *value_string = NULL;
			res = _kk_tsl_get_service_input_value_byId(devid, key, key_len, (void *)&value_string);
			if (res == SUCCESS_RETURN) {
				if (value) {
					memcpy(value, value_string, strlen(value_string));
				}
				if (value_str) {
					*value_str = value_string;
				} else {
					free(value_string);
				}
			}
		}
		break;
		default: {
			res =  FAIL_RETURN;
		}
		break;
	}

	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}
	return SUCCESS_RETURN;
}
static int _kk_tsl_get_service_output_value_byId(_IN_ int devid, _IN_ char *key, _IN_ int key_len, _IN_ void *value)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (devid < 0 || key == NULL || key_len <= 0 || value == NULL) {
        return INVALID_PARAMETER;
    }

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

    res = kk_tsl_get_service_input_output_value(KK_TSL_DATA_TARGET_SERVICE_OUTPUT_DATA, node->dev_shadow, key, key_len,
            value);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}
static int _kk_tsl_get_service_output_value(_IN_ int devid, _IN_ char *key, _IN_ int key_len,
		_IN_ void *value,
		_IN_ char **value_str)
{
	int res = 0;
	void *data = NULL;
	kk_tsl_data_type_e type;

	if (devid < 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
		return INVALID_PARAMETER;
	}

	res = _kk_msg_get_service_output_data(devid, key, key_len, &data);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}

	res = kk_tsl_get_data_type(data, &type);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}

	switch (type) {
		case KK_TSL_DATA_TYPE_INT:
		case KK_TSL_DATA_TYPE_ENUM:
		case KK_TSL_DATA_TYPE_BOOL: {
			int value_int = 0;
			res = _kk_tsl_get_service_output_value_byId(devid, key, key_len, (void *)&value_int);
			if (res == SUCCESS_RETURN) {
				if (value) {
					*(int *)value = value_int;
				}
				if (value_str) {
					res = kk_utils_itoa_direct(value_int, value_str);
				}
			}
		}
		break;
		case KK_TSL_DATA_TYPE_FLOAT: {
			float value_float = 0;
			res = _kk_tsl_get_service_output_value_byId(devid, key, key_len, (void *)&value_float);
			if (res == SUCCESS_RETURN) {
				if (value) {
					*(float *)value = value_float;
				}
				if (value_str) {
					res = kk_utils_ftoa_direct(value_float, value_str);
				}
			}
		}
		break;
		case KK_TSL_DATA_TYPE_DOUBLE: {
			double value_double = 0;
			res = _kk_tsl_get_service_output_value_byId(devid, key, key_len, (void *)&value_double);
			if (res == SUCCESS_RETURN) {
				if (value) {
					*(double *)value = value_double;
				}
				if (value_str) {
					res = kk_utils_ftoa_direct(value_double, value_str);
				}
			}
		}
		break;
		case KK_TSL_DATA_TYPE_TEXT:
		case KK_TSL_DATA_TYPE_DATE: {
			char *value_string = NULL;
			res = _kk_tsl_get_service_output_value_byId(devid, key, key_len, (void *)&value_string);
			if (res == SUCCESS_RETURN) {
				if (value) {
					memcpy(value, value_string, strlen(value_string));
				}
				if (value_str) {
					*value_str = value_string;
				} else {
					free(value_string);
				}
			}
		}
		break;
		default: {
			res =  FAIL_RETURN;
		}
		break;
	}

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

int kk_tsl_get_value(kk_tsl_get_t method_get, int devId, const char *identifier,
                                       void *value,
                                       char **value_str)
{
    int res = 0;
    kk_tsl_api_ctx_t *kk_tsl_api_ctx = _kk_tsl_api_get_ctx();

    if ( identifier == NULL || (value == NULL && value_str == NULL)) {
        ERROR_PRINT("Invalid Parameter");
        return FAIL_RETURN;
    }

    _kk_tsl_api_lock();

    switch (method_get) {
        case kk_tsl_get_property_value: {
            res = _kk_tsl_get_property_value(devId, (char *)identifier, strlen(identifier), value, value_str);
        }
        break;
        case kk_tsl_get_event_output_value: {
            res = _kk_tsl_get_event_output_value(devId, (char *)identifier, strlen(identifier), value, value_str);
        }
        break;
        case kk_tsl_get_service_input_value: {
            res = _kk_tsl_get_service_input_value(devId, (char *)identifier, strlen(identifier), value,
                    value_str);
        }
        break;
        case kk_tsl_get_service_output_value: {
            res = _kk_tsl_get_service_output_value(devId, (char *)identifier, strlen(identifier), value,
                    value_str);
        }
        break;
        default: {
            ERROR_PRINT("Invalid Parameter");
            res = FAIL_RETURN;
        }
        break;
    }

    if (res < SUCCESS_RETURN) {
        _kk_tsl_api_unlock();
        return FAIL_RETURN;
    }

    _kk_tsl_api_unlock();

    return SUCCESS_RETURN;
}

int kk_tsl_set_value(kk_tsl_set_t set, int devId, const char *identifier,
                                       const void *value,
                                       const char *value_str)
{
    int res = 0;
    kk_tsl_api_ctx_t *kk_tsl_api_ctx = _kk_tsl_api_get_ctx();

    if ( identifier == NULL || (value == NULL && value_str == NULL)) {
        ERROR_PRINT("Invalid Parameter");
        return FAIL_RETURN;
    }

    _kk_tsl_api_lock();
    switch (set) {
        case kk_tsl_set_property_value: {
            res = _kk_tsl_set_property_value(devId, (char *)identifier, strlen(identifier), (void *)value,
                    (char*)value_str);
        }
        break;
        case kk_tsl_set_event_output_value: {	
            res = _kk_set_event_output_value(devId, (char *)identifier, strlen(identifier), (void *)value,
                    (char *)value_str);
        }
        break;
        case kk_tsl_set_service_output_value: {
            res = _kk_set_service_output_value(devId, (char *)identifier, strlen(identifier), (void *)value,
                    (char *)value_str);
        }
        break;
        default: {
            ERROR_PRINT("Invalid Parameter");
            res = FAIL_RETURN;
        }
        break;
    }

    if (res < SUCCESS_RETURN) {
        _kk_tsl_api_unlock();
        return FAIL_RETURN;
    }

    _kk_tsl_api_unlock();

    return SUCCESS_RETURN;
}
int kk_msg_uri_parse_pkdn(_IN_ char *uri, _IN_ int uri_len, _IN_ int start_deli, _IN_ int end_deli,
                          _OU_ char productType[PRODUCT_TYPE_MAXLEN], _OU_ char deviceCode[DEVICE_CODE_MAXLEN])
{
    int res = 0, start = 0, end = 0, slice = 0;

    if (uri == NULL || uri_len <= 0 || productType == NULL || deviceCode == NULL ||
        (strlen(productType) >= PRODUCT_TYPE_MAXLEN) || (strlen(deviceCode) >= DEVICE_CODE_MAXLEN)) {
        return INVALID_PARAMETER;
    }

    res = kk_utils_memtok(uri, uri_len, KK_URI_SERVICE_DELIMITER, start_deli, &start);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    res = kk_utils_memtok(uri, uri_len, KK_URI_SERVICE_DELIMITER, start_deli + 1, &slice);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    res = kk_utils_memtok(uri, uri_len, KK_URI_SERVICE_DELIMITER, end_deli, &end);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    /* dm_log_debug("URI Product Key: %.*s, Device Name: %.*s", slice - start - 1, uri + start + 1, end - slice - 1,
                 uri + slice + 1); */

    memcpy(productType, uri + start + 1, slice - start - 1);
    memcpy(deviceCode, uri + slice + 1, end - slice - 1);

    return SUCCESS_RETURN;
}

int kk_tsl_property_set_by_devicecode(const char deviceCode[DEVICE_CODE_MAXLEN], const char *payload, unsigned int payload_len)
{
    kk_msg_request_payload_t request;
    int res = 0, devid = 0;

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

    res = dm_mgr_get_devId_by_devicecode(deviceCode, &devid);
	if(res != SUCCESS_RETURN){
		return FAIL_RETURN;
	}
    res = _kk_msg_request_parse((char *)payload, payload_len, &request);
    if (res < SUCCESS_RETURN) {
        return res ;
    }

    /* Operation */
    res = _kk_msg_property_set(devid, &request);

    /* Response */
	kk_tsl_post_property(devid,NULL);

#if 0
#define EVENT_ERROR_IDENTIFIER "Error"
#define EVENT_ERROR_OUTPUT_INFO_IDENTIFIER "ErrorCode"

	//kk_tsl_post_property(devid,NULL);
    char event_output_identifier[64];
    snprintf(event_output_identifier, sizeof(event_output_identifier), "%s.%s",
             EVENT_ERROR_IDENTIFIER, EVENT_ERROR_OUTPUT_INFO_IDENTIFIER);

    int errorCode = 0;
	printf("[%s][%d]\n",__FUNCTION__,__LINE__);
    kk_tsl_set_value(kk_tsl_set_event_output_value, devid,
                      event_output_identifier, &errorCode, NULL);
	kk_tsl_post_event(devid,EVENT_ERROR_IDENTIFIER);
#endif
    return SUCCESS_RETURN;
}

int kk_tsl_service_property_set(const char *topic, const char *payload, unsigned int payload_len,
        void *context)
{
    kk_msg_request_payload_t request;


    int res = 0, devid = 0;
    char productType[PRODUCT_TYPE_MAXLEN] = {0};
    char deviceCode[DEVICE_CODE_MAXLEN] = {0};

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



	/**************to do*******************/	

    //dm_log_info(DM_URI_THING_SERVICE_PROPERTY_SET);

    /* Request */
    /* Request */
    res =kk_msg_uri_parse_pkdn((char *)topic, strlen(topic), 2 + KK_URI_OFFSET, 4 + KK_URI_OFFSET, productType,
                                deviceCode);


    res = dm_mgr_search_device_by_pkdn(productType, deviceCode, &devid);
    if (res < SUCCESS_RETURN) {
        return res;
    }
    res = _kk_msg_request_parse((char *)payload, payload_len, &request);
    if (res < SUCCESS_RETURN) {
        return res ;
    }

    /* Operation */
    res = _kk_msg_property_set(devid, &request);

    /* Response */
	kk_tsl_post_property(devid,NULL);

#if 0
#define EVENT_ERROR_IDENTIFIER "Error"
#define EVENT_ERROR_OUTPUT_INFO_IDENTIFIER "ErrorCode"

	//kk_tsl_post_property(devid,NULL);
    char event_output_identifier[64];
    snprintf(event_output_identifier, sizeof(event_output_identifier), "%s.%s",
             EVENT_ERROR_IDENTIFIER, EVENT_ERROR_OUTPUT_INFO_IDENTIFIER);

    int errorCode = 0;
	printf("[%s][%d]\n",__FUNCTION__,__LINE__);
    kk_tsl_set_value(kk_tsl_set_event_output_value, devid,
                      event_output_identifier, &errorCode, NULL);
	kk_tsl_post_event(devid,EVENT_ERROR_IDENTIFIER);
#endif
    return SUCCESS_RETURN;
}

static int kk_tsl_post_property_start(_IN_ int devid, _OU_ void **handle)
{
    dm_api_property_t *dapi_property = NULL;

    if (devid < 0 || handle == NULL || *handle != NULL) {
        return INVALID_PARAMETER;
    }

    dapi_property = malloc(sizeof(dm_api_property_t));
    if (dapi_property == NULL) {
        return MEMORY_NOT_ENOUGH;
    }
    memset(dapi_property, 0, sizeof(dm_api_property_t));
    /* Set Devid */
    dapi_property->devid = devid;
    /* Init Json Object */
    dapi_property->lite = lite_cjson_create_object();
    if (dapi_property->lite == NULL) {
        free(dapi_property);
        return FAIL_RETURN;
    }
    *handle = (void *)dapi_property;
    return SUCCESS_RETURN;
}
static int _kk_tsl_get_property_by_index(_IN_ int devid, _IN_ int index, _OU_ kk_tsl_data_t **property)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (devid < 0 || index < 0) {
        return INVALID_PARAMETER;
    }

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
	*property = (kk_tsl_data_t *)(node->dev_shadow->properties + index);
    return SUCCESS_RETURN;
}

int kk_tsl_get_property_number(_IN_ int devid, _OU_ int *number)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

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

    res = dm_mgr_search_dev_by_devid(devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
	if(node->dev_shadow == NULL)
	{
		return FAIL_RETURN;
	}
	*number = node->dev_shadow->property_number;
    return SUCCESS_RETURN;
}

static int _kk_tsl_post_property_add(_IN_ void *handle, _IN_ char *identifier, _IN_ int identifier_len)
{
    int res = 0;
    dm_api_property_t *dapi_property = NULL;
    dm_mgr_dev_node_t *node = NULL;

    if (handle == NULL || identifier == NULL || identifier_len <= 0) {
        return INVALID_PARAMETER;
    }
    dapi_property = (dm_api_property_t *)handle;

    /* Assemble Property Payload */
	res = dm_mgr_search_dev_by_devid(dapi_property->devid, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
	
    res = kk_tsl_assemble_property(node->dev_shadow, identifier, identifier_len, dapi_property->lite);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}

int kk_tsl_post_property_add(_IN_ void *handle, _IN_ char *identifier, _IN_ int identifier_len)
{
    int ret = SUCCESS_RETURN, res = 0, index = 0, number = 0;
    kk_tsl_data_t *property_refer = NULL;
    char *identifier_refer = NULL;
    dm_api_property_t *dapi_property = NULL;

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

    dapi_property = (dm_api_property_t *)handle;

    if (identifier != NULL) {
        if (identifier_len <= 0) {
            return FAIL_RETURN;
        }
        ret = _kk_tsl_post_property_add(handle, identifier, identifier_len);
        return ret;
    }

    res = kk_tsl_get_property_number(dapi_property->devid, &number);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    for (index = 0; index < number; index++) {
        property_refer = NULL;
        identifier_refer = NULL;

        res = _kk_tsl_get_property_by_index(dapi_property->devid, index, &property_refer);
        if (res != SUCCESS_RETURN) {
            continue;
        }

		identifier_refer = property_refer->identifier;

        res = _kk_tsl_post_property_add(handle, identifier_refer, strlen(identifier_refer));
        if (res != SUCCESS_RETURN) {
            ret = FAIL_RETURN;
        }
    }
    return ret;
}
static int kk_tsl_post_property_end(_IN_ void *handle)
{
    int res = 0;
    char *payload = NULL;
    dm_api_property_t *dapi_property = NULL;

    if (handle == NULL) {
        return INVALID_PARAMETER;
    }
    dapi_property = (dm_api_property_t *)handle;
    payload = lite_cjson_print_unformatted(dapi_property->lite);
    if (payload == NULL) {
        lite_cjson_delete(dapi_property->lite);
        free(dapi_property);
        return MEMORY_NOT_ENOUGH;
    }
    INFO_PRINT("Post Payload, Length: %d, Payload: %s\n", strlen(payload), payload);
    res = dm_mgr_upstream_thing_property_post(dapi_property->devid, payload, strlen(payload));
    lite_cjson_delete(dapi_property->lite);
    free(dapi_property);
	free(payload);
    dapi_property = NULL;
    return res;
}

int kk_tsl_post_property(int devId, const char *property_identifier)
{
    int res = 0, msgid = 0, property_identifier_len = 0, post_property_reply = 0;
    void *property_handle = NULL;
    kk_tsl_api_ctx_t *kk_tsl_api_ctx = _kk_tsl_api_get_ctx();

    _kk_tsl_api_lock();
    res = kk_tsl_post_property_start(devId, &property_handle);
    if (res != SUCCESS_RETURN) {
        _kk_tsl_api_unlock();
        return FAIL_RETURN;
    }
    property_identifier_len = (property_identifier) ? (strlen((char *)property_identifier)) : (0);
    res = kk_tsl_post_property_add(property_handle, (char *)property_identifier, property_identifier_len);
    if (res != SUCCESS_RETURN) {
        kk_tsl_post_property_end(property_handle);
        _kk_tsl_api_unlock();
        return FAIL_RETURN;
    }
    res = kk_tsl_post_property_end(property_handle);
    if (res < SUCCESS_RETURN) {
        _kk_tsl_api_unlock();
        return FAIL_RETURN;
    }

    _kk_tsl_api_unlock();
    return SUCCESS_RETURN;
}
static int kk_tsl_event_output(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len,
        _IN_ lite_cjson_item_t *lite)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (devid < 0 || identifier == NULL || identifier_len <= 0 || lite == NULL || lite->type != cJSON_Object) {
        return INVALID_PARAMETER;
    }

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

    res = kk_tsl_assemble_event_output(node->dev_shadow, identifier, identifier_len, lite);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

    return SUCCESS_RETURN;
}
static int _kk_tsl_get_event_by_identifier(_IN_ kk_tsl_t *shadow, _IN_ char *identifier, _OU_ void **event)
{
    int index = 0;
    kk_tsl_event_t *search_event = NULL;

    if (shadow == NULL || identifier == NULL ||
        event == NULL || *event != NULL) {
        return INVALID_PARAMETER;
    }

    for (index = 0; index < shadow->event_number; index++) {
        search_event = shadow->events + index;
        if ((strlen(search_event->identifier) == strlen(identifier)) &&
            (memcmp(search_event->identifier, identifier, strlen(identifier)) == 0)) {
            *event = (void *)search_event;
            return SUCCESS_RETURN;
        }
    }

    return FAIL_RETURN;
}

int kk_tsl_get_event_by_identifier(_IN_ int devid, _IN_ char *identifier, _OU_ void **event)
{
    int res = 0;
    dm_mgr_dev_node_t *node = NULL;

    if (devid < 0 || identifier == NULL || event == NULL || *event != NULL) {
        return INVALID_PARAMETER;
    }

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

    return _kk_tsl_get_event_by_identifier(node->dev_shadow, identifier, event);
}
int kk_tsl_get_event_method(_IN_ void *event, _OU_ char **method)
{
    int event_method_len = 0;
    const char *post_identifier = "post";
    const char *property_identifier = "property";
    const char *identifier = NULL;
    const char *event_method_fmt = "thing.event.%s.post";
    kk_tsl_event_t *event_item = (kk_tsl_event_t *)event;

    if (event_item == NULL || method == NULL || *method != NULL) {
        return INVALID_PARAMETER;
    }

    /* God Damn It Special Case! */
    if ((strlen(event_item->identifier) == strlen(post_identifier)) &&
        (memcmp(event_item->identifier, post_identifier, strlen(post_identifier)) == 0)) {
        identifier = property_identifier;
    } else {
        identifier = (const char *)event_item->identifier;
    }

    event_method_len = (strlen(event_method_fmt) + strlen(identifier) + 1);
    *method = malloc(event_method_len);
    if (*method == NULL) {
        return MEMORY_NOT_ENOUGH;
    }
    memset(*method, 0, event_method_len);
    snprintf(*method, event_method_len, event_method_fmt, identifier);

    return SUCCESS_RETURN;
}

static int _kk_tsl_post_event(_IN_ int devid, _IN_ char *identifier, _IN_ int identifier_len)
{
    int res = 0;
    void *event = NULL;
    lite_cjson_item_t *lite = NULL;
    char *method = NULL, *payload = NULL;

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

    lite = lite_cjson_create_object();
    if (lite == NULL) {
        return MEMORY_NOT_ENOUGH;
    }

    res = kk_tsl_event_output(devid, identifier, identifier_len, lite);
    if (res != SUCCESS_RETURN) {
        lite_cjson_delete(lite);
        return FAIL_RETURN;
    }

    payload = lite_cjson_print_unformatted(lite);
    lite_cjson_delete(lite);
    if (payload == NULL) {
        return MEMORY_NOT_ENOUGH;
    }

    INFO_PRINT("\nCurrent Event Post Payload, Length: %d, Payload: %s\n", strlen(payload), payload);

    res = kk_tsl_get_event_by_identifier(devid, identifier, &event);
    if (res != SUCCESS_RETURN) {
        free(payload);
        return FAIL_RETURN;
    }

    res = kk_tsl_get_event_method(event, &method);
    if (res != SUCCESS_RETURN) {
        free(payload);
        return FAIL_RETURN;
    }

    INFO_PRINT("Current Event Method: %s", method);

    res = dm_mgr_upstream_thing_event_post(devid, identifier, identifier_len, method, payload, strlen(payload));

    free(payload);
    free(method);
    return res;
}

int kk_tsl_post_event(int devId, const char *event_identifier)
{
    int res = 0, msgid = 0, post_event_reply = 0;
    kk_tsl_api_ctx_t *kk_tsl_api_ctx = _kk_tsl_api_get_ctx();

    if (event_identifier == NULL) {
        return FAIL_RETURN;
    }

    _kk_tsl_api_lock();

    res = _kk_tsl_post_event(devId, (char *)event_identifier, strlen((char *)event_identifier));
    if (res < SUCCESS_RETURN) {
        _kk_tsl_api_unlock();
        return FAIL_RETURN;
    }
    _kk_tsl_api_unlock();
    return SUCCESS_RETURN;
}

static int _kk_tsl_send_service_response(_IN_ int devid, _IN_ int msgid, _IN_ iotx_dm_error_code_t code,
        _IN_ char *identifier,
        _IN_ int identifier_len)
{
    int res = 0;
    lite_cjson_item_t *lite = NULL;
    char *payload = NULL;
    dm_mgr_dev_node_t *node = NULL;

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

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

    res = kk_tsl_assemble_service_output(node->dev_shadow, identifier, identifier_len, lite);
    if (res != SUCCESS_RETURN) {
        lite_cjson_delete(lite);
        return FAIL_RETURN;
    }

    payload = lite_cjson_print_unformatted(lite);
    lite_cjson_delete(lite);
    if (payload == NULL) {
        return MEMORY_NOT_ENOUGH;
    }

    INFO_PRINT("Current Service Response Payload, Length: %d, Payload: %s", strlen(payload), payload);

    res = dm_mgr_deprecated_upstream_thing_service_response(devid, msgid, code, identifier, identifier_len, payload,
            strlen(payload));

    free(payload);
    return res;
}

int kk_tsl_post_service(int devId, const char *service_identifier, int response_id,
        int code)
{
    int res = 0;
    kk_tsl_api_ctx_t *kk_tsl_api_ctx = _kk_tsl_api_get_ctx();

    if (service_identifier == NULL) {
        ERROR_PRINT("Invalid Parameter");
        return FAIL_RETURN;
    }

    _kk_tsl_api_lock();

    res = _kk_tsl_send_service_response(devId, response_id, (iotx_dm_error_code_t)code,
            (char *)service_identifier, strlen(service_identifier));
    if (res < SUCCESS_RETURN) {
        _kk_tsl_api_unlock();
        return FAIL_RETURN;
    }

    _kk_tsl_api_unlock();

    return SUCCESS_RETURN;
}


static void __kk_tsl_property_free(_IN_ kk_tsl_data_t *property)
{

	if (property->identifier) {
		free(property->identifier);
		property->identifier = NULL;
	}
	
	kk_tsl_datavalue_free(&property->data_value);
}

static void _kk_tsl_properties_free(_IN_ kk_tsl_data_t *properties, _IN_ int number)
{
	int index = 0;
	kk_tsl_data_t *property = NULL;


	for (index = 0; index < number; index++) {
		property = properties + index;
		__kk_tsl_property_free(property);
	}
}

static void _kk_tsl_event_outputdata_free(_IN_ kk_tsl_data_t *outputdata)
{
    if (outputdata->identifier) {
        free(outputdata->identifier);
        outputdata->identifier = NULL;
    }
    kk_tsl_datavalue_free(&outputdata->data_value);
}

static void _kk_tsl_event_outputdatas_free(_IN_ kk_tsl_data_t *outputdatas, _IN_ int number)
{
    int index = 0;
    kk_tsl_data_t *outputdata = NULL;

    for (index = 0; index < number; index++) {
        outputdata = outputdatas + index;
        _kk_tsl_event_outputdata_free(outputdata);
    }
}

static void _kk_tsl_event_free(_IN_ kk_tsl_event_t *event)
{
    if (event->identifier) {
        free(event->identifier);
        event->identifier = NULL;
    }
    if (event->output_datas) {
        _kk_tsl_event_outputdatas_free(event->output_datas, event->output_data_number);
        free(event->output_datas);
        event->output_datas = NULL;
    }
}

static void _kk_tsl_events_free(_IN_ kk_tsl_event_t *events, _IN_ int number)
{
    int index = 0;
    kk_tsl_event_t *event = NULL;

    for (index = 0; index < number; index++) {
        event = events + index;
        _kk_tsl_event_free(event);
    }
}

static void _kk_tsl_service_outputdata_free(_IN_ kk_tsl_data_t *outputdata)
{
    if (outputdata->identifier) {
        free(outputdata->identifier);
        outputdata->identifier = NULL;
    }
    kk_tsl_datavalue_free(&outputdata->data_value);
}

static void _kk_tsl_service_outputdatas_free(_IN_ kk_tsl_data_t *outputdatas, _IN_ int number)
{
    int index = 0;
    kk_tsl_data_t *outputdata = NULL;

    for (index = 0; index < number; index++) {
        outputdata = outputdatas + index;
        _kk_tsl_service_outputdata_free(outputdata);
    }
}

static void _kk_tsl_service_inputdata_free(_IN_ kk_tsl_data_t *inputdata)
{
    if (inputdata->identifier) {
        free(inputdata->identifier);
        inputdata->identifier = NULL;
    }
    kk_tsl_datavalue_free(&inputdata->data_value);
}

static void _kk_tsl_service_inputdatas_free(_IN_ kk_tsl_data_t *inputdatas, _IN_ int number)
{
    int index = 0;
    kk_tsl_data_t *inputdata = NULL;

    for (index = 0; index < number; index++) {
        inputdata = inputdatas + index;
        _kk_tsl_service_inputdata_free(inputdata);
    }
}

static void _kk_tsl_service_free(_IN_ kk_tsl_service_t *service)
{
    if (service->identifier) {
        free(service->identifier);
        service->identifier = NULL;
    }
    if (service->output_datas) {
        _kk_tsl_service_outputdatas_free(service->output_datas, service->output_data_number);
        free(service->output_datas);
        service->output_datas = NULL;
    }
    if (service->input_datas) {
        _kk_tsl_service_inputdatas_free(service->input_datas, service->input_data_number);
        free(service->input_datas);
        service->input_datas = NULL;
    }
}

static void _kk_tsl_services_free(_IN_ kk_tsl_service_t *services, _IN_ int number)
{
    int index = 0;
    kk_tsl_service_t *service = NULL;

    for (index = 0; index < number; index++) {
        service = services + index;
        _kk_tsl_service_free(service);
    }
}

void kk_tsl_destroy(_IN_ kk_tsl_t **shadow)
{
	if (shadow == NULL || *shadow == NULL) {
		return;
	}
	 _kk_tsl_api_lock();
	/* Free Properties */
	if ((*shadow)->properties) {
		_kk_tsl_properties_free((*shadow)->properties, (*shadow)->property_number);
		free((*shadow)->properties);
		(*shadow)->properties = NULL;
	}

	/* Free Events */
	if ((*shadow)->events) {
		_kk_tsl_events_free((*shadow)->events, (*shadow)->event_number);
		free((*shadow)->events);
		(*shadow)->events = NULL;
	}

	/* Free Services */
	if ((*shadow)->services) {
		_kk_tsl_services_free((*shadow)->services, (*shadow)->service_number);
		free((*shadow)->services);
		(*shadow)->services = NULL;
	}

	free(*shadow);
	*shadow = NULL;
	 _kk_tsl_api_unlock();
}


