#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"
#include "kk_log.h"
#include "kk_hal.h"
#include "kk_product.h"
#include "kk_tsl_common.h"
#include "kk_tsl_api.h"
#include "kk_dm_api.h"
#include "kk_dm_msg.h"
#include "kk_dm_mng.h"
#include "kk_property_db.h"
#include "kk_mutictrl_handle.h"
#include "kk_scene_handle.h"
#include "kk_utils.h"
// g_mc_stamp[6] = {0};
#if 1
void split(char *src,const char *separator,char **dest,int *num);
int kk_mutictrl_rm_list(mutictrl_record_t *node);
static dm_mutictrl_ctx g_dm_mutictrl = {0};
static dm_mutictrl_ctx *_dm_mutictrl_get_ctx(void)
{
	return &g_dm_mutictrl;
}

static void _dm_mutictrl_mutex_lock(void)
{
    dm_mutictrl_ctx *ctx = _dm_mutictrl_get_ctx();
    if (ctx->mutex) {
        kk_MutexLock(ctx->mutex);
    }
}

static void _dm_mutictrl_mutex_unlock(void)
{
    dm_mutictrl_ctx *ctx = _dm_mutictrl_get_ctx();
    if (ctx->mutex) {
        kk_MutexUnLock(ctx->mutex);
    }
}
void *kk_muti_dispatch_yield(void *args)
{
	dm_mutictrl_ctx *ctx = _dm_mutictrl_get_ctx();
	time_t timestampnow = 0;
	while (1) {
		mutictrl_record_t *search_node = NULL;	
		timestampnow = HAL_Uptimes();
		_dm_mutictrl_mutex_lock();
		list_for_each_entry(search_node, &ctx->mutictrl_list, linked_list, mutictrl_record_t) {
			if (timestampnow - search_node->timestamp >=5){
				INFO_PRINT("kk_muti_dispatch_yield kk_mutictrl_rm_list\n");
				kk_mutictrl_rm_list(search_node);
			}
		}
		_dm_mutictrl_mutex_unlock();
		usleep(500000);
	}
	return NULL;
}
int kk_mutictrl_init(void)
{
	int res = 0;
	dm_mutictrl_ctx *ctx = _dm_mutictrl_get_ctx();
	memset(ctx, 0, sizeof(dm_mutictrl_ctx));
	ctx->mutex = kk_MutexCreate();
	if (ctx->mutex == NULL) {
		return -1;
	}
	INIT_LIST_HEAD(&ctx->mutictrl_list);
	res = pthread_create((pthread_t *)&ctx->g_mutictrl_thread, NULL, kk_muti_dispatch_yield, NULL);
	if (res < 0) {
		ERROR_PRINT("HAL_ThreadCreate mid Failed\n");
		//IOT_Linkkit_Close(mid_ctx->master_devid);
		return -1;
	}	
	return 0;
}
int kk_mutictrl_add_list(char *sceneId,char *deviceCode,int ep)
{
	dm_mutictrl_ctx *ctx = _dm_mutictrl_get_ctx();
	mutictrl_record_t *node = NULL;	
	mutictrl_record_t *search_node = NULL;	
	_dm_mutictrl_mutex_lock();
	list_for_each_entry(search_node, &ctx->mutictrl_list, linked_list, mutictrl_record_t) {
		if (search_node->epNum == ep &&
			(memcmp(search_node->deviceCode, deviceCode, strlen(deviceCode)) == 0)&&
			(memcmp(search_node->sceneId, sceneId, strlen(sceneId)) == 0)) {
			/* dm_log_debug("Device Found, Product Key: %s, Device Name: %s", product_key, device_name); */
			_dm_mutictrl_mutex_unlock();	
			return SUCCESS_RETURN;
		}
	}	
	
	node = malloc(sizeof(mutictrl_record_t));
	if (node == NULL) {
		_dm_mutictrl_mutex_unlock();	
		return MEMORY_NOT_ENOUGH;
	}
	memset(node, 0, sizeof(mutictrl_record_t));
	memcpy(node->sceneId,sceneId,strlen(sceneId));
	memcpy(node->deviceCode,deviceCode,strlen(deviceCode));
	node->epNum = ep;
	node->timestamp = HAL_Uptimes();
	INFO_PRINT("kk_mutictrl_add_list[%s][%d]\n",deviceCode,ep);
	INIT_LIST_HEAD(&node->linked_list);
	list_add_tail(&node->linked_list, &ctx->mutictrl_list);
	_dm_mutictrl_mutex_unlock();	
	return 0;
}

