#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "kk_data_mng.h"
#include "kk_login_handle.h"
#include "kk_lan_node_db.h"
#include "kk_log.h"
#include "klist.h"
#include "kk_product.h"
#include "com_api.h"
#include "kk_opcode.h"
#include "kk_lan_ctrl.h"
#include "kk_data_mng.h"
#include "kk_oldccu_msg.h"
#include "kk_lan_sync.h"
#include "kk_data_mng.h"
#include "kk_data_handle.h"
cJSON *old_ccu_msg_build_json(const char* nodeid,const char*  opcode,const char*  status,cJSON * arg)
{
	cJSON *root;

	if(nodeid==NULL||opcode==NULL||arg==NULL) {
		return NULL;
	}
	root=cJSON_CreateObject();
	if(root){
		cJSON_AddStringToObject(root, "nodeid", nodeid);
		cJSON_AddStringToObject(root, "opcode", opcode);
		cJSON_AddStringToObject(root, "status", "success");
		cJSON_AddItemToObject(root, "arg", arg);
	}
	return root;
}

cJSON *old_ccu_msg_build(const char* nodeid,const char* opcode,const char* status,const char* arg)
{
	cJSON *root;

	if(nodeid==NULL||opcode==NULL||arg==NULL) {
		return NULL;
	}
	
	root=cJSON_CreateObject();
	if(root){
		cJSON_AddStringToObject(root, "nodeid", nodeid);
		cJSON_AddStringToObject(root, "opcode", opcode);
		if(status==NULL){
			cJSON_AddStringToObject(root, "status", "success");
		}else{
			cJSON_AddStringToObject(root, "status", status);
		}
		cJSON_AddStringToObject(root, "arg", arg);
	}
	return root;
}

int send_msg_to_module(cJSON *root)
{
	char *msg;
	
	if(root==NULL){
		return -1;
	}
	if((msg = cJSON_Print(root))!=NULL){
		//debug_log(LOG_INFO_LEVEL,"[lan->module]\n%s\n",msg);
		cJSON_Minify(msg);
		kk_send_data_to_sdk(msg);
		free(msg);
	}
	return 0;
}

cJSON * val_conver_new2old(cJSON *newccuItem,cJSON *oldccuItem,int syn_type)
{
	cJSON *n_value = NULL,*n_dataType = NULL,*o_dataType = NULL;
	cJSON *o_valueRange = NULL,*n_valueRange = NULL;

	if(newccuItem==NULL||newccuItem->type!=cJSON_Object||
		oldccuItem==NULL||oldccuItem->type!=cJSON_Object){
		debug_log(LOG_DEBUG_LEVEL,"[err] para.\n");
		return NULL;
	}

	o_valueRange = cJSON_GetObjectItem(oldccuItem,"valueRange");
	n_valueRange = cJSON_GetObjectItem(newccuItem,"valueRange");


	n_dataType = cJSON_GetObjectItem(newccuItem,DATATYPE_STRING);
	n_value  = cJSON_GetObjectItem(newccuItem,"value");

	if(syn_type==1){
		o_dataType = cJSON_GetObjectItem(oldccuItem,"synType");
	}else{
		o_dataType = cJSON_GetObjectItem(oldccuItem,DATATYPE_STRING);
	}

	return ccu_value_convert(n_dataType,n_valueRange,o_dataType,o_valueRange,n_value);
}
static int s_motorPostion = -1;
void kk_record_motorPosition(int value){
	s_motorPostion = value;
	debug_log(LOG_DEBUG_LEVEL,"s_motorPostion:%d\n",s_motorPostion);
}
//更新设备状态
static int _kk_lan_update_device_status(int nodeId,cJSON *opcode,cJSON *arg,const char *syn_opcode)
{
	cJSON *msg = NULL;
	char nodeBuff[33] = {0};
	char valBuff[33] = {0};

	if(opcode==NULL||opcode->type!=cJSON_String||
		arg==NULL){
		debug_log(LOG_DEBUG_LEVEL,"[err] para.\n");
		return -1;
	}

	memset(nodeBuff,0,sizeof(nodeBuff));
	snprintf(nodeBuff,32,"%d",nodeId);
	memset(valBuff,0,sizeof(valBuff));

	if(arg->type==cJSON_String){

		debug_log(LOG_CRIT_LEVEL,"nodeId=%d,opcode=%s,arg=%s\n",nodeId,opcode->valuestring,arg->valuestring);
		snprintf(valBuff,sizeof(valBuff),"%s",arg->valuestring);
	}else if(arg->type==cJSON_Number){

		if(((int)(arg->valuedouble*10))%10==0){
			debug_log(LOG_CRIT_LEVEL,"nodeId=%d,opcode=%s,arg=%d\n",nodeId,opcode->valuestring,arg->valueint);
			snprintf(valBuff,sizeof(valBuff),"%d",arg->valueint);
		}else{
			debug_log(LOG_CRIT_LEVEL,"nodeId=%d,opcode=%s,arg=%f\n",nodeId,opcode->valuestring,arg->valuedouble);
			snprintf(valBuff,sizeof(valBuff),"%f",arg->valuedouble);
		}
	}else if(arg->type==cJSON_True){
		snprintf(valBuff,sizeof(valBuff),"%s","true");
	}else if(arg->type==cJSON_True){
		snprintf(valBuff,sizeof(valBuff),"%s","false");
	}

	if(syn_opcode==NULL || strcmp(syn_opcode,"DOOYA_STATUS")==0){
		msg = old_ccu_msg_build(nodeBuff,opcode->valuestring,"success",valBuff);
		send_msg_to_module(msg);
		cJSON_Delete(msg);
	}

	return 0;
}


