/************************************************************
*版权所有 （C）2020，公司（或个人）名称
*
*文件名称： kk_scene_handle.c
*内容摘要： 场景功能数据解析和逻辑处理
*其他说明： 
*当前版本：  
*************************************************************/

/*************************************************************
头文件引用 
*************************************************************/

#include <stdio.h>
#include "kk_tsl_api.h"
#include "kk_dm_mng.h"
#include "kk_scene_handle.h"
#include "kk_scene_db.h"
#include "cJSON.h"
#include <time.h>


/*************************************************************
全局变量定义 
*************************************************************/

extern int g_timezone;
static void kk_scene_send_action_msg(kk_scene_action_info_t *pInfo);
static int kk_scene_update_starttime(kk_scene_timer_list_t *pInfo,time_t current);
static time_t kk_scene_creat_timer_starttime(int week,int starttime,time_t current);
static int kk_scene_parse_repeatday(cJSON *repeatday);
static kk_scene_action_delay_t *p_delay_action_list = NULL;
static kk_scene_embed_delay_t *p_delay_embed_list = NULL;
static kk_scene_timer_list_t *p_scene_timer_list = NULL;
extern uint64_t s_start_time;
static kk_scene_action_t *p_kk_scene_action = NULL;
static kk_scene_ctx_t s_kk_scene_ctx = {NULL};
int kk_scene_check_trigger_condition(const char *sceneId);
static int kk_scene_embed_find(const char *sceneId);


/*************************************************************
函数实现 
*************************************************************/

static int kk_scene_check_value_ex(const char * compareType,const char * compareValue1,const char * compareValue2)
{
	int res = FAIL_RETURN;
	int type = 0;
	int ivalue = 0;
	int itemValue = 0;
	double dvalue = 0;
	double ditemValue = 0;

	if(compareType == NULL || compareValue1 == NULL ||compareValue2 == NULL){
		ERROR_PRINT("[%d]kk_scene_check_value fail!!!\n",__LINE__);
		return INVALID_PARAMETER;
	}
	printf("[%s][%d]compareValue1:%s,compareValue2:%s\n",__FUNCTION__,__LINE__,compareValue1,compareValue2);
	if(!strcmp(compareType,"=") && !strcmp(compareValue1,compareValue2)){
			printf("[%s][%d]\n",__FUNCTION__,__LINE__);
		res = 0;
	}
	else if(!strcmp(compareType,">") && strcmp(compareValue1,compareValue2) > 0){
		res = 0;
	}
	else if(!strcmp(compareType,">=") && strcmp(compareValue1,compareValue2) >= 0){
		res = 0;
	}	
	else if(!strcmp(compareType,"<=") && strcmp(compareValue1,compareValue2) <= 0){
		res = 0;
	}	
	else if(!strcmp(compareType,"<") && strcmp(compareValue1,compareValue2) < 0){
		res = 0;
	}		
	
	
	return res;

}

kk_scene_ctx_t *_kk_scene_get_ctx(void)
{
    return &s_kk_scene_ctx;
}
void _kk_scene_lock(void)
{
    kk_scene_ctx_t *ctx = _kk_scene_get_ctx();
    if (ctx->mutex) {
        HAL_MutexLock(ctx->mutex);
    }
}

void _kk_scene_unlock(void)
{
    kk_scene_ctx_t *ctx = _kk_scene_get_ctx();

    if (ctx->mutex) {
        HAL_MutexUnlock(ctx->mutex);
    }
}



#define KK_DEVICE_TSL_TYPE (0x08)
static kk_tsl_t *s_scene_shadow = NULL;
static int kk_scene_tsl_load(void)
{
	int res = 0;
	char *tsl_str = NULL;
	int heartTime = 0;
	char isDormancyDev = 0;
	tsl_str = kk_load_json("15", KK_DEVICE_TSL_TYPE);
	if(tsl_str != NULL)
	{
		res = kk_tsl_create(tsl_str,strlen(tsl_str),&s_scene_shadow,&heartTime,&isDormancyDev);
		free(tsl_str);
		if(res != 0){
			return FAIL_RETURN;
		}
	}
	return SUCCESS_RETURN;

}
/******************************************************************************/
/* 函 数 名:  kk_scene_timer_check_able                                                     */
/* 描    述:  check定时场景是否有效         										                 */ 	                        
/* 输入参数:  mina_recmsg:	接收到的命令                                      */
/* 返 回 值:  返回'0'表示成功，其它返回值表示出错号                           */
/******************************************************************************/
static int kk_scene_timer_check_able(char *sceneId)
{
	int res = 0;
	int sceneType = 0;
	int enable = 0;
	if(sceneId == NULL){
		return INVALID_PARAMETER;
	}
	res = kk_scene_get_scene_info(sceneId,&sceneType,&enable);
	if(res == SUCCESS_RETURN&&sceneType == DB_SCENETYPE_TIMING && enable == 1){
		return SUCCESS_RETURN;
	}
	return FAIL_RETURN;
}
/******************************************************************************/
/* 函 数 名:  kk_scene_timer_load                                                           */
/* 描    述:  时场景定时信息加载    							  					                 */ 	                        
/* 输入参数:   无                        										             */
/* 返 回 值:  返回'0'表示成功，其它返回值表示出错号               								             */
/******************************************************************************/
static int kk_scene_timer_load(void)
{
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();
	sqlite3_stmt *stmt;
	char *sceneId = NULL;
	char *sqlCmd = "select * from SceneTimerInfo;";
	sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);

	while(sqlite3_step(stmt) == SQLITE_ROW){
	    sceneId = sqlite3_column_text(stmt, DB_SCENETIMER_SCENEID);
		if(kk_scene_timer_check_able(sceneId) == SUCCESS_RETURN){
			int starttime = sqlite3_column_int(stmt, DB_SCENETIMER_TIME);
			int repeatday = sqlite3_column_int(stmt, DB_SCENETIMER_WEEK);
			kk_scene_push_timer_info(starttime,repeatday,sceneId);
		}
	}
	sqlite3_finalize(stmt);
	
	return SUCCESS_RETURN;

}
kk_tsl_t * kk_scene_shadow(void)
{
	return s_scene_shadow;
}

/************************************************************
*功能描述： 定时场景和延时功能的处理
*输入参数： args传入参数
*输出参数： 无
*返 回 值：  无
*其他说明：
*************************************************************/
void *kk_scene_yield(void *args)
{
	time_t current_time = 0;
	kk_scene_action_delay_t *actionDelayInfo = NULL;
	kk_scene_action_delay_t *pTemp = NULL;	
	kk_scene_embed_delay_t *embedDelayInfo = NULL;
	kk_scene_embed_delay_t *pTempEmbed = NULL;		
	kk_scene_timer_list_t *scene_timer_list = NULL;
    kk_scene_ctx_t *ctx = _kk_scene_get_ctx();
    while (1) {
		current_time = HAL_GetTime();
		/****系统起来15s后开始定时处理****/
		if((HAL_Uptimes() - s_start_time) <= 15){
			sleep(1);
			INFO_PRINT("[%s][%d] HAL_Uptimes:%ld\n",__FUNCTION__,__LINE__,HAL_Uptimes());
			continue;
		}
		
		_kk_scene_lock();
		/*处理action delay*/
		actionDelayInfo = p_delay_action_list;
		while(actionDelayInfo){	
			INFO_PRINT("[%s][%d] current_time:%d\n",__FUNCTION__,__LINE__,current_time);
			INFO_PRINT("[%s][%d] actionDelayInfo->starttime:%d\n",__FUNCTION__,__LINE__,actionDelayInfo->starttime);
			if(current_time >= actionDelayInfo->starttime){
				INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
				kk_scene_send_action_msg(actionDelayInfo->action);
				if(actionDelayInfo == p_delay_action_list){
					pTemp = p_delay_action_list;
					p_delay_action_list = p_delay_action_list->next;
					free(pTemp);
					actionDelayInfo = p_delay_action_list;
				}
				else{
					pTemp->next = actionDelayInfo->next;
					free(actionDelayInfo);
					actionDelayInfo = pTemp->next;
				}
			}
			else{
				pTemp= actionDelayInfo;
				actionDelayInfo = actionDelayInfo->next;
			}
		}
		_kk_scene_unlock();
		sleep(1);		
		
		_kk_scene_lock();
		/*处理场景嵌套delay*/
		embedDelayInfo = p_delay_embed_list;
		while(embedDelayInfo){	
			INFO_PRINT("[%s][%d] current_time:%d\n",__FUNCTION__,__LINE__,current_time);
			INFO_PRINT("[%s][%d] embedDelayInfo->starttime:%d\n",__FUNCTION__,__LINE__,embedDelayInfo->starttime);
			if(current_time >= embedDelayInfo->starttime){
				kk_scene_execute_action(embedDelayInfo->executeSceneId,NULL);
				if(embedDelayInfo == p_delay_embed_list){
					pTempEmbed = p_delay_embed_list;
					p_delay_embed_list = p_delay_embed_list->next;
					free(pTempEmbed);
					embedDelayInfo = p_delay_embed_list;
				}
				else{
					pTempEmbed->next = embedDelayInfo->next;
					free(embedDelayInfo);
					embedDelayInfo = pTempEmbed->next;
				}
			}
			else{
				pTempEmbed= embedDelayInfo;
				embedDelayInfo = embedDelayInfo->next;
			}
		}
		_kk_scene_unlock();
		sleep(1);
		
		/*******定时模式**********/
		_kk_scene_lock();
		scene_timer_list = p_scene_timer_list;
		while(scene_timer_list){	
			INFO_PRINT("scene_timer_list->starttime:%d\n",scene_timer_list->starttime);
			INFO_PRINT("current_time %d\n",current_time);
			if(scene_timer_list->starttime != 0 && current_time >= scene_timer_list->starttime){
				if(kk_scene_check_trigger_condition(scene_timer_list->sceneId) == 0){
					if(kk_scene_embed_find(scene_timer_list->sceneId) == 0){
						kk_scene_execute_action(scene_timer_list->sceneId,NULL);
					}		
				}
				kk_scene_update_starttime(scene_timer_list,current_time);
			}
			if(scene_timer_list->starttime == 0){
				kk_scene_remove_timer_info(scene_timer_list->sceneId,0);
			}
			scene_timer_list = scene_timer_list->next;
		}
		_kk_scene_unlock();
		sleep(1);
    }

    return NULL;
}

