
#include <stdio.h>
#include "kk_tsl_api.h"
#include "kk_sub_db.h"
#include "kk_dm_mng.h"

#include "sqlite3.h"
#include "kk_log.h"

extern sqlite3 *g_kk_pDb;

typedef struct {
    void *mutex;
	int  subDevNum;
    sqlite3 *pDb;	
} kk_subDb_ctx_t;
typedef enum{
	DB_IDX = 0,
	DB_ONLINE,
	DB_PRODUCTCODE,
	DB_DEVICECODE,
	DB_MAC,
	DB_FATHERDEVICECODE,
	DB_VERSION,
	DB_AUTH,
	DB_DEVTYPE,	
	DB_HEARTBEAT,	
	DB_PRODUCTTYPE
};

static kk_subDb_ctx_t s_kk_subDb_ctx = {NULL,0,NULL};
static kk_subDb_ctx_t *_kk_subDb_get_ctx(void)
{
    return &s_kk_subDb_ctx;
}
static void _kk_subDb_lock(void)
{
    kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();
    if (ctx->mutex) {
        HAL_MutexLock(ctx->mutex);
    }
}

static void _kk_subDb_unlock(void)
{
    kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();
    if (ctx->mutex) {
        HAL_MutexUnlock(ctx->mutex);
    }
}

static int kk_subDev_db_Init(void)
{
    kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();

    //eUtils_LockLock(&sLock);
    _kk_subDb_lock();
	
	ctx->pDb = g_kk_pDb;
       
    INFO_PRINT("sub db Database opened\n");
    {
		const char *pSubDevTable = "CREATE TABLE IF NOT EXISTS SubDeviceInfo( \
			idx INTEGER, \
			isOffline INTEGER, \
			productCode varchar(33), \
			deviceCode varchar(33), \
			mac varchar(17), \
			fatherDeviceCode varchar(33), \
			version varchar(33), \
			isAuth INTEGER, \
			devType INTEGER, \
			heartbeat INTEGER,\
			productType varchar(33))";

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

    //eUtils_LockUnlock(&sLock);
    _kk_subDb_unlock();
    return SUCCESS_RETURN;
}
static int _kk_load_subDevice(void)
{
	const char *searchCmd = "select * from SubDeviceInfo;";	
	sqlite3_stmt *stmt;	
    kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();
	int devId = 0,heartbeat = 0;
	int res = 0;
	_kk_subDb_lock();
	sqlite3_prepare_v2(ctx->pDb, searchCmd, strlen(searchCmd), &stmt, NULL);
	while(sqlite3_step(stmt) == SQLITE_ROW){
	   res = dm_mgr_subdev_create(sqlite3_column_int(stmt, DB_DEVTYPE),
	   					sqlite3_column_text(stmt, DB_PRODUCTCODE),
	   					sqlite3_column_text(stmt, DB_DEVICECODE),
	   					sqlite3_column_text(stmt, DB_MAC),
	   					sqlite3_column_text(stmt, DB_FATHERDEVICECODE),
	   					sqlite3_column_int(stmt, DB_ONLINE),&devId,&heartbeat);
	
	   if(res != SUCCESS_RETURN){
		   ERROR_PRINT("[%s][%d]dm_mgr_subdev_create FAIL!!!\n",__FUNCTION__,__LINE__);
	   }
	   else{
	   	   ctx->subDevNum++;
	   }
	   usleep(100000);
	   // send the topc info  
	   iotx_dm_subscribe(devId);
	   
	   //sync the data from property db
	   kk_property_sync_values(sqlite3_column_text(stmt, DB_DEVICECODE));
	   usleep(100000);
	   
	   //post the property to cloud
	   dm_msg_thing_property_post_all(sqlite3_column_text(stmt, DB_DEVICECODE));
	    //kk_dm_ota_report_version(devId,sqlite3_column_text(stmt, DB_VERSION));//post version
	   //usleep(100000);
    }	
	sqlite3_finalize(stmt);
	_kk_subDb_unlock();
	return SUCCESS_RETURN;

}
int kk_subDb_init(void)
{
	int res = 0;
    kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();
	
    /* Create Mutex */
    ctx->mutex = HAL_MutexCreate();
    if (ctx->mutex == NULL) {
        return FAIL_RETURN;
    }

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

	}
	_kk_load_subDevice();
	return SUCCESS_RETURN;
}
static int _kk_check_subDev_exist(const char* deviceCode)
{
	int isExist = 0;
	sqlite3_stmt *stmt;
	char *pmac = NULL;
    kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();
	const char *searchCmd = "select * from SubDeviceInfo;";	
	_kk_subDb_lock();
	sqlite3_prepare_v2(ctx->pDb, searchCmd, strlen(searchCmd), &stmt, NULL);
	//INFO_PRINT("total_column = %d\n", sqlite3_column_count(stmt));
	while(sqlite3_step(stmt) == SQLITE_ROW){
	   pmac = sqlite3_column_text(stmt, DB_DEVICECODE);
	   if(!strcmp(deviceCode,pmac))
	   
{
		 isExist = 1;
		 break;
	   }
    }
    INFO_PRINT("\n");
	sqlite3_finalize(stmt);
	_kk_subDb_unlock();
	return isExist;

	

}