int kk_mutictrl_get_by_devicecode(char *deviceCode,char *sceneId,int ep, mutictrl_record_t **node)
{
	dm_mutictrl_ctx *ctx = _dm_mutictrl_get_ctx();
	mutictrl_record_t *search_node = NULL;

	list_for_each_entry(search_node, &ctx->mutictrl_list, linked_list, mutictrl_record_t) {
		if (search_node->epNum == ep &&
			(memcmp(search_node->deviceCode, deviceCode, strlen(deviceCode)) == 0)&&
			(memcmp(search_node->sceneId, sceneId, strlen(sceneId)) == 0)) {
			/* dm_log_debug("Device Found, Product Key: %s, Device Name: %s", product_key, device_name); */
			if (node) {
				*node = search_node;
			}
			return SUCCESS_RETURN;
		}
	}

	ERROR_PRINT("kk_mutictrl_get_by_devicecode, deviceCode: %s\n", deviceCode);
	return FAIL_RETURN;
}
int kk_mutictrl_rm_list(mutictrl_record_t *node)
{
	dm_mutictrl_ctx *ctx = _dm_mutictrl_get_ctx();
	if(node == NULL){
		return -1;
	}
	//_dm_mutictrl_mutex_lock();
	INFO_PRINT("kk_mutictrl_rm_list[%s][%d]\n",node->deviceCode,node->epNum);
	list_del(&node->linked_list);
	free(node);
	node = NULL;
	//_dm_mgr_mutex_unlock();
	return SUCCESS_RETURN;
}
char * g_manualMutiCtrlDev[] = 
{
	(char *){"3062"},
//	(char *){"3031"},
//	(char *){"3033"},	
//	(char *){"3034"},
//	(char *){"3035"},	
//	(char *){"3036"},
//	(char *){"3095"},
//	(char *){"3098"},	
	(char *){"5004"},	
	(char *){"3028"},	
};
static int _kk_check_manualMutiCtrlDev(const char* deviceCode)
{
	int i = 0,num = 0;
	int res = 0;
	dm_mgr_dev_node_t *node = NULL;
	num = sizeof(g_manualMutiCtrlDev)/sizeof(char *);
	res = dm_mgr_get_device_by_devicecode((char*)deviceCode, &node);
	if(res != SUCCESS_RETURN){
		INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		return -1;
	}	
	for(i =0; i < num; i++){
		if(strcmp(node->productCode,g_manualMutiCtrlDev[i]) == 0)
		{
			return 1;
		}
	}
	return 0;
}
static int _kk_get_MutiCtrl_sceneId(char *deviceCode,char *sceneId,int epNum)
{
	char *type = NULL;
	char *sqlCmd = NULL;
	char *psceneId = NULL;	
	sqlite3_stmt *stmt;
	int ep = 0;
	int exsit = 0;
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();	
	sqlCmd = sqlite3_mprintf("select * from SceneActionInfo WHERE deviceCode= '%s' and active = '%d'",deviceCode,1);//actice判断设备是否移入待分配
	sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);
	while(sqlite3_step(stmt) == SQLITE_ROW){
		type = (char*)sqlite3_column_text(stmt,DB_SCENEACTION_TYPE);
		ep = sqlite3_column_int(stmt, DB_SCENEACTION_EPNUM);
		if(strcmp(type,"action/thing/group") != 0 || epNum != ep){
			continue;
		}
		psceneId = (char*)sqlite3_column_text(stmt,DB_SCENEACTION_SCENEID);
		memcpy(sceneId,psceneId,strlen(psceneId));
		exsit = 1;
		break;
	}	
	sqlite3_free(sqlCmd);
	sqlite3_finalize(stmt);	
	if(exsit){
		return 0;
	}
	return -1;
}
static int _kk_manual_mutictrl_set(cJSON *param,char *setDeviceCode,int ep,char* srcDeviceCode,int isMutiEp,char *sceneId)
{
	int res = 0,idx = 0;
	char valueStr[32] = {0};
	char oldvalueStr[32] = {0};
	char newIdentifier[64] = {0};	
	dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *setDevnode = NULL;
	kk_tsl_data_t *property = NULL;	
	int num = 0;
	char epStr[4] = {0};
	int offflag = 0;
	int exexuteFlag = 0;
	cJSON *propertyItem = NULL;	
	res = dm_mgr_get_device_by_devicecode((char*)srcDeviceCode, &node);
	if(res != SUCCESS_RETURN){
		INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		return -1;
	}	
	res = dm_mgr_get_device_by_devicecode((char*)setDeviceCode, &setDevnode);
	if(res != SUCCESS_RETURN){
		INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		return -1;
	}	
	
	for(idx = 0; idx < node->dev_shadow->property_number; idx++){
		offflag = 0;
		memset(valueStr,0x0,sizeof(valueStr));
		memset(oldvalueStr,0x0,sizeof(oldvalueStr));
		property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
		propertyItem = cJSON_GetObjectItem(param, property->identifier);
		if(propertyItem != NULL){
			if(strstr(property->identifier,"CurrentTemperature") != NULL||
				strstr(property->identifier,"TimingOffTime") != NULL||
				strstr(property->identifier,"Brightness") != NULL){
				continue;
			}
			if(propertyItem->type == cJSON_Number){
				if(property->data_value.type == KK_TSL_DATA_TYPE_INT ||
					property->data_value.type == KK_TSL_DATA_TYPE_ENUM||
						property->data_value.type == KK_TSL_DATA_TYPE_BOOL){
					sprintf(valueStr,"%d",propertyItem->valueint);
				}else{
					sprintf(valueStr,"%f",propertyItem->valuedouble);
				}
			}else if(propertyItem->type == cJSON_String){
				memcpy(valueStr,propertyItem->valuestring,strlen(propertyItem->valuestring));
			}
			char *propertiesbuf[64] = {0};
			char propertiesTmp[64] = {0};
			memset(propertiesTmp,0x0,sizeof(propertiesTmp));
			memcpy(propertiesTmp,property->identifier,strlen(property->identifier));	
			if(isMutiEp){
				split(propertiesTmp,"_",propertiesbuf,&num);
			}
			if(kk_is_mutiEp_device(setDeviceCode) == 1){
				if(isMutiEp){
					sprintf(newIdentifier,"%s_%d",propertiesbuf[0],ep);
				}else{
					sprintf(newIdentifier,"%s_%d",propertiesTmp,ep);
				}
			}else{
				if(isMutiEp){
					sprintf(newIdentifier,"%s",propertiesbuf[0]);
				}else{
					sprintf(newIdentifier,"%s",propertiesTmp);
				}				
			}			
			//INFO_PRINT("[%s][%d]valueStr:%s\n",__FUNCTION__,__LINE__,valueStr);
			//INFO_PRINT("[%s][%d]newIdentifier:%s\n",__FUNCTION__,__LINE__,newIdentifier);
			if(strcmp(setDevnode->productCode,"3062") == 0){
				kk_indoorair_property_db_get_value_directly((const char*)setDeviceCode,(const char*)newIdentifier,oldvalueStr,ep);
			}else{
				kk_property_db_get_value_directly((const char*)setDeviceCode,(const char*)newIdentifier,oldvalueStr);
			}
			//INFO_PRINT("[%s][%d]oldvalueStr:%s\n",__FUNCTION__,__LINE__,oldvalueStr);
			//INFO_PRINT("[%s][%d]setDeviceCode:%s\n",__FUNCTION__,__LINE__,setDeviceCode);
			if(strcmp(oldvalueStr,valueStr) == 0){
				continue;
			}else{
				char *paramstr = NULL;
				cJSON *params = cJSON_CreateObject();
				if(property->data_value.type == KK_TSL_DATA_TYPE_INT ||
					property->data_value.type == KK_TSL_DATA_TYPE_ENUM||
						property->data_value.type == KK_TSL_DATA_TYPE_BOOL){
					cJSON_AddNumberToObject(params, newIdentifier, propertyItem->valueint);
					//if(strstr(newIdentifier,"PowerSwitch") != NULL && propertyItem->valueint == 0){
						//offflag = 1;
					//}	
				}else if(property->data_value.type == KK_TSL_DATA_TYPE_DOUBLE){
					cJSON_AddNumberToObject(params, newIdentifier, propertyItem->valuedouble);
				}else{
					cJSON_AddStringToObject(params, newIdentifier, propertyItem->valuestring);
				}
				if(strcmp(setDevnode->productCode,"3062") == 0){
					memset(epStr,0x0,sizeof(epStr));
					sprintf(epStr,"%d",ep);
					cJSON_DeleteItemFromObject(param, "epNum");
					cJSON_AddStringToObject(param, "epNum", epStr);
					paramstr=cJSON_Print(param);
					offflag = 1;
				}else{
					paramstr=cJSON_Print(params);
				}
				exexuteFlag = 1;
				kk_msg_execute_property_set(setDevnode->productCode,setDevnode->deviceCode,paramstr,setDevnode->fatherDeviceCode);
				free(paramstr);
				cJSON_Delete(params);
				if(offflag){
					break;
				}		
				usleep(500000);	
			}
		}
	}
	if(exexuteFlag == 0){
		mutictrl_record_t *search_node = NULL;
		_dm_mutictrl_mutex_lock();
		res = kk_mutictrl_get_by_devicecode((char*)setDeviceCode,sceneId,ep,&search_node);
		if(res == 0){
			kk_mutictrl_rm_list(search_node);
			_dm_mutictrl_mutex_unlock();
			INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
			return -1;
		}
		_dm_mutictrl_mutex_unlock();
	}
	return 0;
}
static int _kk_manual_mutictrl_ctrl(char *sceneId,char *deviceCode,int ep,cJSON *param,int isMutiEp)
{
	char *sqlCmd = NULL;	
	sqlite3_stmt *stmt;
	char *pdeviceCode = NULL;
	int res = 0;
	int epNum = 0;
	int isManualDev = 0;
	int isAutoCtrlDev = 0;
	dm_mgr_dev_node_t *node = NULL;
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();
	isManualDev = _kk_check_manualMutiCtrlDev((const char*)deviceCode);//上报的设备是否是需要手动触发多控设备
	if(isManualDev == -1){
		return -1;
	}

	sqlCmd = sqlite3_mprintf("select * from SceneActionInfo WHERE sceneId= '%s' and type = '%s'",sceneId,"action/thing/group");//actice判断设备是否移入待分配
	sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);
	while(sqlite3_step(stmt) == SQLITE_ROW){
		pdeviceCode = (char*)sqlite3_column_text(stmt,DB_SCENEACTION_DEVICECODE);
		epNum = sqlite3_column_int(stmt, DB_SCENEACTION_EPNUM);
		if(strcmp(pdeviceCode,deviceCode) == 0 && ep == epNum){//过滤掉刚上报的这路
			continue;
		}
		kk_mutictrl_add_list(sceneId,pdeviceCode,epNum);
		isAutoCtrlDev = _kk_check_manualMutiCtrlDev((const char*)pdeviceCode);
		if(isAutoCtrlDev == 0){//过滤下自动多控设备，手动多控设备先都手动执行下
			continue;
		}
		_kk_manual_mutictrl_set(param,pdeviceCode,epNum,deviceCode,isMutiEp,sceneId);		
	}
	sqlite3_free(sqlCmd);
	sqlite3_finalize(stmt);	
	if(isManualDev){
		sqlCmd = sqlite3_mprintf("select * from SceneActionInfo WHERE sceneId= '%s' and type = '%s'",sceneId,"action/thing/group");//actice判断设备是否移入待分配
		sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);	
		while(sqlite3_step(stmt) == SQLITE_ROW){
			pdeviceCode = (char*)sqlite3_column_text(stmt,DB_SCENEACTION_DEVICECODE);
			epNum = sqlite3_column_int(stmt, DB_SCENEACTION_EPNUM);
			if(strcmp(pdeviceCode,deviceCode) == 0 && ep == epNum){
				continue;
			}
			isAutoCtrlDev = _kk_check_manualMutiCtrlDev((const char*)pdeviceCode);
			if(isAutoCtrlDev == 0){//手动多控设备先都手动执行下，过滤下自动多控设备
				//kk_mutictrl_add_list(sceneId,pdeviceCode,epNum);
				_kk_manual_mutictrl_set(param,pdeviceCode,epNum,deviceCode,isMutiEp,sceneId);
				break;
			}		
		}		
		sqlite3_free(sqlCmd);
		sqlite3_finalize(stmt);	
	}	
	return SUCCESS_RETURN;

}
int kk_manual_mutictrl_execute(const char*deviceCode,cJSON *param)
{
	int res = 0,idx = 0;
	dm_mgr_dev_node_t *node = NULL;
	kk_tsl_data_t *property = NULL;	
	cJSON *propertyItem = NULL;	
	int ep = 0;
	char *propertiesbuf[64] = {0};
	char propertiesTmp[64] = {0};	
	int num = 0;
	int isMutiEp = 0;
	char sceneId[16] = {0};
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();

	res = dm_mgr_get_device_by_devicecode((char*)deviceCode, &node);
	if(res != SUCCESS_RETURN){
		INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		return -1;
	}
	for(idx = 0; idx < node->dev_shadow->property_number; idx++){//解析当前设备上报的epnum
		property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
		propertyItem = cJSON_GetObjectItem(param, property->identifier);
		if(propertyItem != NULL){
			if(strstr(property->identifier,"_") != NULL){
				memset(propertiesTmp,0x0,sizeof(propertiesTmp));
				memcpy(propertiesTmp,property->identifier,strlen(property->identifier));
				split(propertiesTmp,"_",propertiesbuf,&num);
				if(num == 2){
					ep = atoi(propertiesbuf[1]);
					isMutiEp = 1;
				}else{
					ep = 1;
				}
			}else{
				ep = 1;
			}
			break;
		}
	}	
	if(strcmp(node->productCode,"3062") == 0){	//空调网关
		 cJSON * epJson = cJSON_GetObjectItem(param, "epNum");
		 if(epJson == NULL){
			 INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
			 return -1;
		 }
		 ep = atoi(epJson->valuestring); 
		 if(ep == 1){//空调网关第一路为网关本身，不处理
			 INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
			 return -1;
		 }
	}
	res = _kk_get_MutiCtrl_sceneId((char*)deviceCode,sceneId,ep);
	if(res != 0){
		INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		return -1;
	}	
	mutictrl_record_t *search_node = NULL;
	_dm_mutictrl_mutex_lock();
	res = kk_mutictrl_get_by_devicecode((char*)deviceCode,sceneId,ep,&search_node);
	if(res == 0){
		kk_mutictrl_rm_list(search_node);
		_dm_mutictrl_mutex_unlock();
		INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		return -1;
	}	
	_dm_mutictrl_mutex_unlock();
	INFO_PRINT("sceneId:%s\n",sceneId);
	_kk_manual_mutictrl_ctrl(sceneId,(char*)deviceCode,ep,param,isMutiEp);
	return SUCCESS_RETURN;
}
#endif