static int _kk_lan_check_channel(cJSON *channelObj,cJSON *epNumObj)
{
	int channel = -1;

	if(channelObj!=NULL && epNumObj!=NULL){

		if(epNumObj->type!=cJSON_String){

			debug_log(LOG_INFO_LEVEL,"[err] epNumObj.\n");
			return -1;
		}

		if(strlen(channelObj->valuestring)!=strlen(epNumObj->valuestring) ||
			strcmp(channelObj->valuestring,epNumObj->valuestring)!=0){

			//debug_log(LOG_INFO,"[err] not match.\n");
			return -1;
		}

		channel = atoi(channelObj->valuestring);
	}else{

		if(channelObj==NULL){

			if(epNumObj==NULL||epNumObj->type!=cJSON_String){
				debug_log(LOG_INFO_LEVEL,"[err] epNumObj.\n");
				return 1;
			}

			channel = atoi(epNumObj->valuestring);
		}else if(epNumObj==NULL){
		
			if(channelObj->type!=cJSON_String){
				debug_log(LOG_INFO_LEVEL,"[err] channelObj.\n");
				return 1;
			}

			channel = atoi(channelObj->valuestring);
		}else{
	
			channel = 1;
		}
	}

	return channel;
}


static int _kk_lan_sync_device_status(const char *deviceCode,kk_map_dev_node_t *devNode,int ch)
{
	cJSON *msg = NULL;
	cJSON *arg = NULL;
	int ignore = 0;
	int nodeId = -1;
	char nodeBuff[33] = {0};

	if(devNode==NULL||devNode->syn_type!=1||devNode->syn_opcode==NULL){
		return -1;
	}

	if((arg =_kk_sync_devicestatus_arg_build(devNode,ch))==NULL){
		debug_log(LOG_DEBUG_LEVEL,"[err] arg.\n");
		return -1;
	}
	if(strcmp(devNode->productCode,AIR_FRESH_MUTI_DEVICE) == 0){
		if((nodeId = kk_lan_db_node_get(deviceCode,3))==-1){
			debug_log(LOG_DEBUG_LEVEL,"[err] nodeId.\n");
			return -1;
		} 
	}else if(strcmp(devNode->productCode,HEATING_FRESH_MUTI_DEVICE) == 0){
		if((nodeId = kk_lan_db_node_get(deviceCode,2))==-1){
			debug_log(LOG_DEBUG_LEVEL,"[err] nodeId.\n");
			return -1;
		} 
	}else{
		if((nodeId = kk_lan_db_node_get(deviceCode,ch))==-1){
			debug_log(LOG_DEBUG_LEVEL,"[err] nodeId.\n");
			return -1;
		} 
	}
	debug_log(LOG_CRIT_LEVEL,"[sync] device status.\n");

	memset(nodeBuff,0,sizeof(nodeBuff));
	snprintf(nodeBuff,sizeof(nodeBuff),"%d",nodeId);
	//printf("----------------------[%s][%d]\n",__FUNCTION__,__LINE__);
	cJSON *motorPosCJSON  = cJSON_GetObjectItem(arg,"motorPos");
	//printf("----------------------[%s][%d]\n",__FUNCTION__,__LINE__);
	if(motorPosCJSON != NULL&& motorPosCJSON->type == cJSON_String){//窗帘电机上报的position与设置的不一致，忽略上报
		//printf("----------------------[%s][%d]s_motorPostion:%d\n",__FUNCTION__,__LINE__,s_motorPostion);
		//printf("----------------------[%s][%d]atoi(motorPosCJSON->valuestring):%d\n",__FUNCTION__,__LINE__,atoi(motorPosCJSON->valuestring));
		if(s_motorPostion != atoi(motorPosCJSON->valuestring) && s_motorPostion != -1){
			ignore = 1;
		}
	}
	//printf("----------------------[%s][%d]\n",__FUNCTION__,__LINE__);
	msg=old_ccu_msg_build_json(nodeBuff,devNode->syn_opcode,NULL,arg);
	if(!ignore){
		send_msg_to_module(msg);
		s_motorPostion = -1;
	}
	
	cJSON_Delete(msg);
	return 0;
}