/************************************************************
*功能描述： 场景模块的初始化，包括数据库的初始化
*输入参数： 无
*输出参数： 无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/

int kk_scene_init(void)
{
	int res = 0;
    kk_scene_ctx_t *ctx = _kk_scene_get_ctx();

    /* Create Mutex */
    ctx->mutex = HAL_MutexCreate();
    if (ctx->mutex == NULL) {
        return FAIL_RETURN;
    }

	kk_scene_db_init();

	res = kk_scene_tsl_load();
	if(res != SUCCESS_RETURN){
		ERROR_PRINT("[%s][%d]kk_scene_init FAIL!!!\n",__FUNCTION__,__LINE__);
	}

	kk_scene_timer_load();
    res = pthread_create(&ctx->s_scene_thread, NULL, kk_scene_yield, NULL);
    if (res < 0) {
        ERROR_PRINT("HAL_ThreadCreate mid Failed\n");
        //IOT_Linkkit_Close(mid_ctx->master_devid);
        return -1;
    }	

	return SUCCESS_RETURN;
}


static int kk_scene_action_info_add(kk_scene_action_info_ex_t **head,kk_scene_action_detail_t detail)
{
	int len;
	kk_scene_action_info_ex_t *ptr,*pre;
	
	ptr = pre = *head;

	while(ptr!=NULL){
		pre = ptr;
		ptr = ptr->next;
	}
	ptr = (kk_scene_action_info_ex_t*)malloc(sizeof(kk_scene_action_info_ex_t));
	if(ptr == NULL){
		return FAIL_RETURN;
	}
	//printf("kk_scene_action_add 11 add:%p\n",ptr);

	memset(ptr,0,sizeof(kk_scene_action_info_ex_t));
	memcpy(&ptr->info,&detail,sizeof(kk_scene_action_detail_t));

	if(*head==NULL){
		*head = ptr;
	}else{
		pre->next = ptr;
	}

	return SUCCESS_RETURN;
}

/************************************************************
*功能描述： 添加场景action到action队列
*输入参数： gwdeviceCode:网关devieCode;
           sceneId:场景Id;
           detail:具体action内容
*输出参数： 无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/
int kk_scene_action_add(const char *gwdeviceCode,const char *sceneId,kk_scene_action_detail_t detail)
{
	int len;
	kk_scene_action_t *ptr,*pre;
	
	ptr = pre = p_kk_scene_action;
	if(gwdeviceCode == NULL || sceneId == NULL){
		return FAIL_RETURN;
	}
	while(ptr!=NULL){
		pre = ptr;
		if(strcmp(ptr->gwdeviceCode,gwdeviceCode) == 0){
			kk_scene_action_info_add(&ptr->actionInfo,detail);
			return SUCCESS_RETURN;
		}
		ptr = ptr->next;
	}
	ptr = (kk_scene_action_t*)malloc(sizeof(kk_scene_action_t));
	if(ptr == NULL){
		return FAIL_RETURN;
	}	
	//printf("kk_scene_action_add add:%p\n",ptr);

	memset(ptr,0,sizeof(kk_scene_action_t));
	memcpy(ptr->gwdeviceCode,gwdeviceCode,strlen(gwdeviceCode));
	memcpy(ptr->sceneId,sceneId,strlen(sceneId));
	kk_scene_action_info_add(&ptr->actionInfo,detail);

	if(p_kk_scene_action==NULL){
		p_kk_scene_action = ptr;
	}else{
		pre->next = ptr;
	}

	return SUCCESS_RETURN;
}

 /************************************************************
 *功能描述：释放action队列
 *输入参数：无
 *输出参数：无
 *返 回 值：  0：成功；其他：失败
 *其他说明：
 *************************************************************/
 static int kk_scene_action_free(void)
 {
	 int len;
	 kk_scene_action_t *ptr,*pnext;
	 kk_scene_action_info_ex_t *actionTemp = NULL;
	 ptr = p_kk_scene_action;
	 
	 while(ptr){
		pnext = ptr->next;
		actionTemp = ptr->actionInfo;
		while(actionTemp != NULL){
			kk_scene_action_info_ex_t *ptemp = actionTemp->next;
			//printf("kk_scene_action_free free:%p\n",actionTemp);
			free(actionTemp);
			actionTemp = NULL;
			actionTemp = ptemp;
		}
		//printf("kk_scene_action_free free ptr:%p\n",ptr);
		free(ptr);
		ptr = NULL;
		ptr = pnext;
	 }
	 p_kk_scene_action = NULL;
	 
	 return SUCCESS_RETURN;
 }

 /************************************************************
 *功能描述：删除数据库中的场景数据
 *输入参数：sceneId：要删除的场景Id;
 		  isforword:是否要往网关转发删除消息，1：转发；0：不转发
 *输出参数：无
 *返 回 值： 无
 *其他说明：
 *************************************************************/
 static void kk_scene_delete(char* sceneId,int isforword)
{
	kk_scene_remove_timer_info(sceneId,1);
	kk_scene_delete_scene_timing(sceneId);	
	kk_scene_delete_scene_embed(sceneId);
	kk_scene_delete_scene_info(sceneId);
	kk_scene_delete_scene_trigger(sceneId);
	kk_scene_delete_scene_condition(sceneId);	
	kk_scene_delete_scene_action(sceneId,isforword);
}

  /************************************************************
 *功能描述：发送删除消息给网关
 *输入参数：sceneId：要删除的场景Id;
 *输出参数：无
 *返 回 值： 0：成功；其他：失败
 *其他说明：
 *************************************************************/
 int kk_scene_delete_send_to_gw(const char *sceneId)
 {
	 char gwdevice[][DEVICE_CODE_MAXLEN] = {0};
	 sqlite3_stmt *stmt; 
	 char *sqlCmd = NULL;
	 char *zErrMsg = 0;
	 char *gwdeviceCode = NULL;
	 kk_scene_ctx_t *ctx = _kk_scene_get_ctx();
	 int idx=0,num = 0;
	 int res = 0;
 
	 sqlCmd = sqlite3_mprintf("select * from SceneActionInfo WHERE sceneId = '%s'",sceneId);
	 sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);
 
 next:	 
	 while(sqlite3_step(stmt) == SQLITE_ROW){		 
		 gwdeviceCode = sqlite3_column_text(stmt,DB_SCENEACTION_GWDEVICECODE);
		 if(kk_subDev_check_scene_support(gwdeviceCode) == 1){
			 for(idx = 0; idx < num;idx++){
				 /*此网关已经发送过*/
				 if(!strcmp(gwdevice[idx],gwdeviceCode)){
					 INFO_PRINT("kk_scene_delete_send_to_gw repeat,ignore!!!\n");
					 goto next;
				 }
			 }
			 memcpy(gwdevice[num],gwdeviceCode,strlen(gwdeviceCode));
			 num++;
			 cJSON *root=cJSON_CreateObject();
			 cJSON_AddStringToObject(root,MSG_SCENE_SCENEID,sceneId);
			 char *out=cJSON_Print(root);
			 res = kk_msg_execute_scene_delete(out,gwdeviceCode);
			 cJSON_Delete(root); 
			 free(out); 		 
		 }
	 }
	 sqlite3_finalize(stmt);
	 sqlite3_free(sqlCmd);
	 return res;
 
 }
 /************************************************************
 *功能描述：发送场景action信息给网关，在添加场景时调用
 *输入参数：isUpdate：1，updateScene；0，addScene
 *输出参数：无
 *返 回 值： 0：成功；其他：失败
 *其他说明：
 *************************************************************/

 int kk_scene_action_info_send(int isUpdate)
{
	kk_scene_action_t *ptr = p_kk_scene_action;
	kk_scene_action_info_ex_t *ptmp = NULL;
	if(ptr == NULL){
		return FAIL_RETURN;
	}
	while(ptr){
		cJSON *root=cJSON_CreateObject();
		cJSON *array = cJSON_CreateArray(); 	
		cJSON_AddStringToObject(root,MSG_SCENE_SCENEID,ptr->sceneId);
		ptmp = ptr->actionInfo;
		while(ptr->actionInfo){
			cJSON *info=cJSON_CreateObject();
			cJSON_AddStringToObject(info,MSG_DEVICE_CODE_STR,ptr->actionInfo->info.deviceCode);
			cJSON_AddStringToObject(info,MSG_SCENE_PROPERTYNAME,ptr->actionInfo->info.propertyName);
			cJSON_AddStringToObject(info,MSG_SCENE_PROPERTYVALUE,ptr->actionInfo->info.propertyValue);
			cJSON_AddNumberToObject(info,MSG_SCENE_DELAY,ptr->actionInfo->info.delay);
			cJSON_AddNumberToObject(info,MSG_SCENE_EPNUM,ptr->actionInfo->info.epNum);
			cJSON_AddItemToArray(array,info);
			ptr->actionInfo = ptr->actionInfo->next;
		}
		ptr->actionInfo = ptmp;
		cJSON_AddItemToObject(root,MSG_SCENE_ACTIONS,array);
		char *out=cJSON_Print(root);
		//printf("out:%s\n",out);
		kk_msg_execute_scene_set(out,ptr->gwdeviceCode,isUpdate);
		cJSON_Delete(root); 
		free(out);
		ptr = ptr->next;
	}

	kk_scene_action_free();
	return SUCCESS_RETURN;
}

 /************************************************************
 *功能描述：发送场景多控信息给网关，在添加场景时调用
 *输入参数：action：具体内容；
          gwdeviceCode：对应网关deviceCode;
          sceneId:场景Id
 *输出参数：无
 *返 回 值： 0：成功；其他：失败
 *其他说明：
 *************************************************************/

 int kk_scene_muticontrol_info_send(cJSON* action,const char *gwdeviceCode,const char *sceneId)
{
	if(action == NULL || gwdeviceCode == NULL || sceneId == NULL){
		return INVALID_PARAMETER;
	}
	cJSON *root=cJSON_CreateObject();	
	cJSON_AddStringToObject(root,MSG_SCENE_SCENEID,sceneId);
	cJSON_AddStringToObject(root,MSG_SCENE_ACTIONS,action->valuestring);	
	char *out=cJSON_Print(root);
	printf("kk_scene_muticontrol_info_send:%s\n",out);
	kk_msg_execute_scene_set(out,gwdeviceCode);
	cJSON_Delete(root); 
	free(out);
	return SUCCESS_RETURN;
}
 /************************************************************
 *功能描述：解析场景触发条件的具体内容，解析后保存到数据库
 *输入参数：type：触发类型；
          item：触发内容的CJSON字串;
          sceneId:场景Id
          isAnd:是否是且操作
 *输出参数：无
 *返 回 值： 0：成功；其他：失败
 *其他说明：
 *************************************************************/

