#include "kk_device_manager.h"

#include <fcntl.h>
#include "sqlite3.h"


/****************** ******************************************************************
* File Name			: kk_device_manager.c
* Author			: yjq
* data				: 2020/09/01
*************************************************************************************/
#define KK_GP_EP									242


kk_device_table_s *kk_zb_device_table=NULL;


static void kk_device_table_save(void);
static void kk_device_table_load(void);

void kk_print_device_table(void)
{
	int i,cnt = 0;
	kk_device_table_s *ptr = kk_zb_device_table;
	emberAfCorePrintln("\n-----------kk device table-----------\n");

	while(ptr!=NULL){
		emberAfAppPrint("\n%d:",++cnt);
		emberAfAppPrint("\nMAC = " );
		emberAfPrintBigEndianEui64(ptr->mac);
		emberAfAppPrint("\nproductCode = %s",(ptr->productCode!=NULL)?ptr->productCode:"unknow");
		emberAfAppPrint("\nidentifyCnt = %d",ptr->identifyCnt);
		
		ptr = ptr->next;
	}

}
static kk_device_table_s *kk_device_table_create()
{
	emberAfCorePrintln("\n[KK device table] add!");
	
	kk_device_table_s *node = (kk_device_table_s *)malloc(sizeof(kk_device_table_s));

	if(node==NULL){
		emberAfCorePrintln("[KK device table] malloc fail!!!%s",__LINE__);
		return node;
	}

	MEMSET(node, 0, sizeof(kk_device_table_s));

	return node;
}

static kk_device_table_s *kk_device_table_find_next_empty()
{
	kk_device_table_s *ptr = kk_zb_device_table;

	if(ptr==NULL) return ptr;
	
	while(ptr!=NULL){
		if(ptr->next==NULL) return ptr;
		ptr = ptr->next;
	}
}

static void kk_device_fill(kk_device_table_s *ptr,EmberEUI64 mac,EmberNodeId nodeId,char *productCode,uint16_t deviceId)
{
	memcpy(ptr->mac,mac,sizeof(EmberEUI64));
	ptr->nodeId = nodeId;
	ptr->deviceId = deviceId;

	ptr->identifyCnt = KK_MAX_READ_MODLE_ID_COUNT;
	ptr->productCode = productCode;
}

kk_device_table_s * kk_device_find_by_mac(EmberEUI64 mac)
{
	kk_device_table_s *ptr = kk_zb_device_table;
	
	while(ptr!=NULL){
		if(MEMCOMPARE(ptr->mac,mac,sizeof(EmberEUI64))==0){
			return ptr;
		}
		ptr = ptr->next;
	}
	return NULL;
}
kk_device_table_s * kk_device_find_by_node(EmberNodeId node)
{
	kk_device_table_s *ptr = kk_zb_device_table;
	
	while(ptr!=NULL){
		if(ptr->nodeId==node){
			return ptr;
		}
		ptr = ptr->next;
	}
	return NULL;
}


bool kk_device_find_by_mac11111(EmberEUI64 mac)
{
	kk_device_table_s *ptr = kk_zb_device_table;
	
	while(ptr!=NULL){
		if(MEMCOMPARE(ptr->mac,mac,sizeof(EmberEUI64))==0){
			return true;
		}
		ptr = ptr->next;
	}
	return false;
}

void kk_device_table_add(EmberEUI64 mac,EmberNodeId nodeId,const char *productCode,uint16_t deviceId)
{
	kk_device_table_s *ptr = kk_zb_device_table;
	kk_device_table_s *newNode;

	UTIL_LOG_INFO("\n********************kk device table add********************\n");
	emberAfAppPrint("mac:");
	emberAfPrintBigEndianEui64(mac);
	if(kk_device_find_by_node(nodeId)!=NULL){
		emberAfAppPrintln(" is already in device table!!!");
		return ;
	}
	
	emberAfAppPrintln(",nodeId:0x%02x,productCode:%s,device id:0x%04x",nodeId,(productCode==NULL)?"nukown":productCode,deviceId);

	if(ptr==NULL){
		kk_zb_device_table = kk_device_table_create();
		ptr = kk_zb_device_table;		
		
		kk_device_fill(ptr,mac,nodeId,productCode,deviceId);
		
		return;
	}

	ptr = kk_device_table_find_next_empty();
	if(ptr!=NULL){
		newNode = kk_device_table_create();
		
		if(newNode!=NULL){
			ptr->next = newNode;
			kk_device_fill(newNode,mac,nodeId,productCode,deviceId);
		}
	}else{
		emberAfCorePrintln("[KK device table] fatal!!!%s",__LINE__);
	}
}