//属性转换
static int kk_lan_property_convert(const char *deviceCode,kk_map_dev_node_t *devNode,cJSON *params)
{
	int i = 0,k=0,channel = -1,nodeId = -1;
	cJSON *args = NULL,*valObj = NULL;

	cJSON *newccu = NULL,*oldccu = NULL;
	cJSON *n_item = NULL,*o_item = NULL;
	cJSON *o_valueRange = NULL,*n_valueRange = NULL;
	cJSON *o_dataType = NULL,*n_dataType = NULL;
	cJSON *opcode = NULL,*channelObj = NULL,*epNumObj = NULL;
	cJSON *n_id = NULL;
	int o_item_size=0,n_item_size=0;
	int item_size = 0;
	
	cJSON *epsAry = NULL,*epAryItem = NULL,*epAryEpNumObj = NULL;
	int j,mFlag=0,epsArySize = 0;
	
	if(deviceCode==NULL||devNode==NULL||
		params==NULL||params->type!=cJSON_Object){
		debug_log(LOG_DEBUG_LEVEL,"[err] para.\n");
		return -1;
	}
	

	oldccu = devNode->oldccu;
	newccu = devNode->newccu;


	o_item_size = cJSON_GetArraySize(oldccu);
	n_item_size = cJSON_GetArraySize(newccu);

	item_size = (n_item_size>o_item_size)?o_item_size:n_item_size;

	for(i=0;i<item_size;i++){

		n_item = cJSON_GetArrayItem(newccu,i);


		if((o_item = cJSON_GetArrayItem(oldccu,i))==NULL||
			o_item->type!=cJSON_Object){
			debug_log(LOG_INFO_LEVEL,"[err] para.i=%d\n",i);
			continue ;
		}


		if((n_id = cJSON_GetObjectItem(n_item,"identifier"))==NULL||
			n_id->type!=cJSON_String){
			debug_log(LOG_DEBUG_LEVEL,"[err] cfg file.\n");
			continue;
		}
		n_dataType = cJSON_GetObjectItem(n_item,"dataType");
		n_valueRange = cJSON_GetObjectItem(n_item,"valueRange");

		o_dataType = cJSON_GetObjectItem(o_item,"dataType");
		o_valueRange = cJSON_GetObjectItem(o_item,"valueRange");
		

		if(n_dataType==NULL||n_dataType->type!=cJSON_String||
			o_dataType==NULL||o_dataType->type!=cJSON_String){
			debug_log(LOG_DEBUG_LEVEL,"[err] dataType.\n");
			continue;
		}

		channelObj = cJSON_GetObjectItem(o_item,"channel");
	
		epNumObj = cJSON_GetObjectItem(params,"epNum");

		if((channel = _kk_lan_check_channel(channelObj,epNumObj))==-1){
			debug_log(LOG_DEBUG_LEVEL,"[channel] %d.\n",channel);
			continue;
		}


		if((epsAry = cJSON_GetObjectItem(params,"eps"))!=NULL&&epsAry->type==cJSON_Array){
			epsArySize = cJSON_GetArraySize(epsAry);
			for(j=0;j<epsArySize;j++){
				epAryItem = cJSON_GetArrayItem(epsAry,j);

				epAryEpNumObj = cJSON_GetObjectItem(epAryItem,"epNum");
				if(epAryEpNumObj==NULL||epAryEpNumObj->type!=cJSON_String ||channel!=atoi(epAryEpNumObj->valuestring)){
					debug_log(LOG_DEBUG_LEVEL,"[epsAry match 11] next.\n");
					continue ;
				}
				if((valObj=cJSON_GetObjectItem(epAryItem,n_id->valuestring))==NULL){
					debug_log(LOG_DEBUG_LEVEL,"[epsAry match 22] next.\n");
					continue ;
				}else{
					mFlag = 1;
					break;
				}
			}
			if(mFlag!=1){
				continue ;
			}
		}else{
			if((valObj=cJSON_GetObjectItem(params,n_id->valuestring))==NULL){
				debug_log(LOG_DEBUG_LEVEL,"[match] next.\n");
				continue ;
			}
		}
	
		if((nodeId = kk_lan_db_node_get(deviceCode,channel))==-1){
			debug_log(LOG_DEBUG_LEVEL,"[err] not find node.\n");
			continue;
		}


		if((opcode = cJSON_GetObjectItem(n_item,"opcodemap"))==NULL||
			opcode->type!=cJSON_String){
			debug_log(LOG_DEBUG_LEVEL,"[err] cfg file.\n");
			continue;
		}
	
		kk_lan_replace_val_to_obj(n_item,valObj,"value");

		if((args = ccu_value_convert(n_dataType,n_valueRange,o_dataType,o_valueRange,valObj))!=NULL){
			//printf("[%s][%d]\n",__FUNCTION__,__LINE__);
			_kk_lan_update_device_status(nodeId,opcode,args,devNode->syn_opcode);
			//printf("[%s][%d]\n",__FUNCTION__,__LINE__);


		}
	}

	debug_log(LOG_EMERG_LEVEL,"devNode->channelNum=%d\n",devNode->channelNum);

	for(k=0;k<devNode->channelNum;k++){
		debug_log(LOG_EMERG_LEVEL,"k=%d\n",k);
		_kk_lan_sync_device_status(deviceCode,devNode,k+1);
	}
	return 0;
}