static int kk_scene_parse_trigger_detail(const char *type,const cJSON *item,const char *sceneId,int isAnd)
{
	int res = FAIL_RETURN;
	if(type == NULL || item == NULL || sceneId == NULL){
		return INVALID_PARAMETER;
	}
	cJSON *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR);
	if(deviceCode == NULL) return FAIL_RETURN;	
	cJSON *epNum = cJSON_GetObjectItem(item,MSG_SCENE_EPNUM);
	if(epNum == NULL) return FAIL_RETURN;		
	cJSON *propertyName = cJSON_GetObjectItem(item,MSG_SCENE_PROPERTYNAME);
	if(propertyName == NULL) return FAIL_RETURN;
	cJSON *compareType = cJSON_GetObjectItem(item,MSG_SCENE_COMPARETYPE);
	if(compareType == NULL) return FAIL_RETURN; 	
	cJSON *compareValue = cJSON_GetObjectItem(item,MSG_SCENE_COMPAREVALUE);
	if(compareValue == NULL) return FAIL_RETURN;	
	res = kk_scene_insert_scene_trigger(type,deviceCode->valuestring,epNum->valueint,
			propertyName->valuestring,compareType->valuestring,compareValue->valuestring,sceneId,isAnd);
	if(res != SUCCESS_RETURN){
		ERROR_PRINT("kk_scene_parse_scene_trigger fail!!!\n");
	}
	return res;

}
/************************************************************
*功能描述：解析场景触发条件
*输入参数：str：触发内容的CJSON字串;
		  sceneId:场景Id
*输出参数：无
*返 回 值： 0：成功；其他：失败
*其他说明：
*************************************************************/
int kk_scene_parse_scene_trigger(const cJSON* str,const char *sceneId)
{
	int res = 0;
	int weekflag = 0;
	if(str == NULL || sceneId == NULL){
		return INVALID_PARAMETER;
	}

	cJSON *triggers = cJSON_GetObjectItem(str,MSG_SCENE_TRIGGERS);
	if(triggers == NULL) return FAIL_RETURN;	
	cJSON *items = cJSON_GetObjectItem(triggers,MSG_SCENE_ITEMS);
	if(items == NULL) return FAIL_RETURN;
	cJSON * item = items->child;
	while(item != NULL){
		cJSON *type = cJSON_GetObjectItem(item,MSG_SCENE_TYPE);
		if(type == NULL) return FAIL_RETURN;
		if(!strcmp("trigger/thing/property",type->valuestring)){
			res = kk_scene_parse_trigger_detail(type->valuestring,item,sceneId,0);
			if(res != SUCCESS_RETURN){
				ERROR_PRINT("kk_scene_parse_scene_trigger fail!!!\n");
				return res;
			}
		}
		else if(!strcmp("trigger/timing",type->valuestring)){
			cJSON *week = cJSON_GetObjectItem(item,MSG_SCENE_WEEK);
			if(week == NULL) return FAIL_RETURN;
			weekflag = kk_scene_parse_repeatday(week);
			cJSON *time = cJSON_GetObjectItem(item,MSG_SCENE_TIME);
			if(time == NULL) return FAIL_RETURN;
			time_t current = HAL_GetTime();			
			time_t newStart = kk_scene_creat_timer_starttime(weekflag,atoi(time->valuestring),current);
			kk_scene_insert_scene_timer(newStart,weekflag,sceneId);
			kk_scene_push_timer_info(newStart,weekflag,sceneId);
		}
		item = item->next;	
	}
	INFO_PRINT("kk_scene_parse_scene_trigger success!!!\n");
	return SUCCESS_RETURN;
}

