#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mqtt_api.h"
#include "com_api.h"
#include "cJSON.h"
#include "kk_product.h"
//#include "kcloud_log.h"

#define KK_FILTER_TOPO_TOPIC 		           "/thing/topo/"
#define KK_FILTER_TOPO_REPLY 		           "_reply"
#define KK_FILTER_DELETE_TOPIC                 "/thing/topo/delete"
#define KK_FILTER_DELETE_TOPIC_REPLY           "/thing/topo/delete_reply"
#define KK_FILTER_REGISTER_TOPIC               "/thing/sub/register"
#define KK_FILTER_REGISTER_TOPIC_REPLY         "/thing/sub/register_reply"
#define KK_FILTER_LOGIN_TOPIC                  "/thing/combine/login"
#define KK_FILTER_LOGIN_TOPIC_REPLY            "/thing/combine/login_reply"
#define KK_FILTER_SET_TOPIC                    "/thing/service/property/set"
#define KK_FILTER_SET_TOPIC_REPLY              "/thing/service/property/set_reply"
#define KK_FILTER_EVENT_POST_TOPIC1            "/thing/event/"
#define KK_FILTER_EVENT_POST_TOPIC2            "/post"
#define KK_FILTER_EVENT_POST_REPLY             "/post_reply"
#define KK_FILTER_STATUS_ONLINE                "/thing/status/online"
#define KK_FILTER_STATUS_ONLINE_REPLY          "/thing/status/online_reply"
#define KK_FILTER_STATUS_OFFLINE               "/thing/status/offline"
#define KK_FILTER_STATUS_OFFLINE_REPLY         "/thing/status/offline_reply"
#define KK_FILTER_TOPO_BATCH_DELETE            "/thing/topo/batch_delete"
#define KK_FILTER_TOPO_CHANEG_REPLY            "/thing/topo/change_reply"

#define KK_CLOUDSTATE_MSG                      "/thing/ccu/cloudstate"
#define KK_CLOUDSTATE_MSG_REPLY                "/thing/ccu/cloudstate_reply"
#define KK_TOPO_CHANGE_MSG_STR                 "/thing/topo/change"
#define KK_FILTER_SERVICE_CALL_TOPIC          "/thing/service/"
#define KK_FILTER_SERVICE_CALL_REPLY           "_reply"

const char DM_MSG_TO_MIDDWARE[] = "{\"msgtype\":\"%s\",\"productCode\":\"%s\",\"deviceCode\":\"%s\"}";
#define KK_TOPIC_SERVICE_DELIMITER 			  '/'
#define KK_POWER_SWITCH_1      		"PowerSwitch_1"
#define KK_POWER_SWITCH_2      		"PowerSwitch_2"
#define KK_POWER_SWITCH_3      		"PowerSwitch_3"



