#include <stdio.h>
#include "kk_tsl_api.h"
#include "kk_dm_mng.h"
#include "sqlite3.h"
#include "kk_log.h"
#include "kk_hal.h"
#include "kk_timer_handle.h"

//#define KK_AREA_DB_FILE                                   "kk_area.db"

//static kk_dev_list_t *s_device_list = NULL;
#define KK_TSL_SETLOCALTIMER_TIMER      	   "getLocalTimer.LocalTimer[%d].Timer"
#define KK_TSL_SETLOCALTIMER_ENABLE      	   "getLocalTimer.LocalTimer[%d].Enable"
#define KK_TSL_SETLOCALTIMER_ISVALID      	   "getLocalTimer.LocalTimer[%d].IsValid"
#define KK_TSL_SETLOCALTIMER_ZONEOFFSET        "getLocalTimer.LocalTimer[%d].TimezoneOffset"
#define KK_TSL_SETLOCALTIMER_TARGETS           "getLocalTimer.LocalTimer[%d].Targets"

#define KK_TSL_SETCOUNTDOWN_DELAYTIME      	   "getCountDown.CountDown[%d].DelayTime"
#define KK_TSL_SETCOUNTDOWN_CURRENTTIME        "getCountDown.CountDown[%d].CurrentTime"
#define KK_TSL_SETCOUNTDOWN_ENABLE      	   "getCountDown.CountDown[%d].Enable"
#define KK_TSL_SETCOUNTDOWN_ISVALID            "getCountDown.CountDown[%d].IsValid"
#define KK_TSL_SETCOUNTDOWN_TARGETS            "getCountDown.CountDown[%d].Targets"

typedef struct {
    void *mutex;
	void *s_timer_thread;	
	int  timerNum;
    int  countDownNum;	
   // sqlite3 *pDb;	
} kk_timer_ctx_t;

typedef struct kk_timer_list{
	char deviceCode[DEVICE_CODE_MAXLEN];	
    uint64_t startTime;
	uint64_t endTime;	
	int isValid;
    int isEnable;	
	int action;
	struct kk_timer_list *next;
   // sqlite3 *pDb;	
} kk_timer_info_t;
   
static kk_timer_info_t *p_timer_info_list = NULL;

static kk_timer_ctx_t s_kk_timer_ctx = {NULL,NULL,0,0};

static kk_timer_ctx_t *_kk_timer_get_ctx(void)
{
    return &s_kk_timer_ctx;
}
static void _kk_timer_lock(void)
{
    kk_timer_ctx_t *ctx = _kk_timer_get_ctx();
    if (ctx->mutex) {
        HAL_MutexLock(ctx->mutex);
    }
}

static void _kk_timer_unlock(void)
{
    kk_timer_ctx_t *ctx = _kk_timer_get_ctx();
	
    if (ctx->mutex) {
        HAL_MutexUnlock(ctx->mutex);
    }
}
void *kk_timer_yield(void *args)
{
	uint64_t current_time = 0;
    kk_timer_info_t *ptr = NULL;	
    while (1) {
		current_time = HAL_GetTime();
		_kk_timer_lock();
		kk_del_expired_timer_from_list(current_time);
		
		ptr = p_timer_info_list;
		while(ptr){			
			
			if(current_time >= ptr->startTime && current_time < ptr->endTime && ptr->isEnable && ptr->isValid){
				/*****do action*******/
			}
			ptr = ptr->next;
		}
		_kk_timer_unlock();
		sleep(5);
    }

    return NULL;
}

int kk_timer_init(void)
{
	int res = 0;
    kk_timer_ctx_t *ctx = _kk_timer_get_ctx();
	
    /* Create Mutex */
    ctx->mutex = HAL_MutexCreate();
    if (ctx->mutex == NULL) {
        return FAIL_RETURN;
    }
    res = pthread_create(&ctx->s_timer_thread, NULL, kk_timer_yield, NULL);
    if (res < 0) {
        ERROR_PRINT("HAL_ThreadCreate mid Failed\n");
        //IOT_Linkkit_Close(mid_ctx->master_devid);
        return -1;
    }	
	return SUCCESS_RETURN;
}

int kk_service_get_array_size(kk_tsl_t *shadow)
{
	int idx = 0,index = 0,num = 0,outputNum = 0;
	kk_tsl_service_t *serviceItem = NULL;
	kk_tsl_data_t *serviceData = NULL;
	if(shadow == NULL){
		return FAIL_RETURN;
	}
	num = shadow->service_number;
	for(idx = 0; idx < num; idx++){
		serviceItem = shadow->services + idx;
		if(strcmp(serviceItem->identifier,MSG_TIMER_GETLOCALTIMER_GETLOCALTIMER) == 0){
			outputNum = serviceItem->output_data_number;
			for(index = 0; index < outputNum; index ++){
				serviceData = serviceItem->output_datas + index;
				if(strcmp(serviceData->identifier,MSG_TIMER_SETLOCALTIMER_LOCALTIMER) == 0){
					kk_tsl_data_value_complex_t *complex_struct = serviceData->data_value.value;
					return complex_struct->size;
				}
			}
			

		}
	}
	return FAIL_RETURN;
}
int kk_service_localtimer_set(kk_tsl_t *shadow,const char *timer,int isEnable,int isValid,int TimezoneOffset,const char *Targets,int size)
{
    kk_timer_ctx_t *ctx = _kk_timer_get_ctx();	
	char identifier_name[256] = {0};	
	if(shadow == NULL){
		return INVALID_PARAMETER;
	}

	if(ctx->timerNum >= size){
		ctx->timerNum = 0;
	}
	_kk_timer_lock();
	sprintf(identifier_name,KK_TSL_SETLOCALTIMER_TIMER,ctx->timerNum);
	kk_tsl_set_value(kk_tsl_set_service_output_value,shadow,identifier_name,NULL,timer);
	
	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_SETLOCALTIMER_ENABLE,ctx->timerNum);
	kk_tsl_set_value(kk_tsl_set_service_output_value,shadow,identifier_name,&isEnable,NULL);

	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_SETLOCALTIMER_ISVALID,ctx->timerNum);
	kk_tsl_set_value(kk_tsl_set_service_output_value,shadow,identifier_name,&isValid,NULL);

	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_SETLOCALTIMER_ZONEOFFSET,ctx->timerNum);
	kk_tsl_set_value(kk_tsl_set_service_output_value,shadow,identifier_name,&TimezoneOffset,NULL);


	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_SETLOCALTIMER_TARGETS,ctx->timerNum);
	kk_tsl_set_value(kk_tsl_set_service_output_value,shadow,identifier_name,NULL,Targets);

	_kk_timer_unlock();
	ctx->timerNum++;
	return SUCCESS_RETURN;
	
}