/************************************************************
*功能描述：解析重复星期
*输入参数：repeatday：重复星期的CJSON内容;
*输出参数：无
*返 回 值： 重复星期内容，每位代表一个星期，最低位代表星期一
		  weekflag 01111111  ---> week 7 6 5 4 3 2 1
*其他说明：
*************************************************************/
static int kk_scene_parse_repeatday(cJSON *repeatday)
{
	/***weekflag 01111111  ---> week 7 6 5 4 3 2 1*/
	char weekflag = 0;
	int iCnt = 0;
	if(repeatday == NULL){
		return INVALID_PARAMETER;
	}
	int  array_size = cJSON_GetArraySize (repeatday);
	INFO_PRINT("array_size:%d\n",array_size);
	if(array_size == 0){
		weekflag = 0;
	}else{
		for(iCnt = 0; iCnt < array_size; iCnt++){
			cJSON * pSub = cJSON_GetArrayItem(repeatday, iCnt);
			if(pSub != NULL){
				weekflag = weekflag|(1<<(pSub->valueint-1));
			}
		}
	}
	INFO_PRINT("kk_scene_parse_repeatday weekflag:%d!!!\n",weekflag);
	return weekflag;
	
}
/************************************************************
*功能描述：移除定时信息
*输入参数：sceneId：对应场景Id;
	      lockflag: 1，需要加锁；0，不需要
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/

void kk_scene_remove_timer_info(char *sceneId,int lockflag)
{
	kk_scene_timer_list_t *ptr = NULL,*ptemp = NULL;
	if(lockflag){
	_kk_scene_lock();
	}
	ptemp = ptr = p_scene_timer_list;
	while(ptr){ 		
		if(!strcmp(ptr->sceneId,sceneId)){
			if(ptr == p_scene_timer_list){
				ptemp = p_scene_timer_list;
				p_scene_timer_list = p_scene_timer_list->next;
				free(ptemp);
				ptr = p_scene_timer_list;
			}
			else{
				ptemp->next = ptr->next;
				free(ptr);
				ptr = ptemp->next;
			}
		}
		else{
			ptemp= ptr;
			ptr = ptr->next;
		}
	}
	if(lockflag){
	_kk_scene_unlock();
	}

}
/************************************************************
*功能描述：添加定时信息到队列
*输入参数：sceneId：对应场景Id;
		  starttime：开始时间（Unix时间戳）
		  repeatday：重复星期
*输出参数：无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/

int kk_scene_push_timer_info(time_t starttime,int repeatday,char *sceneId)
{
	kk_scene_timer_list_t *ptr = NULL,*ptemp = NULL;
	if(sceneId == NULL){
		return INVALID_PARAMETER;
	}
	_kk_scene_lock();
	ptemp = ptr = p_scene_timer_list;
	while(ptr){
		ptemp = ptr;
		ptr = ptr->next;
	}		
	ptr = malloc(sizeof(kk_scene_timer_list_t));
	if(ptr == NULL) {
		_kk_scene_unlock();		
		return MEMORY_NOT_ENOUGH;
	}
	memset(ptr,0x0,sizeof(kk_scene_timer_list_t));
	ptr->starttime = starttime;
	ptr->repeatday = repeatday;
	memcpy(ptr->sceneId,sceneId,strlen(sceneId));
	if(p_scene_timer_list == NULL){
		p_scene_timer_list = ptr;
	}else{
		ptemp->next = ptr;
	}
	_kk_scene_unlock();
	INFO_PRINT("kk_scene_push_timer_info called!!!\n");
	return SUCCESS_RETURN;
}

/************************************************************
*功能描述：解析触发条件
*输入参数：sceneId：对应场景Id;
		  str：触发条件的CJSON字串
*输出参数：无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/

int kk_scene_parse_scene_condition(const cJSON* str,const char *sceneId)
{
	char weekflag = 0;
	int res = 0;
	if(str == NULL || sceneId == NULL){
		ERROR_PRINT("kk_scene_parse_scene_condition failed\n");
		return INVALID_PARAMETER;
	}

	cJSON *conditon = cJSON_GetObjectItem(str,MSG_SCENE_CONDITIONS);
	if(conditon == NULL) return FAIL_RETURN;	

	cJSON *items = cJSON_GetObjectItem(conditon,MSG_SCENE_ITEMS);
	if(items == NULL) return FAIL_RETURN;
	cJSON * item = items->child;
	while(item != NULL){
		cJSON *type = cJSON_GetObjectItem(item,MSG_SCENE_TYPE);
		if(type == NULL) return FAIL_RETURN;
		if(!strcmp("condition/timeRange",type->valuestring)){
			cJSON *startTime = cJSON_GetObjectItem(item,MSG_SCENE_STARTTIME);
			if(startTime == NULL) return FAIL_RETURN;
			cJSON *endTime = cJSON_GetObjectItem(item,MSG_SCENE_ENDTIME);
			if(endTime == NULL) return FAIL_RETURN;	
			cJSON *repeatday = cJSON_GetObjectItem(item,MSG_SCENE_REPEATDAYS);
			if(repeatday == NULL) return FAIL_RETURN;
			weekflag = kk_scene_parse_repeatday(repeatday);			
			//kk_scene_push_timer_info(startTime->valueint,endTime->valueint,weekflag,sceneId);
			res = kk_scene_insert_scene_condition(type->valuestring,startTime->valueint,endTime->valueint,
					0,weekflag,sceneId);
			if(res != SUCCESS_RETURN){
				INFO_PRINT("kk_scene_insert_scene_condition fail!!!\n");
				return res;
			}			
		}
		else if(!strcmp("trigger/thing/property",type->valuestring)){
			kk_scene_parse_trigger_detail(type->valuestring,item,sceneId,1);
		}
		else{
			INFO_PRINT("kk_scene_parse_scene_condition wrong type!!!\n");
		}
		item = item->next;
	}
	INFO_PRINT("kk_scene_parse_scene_condition success!!!\n");
	return SUCCESS_RETURN;
}

/************************************************************
*功能描述：解析执行动作
*输入参数：sceneId：对应场景Id;
		  str：执行动作的CJSON字串
		  isUpdate：1，updateScene；0，addScene
*输出参数：无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/

int kk_scene_parse_scene_action(const cJSON* str,const char *sceneId,int isUpdate)
{
	int res = 0;
	int propertySetType = 0;
    dm_mgr_dev_node_t *node = NULL;	
	if(str == NULL || sceneId == NULL){
		ERROR_PRINT("kk_scene_parse_scene_action failed\n");
		return INVALID_PARAMETER;
	}

	cJSON *action = cJSON_GetObjectItem(str,MSG_SCENE_ACTIONS);
	if(action == NULL) return FAIL_RETURN;
	cJSON * item = action->child;
	while(item != NULL){
		cJSON *type = cJSON_GetObjectItem(item,MSG_SCENE_TYPE);
		if(type == NULL) return FAIL_RETURN;
		/*内嵌场景设置*/
		if(!strcmp(type->valuestring,"action/scene"))
		{
			cJSON *delay = cJSON_GetObjectItem(item,MSG_SCENE_DELAY);
			if(delay == NULL) return FAIL_RETURN;
			cJSON *exeucteSceneId = cJSON_GetObjectItem(item,MSG_SCENE_SCENEID);
			if(exeucteSceneId == NULL) return FAIL_RETURN;		
			kk_scene_insert_scene_embed(delay->valueint,exeucteSceneId->valuestring,sceneId);
		}
		else
		{
			propertySetType = 1;
			cJSON *propertyName = cJSON_GetObjectItem(item,MSG_SCENE_PROPERTYNAME);
			if(propertyName == NULL) return FAIL_RETURN;
			cJSON *propertyValue = cJSON_GetObjectItem(item,MSG_SCENE_PROPERTYVALUE);
			if(propertyValue == NULL) return FAIL_RETURN;	
			cJSON *productType = cJSON_GetObjectItem(item,MSG_PRODUCT_TYPE_STR);
			if(productType != NULL){
				kk_subDev_set_action_by_productType(productType->valuestring,sceneId,propertyName->valuestring,
									propertyValue->valuestring,type->valuestring);
			}
			else{
			
				cJSON *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR);
				if(deviceCode == NULL) return FAIL_RETURN;	
				cJSON *epNum = cJSON_GetObjectItem(item,MSG_SCENE_EPNUM);
				if(epNum == NULL) return FAIL_RETURN;	
				epNum = epNum->valueint;
				cJSON *delay = cJSON_GetObjectItem(item,MSG_SCENE_DELAY);
				if(delay == NULL) return FAIL_RETURN;
				delay = delay->valueint;
				res = dm_mgr_get_device_by_devicecode(deviceCode->valuestring,&node);
			    if (res != SUCCESS_RETURN) {
					item = item->next;
			        continue;
			    }		
				if(kk_subDev_check_scene_support(node->fatherDeviceCode) == 1){
					kk_scene_action_detail_t info = {0};
					memcpy(info.deviceCode,node->deviceCode,strlen(node->deviceCode));
					memcpy(info.propertyName,propertyName->valuestring,strlen(propertyName->valuestring));
					memcpy(info.propertyValue,propertyValue->valuestring,strlen(propertyValue->valuestring));
					info.epNum = epNum;
					info.delay = delay;
					kk_scene_action_add(node->fatherDeviceCode,sceneId,info);

				}
				res = kk_scene_insert_scene_action(type->valuestring,node->deviceCode,epNum,
						propertyName->valuestring,propertyValue->valuestring,delay,sceneId,node->fatherDeviceCode);
				if(res != SUCCESS_RETURN){
					INFO_PRINT("kk_scene_insert_scene_action fail!!!\n");
					return res;
				}			
			}
		}
		item = item->next;
	}
	if(propertySetType){
		kk_scene_action_info_send(isUpdate);
	}
	return SUCCESS_RETURN;
}
/************************************************************
*功能描述：解析多控
*输入参数：sceneId：对应场景Id;
		  str：多控的CJSON字串

*输出参数：无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/

int kk_scene_parse_scene_muticontrol(const cJSON* str,const char *sceneId)
{
	int res = 0;
    dm_mgr_dev_node_t *node = NULL;	
	if(str == NULL){
		ERROR_PRINT("kk_scene_parse_scene_muticontrol failed\n");
		return INVALID_PARAMETER;
	}

	cJSON *action = cJSON_GetObjectItem(str,MSG_SCENE_ACTIONS);
	if(action == NULL) return FAIL_RETURN;
	cJSON * item = action->child;
	while(item != NULL){
		cJSON *type = cJSON_GetObjectItem(item,MSG_SCENE_TYPE);
		if(type == NULL) return FAIL_RETURN;	
		if(!strcmp(type->valuestring,"action/thing/group")){
			cJSON *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR);
			if(deviceCode == NULL) return FAIL_RETURN;
			res = dm_mgr_get_device_by_devicecode(deviceCode->valuestring,&node);
		    if (res != SUCCESS_RETURN) {
				item = item->next;
		        continue;
		    }
			break;
		}

		item = item->next;
	}
	kk_scene_muticontrol_info_send(action,node->fatherDeviceCode,sceneId);
	return SUCCESS_RETURN;
}

/************************************************************
*功能描述：解析添加场景的消息
*输入参数：sceneId：对应场景Id;
		  args：场景的CJSON字串
		  isUpdate：1，updateScene；0，addScene
*输出参数：无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/

int kk_scene_parse_addscene(const cJSON* args,char *sceneId,int isUpdate)
{
	int res = 0;

	if(args == NULL||sceneId == NULL){
		ERROR_PRINT("[%d]kk_scene_parse_addscene fail!!!\n",__LINE__);
		return INVALID_PARAMETER;
	}
	
	cJSON *name = cJSON_GetObjectItem(args,MSG_SCENE_NAME);
	if(name == NULL) return FAIL_RETURN;
	cJSON *sceneType = cJSON_GetObjectItem(args,MSG_SCENE_SCENCTYPE);
	if(sceneType == NULL) return FAIL_RETURN;
	cJSON *enable = cJSON_GetObjectItem(args,MSG_SCENE_ENABLE);
	if(enable == NULL) return FAIL_RETURN;	
	if(!isUpdate){
		HAL_GetTime_s(sceneId);//use time to create the sceneId
	}
	/*多控直接下发给网关处理*/
	if(enable->valueint == 1 && sceneType->valueint ==  DB_SCENETYPE_MUTICONTROL){
		kk_scene_parse_scene_muticontrol(args,sceneId);
	}
	else{
		res = kk_scene_insert_scene_info(name->valuestring,sceneType->valueint,enable->valueint,sceneId);
		if(res != SUCCESS_RETURN){
			INFO_PRINT("kk_scene_insert_scene_info fail!!!\n");
			return res;
		}	

		res = kk_scene_parse_scene_trigger(args,sceneId);
		if(res != SUCCESS_RETURN){
			ERROR_PRINT("kk_scene_parse_scene_trigger failed\n");
			return FAIL_RETURN;
		}
		res = kk_scene_parse_scene_condition(args,sceneId);
		if(res != SUCCESS_RETURN){
			ERROR_PRINT("kk_scene_parse_scene_condition failed\n");
			//return FAIL_RETURN;
		}	

		res = kk_scene_parse_scene_action(args,sceneId,isUpdate);
		if(res != SUCCESS_RETURN){
			ERROR_PRINT("kk_scene_parse_scene_action failed\n");
			kk_scene_delete(sceneId,0);
			return FAIL_RETURN;
		}		
	}
	return SUCCESS_RETURN;

}