static char *s_split_product[] = {
	"85", 			//三路面板
	"97",           //双路面板
	"3003"			//三路面板	

};
static int kk_check_need_split(cJSON * info)
{
	//return 0;//暂时不用拆分处理
#if 1	
	cJSON *productCode = NULL;
	int i = 0;
	int num = sizeof(s_split_product)/sizeof(char*);

	
	if(info == NULL){
		return 0;
	}
	productCode = cJSON_GetObjectItem(info, MSG_PRODUCT_CODE_STR);
	if(productCode == NULL){
		return 0;
	}
	for(i = 0; i < num; i++){
		if(strncmp(s_split_product[i],productCode->valuestring,strlen(productCode->valuestring)) == 0){
			return 1;
		}
	}
	return 0;
#endif	
}
static int kk_split_send_data(cJSON *pData,const char* topic)
{ 
	cJSON *pParam = NULL;
	cJSON *pParam_new = NULL;	
	cJSON *powerswitch1 = NULL;
	cJSON *powerswitch2 = NULL;	
	cJSON *powerswitch3 = NULL;		
	if(pData == NULL){
		return RETURN_FAIL;
	}
	pParam = cJSON_GetObjectItem(pData, MSG_PARAMS_STR);
	if(pParam == NULL){
		return RETURN_FAIL;
	}	
	char* param_tmp = cJSON_Print(pParam);		
	powerswitch1 = cJSON_GetObjectItem(pParam, KK_POWER_SWITCH_1);
	if(powerswitch1 != NULL){
		cJSON_DeleteItemFromObject(pData,MSG_PARAMS_STR);
		cJSON *pParam_new = cJSON_CreateObject();
	 	cJSON_AddNumberToObject(pParam_new, KK_POWER_SWITCH_1, powerswitch1->valueint);
		cJSON_AddItemToObject(pData,MSG_PARAMS_STR,pParam_new);
		char* out=cJSON_Print(pData);
		KK_MQTT_SendMsg(topic,(const char*)out);	
		free(out);
		
	}
	pParam = cJSON_Parse(param_tmp);
	powerswitch2 = cJSON_GetObjectItem(pParam, KK_POWER_SWITCH_2);
	if(powerswitch2 != NULL){
		cJSON_DeleteItemFromObject(pData,MSG_PARAMS_STR);
		pParam_new = cJSON_CreateObject();
	 	cJSON_AddNumberToObject(pParam_new, KK_POWER_SWITCH_2, powerswitch2->valueint);
		cJSON_AddItemToObject(pData,MSG_PARAMS_STR,pParam_new);
		char* out=cJSON_Print(pData);
		KK_MQTT_SendMsg(topic,(const char*)out);	
		free(out);
	}	
	powerswitch3 = cJSON_GetObjectItem(pParam, KK_POWER_SWITCH_3);
	if(powerswitch3 != NULL){
		cJSON_DeleteItemFromObject(pData,MSG_PARAMS_STR);
		pParam_new = cJSON_CreateObject();
	 	cJSON_AddNumberToObject(pParam_new, KK_POWER_SWITCH_3, powerswitch3->valueint);
		cJSON_AddItemToObject(pData,MSG_PARAMS_STR,pParam_new);
		char* out=cJSON_Print(pData);
		KK_MQTT_SendMsg(topic,(const char*)out);	
		free(out);
	}	
	free(param_tmp);
	return RETURN_SUCCESS;
	
}
int _kk_sendto_cloud(cJSON *root)
{
	cJSON *info,*pData;
	char *topic = NULL;
	cJSON *msgTypeStr = NULL;
	info = cJSON_GetObjectItem(root, MSG_INFO_STR);
	if(info == NULL){
		return RETURN_FAIL;
	}
	msgTypeStr = cJSON_GetObjectItem(info, MSG_TYPE_STR);
	if(msgTypeStr == NULL){
		return RETURN_FAIL;
	}	
	topic = KK_Make_Topic(info);
	if(topic == NULL){
		return RETURN_FAIL;
	}
	pData = cJSON_GetObjectItem(root, MSG_PAYLOAD_STR);
	if(pData == NULL){
		free(topic);
		return RETURN_FAIL;
	}
	//If topo delete,need UnSubscribe the topic
	if(strstr(msgTypeStr->valuestring,KK_FILTER_DELETE_TOPIC) != NULL){
		KK_Subdev_UnSubscribe(pData);
		char* out=cJSON_Print(pData);
		KK_MQTT_SendMsg(topic,(const char*)out);	
		free(out);		
		free(topic);
		return RETURN_SUCCESS;

	}
	else if(strstr(msgTypeStr->valuestring,KK_FILTER_TOPO_BATCH_DELETE) != NULL){
		cJSON *params = NULL;
		params = cJSON_GetObjectItem(pData, MSG_PARAMS_STR);
		if(params != NULL){
			cJSON * devices = cJSON_GetObjectItem(params, MSG_TOPO_CHANGE_DEVICES_STR);
			if(devices != NULL){
				cJSON * item = devices->child;
				while(item != NULL){
					char *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR)->valuestring;
					char *productCode = cJSON_GetObjectItem(item,MSG_PRODUCT_CODE_STR)->valuestring;
					KK_Subdev_UnSubscribe_By_DeviceCode(deviceCode,productCode);
					item = item->next;
				} 
			}	
		}
		char* out=cJSON_Print(pData);
		KK_MQTT_SendMsg(topic,(const char*)out);	
		free(out);		
		free(topic);
		return RETURN_SUCCESS;
	}
	else if(strstr(msgTypeStr->valuestring,KK_CLOUDSTATE_MSG) != NULL){
		KK_Send_CloudState(kk_get_cloud_status());
		free(topic);
		return RETURN_SUCCESS;

	}
	if(kk_check_need_split(info)){
		kk_split_send_data(pData,topic);
	}
	else{
		char* out=cJSON_Print(pData);
		KK_MQTT_SendMsg(topic,(const char*)out);	
		free(out);
	}
	free(topic);
	return RETURN_SUCCESS;
}