int kk_subDev_insert_db(int devType,char productCode[PRODUCT_CODE_MAXLEN], \
										char deviceCode[DEVICE_CODE_MAXLEN],char fatherDeviceCode[DEVICE_CODE_MAXLEN],char mac[DEVICE_MAC_MAXLEN],char version[DEVICE_VERSION_MAXLEN],int heartbeat)
{
	const char *insertCmd = "insert into SubDeviceInfo (idx,isOffline,productCode,deviceCode,mac,fatherDeviceCode,version,isAuth,devType,heartbeat) \
								values ('%d','%d', '%s','%s','%s','%s','%s','%d','%d','%d');";
	char *sqlCmd = NULL;
	int rc = 0;
	char *zErrMsg = 0;
    kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();


	if(_kk_check_subDev_exist((const char*)deviceCode) == 1)
	{
		WARNING_PRINT("[%s][%d] DATA ALREADY EXIST!!!\n",__FUNCTION__,__LINE__);
		return SUCCESS_RETURN;
	}
	_kk_subDb_lock();
	sqlCmd = sqlite3_mprintf(insertCmd,ctx->subDevNum,0,productCode,deviceCode,mac,fatherDeviceCode,version,0,devType,heartbeat);	

	rc = sqlite3_exec(ctx->pDb, sqlCmd, NULL, NULL, &zErrMsg);
	if( rc != SQLITE_OK ){
	   ERROR_PRINT("SQL error: %s\n", zErrMsg);
	   sqlite3_free(zErrMsg);
	}else{
	   //INFO_PRINT("sub device insert data successfully\n");
	}
	sqlite3_free(sqlCmd);
	ctx->subDevNum++;
	_kk_subDb_unlock();
	return SUCCESS_RETURN;
}
int kk_subDev_delete_by_dcode(char deviceCode[DEVICE_CODE_MAXLEN])
{
	const char *deleteCmd = "delete from SubDeviceInfo where deviceCode = '%s';";
	char *sqlCmd = NULL;
	int rc = 0;
	char *zErrMsg = 0;
	kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();

	_kk_subDb_lock();
	 sqlCmd = sqlite3_mprintf(deleteCmd,deviceCode);	

	INFO_PRINT("Table delete data sqlCmd:%s\n",sqlCmd);
	rc = sqlite3_exec(ctx->pDb, sqlCmd, NULL, NULL, &zErrMsg);
	if( rc != SQLITE_OK ){
	   ERROR_PRINT("SQL error: %s\n", zErrMsg);
	   sqlite3_free(zErrMsg);
	}else{
	   //INFO_PRINT("Table delete data successfully\n");
	}
	sqlite3_free(sqlCmd);
	_kk_subDb_unlock();
	return SUCCESS_RETURN;
}

int kk_subDev_update_offline(int isOffline,const char *deviceCode)
{
	char *sqlCmd = NULL;
	int len =0;
	int rc = 0;
	char *zErrMsg = 0;
	kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();

	//_kk_subDb_lock();
	sqlCmd = sqlite3_mprintf("UPDATE SubDeviceInfo SET isOffline=%d  WHERE deviceCode= '%s'",isOffline,deviceCode);	
	INFO_PRINT("kk_subDev_update_offline sqlCmd:%s\n",sqlCmd);
	rc = sqlite3_exec(ctx->pDb, sqlCmd, NULL, NULL, &zErrMsg);
	if( rc != SQLITE_OK ){
	   ERROR_PRINT("SQL error: %s\n", zErrMsg);
	   sqlite3_free(zErrMsg);
	}else{
	   //INFO_PRINT("Table updata data successfully\n");
	}
    sqlite3_free(sqlCmd);
	//_kk_subDb_unlock();
	return SUCCESS_RETURN;
}
int kk_subDev_update_productType(char *productType,const char *deviceCode)
{
	char *sqlCmd = NULL;
	int len =0;
	int rc = 0;
	char *zErrMsg = 0;
	kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();

	//_kk_subDb_lock();
	sqlCmd = sqlite3_mprintf("UPDATE SubDeviceInfo SET productType='%s'  WHERE deviceCode= '%s'",productType,deviceCode);	
	INFO_PRINT("kk_subDev_update_productType sqlCmd:%s\n",sqlCmd);
	rc = sqlite3_exec(ctx->pDb, sqlCmd, NULL, NULL, &zErrMsg);
	if( rc != SQLITE_OK ){
	   ERROR_PRINT("SQL error: %s\n", zErrMsg);
	   sqlite3_free(zErrMsg);
	}else{
	   //INFO_PRINT("Table updata data successfully\n");
	}
    sqlite3_free(sqlCmd);
	//_kk_subDb_unlock();
	return SUCCESS_RETURN;
}

int kk_subDev_update_auth(int isAuth,const char *deviceCode)
{
	char *sqlCmd = NULL;
	int len =0;
	int rc = 0;
	char *zErrMsg = 0;
	kk_subDb_ctx_t *ctx = _kk_subDb_get_ctx();

	_kk_subDb_lock();
	sqlCmd = sqlite3_mprintf("UPDATE SubDeviceInfo SET isAuth=%d  WHERE deviceCode= '%s'",isAuth,deviceCode);	
	INFO_PRINT("kk_subDev_update_auth sqlCmd:%s\n",sqlCmd);
	rc = sqlite3_exec(ctx->pDb, sqlCmd, NULL, NULL, &zErrMsg);
	if( rc != SQLITE_OK ){
	   ERROR_PRINT("SQL error: %s\n", zErrMsg);
	   sqlite3_free(zErrMsg);
	}else{
	   INFO_PRINT("Table updata data successfully\n");
	}
    sqlite3_free(sqlCmd);
	_kk_subDb_unlock();
	return SUCCESS_RETURN;
}