/************************************************************
*功能描述：解析场景更新的消息
*输入参数：sceneId：对应场景Id;
		  args：场景的CJSON字串
*输出参数：无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/

int kk_scene_parse_updatescene(const cJSON* arg,char *sceneId)
{

	if(arg == NULL||sceneId == NULL){
		ERROR_PRINT("[%d]kk_scene_parse_addscene fail!!!\n",__LINE__);
		return INVALID_PARAMETER;
	}
	kk_scene_delete(sceneId,0);
	return kk_scene_parse_addscene(arg,sceneId,1);
}

/************************************************************
*功能描述：解析删除场景的消息
*输入参数：sceneId：对应场景Id;
*输出参数：无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/
int kk_scene_parse_deletescene(char *sceneId)
{

	if(sceneId == NULL){
		ERROR_PRINT("[%d]kk_scene_parse_deletescene fail!!!\n",__LINE__);
		return INVALID_PARAMETER;
	}
	kk_scene_delete(sceneId,1);	
	return SUCCESS_RETURN;
}
/************************************************************
*功能描述：从数据库获取场景信息
*输入参数：sceneId：对应场景Id;
*输出参数：sceneType：场景类型
          enable：场景是否使能
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/

int kk_scene_get_scene_info(const char* sceneId,int *sceneType,int *enable)
{	
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();
	sqlite3_stmt *stmt;
	int res = FAIL_RETURN;
	char *sqlCmd = NULL;
	sqlCmd = sqlite3_mprintf("select * from SceneInfo WHERE sceneId = '%s'",sceneId);	
	sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);
	while(sqlite3_step(stmt) == SQLITE_ROW){
	    *sceneType = sqlite3_column_int(stmt, DB_SCENEINFO_SCENETYPE);
		*enable = sqlite3_column_int(stmt, DB_SCENEINFO_ENABLE);
		res =  SUCCESS_RETURN;
	}
	sqlite3_finalize(stmt);
	sqlite3_free(sqlCmd);	
	return res;
}
/************************************************************
*功能描述：通过时间获取星期
*输入参数：t：当前时间
*输出参数：无
*返 回 值：  1-7，代表星期一~星期七
*其他说明：
*************************************************************/
static char kk_scene_date_to_week(time_t t)
{
	struct tm *p = localtime(&t);  
	INFO_PRINT("kk_scene_date_to_week t p->tm_wday:%d\n",p->tm_wday);
    return ((p->tm_wday == 0)?7 : p->tm_wday);
}

/************************************************************
*功能描述：更新开始时间
*输入参数：pInfo：定时场景队列
          current：当前时间
*输出参数：无
*返 回 值：0：成功；其他：失败
*其他说明：
*************************************************************/
static int kk_scene_update_starttime(kk_scene_timer_list_t *pInfo,time_t current)
{
	char curWeek = 0;
	char i = 0;
	if(pInfo == NULL){
		return FAIL_RETURN;
	}
	/*only support once*/
	if(pInfo->repeatday == 0){
		pInfo->starttime = 0;
		//kk_scene_update_scene_enable(0,pInfo->sceneId);
		return SUCCESS_RETURN;
	}else{
		curWeek = kk_scene_date_to_week(current);
		for(i = 1; i < 8; i++){
			if(curWeek == 0x40){ //0x40 ==>01000000 ,sunday
				curWeek = curWeek>>6;
			}
			else{
				curWeek = curWeek<<1;
			}
			if(curWeek & pInfo->repeatday){
				pInfo->starttime = pInfo->starttime + 86400*i;
				return SUCCESS_RETURN;
			}			
		}
	
	}
	return FAIL_RETURN;

}

/************************************************************
*功能描述：创建新的开始时间
*输入参数：starttime：开始时间（一天内的秒数）
          current：当前时间
*输出参数：无
*返 回 值：新的开始时间（Unix时间戳）
*其他说明：
*************************************************************/

static time_t kk_scene_creat_new_starttime(time_t starttime,time_t current)
{
	int hour,min,sec;
	time_t newTime = 0;

	INFO_PRINT("[%d]startTime :%d\n",__LINE__,starttime);

	hour = starttime/3600;
	min = starttime%3600/60;

	INFO_PRINT("[hour:%d][min:%d]\n",hour,min);
	struct tm *c = localtime(&current); 
	c->tm_hour = hour;
	c->tm_min = min;
	c->tm_sec = 0;
	newTime = mktime(c);
	INFO_PRINT("kk_scene_creat_new_starttime:%ld\n",newTime);
    return newTime;
}
/************************************************************
*功能描述：创建新的定时开始时间
*输入参数：starttime：开始时间（一天内的秒数）
          current：当前时间
          week：重复星期
*输出参数：无
*返 回 值：新的开始时间（Unix时间戳）
*其他说明：
*************************************************************/

