#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"
#include "kk_utils.h"
#include "kk_tsl_parse.h"

typedef enum {
    KK_MSG_PROPERTY_SET,
    KK_MSG_SERVICE_SET
} kk_msg_set_type_t;

typedef int (*dm_get_shadow_data)(_IN_ kk_tsl_t *  dev_shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **data);
typedef int (*dm_set_shadow_data)(_IN_ kk_tsl_t *  dev_shadow, _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, kk_tsl_t *dev_shadow, char *key, lite_cjson_t *root);
static int _kk_msg_get_property_data(_IN_ kk_tsl_t * dev_shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **data)
{
    int res = 0;

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

    res = kk_tsl_get_property_data(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_ kk_tsl_t * dev_shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **data)
{
    int res = 0;

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

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

    return SUCCESS_RETURN;
}

#endif

static int _kk_msg_get_service_input_data(_IN_ kk_tsl_t *dev_shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **data)
{
    int res = 0;


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

    res = dm_tsl_get_service_input_output_data(KK_TSL_DATA_TARGET_SERVICE_INPUT_DATA,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_ kk_tsl_t *dev_shadow, _IN_ char *key, _IN_ int key_len, _OU_ void **data)
{
    int res = 0;

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


    res = dm_tsl_get_service_input_output_data(KK_TSL_DATA_TARGET_SERVICE_OUTPUT_DATA,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_ kk_tsl_t *dev_shadow, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
        _IN_ int value_len)
{
    int res = 0;

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

    res = dm_tsl_set_service_input_output_value(KK_TSL_DATA_TARGET_SERVICE_INPUT_DATA, 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_ kk_tsl_t *dev_shadow, _IN_ char *key, _IN_ int key_len, _IN_ void *value,
        _IN_ int value_len)
{
    int res = 0;

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

    res = dm_tsl_set_service_input_output_value(KK_TSL_DATA_TARGET_SERVICE_OUTPUT_DATA, 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_ kk_tsl_t *dev_shadow , _IN_ char *key, _IN_ int key_len, _IN_ void *value,
        _IN_ int value_len)
{
    int res = 0;

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

    res = dm_tsl_set_property_value(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_ kk_tsl_t * dev_shadow, _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 (dev_shadow == NULL|| key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
		return INVALID_PARAMETER;
	}

	res = _kk_msg_get_property_data(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 = _kk_msg_set_property_value(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 = _kk_msg_set_property_value(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 = _kk_msg_set_property_value(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 = _kk_msg_set_property_value(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_msg_set_numberOrStr(kk_msg_set_type_t type, kk_tsl_t *dev_shadow, 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(dev_shadow, 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(dev_shadow, 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(dev_shadow, key, strlen(key), &value_float, 0);
        }
        break;
        case KK_TSL_DATA_TYPE_DOUBLE: {
            if (root->type == cJSON_String && root->value_length > 0){
                root->value_double = atof(root->value);
            }			
            res = set_shadow_data_func(dev_shadow, 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(dev_shadow, 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, kk_tsl_t *dev_shadow, 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, dev_shadow, new_key, &lite_item_value);
        }
        if (lite_cjson_is_array(&lite_item_value)) {
            res = _kk_msg_set_array(type, dev_shadow, new_key, &lite_item_value);
        }
        if (lite_cjson_is_number(&lite_item_value)) {
            res = _kk_msg_set_numberOrStr(type, dev_shadow, new_key, &lite_item_value);
        }
        if (lite_cjson_is_string(&lite_item_value)) {
            res = _kk_msg_set_numberOrStr(type, dev_shadow, 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, kk_tsl_t *dev_shadow, 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, dev_shadow, new_key, &lite_item_value);
        }
        if (lite_cjson_is_array(&lite_item_value)) {
            res = _kk_msg_set_array(type, dev_shadow, new_key, &lite_item_value);
        }
        if (lite_cjson_is_number(&lite_item_value)) {
            res = _kk_msg_set_numberOrStr(type, dev_shadow, new_key, &lite_item_value);
        }
        if (lite_cjson_is_string(&lite_item_value)) {
            res = _kk_msg_set_numberOrStr(type, dev_shadow, new_key, &lite_item_value);
        }

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

int _kk_msg_property_set(kk_tsl_t         *dev_shadow, kk_msg_request_payload_t *request)
{
    int res = 0;
    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, dev_shadow, NULL, &lite);
    }

    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
    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;
    }
    return SUCCESS_RETURN;
}

static int _kk_set_event_output_value(_IN_ kk_tsl_t *dev_shadow, _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 (dev_shadow == NULL || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
        return INVALID_PARAMETER;
    }

    res = dm_tsl_get_event_output_data(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(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(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(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(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_ kk_tsl_t *dev_shadow, _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 (dev_shadow == 0 || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
        return INVALID_PARAMETER;
    }

    res = _kk_msg_get_service_output_data(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 = _kk_msg_set_service_output_value(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 = _kk_msg_set_service_output_value(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 = _kk_msg_set_service_output_value(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 = _kk_msg_set_service_output_value(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;
}

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

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;
}
int kk_tsl_get_property_type(_IN_ kk_tsl_t *dev_shadow, _IN_ char *key)
{
    int res = 0;
    void *data = NULL;
    kk_tsl_data_type_e type;

    if (dev_shadow == NULL || key == NULL ) {
        return INVALID_PARAMETER;
    }

    res = _kk_msg_get_property_data(dev_shadow, key, strlen(key), &data);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
    res = kk_tsl_get_data_type(data, &type);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
	return type;
}
static int _kk_tsl_get_property_value(_IN_ kk_tsl_t *dev_shadow, _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 (dev_shadow == NULL || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
        return INVALID_PARAMETER;
    }

    res = _kk_msg_get_property_data(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 = 0;
            res = kk_tsl_get_property_value_ex(dev_shadow, 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_ex(dev_shadow, 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_ex(dev_shadow, 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_ex(dev_shadow, 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); 
					value_string = NULL;
                }
                
				
            }
        }
        break;
        default: {
            res =  FAIL_RETURN;
        }
        break;
    }

    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
    return SUCCESS_RETURN;
}
		
static int _kk_tsl_get_event_output_value(_IN_ kk_tsl_t * dev_shadow, _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 (dev_shadow == NULL || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
		return INVALID_PARAMETER;
	}

	res = kk_msg_get_event_output_data(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 = 0;
			res = kk_tsl_get_event_oput_value(dev_shadow, 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_oput_value(dev_shadow, 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_oput_value(dev_shadow, 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_oput_value(dev_shadow, 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_ kk_tsl_t *dev_shadow, _IN_ char *key, _IN_ int key_len, _IN_ void *value)
{
	int res = 0;

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

	res = kk_tsl_get_service_input_output_value(KK_TSL_DATA_TARGET_SERVICE_INPUT_DATA, 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_ kk_tsl_t * dev_shadow, _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 (dev_shadow == NULL || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
		return INVALID_PARAMETER;
	}

	res = _kk_msg_get_service_input_data(dev_shadow, 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(dev_shadow, 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(dev_shadow, 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(dev_shadow, 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(dev_shadow, 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_ kk_tsl_t *dev_shadow, _IN_ char *key, _IN_ int key_len, _IN_ void *value)
{
    int res = 0;

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

    res = kk_tsl_get_service_input_output_value(KK_TSL_DATA_TARGET_SERVICE_OUTPUT_DATA, 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_ kk_tsl_t *dev_shadow, _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 (dev_shadow == NULL || key == NULL || key_len <= 0 || ((value == NULL) && (value_str == NULL))) {
		return INVALID_PARAMETER;
	}

	res = _kk_msg_get_service_output_data(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 = 0;
			res = _kk_tsl_get_service_output_value_byId(dev_shadow, 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(dev_shadow, 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(dev_shadow, 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(dev_shadow, 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, kk_tsl_t * dev_shadow, const char *identifier,
                                       void *value,
                                       char **value_str)
{
    int res = 0;

    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(dev_shadow, (char *)identifier, strlen(identifier), value, value_str);
        }
        break;
        case kk_tsl_get_event_output_value: {
            res = _kk_tsl_get_event_output_value(dev_shadow, (char *)identifier, strlen(identifier), value, value_str);
        }
        break;
        case kk_tsl_get_service_input_value: {
            res = _kk_tsl_get_service_input_value(dev_shadow, (char *)identifier, strlen(identifier), value,
                    value_str);
        }
        break;
        case kk_tsl_get_service_output_value: {
            res = _kk_tsl_get_service_output_value(dev_shadow, (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, kk_tsl_t * dev_shadow, const char *identifier,
                                       const void *value,
                                       const char *value_str)
{
    int res = 0;
	char tmp[128] = {0};
	int index = 0;
	kk_tsl_event_t *property = NULL;
	char *e_identifier = NULL;

    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: {
			for (index = 0; index < dev_shadow->event_number; index++) {
				property = dev_shadow->events + index;
				if(strcmp(property->identifier,"property") == 0 ||
					strcmp(property->identifier,"post") == 0)
{
					e_identifier = property->identifier;
					break;
				}
			}
			sprintf(tmp,"%s.%s",e_identifier,identifier);
            _kk_set_event_output_value(dev_shadow, (char *)tmp, strlen(tmp), (void *)value,
                    (char *)value_str);			
            res = _kk_tsl_set_property_value(dev_shadow, (char *)identifier, strlen(identifier), (void *)value,
                    (char*)value_str);
        }
        break;
        case kk_tsl_set_event_output_value: {	
            res = _kk_set_event_output_value(dev_shadow, (char *)identifier, strlen(identifier), (void *)value,
                    (char *)value_str);
        }
        break;
        case kk_tsl_set_service_output_value: {
            res = _kk_set_service_output_value(dev_shadow, (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_shadow(kk_tsl_t* dev_shadow, const char *payload, unsigned int payload_len)
{
    kk_msg_request_payload_t request;
    int res = 0;

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

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

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

    return SUCCESS_RETURN;
}
#if 0
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};
	kk_tsl_t *dev_shadow = NULL;

    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_get_device_shadow_by_devicecode(deviceCode, &dev_shadow);
    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(dev_shadow, &request);

    /* Response */
	kk_tsl_post_property(dev_shadow,NULL,0);

    return SUCCESS_RETURN;
}
#endif
static int kk_tsl_post_property_start(_IN_ kk_tsl_t * dev_shadow, _OU_ void **handle)
{
    dm_api_property_t *dapi_property = NULL;

    if (dev_shadow == NULL || 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->shadow = dev_shadow;
    /* 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;
}

int kk_tsl_get_property_number(_IN_ kk_tsl_t *shadow, _OU_ int *number)
{
	int index = 0;
	kk_tsl_event_t *property = NULL;	
    if (shadow == NULL || number == NULL) {
        return INVALID_PARAMETER;
    }
    for (index = 0; index < shadow->event_number; index++) {
        property = shadow->events + index;
		if(strcmp(property->identifier,"property") == 0 ||
			strcmp(property->identifier,"post") == 0)
{
			*number = property->output_data_number;
			return SUCCESS_RETURN;
		}
    }	
	*number = 0;
    return FAIL_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;

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

	
    res = kk_tsl_assemble_property(dapi_property->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;
	kk_tsl_event_t *event = NULL;
    kk_tsl_data_t *pEventoutput = 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;
    }

    for (index = 0; index < dapi_property->shadow->event_number; index++) {
        event = dapi_property->shadow->events + index;
		if(strcmp(event->identifier,"property") == 0 ||
			strcmp(event->identifier,"post") == 0)
{
			pEventoutput = (kk_tsl_data_t *)(event->output_datas);
			number = event->output_data_number;
			break;
		}
    }

    for (index = 0; index < number; index++) {
        property_refer = NULL;
        identifier_refer = NULL;
		property_refer = pEventoutput+index;
		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 char* kk_tsl_post_property_end(_IN_ void *handle)
{
    char *payload = NULL;
    dm_api_property_t *dapi_property = NULL;

    if (handle == NULL) {
        return NULL;
    }
    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 NULL;
    }
    INFO_PRINT("Post Payload, Length: %d, Payload: %s\n", strlen(payload), payload);
    //res = dm_mgr_upstream_thing_property_post(dapi_property->shadow, payload, strlen(payload),isAsync);
    lite_cjson_delete(dapi_property->lite);
    free(dapi_property);
	//free(payload);
    dapi_property = NULL;
    return payload;
}

char* kk_tsl_get_post_property_str(kk_tsl_t		   *dev_shadow, const char *property_identifier)
{
    int res = 0, property_identifier_len = 0;
    void *property_handle = NULL;

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

	_kk_tsl_api_unlock();
    return kk_tsl_post_property_end(property_handle);

}
static int kk_tsl_event_output(_IN_ kk_tsl_t *dev_shadow, _IN_ char *identifier, _IN_ int identifier_len,
        _IN_ lite_cjson_item_t *lite)
{
    int res = 0;

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

    res = kk_tsl_assemble_event_output(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_ kk_tsl_t *dev_shadow, _IN_ char *identifier, _OU_ void **event)
{
    if (dev_shadow == NULL || identifier == NULL || event == NULL || *event != NULL) {
        return INVALID_PARAMETER;
    }

    return _kk_tsl_get_event_by_identifier(dev_shadow, identifier, event);
}

static int _kk_tsl_get_service_by_identifier(_IN_ kk_tsl_t *shadow, _IN_ char *identifier, _OU_ void **service)
{
    int index = 0;
    kk_tsl_event_t *search_event = NULL;

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

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

    return FAIL_RETURN;
}

int kk_tsl_get_service_by_identifier(_IN_ kk_tsl_t *dev_shadow, _IN_ char *identifier, _OU_ void **service)
{
    if (dev_shadow == NULL || identifier == NULL || service == NULL || *service != NULL) {
        return INVALID_PARAMETER;
    }

    return _kk_tsl_get_service_by_identifier(dev_shadow, identifier, service);
}

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

char* kk_tsl_get_post_event_str(_IN_ kk_tsl_t *dev_shadow, _IN_ char *identifier, _IN_ int identifier_len)
{
    int res = 0;

    lite_cjson_item_t *lite = NULL;
    char *payload = NULL;

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

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

    res = kk_tsl_event_output(dev_shadow, identifier, identifier_len, lite);
    if (res != SUCCESS_RETURN) {
        lite_cjson_delete(lite);
		_kk_tsl_api_unlock();
        return NULL;
    }

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

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

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

    //free(payload);
    return payload;
}


static char* _kk_tsl_send_service_response(_IN_ kk_tsl_t *dev_shadow,
        _IN_ char *identifier,
        _IN_ int identifier_len)
{
    int res = 0;
    lite_cjson_item_t *lite = NULL;
    char *payload = NULL;

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

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

    res = kk_tsl_assemble_service_output(dev_shadow, identifier, identifier_len, lite);
    if (res != SUCCESS_RETURN) {
        lite_cjson_delete(lite);
		_kk_tsl_api_unlock();
        return NULL;
    }
	_kk_tsl_api_unlock();

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

    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 payload;
}
int kk_tsl_get_service_method(_IN_ void *service, _OU_ char **method)
{
	int service_method_len = 0;
	const char *identifier = NULL;
	const char *service_method_fmt = "thing.service.%s_reply";
	kk_tsl_service_t *service_item = (kk_tsl_service_t *)service;

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


	identifier = (const char *)service_item->identifier;
	

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

	return SUCCESS_RETURN;
}

char * kk_tsl_get_post_service_str(kk_tsl_t *dev_shadow, const char *service_identifier)
{
    if (service_identifier == NULL) {
        ERROR_PRINT("Invalid Parameter");
        return NULL;
    }

    return _kk_tsl_send_service_response(dev_shadow,(char *)service_identifier, strlen(service_identifier));
}


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