void KK_Data_FromDev(void* str,int len)
{
	cJSON *root,*cmd;
	if(str == NULL){
		return;
	}
	root=cJSON_Parse((char*)str);
	if(root == NULL){
	    ERROR_PRINT("[%s][%d] root is null \n",__FUNCTION__,__LINE__);
		return;
	}
	cmd = cJSON_GetObjectItem(root, "cmd");
	if(cmd == NULL){
		_kk_sendto_cloud(root);
	}
	else{
		KK_Subdev_Subscribe(root);
	}
	cJSON_Delete(root);

}
static int _check_invalid_topic(const char* topic)
{
	if(strstr(topic, KK_FILTER_TOPO_TOPIC) != NULL && \
		strstr(topic,KK_FILTER_TOPO_REPLY) == NULL && \
		 strstr(topic,KK_TOPO_CHANGE_MSG_STR) == NULL){
		return 1;
	}
	else if(strstr(topic, KK_FILTER_REGISTER_TOPIC) != NULL && \
		strstr(topic,KK_FILTER_REGISTER_TOPIC_REPLY) == NULL){
		return 1;
	}		
	else if(strstr(topic, KK_FILTER_LOGIN_TOPIC) != NULL && \
		strstr(topic,KK_FILTER_LOGIN_TOPIC_REPLY) == NULL){
		return 1;
	}		
	else if(strstr(topic,KK_FILTER_TOPO_CHANEG_REPLY) != NULL){
		return 1;
	}
	else if(strstr(topic, KK_FILTER_EVENT_POST_TOPIC1) != NULL && \
		strstr(topic,KK_FILTER_EVENT_POST_TOPIC2) != NULL && \
		strstr(topic,KK_FILTER_EVENT_POST_REPLY) == NULL){
		return 1;
	}
	else if(strstr(topic, KK_FILTER_SERVICE_CALL_TOPIC) != NULL && \
		strstr(topic,KK_FILTER_SERVICE_CALL_REPLY) != NULL){
		return 1;
	}		
	else if(strstr(topic, KK_FILTER_STATUS_ONLINE) != NULL && \
		strstr(topic,KK_FILTER_STATUS_ONLINE_REPLY) == NULL){
		return 1;
	}
	else if(strstr(topic, KK_FILTER_STATUS_OFFLINE) != NULL && \
		strstr(topic,KK_FILTER_STATUS_OFFLINE_REPLY) == NULL){
		return 1;
	}				
	return 0;
}

static int _kk_topic_parse_msgType(_IN_ char *topic, _IN_ int start_deli,_OU_ char **msgTypeStr)
{
    int res = 0, start = 0, len = 0, slice = 0;
	char *msgTypeStr_tmp = NULL;

    if (topic == NULL) {
        return RETURN_FAIL;
    }
    res = kk_utils_memtok(topic, strlen(topic), KK_TOPIC_SERVICE_DELIMITER, start_deli, &start);
    if (res != 0) {
        return RETURN_FAIL;
    }
	len = strlen(topic) - start + 1;
	msgTypeStr_tmp = (char*)malloc(len+1);
	if(msgTypeStr_tmp == NULL){
		ERROR_PRINT("[%s][%d]malloc fail!!!\n",__FUNCTION__,__LINE__);
		return RETURN_FAIL;
	}
	memcpy(msgTypeStr_tmp, topic + start, len);
	*msgTypeStr = msgTypeStr_tmp;
	INFO_PRINT("[%s][%d]%s\n",__FUNCTION__,__LINE__,*msgTypeStr);


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

    return RETURN_SUCCESS;
}

static int _kk_topic_parse_pkdn(_IN_ char *topic, _IN_ int start_deli,
                           _OU_ char productCode[PRODUCT_CODE_LEN],_OU_ char deviceCode[DEVICE_CODE_LEN])
{
    int res = 0, start = 0, end = 0, slice = 0;

    if (topic == NULL || deviceCode == NULL) {
        return RETURN_FAIL;
    }
    res = kk_utils_memtok(topic, strlen(topic), KK_TOPIC_SERVICE_DELIMITER, start_deli, &start);
    if (res != 0) {
        return RETURN_FAIL;
    }
    res = kk_utils_memtok(topic, strlen(topic), KK_TOPIC_SERVICE_DELIMITER, start_deli + 1, &slice);
    if (res != 0) {
        return RETURN_FAIL;
    }

    res = kk_utils_memtok(topic, strlen(topic), KK_TOPIC_SERVICE_DELIMITER, start_deli + 2, &end);
    if (res != 0) {
        return RETURN_FAIL;
    }

    memcpy(productCode, topic + start + 1, slice - start - 1);	
    memcpy(deviceCode, topic + slice + 1, end - slice - 1);

    return RETURN_SUCCESS;
}
static int _kk_topo_change_handle(cJSON *payload)
{
   cJSON *paramStr = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
   if(paramStr == NULL){
   		ERROR_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
   		return RETURN_FAIL;
   }
   cJSON *state = cJSON_GetObjectItem(paramStr, MSG_TOPO_CHANGE_TYPE_STR);
   if(state != NULL && state->valueint == 1){
	   cJSON *deviceArray = cJSON_GetObjectItem(paramStr, MSG_TOPO_CHANGE_DEVICES_STR);
	   if(deviceArray == NULL){
	   	   ERROR_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		   return RETURN_FAIL;
	   }
	   cJSON * item = deviceArray->child;
	   while(item != NULL){
		   char *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR)->valuestring;
		   char *productCode = cJSON_GetObjectItem(item,MSG_PRODUCT_CODE_STR)->valuestring;
	   	   KK_Subdev_UnSubscribe_By_DeviceCode(deviceCode,productCode);
		   item = item->next;
	   }  
   }
   return RETURN_SUCCESS;

}