static time_t kk_scene_creat_timer_starttime(int week,int starttime,time_t current)
{
	int hour,min,sec;
	time_t newTime = 0;
	char curWeek = 0;
	int startNew = 0;
	int i = 0;
	curWeek = kk_scene_date_to_week(current);
	startNew = starttime + g_timezone*3600;
	startNew = (startNew - 86400) >= 0?(startNew - 86400) : startNew;	
	INFO_PRINT("kk_scene_creat_timer_starttime:%ld\n",startNew);
	
	/*today is not repeat day*/
	if((week > 0)&&(!(week &(1<<(curWeek-1)))))
	{
		for(i = 1; i < 8; i++){
			if(curWeek == 0x40){ //0x40 ==>01000000 ,sunday
				curWeek = curWeek>>6;
			}
			else{
				curWeek = curWeek<<1;
			}
			if(curWeek & week){
				newTime = current + 86400*i;
				return kk_scene_creat_new_starttime(startNew,newTime);
			}			
		}
	}
	else
	{
		return kk_scene_creat_new_starttime(startNew,current);
	}
}

/************************************************************
*功能描述：判断属性限制条件
*输入参数：sceneId：场景Id
*输出参数：无
*返 回 值：0:符合；其他：不符合
*其他说明：
*************************************************************/

int kk_scene_check_trigger_condition(const char *sceneId)
{
	int res = FAIL_RETURN;
	char *sqlCmd = NULL;
	char *pdeviceCode = NULL;
	char *identifier = NULL;
	char *compareType = NULL;
	char *compareValue = NULL;
	int propertyValueType = 0;
	int conditionFlag = 0;
	sqlite3_stmt *stmt;	
	char currentValue[64] = {0};	
	dm_mgr_dev_node_t *node = NULL;	
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();

	sqlCmd = sqlite3_mprintf("select * from SceneTriggerInfo WHERE sceneId = '%s' and isAnd = '%d'",sceneId,1);
	sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);
	while(sqlite3_step(stmt) == SQLITE_ROW){
		conditionFlag = 1;
		
	    pdeviceCode = sqlite3_column_text(stmt, DB_SCENETRIGGER_DEVICECODE);
		identifier = sqlite3_column_text(stmt,DB_SCENETRIGGER_PROPERTYNAME);
		compareType = sqlite3_column_text(stmt,DB_SCENETRIGGER_COMPARETYPE);
		compareValue = sqlite3_column_text(stmt,DB_SCENETRIGGER_COMPAREVALUE);

		kk_property_db_get_value_directly(pdeviceCode,identifier,currentValue);	
		INFO_PRINT("currentValue:%s\n",currentValue);
		res = kk_scene_check_value_ex(compareType,currentValue,compareValue);
		INFO_PRINT("kk_scene_check_value_ex:res:%d\n",res);		
		if(res != 0){
			break;
		}

	}
	sqlite3_finalize(stmt);
	sqlite3_free(sqlCmd);

	/*如果没有设置条件，直接return success*/
	if(conditionFlag == 0){
		res =  SUCCESS_RETURN;
	}
	INFO_PRINT("kk_scene_check_trigger_condition:res:%d\n",res);	
	return res;

}
/************************************************************
*功能描述：判断时间限制条件
*输入参数：sceneId：场景Id
*输出参数：无
*返 回 值：0:符合；其他：不符合
*其他说明：
*************************************************************/
int kk_scene_check_condition(const char *sceneId)
{
	int res = FAIL_RETURN;
	char *sqlCmd = NULL;
	char curWeek = 0;
	char repeatday = 0;
	time_t startTime = 0,startTime_m = 0;
	time_t endTime = 0,endTime_m = 0;
	int duration = 0;
	int crossDay = 0;
	int conditionFlag = 0;
	sqlite3_stmt *stmt;	
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();
	time_t current = HAL_GetTime();
	curWeek = kk_scene_date_to_week(current);

	sqlCmd = sqlite3_mprintf("select * from SceneConditionInfo WHERE sceneId = '%s'",sceneId);
	sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);
	while(sqlite3_step(stmt) == SQLITE_ROW){
		conditionFlag = 1;
	    repeatday = sqlite3_column_int(stmt, DB_SCENECONDITION_REPEATDAY);
		startTime = sqlite3_column_int(stmt, DB_SCENECONDITION_STARTTIME);
		endTime = sqlite3_column_int(stmt, DB_SCENECONDITION_ENDTIME);
		//crossDay = sqlite3_column_int(stmt, DB_SCENECONDITION_CROSSDAY);
		startTime = startTime + g_timezone*3600;
		startTime = (startTime - 86400) >= 0?(startTime - 86400) : startTime;
		endTime = endTime + g_timezone*3600;
		endTime = (endTime - 86400) >= 0?(endTime - 86400) : endTime;
		INFO_PRINT("[endTime:%d][startTime:%d]\n",endTime,startTime);
		if(endTime < startTime){
			duration = 86400- (startTime - endTime);
			crossDay = 1;
		}
		else{
			duration = endTime - startTime;
			crossDay = 0;
		}
		startTime_m = kk_scene_creat_new_starttime(startTime,current);
		INFO_PRINT("current:%ld,startTime_m:%ld,repeatday:%d,duration:%d\n",current,startTime_m,repeatday,duration);
		/********check today is one of repeatday**************/
		if((repeatday > 0) && (repeatday &(1<<(curWeek-1)))){	
			if(crossDay && current < startTime_m){
				/*跨天处理，判断当前时间是否在上一天的结束时间内*/
				if(current <= (startTime_m + duration - 86400)){
					res =  SUCCESS_RETURN;
				}
			}
			else if(current >= startTime_m && current <= (startTime_m + duration)){
				res =  SUCCESS_RETURN;
			}
			else{
				INFO_PRINT("time not match current:%ld,startTime_m:%ld,repeatday:%d\n",current,startTime_m,repeatday);
			}
		}
		else if((repeatday > 0)&&(!(repeatday &(1<<(curWeek-1))))){
			/*跨天处理,获取前一天的星期*/
			if(crossDay == 1){
		    	curWeek = (curWeek - 1) == 0? 7:(curWeek - 1);
				/*前一天的星期必须要在重复星期内*/
				if(repeatday &(1<<(curWeek-1))){
					if(current <= (startTime_m + duration - 86400)){
						res =  SUCCESS_RETURN;
					}
				}
			}
		}
		else{
			if(current >= startTime_m && current <= (startTime_m + duration)){
				res =  SUCCESS_RETURN;
			}
			else
			{
				INFO_PRINT("time not match current:%ld,startTime_m:%ld\n",current,startTime_m);
			}
		}
	}
	sqlite3_finalize(stmt);
	sqlite3_free(sqlCmd);

	/*如果没有设置条件，直接return success*/
	if(conditionFlag == 0){
		res =  SUCCESS_RETURN;
	}
	INFO_PRINT("kk_scene_check_condition:res:%d\n",res);
	return res;

}

/************************************************************
*功能描述：判断value值是否符合条件
*输入参数：compareType：比对符号
          compareValue：比对值
          item：当前值的CJSON字串
          valueType：比对值的数据类型
*输出参数：无
*返 回 值：0:符合；其他：不符合
*其他说明：
*************************************************************/

