
#include <stdio.h>
#include "kk_tsl_api.h"
#include "kk_wlist_mng.h"
#include "sqlite3.h"

#define KK_TSL_GATAWAY_ADDWHITELIST_IDENTIFIER      	   "addWhiteList"
#define KK_TSL_GATAWAY_WHITELISTDEVICE_IDENTIFIER      	   "Devices"
#define KK_TSL_GATAWAY_WHITELISTMAC_IDENTIFIER      	   "getWhiteListNotification.Devices[%d].MACAddress"
#define KK_TSL_GATAWAY_WHITELISTPRODUCTID_IDENTIFIER       "getWhiteListNotification.Devices[%d].ProductId"
#define KK_TSL_GATAWAY_WHITELISTSN_IDENTIFIER      	       "getWhiteListNotification.Devices[%d].SN"
#define KK_TSL_GATAWAY_WHITELISTDEVICEID_IDENTIFIER        "getWhiteListNotification.Devices[%d].deviceId"
#define KK_WLIST_DB_FILE                                   "wlist.db"

typedef struct {
    void *mutex;
	int  isOpened;
	int  wlistNum;
    sqlite3 *pDb;	
} kk_wlist_ctx_t;

static kk_wlist_ctx_t s_kk_wlist_ctx = {NULL,0,0,NULL};
static kk_wlist_ctx_t *_kk_wlist_get_ctx(void)
{
    return &s_kk_wlist_ctx;
}
static void _kk_wlist_lock(void)
{
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
    if (ctx->mutex) {
        HAL_MutexLock(ctx->mutex);
    }
}

static void _kk_wlist_unlock(void)
{
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
    if (ctx->mutex) {
        HAL_MutexUnlock(ctx->mutex);
    }
}