void kk_device_table_delete(EmberEUI64 mac)
{
	kk_device_table_s *ptr = kk_zb_device_table;
	kk_device_table_s *ptr_temp = kk_zb_device_table;
	if(ptr==NULL){
		emberAfCorePrintln("[KK device table] is empty!!!");
		return ;
	}
	while(ptr!=NULL){
		if(MEMCOMPARE(ptr->mac,mac,sizeof(EmberEUI64))==0){
			if(ptr->next==NULL){
				free(ptr);
				kk_zb_device_table = NULL;
				emberAfCorePrintln("[KK device table]delete,now is empty !!!");
				return ;
			}else{
				if(ptr==kk_zb_device_table){
					kk_zb_device_table = ptr->next;
					emberAfCorePrintln("[KK device table] delete list header");
			
					free(ptr);
					return ;
				}else{
					ptr_temp->next = ptr->next;
				
					free(ptr);
					emberAfCorePrintln("[KK device table] delete ");
					return ;
				}
			}
		}
		ptr_temp = ptr;
		ptr = ptr->next;
	}
}



static void kk_device_table_save(void)
{
	FILE *fp;
	int i;
	uint16_t pLen;
	kk_device_table_s *ptr = kk_zb_device_table;

	fp = fopen("kk_devices.txt", "w");
	
	while(ptr!=NULL){
		for (i = 0; i < 8; i++) {
			fprintf(fp, "%x ", ptr->mac[i]);
		}
		
		fprintf(fp, "%x ",ptr->nodeId);
		fprintf(fp, "%x ",ptr->deviceId);

		if(ptr->productCode==NULL){
			pLen = 0;
		}else{
			pLen = strlen(ptr->productCode);
		}
		
		fprintf(fp,"%x ",pLen);
		for(i=0;i<pLen;i++){
			fprintf(fp,"%x ",ptr->productCode[i]);
		}
		ptr = ptr->next;
	}

	fclose(fp);
}

static void kk_device_table_load(void)
{
	UTIL_LOG_INFO("\n********************kk load device table********************\n");
	
	FILE *fp;
	int i;
	EmberEUI64 mac;
	uint16_t nodeId;
	uint16_t deviceId;
	uint16_t len;
	char pCode[33];

	fp = fopen("kk_devices.txt", "r");
	
	if(fp==NULL) return;
	while(feof(fp) == false){
		emberAfDebugPrintln("111");
		for (i = 0; i< 8; i++) {
			fscanf(fp, "%x ", &mac[i]);
		}
		emberAfDebugPrintln("222");
		fscanf(fp, "%x", &nodeId);
		fscanf(fp, "%x ", &deviceId);
	

		emberAfDebugPrintln("len=%d",len);
		fscanf(fp, "%x", &len);

		for(i=0;i<len;i++){
			fscanf(fp,"%x ",&pCode[i]);
		}
		pCode[i] = 0;
		if(len==0){
			kk_device_table_add(mac,nodeId,NULL,deviceId);
		}else{
			kk_device_table_add(mac,nodeId,pCode,deviceId);
		}
		
	}
	fclose(fp);
	//kk_device_table_add(EmberEUI64 mac,EmberNodeId nodeId,uint8_t epNum,uint8_t* epVal,char *productCode)
	//kk_print_device_table();
}
void kk_device_table_clear(void)
{
	kk_device_table_s *ptr = kk_zb_device_table;
	kk_device_table_s *ptr_temp = kk_zb_device_table;
	if(ptr==NULL){
		return ;
	}
	while(ptr!=NULL){
		if(ptr->next==NULL){
			free(ptr);
			kk_zb_device_table = NULL;
			return ;
		}else{
			if(ptr==kk_zb_device_table){
				kk_zb_device_table = ptr->next;
				free(ptr);
				return ;
			}else{
				ptr_temp->next = ptr->next;
			
				free(ptr);
				return ;
			}
		}
		ptr_temp = ptr;
		ptr = ptr->next;
	}
	kk_device_table_save();
}

static const char *kk_match_tsl_productCode(const char* modelId)
{
	int i;
	int num = kk_get_product_code_table_size();

	UTIL_LOG_INFO("device model id:%s\n",modelId);
	for(i=0;i<num && kk_product_code[i].modelId!=NULL;i++){
		if(strstr(modelId,kk_product_code[i].modelId)!=NULL){
			UTIL_LOG_INFO("match model id:%s\n",kk_product_code[i].modelId);
			UTIL_LOG_INFO("tsl product code:%s\n",kk_product_code[i].code);
			#ifdef KK_PRODUCT_CODE_STRING_ENABLE
			UTIL_LOG_INFO("match product:%s\n",kk_product_code[i].name);
			#endif
			
			return kk_product_code[i].code;
		}
	}
	return NULL;
}