static int attr_indoorAir_report(cJSON *params,const char *deviceCode)
{
	int k = 0;
	if(params == NULL){
		return -1;
	}
	cJSON *epsAry = cJSON_GetObjectItem(params,"eps");
	if(epsAry == NULL){
		kk_send_indoorAir_status(params,deviceCode);
		return -1;
	}else{
		int epsize = cJSON_GetArraySize(epsAry);
		for(k = 0; k < epsize; k++){
			cJSON *infoItem = cJSON_GetArrayItem(epsAry,k);
			if(infoItem == NULL) continue;

			kk_send_indoorAir_status(infoItem,deviceCode);
	
		}
	}
	return 0;
}
//属性状态上报处理
int kk_lan_property_post_deal(const char *deviceCode,cJSON *payload)
{
	cJSON *params = NULL;
	kk_map_dev_node_t *dev = NULL;

	debug_log(LOG_CRIT_LEVEL,"[property post] deviceCode(%s).\n",deviceCode);
		
	if(kk_map_dev_search_by_deviceCode(deviceCode, &dev)==0){
		params = cJSON_GetObjectItem(payload,"params");

		if(strcmp(dev->productCode,"3062") == 0){
			attr_indoorAir_report(params,deviceCode);
		}else{
			return kk_lan_property_convert(deviceCode,dev,params);
		}
	}else{
		debug_log(LOG_DEBUG_LEVEL,"[err] not find deviceCode(%s).\n",deviceCode);
		return -1;
	}
	return 0;
}

//属性状态同步处理
int kk_lan_property_syn_deal(const char *deviceCode,cJSON *properties)
{
	cJSON *params = NULL;
	kk_map_dev_node_t *dev = NULL;
	
	debug_log(LOG_CRIT_LEVEL,"[property syn] deviceCode(%s).\n",deviceCode);

	if(kk_map_dev_search_by_deviceCode(deviceCode, &dev)==0){

		return kk_lan_property_convert(deviceCode,dev,properties);
	}else{
		debug_log(LOG_DEBUG_LEVEL,"[err] not find deviceCode(%s).\n",deviceCode);
		return -1;
	}
	return 0;
}

//添加场景通知
void kk_lan_add_scene_notify(const char* scene_id)
{
	debug_log(LOG_CRIT_LEVEL,"[notify] add scene(%s).\n",scene_id);

	kk_handle_sync_push_info();
}