static int kk_wlist_db_Init(void)
{
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();

    //eUtils_LockLock(&sLock);
    _kk_wlist_lock();
    
    if (sqlite3_open_v2(KK_WLIST_DB_FILE, &ctx->pDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK)
    { 
        printf("Error initialising linkage database (%s)", sqlite3_errmsg(ctx->pDb));
		_kk_wlist_unlock();
        return FAIL_RETURN; 
    }     
    printf("wlist Database opened\n");
    {
		const char *pwListTable = "CREATE TABLE IF NOT EXISTS WhiteList(idx INTEGER, deviceMac varchar(17),productId varchar(33), deviceSN varchar(33), deviceId varchar(33))";

	    char *pcErr;
        
//     DBG_vPrintf(DBG_SQL, "Execute SQL: '%s'\n", pConditionTableDef);
        
        if (sqlite3_exec(ctx->pDb, pwListTable, NULL, NULL, &pcErr) != SQLITE_OK)
        {
            printf("Error creating table (%s)\n", pcErr);
            sqlite3_free(pcErr);
            //eUtils_LockUnlock(&sLock);
            _kk_wlist_unlock();
            return FAIL_RETURN;
        }
	 
    }

    //eUtils_LockUnlock(&sLock);
    _kk_wlist_unlock();
    return SUCCESS_RETURN;
}
static int _kk_check_exist(const char* device_mac)
{
	int isExist = 0;
	sqlite3_stmt *stmt;
	char *pmac = NULL;
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
	const char *searchCmd = "select * from WhiteList;";	
	sqlite3_prepare_v2(ctx->pDb, searchCmd, strlen(searchCmd), &stmt, NULL);
	printf("total_column = %d\n", sqlite3_column_count(stmt));
	while(sqlite3_step(stmt) == SQLITE_ROW){
	   pmac = sqlite3_column_text(stmt, 1);
	   if(!strcmp(device_mac,pmac))
	   
{
		 isExist = 1;
		 break;
	   }
    }
    printf("\n");
	sqlite3_finalize(stmt);
	return isExist;

	

}
static int kk_wlist_insert_db(int index,char device_mac[DEVICE_MAC_MAXLEN],char product_Id[PRODUCT_KEY_MAXLEN], \
										char device_SN[DEVICE_SN_MAXLEN],char device_Id[DEVICE_NAME_MAXLEN])
{
	const char *insertCmd = "insert into WhiteList (idx, deviceMac, productId,deviceSN,deviceId) values ('%d', '%s', '%s','%s','%s');";
	char *sqlCmd = NULL;
	int rc = 0;
	char *zErrMsg = 0;
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();

	_kk_wlist_lock();

	sqlCmd = sqlite3_mprintf(insertCmd, index,device_mac,product_Id,device_SN,device_Id);	
	
	rc = sqlite3_exec(ctx->pDb, sqlCmd, NULL, NULL, &zErrMsg);
	if( rc != SQLITE_OK ){
	   printf("SQL error: %s\n", zErrMsg);
	   sqlite3_free(zErrMsg);
	}else{
	   printf("Table insert data successfully\n");
	}
	sqlite3_free(sqlCmd);
	_kk_wlist_unlock();
	return SUCCESS_RETURN;
}

static int _kk_wlist_delete_db_byMac(char device_mac[DEVICE_MAC_MAXLEN])
{
	const char *deleteCmd = "delete from WhiteList where deviceMac = %s;";
	char *sqlCmd = NULL;
	int rc = 0;
	char *zErrMsg = 0;
	kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();

	_kk_wlist_lock();
	sqlCmd = sqlite3_mprintf( deleteCmd,device_mac);	
	 printf("Table delete data sqlCmd:%s\n",sqlCmd);
	rc = sqlite3_exec(ctx->pDb, sqlCmd, NULL, NULL, &zErrMsg);
	if( rc != SQLITE_OK ){
	   printf("SQL error: %s\n", zErrMsg);
	   sqlite3_free(zErrMsg);
	}else{
	   printf("Table delete data successfully\n");
	}
	sqlite3_free(sqlCmd);

	_kk_wlist_unlock();
	return SUCCESS_RETURN;
}

int kk_wlist_status_open(int isOpen)
{
	int res = 0;
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
	res = kk_tsl_set_value(kk_tsl_set_property_value,0,KK_TSL_GATAWAY_WHITELIST_IDENTIFIER,&isOpen,NULL);
	if(res != SUCCESS_RETURN){
		printf("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
		return FAIL_RETURN;
	}	
	ctx->isOpened = 1;
	return SUCCESS_RETURN;
}
int kk_load_wlist(void)
{
	const char *searchCmd = "select * from WhiteList;";	
	sqlite3_stmt *stmt;	
	char *pmac = NULL,*pPID = NULL,*pSN = NULL,pDID = NULL;
    kk_wlist_dev_t wlist = {0};	
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
	if(ctx->isOpened != 1){
		return FAIL_RETURN;
	}

	sqlite3_prepare_v2(ctx->pDb, searchCmd, strlen(searchCmd), &stmt, NULL);
	printf("kk_load_wlist total_column = %d\n", sqlite3_column_count(stmt));	
	while(sqlite3_step(stmt) == SQLITE_ROW){
	   memset(&wlist,0x0,sizeof(kk_wlist_dev_t));
	   strcpy(wlist.device_mac,sqlite3_column_text(stmt, 1));
	   strcpy(wlist.product_id,sqlite3_column_text(stmt, 2));
	   strcpy(wlist.device_sn,sqlite3_column_text(stmt, 3));
	   strcpy(wlist.device_id,sqlite3_column_text(stmt, 4));
	  // kk_add_wlist(&wlist);
	   kk_set_wlist_byIdx(ctx->wlistNum,&wlist);
	   ctx->wlistNum++;
    }	
	sqlite3_finalize(stmt);
	return SUCCESS_RETURN;

}
int kk_wlist_init(void)
{
	int res = 0;
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
	
    /* Create Mutex */
    ctx->mutex = HAL_MutexCreate();
    if (ctx->mutex == NULL) {
        return FAIL_RETURN;
    }

	res = kk_wlist_db_Init();
	if(res != SUCCESS_RETURN){
		printf("[%s][%d]kk_wlist_db_Init FAIL!!!\n",__FUNCTION__,__LINE__);

	}
	kk_load_wlist();
	return SUCCESS_RETURN;
}
int kk_set_wlist_byIdx(int idx,kk_wlist_dev_t * wlist_dev)
{
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
	int res = 0;
	char identifier_name[64] = {0};
	if(wlist_dev == NULL)
	{
		printf("[%s][%d] wlist_dev == NULL!!!\n",__FUNCTION__,__LINE__);
		return FAIL_RETURN;
	}
	_kk_wlist_lock();
	sprintf(identifier_name,KK_TSL_GATAWAY_WHITELISTMAC_IDENTIFIER,idx);
	res = kk_tsl_set_value(kk_tsl_set_event_output_value,0,identifier_name,NULL,wlist_dev->device_mac);
	if(res != SUCCESS_RETURN){
		goto fail_return;
	}	
	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_GATAWAY_WHITELISTPRODUCTID_IDENTIFIER,idx);
	res = kk_tsl_set_value(kk_tsl_set_event_output_value,0,identifier_name,NULL,wlist_dev->product_id);
	if(res != SUCCESS_RETURN){
		goto fail_return;

	}		
	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_GATAWAY_WHITELISTSN_IDENTIFIER,idx);
	res = kk_tsl_set_value(kk_tsl_set_event_output_value,0,identifier_name,NULL,wlist_dev->device_sn);
	if(res != SUCCESS_RETURN){
		goto fail_return;

	}			
	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_GATAWAY_WHITELISTDEVICEID_IDENTIFIER,idx);
	res = kk_tsl_set_value(kk_tsl_set_event_output_value,0,identifier_name,NULL,wlist_dev->device_id);
	if(res != SUCCESS_RETURN){
		goto fail_return;
	}
	_kk_wlist_unlock();
	return SUCCESS_RETURN;
	