static int kk_scene_check_value(const char * compareType,const char * compareValue,cJSON *item,int valueType)
{
	int res = FAIL_RETURN;
	int type = 0;
	int ivalue = 0;
	int itemValue = 0;
	double dvalue = 0;
	double ditemValue = 0;

	if(compareType == NULL || compareValue == NULL ||item == NULL){
		ERROR_PRINT("[%d]kk_scene_check_value fail!!!\n",__LINE__);
		return INVALID_PARAMETER;
	}
	switch(valueType){
		case KK_TSL_DATA_TYPE_INT:
		case KK_TSL_DATA_TYPE_ENUM:
		case KK_TSL_DATA_TYPE_BOOL:
			ivalue = atoi(compareValue);
		    itemValue = item->valueint;
			break;
		case KK_TSL_DATA_TYPE_FLOAT:
		case KK_TSL_DATA_TYPE_DOUBLE:
			dvalue = atof(compareValue);
			ditemValue = item->valuedouble;
			type = 1;
			break;	
		case KK_TSL_DATA_TYPE_TEXT:
		case KK_TSL_DATA_TYPE_DATE:
			type = 2;//字串
			break;
	}
	if(type == 2){
		if(!strcmp(compareType,"=") && !strcmp(compareValue,item->valuestring)){
			res = 0;
		}
		else if(!strcmp(compareType,">") && strcmp(item->valuestring,compareValue) > 0){
			res = 0;
		}
		else if(!strcmp(compareType,">=") && strcmp(item->valuestring,compareValue) >= 0){
			res = 0;
		}	
		else if(!strcmp(compareType,"<=") && strcmp(item->valuestring,compareValue) <= 0){
			res = 0;
		}	
		else if(!strcmp(compareType,"<") && strcmp(item->valuestring,compareValue) < 0){
			res = 0;
		}		
	}
	else if(type == 1){
		if(!strcmp(compareType,"=")){
			if(ditemValue == dvalue) 
				res = 0;
		}
		else if(!strcmp(compareType,">")){
			if(ditemValue > dvalue) 
				res = 0;
		}
		else if(!strcmp(compareType,">=")){
			if(ditemValue >= dvalue) 
				res = 0;
		}
		else if(!strcmp(compareType,"<=")){
			if(ditemValue <= dvalue) 
				res = 0;
		}
		else if(!strcmp(compareType,"<")){
			if(ditemValue < dvalue) 
				res = 0;
		}	
	}
	else{
		if(!strcmp(compareType,"=")){
			if(itemValue == ivalue) 
				res = 0;
		}
		else if(!strcmp(compareType,">")){
			if(itemValue > ivalue) 
				res = 0;
		}
		else if(!strcmp(compareType,">=")){
			if(itemValue >= ivalue) 
				res = 0;
		}
		else if(!strcmp(compareType,"<=")){
			if(itemValue <= ivalue) 
				res = 0;
		}
		else if(!strcmp(compareType,"<")){
			if(itemValue < ivalue) 
				res = 0;
		}	

	}
	return res;

}
/************************************************************
*功能描述：发送action内容到网关，此函数只有不支持内场景的网关用到
*输入参数：pInfo：action内容
*输出参数：无
*返 回 值：无
*其他说明：
*************************************************************/

static void kk_scene_send_action_msg(kk_scene_action_info_t *pInfo)
{
	int ivalue = 0;
	double dvalue = 0; 
	int valueType = 0;
	if(pInfo == NULL){
		return;
	}
	cJSON *root=cJSON_CreateObject();	

	valueType = kk_dm_get_property_type(pInfo->deviceCode,pInfo->propertyName);
	if(valueType < 0){
		ERROR_PRINT("[%d]kk_scene_send_action_msg valueType < 0!!!\n",__LINE__);
		free(pInfo);
		return;
	}
	switch(valueType){
		case KK_TSL_DATA_TYPE_INT:
		case KK_TSL_DATA_TYPE_ENUM:
		case KK_TSL_DATA_TYPE_BOOL:
			/*pInfo->propertyValue 如果为‘10’，代表需要取反操作*/
			if(strstr(pInfo->propertyName,"PowerSwitch") != NULL && \
							!strcmp(pInfo->propertyValue,"10")){
				kk_property_db_get_value(pInfo->deviceCode,pInfo->propertyName, &ivalue);
				ivalue = !ivalue;				
			}
			else{
				ivalue = atoi(pInfo->propertyValue);
			}
			cJSON_AddNumberToObject(root,pInfo->propertyName,ivalue);
			break;
		case KK_TSL_DATA_TYPE_FLOAT:
		case KK_TSL_DATA_TYPE_DOUBLE:
			dvalue = atof(pInfo->propertyValue);
			cJSON_AddNumberToObject(root,pInfo->propertyName,dvalue);
			break;
		case KK_TSL_DATA_TYPE_TEXT:
		case KK_TSL_DATA_TYPE_DATE:
			cJSON_AddStringToObject(root,pInfo->propertyName,pInfo->propertyValue);
			break;
	}
	
	char *out=cJSON_Print(root);
	kk_msg_execute_property_set(pInfo->productCode,pInfo->deviceCode,out,pInfo->fatherdeviceCode);
	cJSON_Delete(root); 
	free(out);
	free(pInfo);
	return;
}
/************************************************************
*功能描述：添加action到队列，此函数只有不支持内场景的网关用到
*输入参数：actionInfo：action内容
          delay：需要延时的秒数
*输出参数：无
*返 回 值：0:成功；其他：失败
*其他说明：
*************************************************************/

static int kk_scene_push_action_list(kk_scene_action_info_t *actionInfo,int delay)
{
	kk_scene_action_delay_t *ptr = NULL,*ptemp = NULL;
	if(actionInfo == NULL){
		return INVALID_PARAMETER;
	}
	ptemp = ptr = p_delay_action_list;
	while(ptr){
		ptemp = ptr;
		ptr = ptr->next;
	}		
	ptr = malloc(sizeof(kk_scene_action_delay_t));
	if(ptr == NULL) {
		return MEMORY_NOT_ENOUGH;
	}
	memset(ptr,0x0,sizeof(kk_scene_action_delay_t));
	ptr->starttime = HAL_GetTime()+delay;
	ptr->action = actionInfo;
	if(p_delay_action_list == NULL){
		p_delay_action_list = ptr;
	}else{
		ptemp->next = ptr;
	}
	return SUCCESS_RETURN;

}
/************************************************************
*功能描述：开始执行action，此函数只有不支持内场景的网关用到
*输入参数：deviceCode：deviceCode
          propertyName：identifier属性名称
          valueS：value值
          delay：需要延时的秒数
*输出参数：无
*返 回 值：0:成功；其他：失败
*其他说明：
*************************************************************/

static int kk_scene_start_action(const char *deviceCode,const char *propertyName,const char *valueS,int delay)
{
	int res = 0;
	
	INFO_PRINT("[%s][%d]kk_scene_start_action called\n",__FUNCTION__,__LINE__);
	dm_mgr_dev_node_t *node = NULL;
	kk_scene_action_info_t *actionInfo = NULL;
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();
	
	if(deviceCode == NULL || propertyName == NULL || valueS == NULL){
		ERROR_PRINT("[%d]kk_scene_send_action fail!!!\n",__LINE__);
		return INVALID_PARAMETER;
	}
	res = dm_mgr_get_device_by_devicecode(deviceCode, &node);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
	actionInfo = malloc(sizeof(kk_scene_action_info_t));
	if(actionInfo == NULL) {
		return MEMORY_NOT_ENOUGH;	
	}
	memset(actionInfo,0x0,sizeof(kk_scene_action_info_t));
	memcpy(actionInfo->deviceCode,deviceCode,strlen(deviceCode));
	memcpy(actionInfo->productCode,node->productCode,strlen(node->productCode));
	memcpy(actionInfo->fatherdeviceCode,node->fatherDeviceCode,strlen(node->fatherDeviceCode));
	memcpy(actionInfo->propertyName,propertyName,strlen(propertyName));	
	memcpy(actionInfo->propertyValue,valueS,strlen(valueS));		
	if(delay == 0){
		kk_scene_send_action_msg(actionInfo);
	}else{
		INFO_PRINT("[%s][%d]delay:%d\n",__FUNCTION__,__LINE__,delay);
		kk_scene_push_action_list(actionInfo,delay);
	}
	return SUCCESS_RETURN;


}
/************************************************************
*功能描述：触发完成并符合条件后调用此函数执行场景
*输入参数：sceneId：场景Id
*输出参数：无
*返 回 值：0:成功；其他：失败
*其他说明：
*************************************************************/

int kk_scene_execute_action(const char* sceneId,char *msgId)
{
	int res = FAIL_RETURN;
	char *deviceCode = NULL;
	char *propertyName = NULL;
	char *propertyValue = NULL;	
	char *gwdeviceCode = NULL;
	int delay = 0;
	char *sqlCmd = NULL;
	char gwdevice[][DEVICE_CODE_MAXLEN] = {0};
	int idx=0,num = 0;
	sqlite3_stmt *stmt;	
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();
	INFO_PRINT("[%s][%d] kk_scene_execute_action now!!!\n",__FUNCTION__,__LINE__);
	sqlCmd = sqlite3_mprintf("select * from SceneActionInfo WHERE sceneId = '%s'",sceneId);
	sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);