static char * _kk_data_create(const char *topic,const char *data)
{
	cJSON *root;
	char *out;
	char *infoStr = NULL;
	int infoStr_len = 0;
	int res = 0;
    char productCode[PRODUCT_CODE_LEN] = {0};	
    char deviceCode[DEVICE_CODE_LEN] = {0};	
	char * msgStr = NULL;

	res =_kk_topic_parse_pkdn((char *)topic,3,productCode,deviceCode);
	res|=_kk_topic_parse_msgType((char *)topic,5,&msgStr);
	infoStr_len = strlen(DM_MSG_TO_MIDDWARE)+strlen(productCode)+strlen(deviceCode)+strlen(msgStr)+10;
	infoStr = malloc(infoStr_len);
	if(infoStr == NULL){
		ERROR_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		free(msgStr);
		return NULL;
	}
	memset(infoStr,0x0,infoStr_len);
	snprintf(infoStr,infoStr_len,DM_MSG_TO_MIDDWARE,msgStr,productCode,deviceCode);

	root=cJSON_CreateObject();
    cJSON* infoObj = cJSON_Parse(infoStr);
    cJSON* payloadObj = cJSON_Parse(data);
    cJSON_AddItemToObject(root, MSG_INFO_STR, infoObj);
    cJSON_AddItemToObject(root, MSG_PAYLOAD_STR,payloadObj);	
	if(strstr(topic,KK_TOPO_CHANGE_MSG_STR)){
		_kk_topo_change_handle(payloadObj);
	}	
	
	out=cJSON_Print(root);
	cJSON_Minify(out);
	cJSON_Delete(root);
	free(msgStr);
	free(infoStr);
	INFO_PRINT("[%s][%d]%s\n",__FUNCTION__,__LINE__,out);	
	
	return out;
	//free(out);	/* Print to text, Delete the cJSON, print it, release the string. */
}
const char DM_MSG_CLOUDSTATE[] = "{\"msgId\":\"1\",\"version\":\"1.0\",\"params\":{\"IOTCloudState\":\"%d\"},\"method\":\"thing.ccu.cloudstate_reply\"}";
int KK_Send_CloudState(int state)
{
	char *infoStr = NULL;
	char *payloadStr = NULL;	
	int infoStr_len = 0;
	int payloadStr_len = 0;	
	cJSON *root;
	char *out;

	infoStr_len = strlen(DM_MSG_TO_MIDDWARE)+strlen(KK_CLOUDSTATE_MSG_REPLY)+10;
	infoStr = malloc(infoStr_len);
	if(infoStr == NULL){
		ERROR_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		return RETURN_FAIL;
	}
	memset(infoStr,0x0,infoStr_len);
	snprintf(infoStr,infoStr_len,DM_MSG_TO_MIDDWARE,KK_CLOUDSTATE_MSG_REPLY,"","");

	payloadStr_len = strlen(DM_MSG_CLOUDSTATE) + 10;
	payloadStr = malloc(payloadStr_len);
	if(payloadStr == NULL){
		ERROR_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		return RETURN_FAIL;
	}
	memset(payloadStr,0x0,payloadStr_len);
	snprintf(payloadStr,payloadStr_len,DM_MSG_CLOUDSTATE,state);
	
	root=cJSON_CreateObject();
    cJSON* infoObj = cJSON_Parse(infoStr);
    cJSON* payloadObj = cJSON_Parse(payloadStr);
    cJSON_AddItemToObject(root, MSG_INFO_STR, infoObj);
    cJSON_AddItemToObject(root, MSG_PAYLOAD_STR,payloadObj);			
	out=cJSON_Print(root);	
	kk_ipc_send(IPC_APP2MID, out, strlen(out)+1);
	cJSON_Delete(root);
	free(payloadStr);
	free(infoStr);
	INFO_PRINT("[%s][%d]%s\n",__FUNCTION__,__LINE__,out);	
	free(out);
	return RETURN_SUCCESS;
}
void KK_Sendto_DevData(const char *topic,const char *data)
{
	if(_check_invalid_topic(topic))
	{
		INFO_PRINT("[%s][%d]ingore the topic:%s\n",__FUNCTION__,__LINE__,topic);
		return;//ingore the message
	}
	INFO_PRINT("[%s][%d]receive from cloud,topic:%s\n",__FUNCTION__,__LINE__,topic);	
	char *send_data = _kk_data_create(topic,data);
	if(send_data == NULL){
		return;
	}
	kk_ipc_send(IPC_APP2MID, send_data, strlen(send_data)+1);
	free(send_data);
}