fail_return:
	_kk_wlist_unlock();
	printf("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	return FAIL_RETURN;

}


int kk_add_wlist(kk_wlist_dev_t *wlist_dev)
{
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
	int res = 0;
	if(ctx->isOpened != 1){
		printf("[%s][%d] PLEASE OPNE THE WHITELIST FUNCTION FIRST!!!\n",__FUNCTION__,__LINE__);
		return FAIL_RETURN;
	}
	if(ctx->wlistNum >= 512){
		printf("[%s][%d] WHITELIST FULL!!!\n",__FUNCTION__,__LINE__);
		return FAIL_RETURN;

	}
	if(wlist_dev == NULL){
		printf("[%s][%d] wlist_dev == NULL!!!\n",__FUNCTION__,__LINE__);
		return INVALID_PARAMETER;

	}
	if(_kk_check_exist(wlist_dev->device_mac) == 1)
	{
		printf("[%s][%d] DATA ALREADY EXIST!!!\n",__FUNCTION__,__LINE__);
		return SUCCESS_RETURN;
	}
	res = kk_wlist_insert_db(ctx->wlistNum,wlist_dev->device_mac,wlist_dev->product_id,wlist_dev->device_sn,wlist_dev->device_id);	
	res |= kk_set_wlist_byIdx(ctx->wlistNum,wlist_dev);
	ctx->wlistNum++;
	return res;

}
int kk_get_wlist_num(void)
{
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
	if(ctx->isOpened != 1)
	{
		printf("[%s][%d] PLEASE OPNE THE WHITELIST FUNCTION FIRST!!!\n",__FUNCTION__,__LINE__);
		return FAIL_RETURN;
	}
	return ctx->wlistNum;
}
int kk_getwlist_ByIdx(int idx,kk_wlist_dev_t* wlist_dev)
{
	char *macs = NULL;
	char *PID = NULL;	
	char *DID = NULL;	
	char *SN = NULL;	
	char identifier_name[64] = {0};
	int res = 0;
	
	_kk_wlist_lock();
	sprintf(identifier_name,KK_TSL_GATAWAY_WHITELISTMAC_IDENTIFIER,idx);
	res = kk_tsl_get_value(kk_tsl_get_event_output_value,0,identifier_name,NULL,&macs);
	if(res != SUCCESS_RETURN){
		goto fail_return;
	}	
	strcpy(wlist_dev->device_mac,macs);
	
	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_GATAWAY_WHITELISTPRODUCTID_IDENTIFIER,idx);
	res = kk_tsl_get_value(kk_tsl_get_event_output_value,0,identifier_name,NULL,&PID);
	if(res != SUCCESS_RETURN){
		goto fail_return;

	}
	strcpy(wlist_dev->product_id,PID);
	
	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_GATAWAY_WHITELISTSN_IDENTIFIER,idx);
	res = kk_tsl_get_value(kk_tsl_get_event_output_value,0,identifier_name,NULL,&SN);
	if(res != SUCCESS_RETURN){
		goto fail_return;

	}	
	strcpy(wlist_dev->device_sn,SN);
	
	memset(identifier_name,0x0,sizeof(identifier_name));
	sprintf(identifier_name,KK_TSL_GATAWAY_WHITELISTDEVICEID_IDENTIFIER,idx);
	res = kk_tsl_get_value(kk_tsl_get_event_output_value,0,identifier_name,NULL,&DID);
	if(res != SUCCESS_RETURN){
		goto fail_return;
	}	
	strcpy(wlist_dev->device_id,DID);
	_kk_wlist_unlock();
	return SUCCESS_RETURN;
	