//删除场景通知
void kk_lan_delete_scene_notify(const char* scene_id)
{
	debug_log(LOG_CRIT_LEVEL,"[notify] delete scene(%s).\n",scene_id);

	cJSON *msg = old_ccu_msg_build(scene_id,"DELETE_SCENE",SUCCESS_STR,WILDCARD_CHARACTER_STR);
	send_msg_to_module(msg);
	cJSON_Delete(msg);
	
	kk_handle_sync_push_info();
}

//布防撤防状态通知(0-离家布防、1-撤防、2-在家布防、3-区域布防) 
int kk_lan_arming_status_notify(int type)
{
	cJSON *msg = NULL;
	
	debug_log(LOG_CRIT_LEVEL,"[notify] arming status(%d).\n",type);

	if(type==0){
		msg = old_ccu_msg_build(WILDCARD_CHARACTER_STR,GUARD_STATUS_ARMING_LEAVE_HOME,SUCCESS_STR,WILDCARD_CHARACTER_STR);
	}else if(type==1){
		msg = old_ccu_msg_build(WILDCARD_CHARACTER_STR,GUARD_STATUS_DISARMING,SUCCESS_STR,WILDCARD_CHARACTER_STR);
	}else if(type==2){
		msg = old_ccu_msg_build(WILDCARD_CHARACTER_STR,GUARD_STATUS_ARMING_IN_HOME,SUCCESS_STR,WILDCARD_CHARACTER_STR);
	}else if(type==3){
		msg = old_ccu_msg_build(WILDCARD_CHARACTER_STR,ARMING_STATUS_GUARD_ZONE,SUCCESS_STR,WILDCARD_CHARACTER_STR);
	}else{
		debug_log(LOG_DEBUG_LEVEL,"[err] unknow type(%d).\n",type);
		return -1;
	}

	send_msg_to_module(msg);
	cJSON_Delete(msg);
	return 0;
}


static int _kk_lan_delete_node(const char *deviceCode,const char *nodeid)
{
	cJSON *msg;
	cJSON *arg;
	char mac[32] = {0};
	kk_map_dev_node_t *dev;

	if(deviceCode==NULL||nodeid==NULL){
		debug_log(LOG_DEBUG_LEVEL,"[err] params.\n");
		return -1;
	}

	debug_log(LOG_CRIT_LEVEL,"[del dev node] id(%s).\n",nodeid);
	
	arg = cJSON_CreateObject();
	_deviceCode_switchto_mac(deviceCode,mac);
	cJSON_AddStringToObject(arg,"mac",mac);
	msg = old_ccu_msg_build_json(nodeid,"DEL_DEVICE",NULL,arg);
	send_msg_to_module(msg);
	cJSON_Delete(msg);

	return 0;
}

static int _kk_lan_delete_device(const char *deviceCode)
{
	#define MAX_CHANNEL_NUM 				32
	int list[MAX_CHANNEL_NUM] = {0};
	int i,num = 0;
	char nodeId[33] = {0};

	num = kk_lan_db_node_get_all(deviceCode,list);

	debug_log(LOG_CRIT_LEVEL,"[del dev] deviceCode(%s)/node num(%d).\n",deviceCode,num);
	
	for(i=0;i<num;i++){
		memset(nodeId,0,sizeof(nodeId));
		snprintf(nodeId,sizeof(nodeId),"%d",list[i]);
		_kk_lan_delete_node(deviceCode,nodeId);
	}
	
	//删除数据库
	kk_lan_db_node_delete(deviceCode);
	
	if(num){
		kk_handle_sync_push_info();
	}	
	return 0;
}

int kk_lan_device_delete_notify(cJSON *payload)
{
	cJSON *params = NULL;
	cJSON *deviceCode = NULL;

	if((params = cJSON_GetObjectItem(payload,"params"))==NULL||
		params->type!=cJSON_Object){
		debug_log(LOG_DEBUG_LEVEL,"[err] params.\n");
		return -1;
	}

	if((deviceCode = cJSON_GetObjectItem(params, "deviceCode"))==NULL||
		deviceCode->type!=cJSON_String){
		debug_log(LOG_DEBUG_LEVEL,"[err] deviceCode.\n");
		return -1;
	}

	indoor_airstatus_table_delete_item(deviceCode->valuestring);
	_kk_lan_delete_device(deviceCode->valuestring);
		
	return 0;
}

void device_add_sync(cJSON *payload)
{
	//NEW_DEVICES
	printf("[%s][%d]\n",__FUNCTION__,__LINE__);
	kk_handle_sync_push_info();
}