////////////////////////////////////////////////////


void kk_db()
{
	sqlite3 *db = NULL;
	char create[]="create table kk_device(number integer PRIMARY KEY, name text, sex text, age integer);";
	int ret = sqlite3_open("kk_device.db", &db);
    if(ret)
    {
        emberAfDebugPrintln("can not open database.\n");
    }
    else
    {
        emberAfDebugPrintln("open database succsee.\n");
    }
}
void emberAfPluginDeviceTableInitialized(void)
{
	kk_device_table_load();
	kk_db();
}


static int kk_match_device_id(uint16_t deviceId)
{
	int i;

	if(deviceId==0xffff) return -1;
	for(i=0;zb_device_id[i].deviceId!=0xffff;i++){
		if(zb_device_id[i].deviceId==deviceId){
			emberAfDebugPrint("device:");
			#ifdef ZIGBEE_DEVICE_ID_STRING_ENABLE
				emberAfDebugPrintln("%s",zb_device_id[i].deviceIdString);
			#endif
			return 0;
		}
	}
	return -2;
}





static void kk_device_modle_id_identify(EmberNodeId nodeId,
													uint8_t status,
													uint8_t dataType,
													uint8_t dataSize,
													uint8_t *data)
{
	
	kk_device_table_s *ptr = kk_zb_device_table;
	EmberEUI64 eui64;
	uint8_t modelID[33] = {0};
	while(ptr!=NULL){
		if(ptr->nodeId == nodeId){
			emberAfCorePrintln("[match tsl]node:0x%04X,status:0x%02x,dataType:0x%02x",nodeId,status,dataType);
			if(status==EMBER_ZCL_STATUS_SUCCESS ){//dataType==ZCL_CHAR_STRING_ATTRIBUTE_TYPE
				ptr->identifyCnt = 0;
				if(dataSize>=32){
					dataSize = 32;
					emberAfCorePrintln("[warring]modle id size = %d,max = 32!!!");
				}
				memcpy(modelID,data,dataSize);

				ptr->productCode = kk_match_tsl_productCode(modelID);
				if(ptr->productCode!=NULL){
					if(emberAfDeviceTableGetEui64FromNodeId(ptr->nodeId,eui64)){
						kk_rpc_reportDevices(eui64,ptr->productCode);
						kk_device_table_save();
					}else{
						UTIL_LOG_WARNING("not find mac from node in device table!!!");
					}
				}else{
					emberAfCorePrintln("not match tsl!!!");
				}
			}else if(status==EMBER_ZCL_STATUS_UNSUPPORTED_ATTRIBUTE){
				ptr->identifyCnt = 0;
				emberAfCorePrintln("nodeId:0x%04X,unsupport model id attr,CNT=%d",nodeId,ptr->identifyCnt);
				//to do :zdo leave ???
			}else{
				emberAfCorePrintln("nodeId:0x%04X,read modle id fail,status=0x%x",nodeId,status);
			}
			return;
		}
		ptr = ptr->next;
	}

}
void kk_read_attr_response(EmberNodeId nodeId,
										uint8_t ep,
										EmberAfClusterId cluster,
										EmberAfAttributeId attribute,
										uint8_t status,
										uint8_t dataType,
										uint8_t dataSize,
										uint8_t *data)
{
	emberAfAppPrintln("ep=%d,cluster=0x%04X,attribute=0x%04X",ep,cluster,attribute);
	if(cluster==ZCL_BASIC_CLUSTER_ID){
		if(attribute==ZCL_MODEL_IDENTIFIER_ATTRIBUTE_ID){
			if(ep==KK_PRIMARY_EP)
				kk_device_modle_id_identify(nodeId,status,dataType,dataSize,data);
		}
	}

}
void emberAfPluginDeviceTableNewDeviceCallback(EmberEUI64 nodeEui64)
{
	kk_device_joined(emberAfDeviceTableGetNodeIdFromEui64(nodeEui64));
}
void emberAfPluginDeviceTableRejoinDeviceCallback(EmberEUI64 nodeEui64)
{
	kk_device_joined(emberAfDeviceTableGetNodeIdFromEui64(nodeEui64));
}

void emberAfPluginDeviceTableDeviceLeftCallback(EmberEUI64 nodeEui64)
{
	uint16_t deviceTableIndex = emberAfDeviceTableGetFirstIndexFromEui64(nodeEui64);

	if(deviceTableIndex == EMBER_AF_PLUGIN_DEVICE_TABLE_NULL_INDEX){
		return ;
	}
	EmberAfPluginDeviceTableEntry *deviceTable = emberAfDeviceTablePointer();

	cJSON* nodeJson = rpc_reportDeviceState("left",deviceTable[deviceTableIndex].eui64);
	rpc_printfJSON("left",nodeJson);

	kk_rpc_reportLeftDevices(deviceTable[deviceTableIndex].eui64);
}