next:		
	while(sqlite3_step(stmt) == SQLITE_ROW){	
	    deviceCode = sqlite3_column_text(stmt, DB_SCENEACTION_DEVICECODE);
		propertyName = sqlite3_column_text(stmt,DB_SCENEACTION_PROPERTYNAME);
		propertyValue = sqlite3_column_text(stmt,DB_SCENEACTION_PROPERTYVALUE);
		delay = sqlite3_column_int(stmt,DB_SCENEACTION_DELAY);
		gwdeviceCode = sqlite3_column_text(stmt,DB_SCENEACTION_GWDEVICECODE);
		if(kk_subDev_check_scene_support(gwdeviceCode) == 1){
			for(idx = 0; idx < num;idx++){
				if(!strcmp(gwdevice[idx],gwdeviceCode)){
					goto next;
				}
			}
			memcpy(gwdevice[num],gwdeviceCode,strlen(gwdeviceCode));
			num++;
			cJSON *root=cJSON_CreateObject();
			cJSON_AddStringToObject(root,MSG_SCENE_SCENEID,sceneId);
			char *out=cJSON_Print(root);
			res = kk_msg_execute_scene_action(out,gwdeviceCode);
			cJSON_Delete(root); 
			free(out);			
		}
		else{
			res = kk_scene_start_action(deviceCode,propertyName,propertyValue,delay);
		}
	}
	kk_scene_execute_event_post(sceneId,msgId);
	
	sqlite3_finalize(stmt);
	sqlite3_free(sqlCmd);
	return res;

}
/************************************************************
*功能描述：添加嵌套场景到队列
*输入参数：sceneId：场景Id
          delay：延时时间
*输出参数：无
*返 回 值：0:成功；其他：失败
*其他说明：
*************************************************************/
static int kk_scene_push_embed_list(int delay,const char* sceneId)
{
	if(sceneId == NULL){
		return INVALID_PARAMETER;
	}
	kk_scene_embed_delay_t *ptr = NULL,*ptemp = NULL;
	_kk_scene_lock();
	ptemp = ptr = p_delay_embed_list;
	while(ptr){
		ptemp = ptr;
		ptr = ptr->next;
	}		
	ptr = malloc(sizeof(kk_scene_embed_delay_t));
	if(ptr == NULL) {
		return MEMORY_NOT_ENOUGH;
	}
	memset(ptr,0x0,sizeof(kk_scene_embed_delay_t));
	ptr->starttime = HAL_GetTime()+delay;
	memcpy(ptr->executeSceneId,sceneId,strlen(sceneId));
	if(p_delay_embed_list == NULL){
		p_delay_embed_list = ptr;
	}else{
		ptemp->next = ptr;
	}
	_kk_scene_unlock();
	return SUCCESS_RETURN;

}
/************************************************************
*功能描述：查找是否有场景嵌套
*输入参数：sceneId：场景Id
*输出参数：无
*返 回 值：0:成功；其他：失败
*其他说明：
*************************************************************/
static int kk_scene_embed_find(const char *sceneId)
{
	int find = 0;
	char *sqlCmd = NULL;
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();
	sqlite3_stmt *stmt;	
	int delay = 0;
	char *executeSceneId = NULL;
	if(sceneId == NULL){
		return INVALID_PARAMETER;
	}
	INFO_PRINT("kk_scene_embed_find:%s\n",sceneId);
	sqlCmd = sqlite3_mprintf("select * from SceneEmbedInfo WHERE sceneId= '%s'",sceneId);
	sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);	
	while(sqlite3_step(stmt) == SQLITE_ROW){
		find = 1;
		delay = sqlite3_column_int(stmt,DB_SCENEEMBED_WEEK);
		executeSceneId = sqlite3_column_text(stmt,DB_SCENEEMBED_EXECUTESCENEID);
		/*如果有延时，加入到队列*/
		if(delay > 0){
			kk_scene_push_embed_list(delay,executeSceneId);
		}
		else{
			kk_scene_execute_action(executeSceneId,NULL);
		}
	}	
	sqlite3_finalize(stmt);
	sqlite3_free(sqlCmd);	
	return find;
}

/************************************************************
*功能描述：查找是否有场景触发
*输入参数：param：属性CJSON内容
          deviceCode：对应设备的deviceCode
*输出参数：无
*返 回 值：0:成功；其他：失败
*其他说明：
*************************************************************/
int kk_scene_query_trigger_info(const char *deviceCode,cJSON *param)
{
	int res = FAIL_RETURN;
	char *sqlCmd = NULL;
	char *zErrMsg = 0;
	char *sceneId = NULL;
	char *identifier = NULL;
	char *compareType = NULL;	
	char *compareValue = NULL;	
	int propertyValueType = 0;
	int isAnd = 0;
	int sceneType = 0,isEnable = 0;
	sqlite3_stmt *stmt;	
	kk_scene_ctx_t *ctx = _kk_scene_get_ctx();

	sqlCmd = sqlite3_mprintf("select * from SceneTriggerInfo WHERE deviceCode= '%s'",deviceCode);	
	sqlite3_prepare_v2(ctx->pDb, sqlCmd, strlen(sqlCmd), &stmt, NULL);
	while(sqlite3_step(stmt) == SQLITE_ROW){
		
	    sceneId = sqlite3_column_text(stmt, DB_SCENETRIGGER_SCENEID);
		identifier = sqlite3_column_text(stmt,DB_SCENETRIGGER_PROPERTYNAME);
		compareType = sqlite3_column_text(stmt,DB_SCENETRIGGER_COMPARETYPE);
		compareValue = sqlite3_column_text(stmt,DB_SCENETRIGGER_COMPAREVALUE);
		isAnd = sqlite3_column_int(stmt,DB_SCENETRIGGER_ISAND);
		res = kk_scene_get_scene_info(sceneId,&sceneType,&isEnable);
		if(res == SUCCESS_RETURN && isEnable && isAnd == 0){
			cJSON *item = cJSON_GetObjectItem(param,identifier);
			if(item != NULL){
				propertyValueType = kk_dm_get_property_type(deviceCode,identifier);
				res = kk_scene_check_value(compareType,compareValue,item,propertyValueType);
				if(res == SUCCESS_RETURN){
					INFO_PRINT("[%d]kk_scene_check_condition enter!!!\n",__LINE__);
					res = kk_scene_check_condition(sceneId);
					if(res == SUCCESS_RETURN){
						res = kk_scene_check_trigger_condition(sceneId);
						if(res == SUCCESS_RETURN){
							/*check是否时场景嵌套类型*/
							if(kk_scene_embed_find(sceneId) == 0){
								res = kk_scene_execute_action(sceneId,NULL);
							}
						}
					}
				}
			}
		}

	}
	sqlite3_finalize(stmt);
	sqlite3_free(sqlCmd);
	return res;
}

/************************************************************
*功能描述：IFTT场景检测
*输入参数：param：属性CJSON内容
          deviceCode：对应设备的deviceCode
*输出参数：无
*返 回 值：0:成功；其他：失败
*其他说明：
*************************************************************/
int kk_scene_iftt_check(const char*deviceCode,cJSON *param)
{
	INFO_PRINT("deviceCode:%s\n",deviceCode);
	return kk_scene_query_trigger_info(deviceCode,param);
}

/************************************************************
*功能描述：手动场景执行
*输入参数：sceneId：场景Id
*输出参数：无
*返 回 值：0:成功；其他：失败
*其他说明：
*************************************************************/
int kk_scene_execute_scene(const char *sceneId,const char *msgId)
{
	int res = 0;
	int sceneType = 0;
	int isEnable = 0;
	if(sceneId == NULL){
		return INVALID_PARAMETER;
	}
	res = kk_scene_get_scene_info(sceneId,&sceneType,&isEnable);
	if(res == SUCCESS_RETURN && sceneType == DB_SCENETYPE_SCENE && isEnable){
		res = kk_scene_check_condition(sceneId);
		if(res == SUCCESS_RETURN){
			_kk_scene_lock();
			res = kk_scene_execute_action(sceneId,msgId);
			_kk_scene_unlock();
		}
	}
	INFO_PRINT("[%d]kk_scene_execute_scene called!!!\n",__LINE__);
	return res;
}
void kk_scene_execute_event_post(const char* sceneId,const char *msgId)
{
	kk_tsl_t *pSceneShadow = NULL;
	char msgIdbuf[64] = {0};

	if(sceneId == NULL){
		INFO_PRINT("kk_scene_execute_event_post:error\n");
		return;
	}
	if(msgId == NULL){
		sprintf(msgIdbuf,"%d",iotx_report_id());
	}
	else
	{
		memcpy(msgIdbuf,msgId,strlen(msgId));
	}
	pSceneShadow = kk_scene_shadow();
	if(pSceneShadow != NULL){
		kk_tsl_set_value(kk_tsl_set_event_output_value,pSceneShadow,MSG_SCENE_EXECUTENOTIFICATION_SCENEID,NULL,sceneId);
		dm_msg_scene_event_post(MSG_SCENE_EXECUTENOTIFICATION,pSceneShadow,msgIdbuf);		
	}

}