fail_return:
	_kk_wlist_unlock();
	printf("[%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
	return FAIL_RETURN;

}
int kk_get_wlistIdx_byMac(const char* device_mac)
{
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
	int res = 0;
	char *pmac = NULL;	
	char identifier_name[64] = {0};
    int idx = 0,findIdx = 0;
	if(ctx->isOpened != 1)
	{
		printf("[%s][%d] PLEASE OPNE THE WHITELIST FUNCTION FIRST!!!\n",__FUNCTION__,__LINE__);
		return FAIL_RETURN;
	}
	if(idx >= 512)
	{
		printf("[%s][%d]Invalid idx!!!\n",__FUNCTION__,__LINE__);
		return FAIL_RETURN;

	}
	_kk_wlist_lock();
	for(idx = 0; idx < ctx->wlistNum;idx++)
	{
		memset(identifier_name,0x0,sizeof(identifier_name));
		sprintf(identifier_name,KK_TSL_GATAWAY_WHITELISTMAC_IDENTIFIER,idx);
		res = kk_tsl_get_value(kk_tsl_get_event_output_value,0,identifier_name,NULL,&pmac);
		if(res != SUCCESS_RETURN){
			continue;
		}
		if(!strcmp(device_mac,pmac))
		{
			findIdx = idx;
			printf("[%s][%d]find the delete index\n",__FUNCTION__,__LINE__);
			_kk_wlist_unlock();
			return findIdx;
		}
	}
	if(idx == ctx->wlistNum)
	{
		_kk_wlist_unlock();
		return TSL_EVENT_NOT_EXIST;
	}
	_kk_wlist_unlock();
	return FAIL_RETURN;
}

static int _kk_delete_wlist_byIdx(int idx)
{
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
	int res = 0;
	kk_wlist_dev_t dWlist = {0};

	if(idx >= 512)
	{
		printf("[%s][%d]Invalid idx!!!\n",__FUNCTION__,__LINE__);
		return FAIL_RETURN;

	}
	strcpy(dWlist.product_id,"");
	strcpy(dWlist.device_mac,"");
	strcpy(dWlist.device_sn,"");
	strcpy(dWlist.device_id,"");
	res = kk_set_wlist_byIdx(idx,&dWlist);
	return res;

}

int kk_delete_wlist_byMac(const char* device_mac)
{
    kk_wlist_ctx_t *ctx = _kk_wlist_get_ctx();
	char identifier_name[64] = {0};
	int res;
	int idx = 0;
	char *pmac = NULL;
	int findIdx = 0;
	if(ctx->isOpened != 1)
	{
		printf("[%s][%d] PLEASE OPNE THE WHITELIST FUNCTION FIRST!!!\n",__FUNCTION__,__LINE__);
		return FAIL_RETURN;
	}

	findIdx = kk_get_wlistIdx_byMac(device_mac);
	if(findIdx < 0)
	{
		return FAIL_RETURN;
	}
	res = _kk_delete_wlist_byIdx(findIdx);
	res |= _kk_wlist_delete_db_byMac(device_mac);	
	if(res != SUCCESS_RETURN)
	{
		return FAIL_RETURN;
	}
	ctx->wlistNum--;
	return SUCCESS_RETURN;
}


