/************************************************************
*版权所有 （C）2020，公司（或个人）名称
*
*文件名称： kcloud_data_handle.c
*内容摘要： application层数据处理
*其他说明： 
*当前版本：  
*************************************************************/
 
/*************************************************************
头文件引用 
*************************************************************/

#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"

extern char* KK_Make_Topic(cJSON *info);
extern int KK_Subdev_UnSubscribe(cJSON *payload);
extern int KK_Subdev_UnSubscribe_By_DeviceCode(const char *deviceCode,const char *productCode );
extern int KK_Subdev_Subscribe(const cJSON *root);
int KK_Send_CloudState(int state);

static char *s_split_product[] = {
	"3002", 		//星辰系列双路面板
	"3003",         //星辰系列三路面板
	"3010",			//铂金系列双路面板
	"3011",			//铂金系列三路面板	
	"3023",			//肖邦系列双路面板
	"3024"			//肖邦系列三路面板	
};

static int kk_utils_memtok(_IN_ char *input, _IN_ int input_len, _IN_ char delimiter, _IN_ int index, _OU_ int *offset)
{
    int item_index = 0;
    int count = 0;

    if (input == NULL || input_len <= 0 || offset == NULL) {
        return -2;
    }

    for (item_index = 0; item_index < input_len; item_index++) {
        if (input[item_index] == delimiter && (item_index + 1) < input_len) {
            count++;
            if (count == index) {
                *offset = item_index;
                return 0;
            }
        }
    }

    return -1;
}
/************************************************************
*功能描述：灯控面板需要分开上报属性
*输入参数： info：所上报数据
*输出参数： 无
*返 回 值：  1：需要拆分；0：不需要
*其他说明：
*************************************************************/
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	
}

/************************************************************
*功能描述：灯控面板拆分具体的属性并逐个上报
*输入参数： pData：所上报数据
		  topic：主题
*输出参数： 无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/
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((char*)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((char*)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((char*)topic,(const char*)out);	
		free(out);
	}	
	free(param_tmp);
	return RETURN_SUCCESS;
	
}
/************************************************************
*功能描述：上报数据给云端
*输入参数： root：所上报数据
*输出参数： 无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/

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

/************************************************************
*功能描述：获取midware上报的数据
*输入参数： str：所上报数据
          len：数据长度
*输出参数： 无
*返 回 值：  无
*其他说明：
*************************************************************/

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

}
/************************************************************
*功能描述：无效主题过滤
*输入参数： topic：主题
*输出参数： 无
*返 回 值：  1：过滤；0：不过滤
*其他说明：
*************************************************************/

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;
}
/************************************************************
*功能描述：从主题解析出消息
*输入参数： topic：主题
          start_deli：从第start_deli个'/'开始解析
*输出参数： msgTypeStr：消息类型
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/
static int _kk_topic_parse_msgType(_IN_ char *topic, _IN_ int start_deli,_OU_ char **msgTypeStr)
{
    int res = 0, start = 0, len = 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;
}

/************************************************************
*功能描述：从主题解析出productCode和deviceCode
*输入参数： topic：主题
          start_deli：从第start_deli个'/'开始解析
*输出参数： productCode：产品ID
          deviceCode：设备deviceCode
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/

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;
}
						   
/************************************************************
*功能描述：topo change消息处理
*输入参数： payload：具体数据
*输出参数： 无
*返 回 值：  0：成功；其他：失败
*其他说明：此接口主要手机端主动删除设备时调用
*************************************************************/						   
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;

}

/************************************************************
*功能描述：从云端数据转化成业务协议数据
*输入参数： data：具体数据
          topic：主题
*输出参数： 无
*返 回 值：  NULL：失败；其他：具体协议数据
*其他说明：
*************************************************************/			
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,2,productCode,deviceCode);
	//if(!strcmp("gateway_2",productCode)){
		//memset(productCode,0x0,sizeof(productCode));
		//memcpy(productCode,"2",strlen("2"));
	//}
	res|=_kk_topic_parse_msgType((char *)topic,4,&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("[out]%s\n",out);	
	
	return out;
	//free(out);	/* Print to text, Delete the cJSON, print it, release the string. */
}

/************************************************************
*功能描述：通知midware是否连云成功
*输入参数： state：1，连上；0：未连上
*输出参数： 无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/		
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;
}
/************************************************************
*功能描述：发送数据给Midware
*输入参数： topic：主题；
          data：具体数据
*输出参数： 无
*返 回 值：  无
*其他说明：
*************************************************************/	
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);
}