void kk_device_joined(EmberNodeId node)
{
	EmberEUI64 mac;
	uint16_t deviceId;
	uint16_t deviceTableIndex;
	EmberAfPluginDeviceTableEntry*devPtr;
	
	UTIL_LOG_INFO("\n********************kk device joined********************\n");
	
	if(emberAfDeviceTableGetEui64FromNodeId(node,mac)==false){
		deviceTableIndex = emberAfDeviceTableGetIndexFromNodeId(node);
		if(deviceTableIndex!=0xffff){
			devPtr = emberAfDeviceTablePointer();
			kk_add_device_to_table(mac,node,devPtr[deviceTableIndex].deviceId);
		}
	}else{
		emberAfDebugPrintln("[not find 111]");
		if(emberLookupEui64ByNodeId(node,mac)==EMBER_SUCCESS){
			deviceTableIndex = emberAfDeviceTableGetIndexFromNodeId(node);
			if(deviceTableIndex!=0xffff){
				devPtr = emberAfDeviceTablePointer();
				kk_add_device_to_table(mac,node,devPtr[deviceTableIndex].deviceId);
			}
		}else{
			emberAfDebugPrintln("[not find 222]");
		}
	}
}
void kk_productCode_tick()
{
	kk_device_table_s *ptr = kk_zb_device_table;
	EmberEUI64 eui64;
	EmberStatus status;
	
	while(ptr!=NULL){
		if(ptr->productCode == NULL){
			if(ptr->nodeId!=0xffff && ptr->identifyCnt!=0){
				status = zclGRead(ptr->nodeId,
									1,
									1,
									false,
									ZCL_BASIC_CLUSTER_ID,
									ZCL_MODEL_IDENTIFIER_ATTRIBUTE_ID,
									true);
				--ptr->identifyCnt;
				emberAfCorePrintln("read model id from node:0x%02x,status=0x%x,cnt=%d",ptr->nodeId,status,ptr->identifyCnt);
			}else{
				emberAfCorePrintln("not find node!");
			}
		}
		ptr = ptr->next;

	}
}


//to do:syn kk device table with ember device table
void kk_add_device_to_table(EmberEUI64 mac,EmberNodeId nodeId,uint16_t deviceId)
{
	UTIL_LOG_INFO("\n------------------------kk add device------------------------\n");
	emberAfAppPrint("mac:");
	emberAfPrintBigEndianEui64(mac);
	emberAfAppPrintln("\nnode:0x%04X,device id:0x%04x",nodeId,deviceId);

	kk_match_device_id(deviceId);
	
	kk_device_table_add(mac,nodeId,NULL,deviceId);
	kk_device_table_save();
}


void kk_network_check(void)
{
	EmberEUI64 eui64;
	EmberPanId panId;
	EmberStatus status;
	if(ezspNetworkState()!= EMBER_JOINED_NETWORK ){
		emberAfGetEui64(eui64);
		panId = HIGH_LOW_TO_INT(eui64[1],eui64[0]);
		status = kk_network_form(true,panId,KK_NETWORK_PARAMETER_TX_POWER,KK_NETWORK_PARAMETER_CHANNEL);
		if(status==EMBER_SUCCESS){
			emberAfAppPrintln("network form success~~~~~~");
		}else{
			emberAfAppPrintln("network form fail!!!,status=0x%x",status);
		}
	}else{
		kk_print_network_info();
	}
}

//int rpc_nwkPermitJoin(jrpc_context * ctx,const char *mac,unsigned char ep,void* data)
int kk_permit_join(jrpc_context * ctx,EmberNodeId node,unsigned char ep,void* data)
{
	EmberStatus status;
	uint8_t isEnable = *(uint8_t*)data;

	if(isEnable == 0){
		status = nwkPermitJoinCMD(FALSE);
		emberAfCorePrintln("Disable Permit join\r\n");
	}else if(isEnable == 1){
		status = nwkPermitJoinCMD(TRUE);
		emberAfCorePrintln("Enable Permit join %ds\r\n",EMBER_AF_PLUGIN_NETWORK_CREATOR_SECURITY_NETWORK_OPEN_TIME_S);
	}else{
		set_json_error_type(ctx,JRPC_INVALID_PARAMS,MSG_INVALID_PARAMS);
		goto error_return;
	}

	return status;

error_return:
	return -1;
}


