int kk_service_setCountDown_set(kk_tsl_t *shadow,int delaytime,int CurrentTime,int isEnable,int isValid,const char *Targets,int size)
{
    kk_timer_ctx_t *ctx = _kk_timer_get_ctx();	
	char identifier_name[256] = {0};	
	if(shadow == NULL){
		return INVALID_PARAMETER;
	}

	if(ctx->countDownNum >= size){
		ctx->countDownNum = 0;
	}
	_kk_timer_lock();
	sprintf(identifier_name,KK_TSL_SETCOUNTDOWN_DELAYTIME,ctx->countDownNum);
	kk_tsl_set_value(kk_tsl_set_service_output_value,shadow,identifier_name,&delaytime,NULL);
	
	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_SETCOUNTDOWN_CURRENTTIME,ctx->countDownNum);
	kk_tsl_set_value(kk_tsl_set_service_output_value,shadow,identifier_name,&CurrentTime,NULL);

	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_SETCOUNTDOWN_ENABLE,ctx->countDownNum);
	kk_tsl_set_value(kk_tsl_set_service_output_value,shadow,identifier_name,&isEnable,NULL);

	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_SETCOUNTDOWN_ISVALID,ctx->countDownNum);
	kk_tsl_set_value(kk_tsl_set_service_output_value,shadow,identifier_name,&isValid,NULL);


	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_SETCOUNTDOWN_TARGETS,ctx->countDownNum);
	kk_tsl_set_value(kk_tsl_set_service_output_value,shadow,identifier_name,NULL,Targets);

	_kk_timer_unlock();
	ctx->countDownNum++;
	return SUCCESS_RETURN;
	
}

int kk_add_timer_to_list(uint64_t startTime,uint64_t endTime,int isValid, int isEnable, int action,const char *deviceCode)
{
	kk_timer_info_t *ptr = NULL,*ptemp = NULL;

	_kk_timer_lock();

	ptemp = ptr = p_timer_info_list;
	while(ptr){
		ptemp = ptr;
		ptr = ptr->next;
	}
	ptr = (kk_timer_info_t*)malloc(sizeof(kk_timer_info_t));
	if(ptr == NULL){
		_kk_timer_unlock();
		return FAIL_RETURN;
	}
	memcpy(ptr->deviceCode,deviceCode,strlen(deviceCode));
	ptr->startTime = startTime;
	ptr->endTime = endTime;
	ptr->isValid = isValid;
	ptr->isEnable = isEnable;	
	ptr->action = action;	
	if(p_timer_info_list == NULL){
		p_timer_info_list = ptr;
	}else{
		ptemp->next = ptr;
	}
	_kk_timer_unlock();
	return SUCCESS_RETURN;
}
#if 0
int kk_del_expired_timer_from_list(uint64_t current)
{
	kk_timer_info_t *ptr = NULL,*ptemp = NULL;

	if(p_timer_info_list == NULL){
		return FAIL_RETURN;
	}
	if(p_timer_info_list->endTime <= current){
		ptr = p_timer_info_list;
		p_timer_info_list = p_timer_info_list->next;
		free(ptr);
		ptr = NULL;
		return SUCCESS_RETURN;

	}
	else{
		ptr = p_timer_info_list->next;
		ptemp = p_timer_info_list;
		while(ptr){
			if(ptr->endTime <= current){
					ptemp->next = ptr->next;
					free(ptr);
					ptr = NULL;
					return SUCCESS_RETURN;
			}
			ptemp = ptr;
			ptr = ptr->next;
		}
	}

	return FAIL_RETURN;
}
#endif
int kk_del_expired_timer_from_list(uint64_t current)
{
	kk_timer_info_t *ptr = NULL,*ptemp = NULL;

	if(p_timer_info_list == NULL){
		return FAIL_RETURN;
	}
	ptr = p_timer_info_list;
	while(ptr){
		if(ptr->endTime <= current){
			if(ptr == p_timer_info_list){
				ptemp = p_timer_info_list;
				p_timer_info_list = p_timer_info_list->next;
				free(ptemp);
				ptemp = NULL;
				ptr = p_timer_info_list;
			}
			else{
				ptemp->next = ptr->next;
				free(ptr);
				ptr = NULL;
				ptr = ptemp->next;
			}
		}
		else{
			ptemp = ptr;
			ptr = ptr->next;	
		}
	
	}

	return SUCCESS_RETURN;
}





