#include <string.h>

#include "ikk-common-utils.h"
#include "ikk-debug.h"
#include "ikk-module-def.h"

#define NODE_MAX_NUM  		64
#define NODE_ID_DEFAULT		0xFFFF



void SWAP_EUI64(uint8_t *ptr)
{
	uint8_t temp;
	for(uint8_t i = 0;i<4;i++)
	{
		temp     = ptr[7-i];
		ptr[7-i] = ptr[i];
		ptr[i]   = temp;
	}
}
bool All_Same_Data(uint8_t *buffer,uint8_t value,uint8_t len)
{
	if(buffer == NULL)
		return false;
	for(uint8_t i = 0;i<len;i++){
		if(buffer[i] != value)
			return false;
	}
	return true;
}
/*	DESP: Gets the value[in 64-bits] of the specified length from the specified OCT string.
 * 	Note: expected output value max 64bits, so max length input is 16!!!
	Auth: dingmz_frc.20191018.
*/
uint64_t kUtilsOct2Value(char *oct, int length/* ≤ 16 */ )
{
	char temp_string[(sizeof(uint64_t) << 1) + 1] = { 0 };
	uint64_t u64ResultValue = 0;
	int orgslen = strlen(oct);

	// Check whether the string length is less than the specified length. If it is less than the specified length, high-order complement is required.
	memset(temp_string, '0', sizeof(temp_string));

	if( orgslen < length ) {
		memcpy(temp_string + (length - orgslen), oct, orgslen);
	}else {
		memcpy(temp_string, oct, length);
	}

	//iKonkeAfSelfPrint("kUtilsOct2Value:::::[%s][%d]\r\n", temp_string, length);
    for(int i = 0; i < length; ++i ) {
        if( oct[i] > '9') {
        	u64ResultValue = 16 * u64ResultValue + (10 + temp_string[i] - 'a');
        } else{
        	u64ResultValue = 16 * u64ResultValue + (temp_string[i] - '0');
        }
    }

    return u64ResultValue;
}
/*	DESP: Convert OCT string to hex data stream.
	Auth: dingmz_frc.20191018.
*/
int kUtilsStr2Hex(char *octstr, unsigned char *phexout, int max_length )
{
	if( NULL == octstr || NULL == phexout ) {
		return -1;
	}

	int str_len = strlen(octstr), iox = 0;

	for(int index = 0; index < str_len; index += 2 ) {
		phexout[iox++] = (uint8_t)kUtilsOct2Value(octstr + index, 2);

		if( iox >= max_length ) {
			break;
		}
	}

	return iox;
}
/********************************************************************************/
/*	This function converts an HEX number to 2-byte string						*/
/*	Auth: lmm_frc.20210607.														*/
/********************************************************************************/
void kUtilsHex2Str( uint8_t ucChar, uint8_t *pcResult )
{
	uint8_t	tmp;

	tmp = ucChar & 0xF0;		//calculate high
	tmp = tmp >> 4;
	if(tmp <= 9)
		pcResult[0] = tmp + '0';
	else
		pcResult[0] = tmp - 10 + 'a';

	tmp = ucChar & 0x0F;		//calculate low
	if(tmp <= 9)
		pcResult[1] = tmp + '0';
	else
		pcResult[1] = tmp - 10 + 'a';
}
#if 0
//static const DataInfoSt s_datatype_def[] = STATIC_DATA_INFO_DEF;

// global common buffer.
uint8_t g_u8GlobalBufferN1[GLOBAL_BUFFER_SIZE] = { 0 }, g_u8GlobalBufferN2[GLOBAL_BUFFER_SIZE] = { 0 };
uint8_t g_u8GlobalLengthN1 = 0, g_u8GlobalLengthN2 = 0;


/*	DESP: Gets the byte length of the specified data type.
 * 	Auth: dingmz_frc.20191025.
 * */
uint8_t kUtilsGetDataLength(uint8_t type )
{
	for(int index = 0; index < (sizeof(s_datatype_def) / sizeof(DataInfoSt)); ++index ) {
		if( s_datatype_def[index].datatype == type ) {
			return s_datatype_def[index].length;
		}
	}

	return 0;
}

/*	DESP: Check whether the given string is a number.
 * 	Auth: dingmz_frc.20191023.
 * */
bool kUtilsIsNumber(char *string )
{
	if( NULL == string ) return false;

	int length = strlen(string);

	if( length <= 0 ) return false;

	for(int index = 0; index < length; ++index ) {
		if( !isdigit(string[index])) {
			if((length > 1) && (index == 0) && (string[index] == '-' || string[index] == '+')) {
				// do nothing.
			}else {
				return false;
			}
		}
	}

	return true;
}

/*	DESP: Check whether the given string is OCT string.
 * 	Auth: dingmz_frc.20191023.
 * */
bool kUtilsIsOct(char *string )
{
	if( NULL == string ) return false;

	int length = strlen(string);

	if((length > 0) || ((length % 2) == 0)) {
		for(int index = 0; index < length; ++index ) {
			if(	(string[index] >= '0' && string[index] <= '9') || (string[index] >= 'a' && string[index] <= 'f') ||
				(string[index] >= 'A' && string[index] <= 'F')) {
				// do nothing.
			}else {
				return false;
			}
		}
	}else {
		return false;
	}

	return true;
}




/*	DESP: 高精度随机值接口，取值[minNum, maxNum].
	Auth: dingmz_frc.20190701.
*/
uint32_t kUtilsGetRandNum(uint32_t minNum, uint32_t maxNum )
{
	if( minNum >= maxNum ) {
		return 0;
	}

	static uint32_t s_counter = 0;
	//halCommonGetInt32uMillisecondTick();

	uint8_t u8LocalEui64[8] = { 0 };

	emberAfGetEui64(u8LocalEui64);
	++s_counter;

	srand(s_counter * s_counter + u8LocalEui64[0] + (emberAfGetNodeId() & 0x0567)); //提供随机种子
	uint32_t randNum  =  minNum + rand() % (maxNum - minNum + 1);

	iKonkeAfSelfPrint(" xxx rand num = %d\r\n", randNum);

	return randNum;
}

/*	DESP: check whether the data set content is specified byte data!
 * 	Auth: dingmz_frc.20190520.
 * */
bool kUtilsCheckDataSetContext(void *data_set, uint8_t spec_v, int length )
{
	if( NULL == data_set ) {
		return false;
	}

	uint8_t *data_v = (uint8_t *)data_set;

	for(int index = 0; index < length; ++index ) {
		if( data_v[index] != spec_v ) {
			return false;
		}
	}

	return true;
}


/*	DESP: 64bits大小端转换.
	Auth: dingmz_frc.20180627.
*/
uint64_t __CPU_ENDIAN_HTONLL__(uint64_t u64_host )
{
	unsigned int u32_host_l = (u64_host >>  0) & 0xffffffff;
	unsigned int u32_host_h = (u64_host >> 32) & 0xffffffff;

	return ((((uint64_t)NT32(u32_host_l)) << 32 ) |
		NT32(u32_host_h));
}

/*	DESP: Check if it is a valid long address.
 * 	Auth: dingmz_frc.20191106.
 * */
bool kUtilsIsValidEui64Addr(EmberEUI64 ineui64addr )
{
	return !kUtilsCheckDataSetContext(ineui64addr, 0xFF, EUI64_SIZE);
}

///*	DESP: get the crc16 value of specific InstallCode.
// * 	Auth: dingmz_frc.20191007.
// * */
//uint16_t kUtilsInstallCodeX25CRC16(uint8_t* u8InstallCode, uint8_t length )
//{
//  uint16_t crc = 0xFFFF;
//  uint8_t index;
//
//  if( NULL == u8InstallCode ) {
//	  return 0xff;
//  }
//
//  // Compute the CRC and verify that it matches.  The bit reversals, byte swap,
//  // and ones' complement are due to differences between halCommonCrc16 and the
//  // Smart Energy version.
//  for(index = 0; index < length; ++index ) {
//	  crc = halCommonCrc16(reverse(u8InstallCode[index]), crc);
//  }
//
//  crc = ~HIGH_LOW_TO_INT(reverse(LOW_BYTE(crc)), reverse(HIGH_BYTE(crc)));
//
//  return crc;
//}
//
///*	DESP: CRC16 algorithm.
// * 	Auth: dingmz_frc.20191018.
// * */
//uint16_t kUtilsCRC16Sum(const unsigned char *msg, unsigned int length )
//{
//	unsigned short CRC = 0xFFFF;
//	int i;
//
//	while (length--) {
//		CRC ^= *msg++;
//		for (i = 0; i < 8; ++i )  {
//			CRC=(CRC & 0x0001)?((CRC>>1) ^0xA001):(CRC>>1);
//		}
//	}
//
//	return CRC;
//}


/*	DESP: message format parse, String Segmentation parse into Substrings.
	Auth: dingmz_frc.20180607.
*/
int	kUtilsStringSplit(char *string, char (*item)[STRING_ITEM_SIZE_MAX], char spec/*分隔符*/)
{
	if( NULL == string ) return 0;

	uint8_t idex, item_idex = 0, cp_idex = 0;
	char tmp_char;

	// Parse...
	for(idex = 0; idex < strlen(string); ++idex) {
		tmp_char = string[idex];
		if( tmp_char == spec ) {
			item[item_idex][cp_idex] = '\0';
			if( ++item_idex >= STRING_ITEM_NUM_MAX)
				return -1;
			cp_idex = 0;
		}else {
			item[item_idex][cp_idex] = tmp_char;
			if( ++cp_idex >= STRING_ITEM_SIZE_MAX)
				return -2;
		}
	}

	item[item_idex][cp_idex] = '\0';

	return item_idex + 1;
}


/*	DESP: Reverse uint8 array contents.
 * 	PARAM[bModifyOriginalData]: Note that this interface modifies the original data content When bModifyOriginalData is true!!!
	Auth: dingmz_frc.20191019.
*/
uint8_t *kUtilsReverseArrayU8int(uint8_t *org_data, int length, bool bModifyOriginalData )
{
	static uint8_t s_image_data[16] = { 0 };

	if((NULL == org_data || length <= 0) || length > sizeof(s_image_data)) {
		return NULL;
	}

	for(int index = 0; index < length; ++index ) {
		s_image_data[index] = org_data[length - 1 - index];
	}

	if( bModifyOriginalData ) {
		memcpy(org_data, s_image_data, length);
	}

	return s_image_data;
}


static void kArraySort(uint32_t *buf, uint8_t size)
{
	uint8_t i, j;
	uint32_t t;
	for (j = 0; j< size;j++) {
		for(i = 0;i < size-1-j; i++){
			if(buf[i] > buf[i+1]) /* 由小到大,由大到小时改为< */{
				t = buf[i];
				buf[i] = buf[i+1];
				buf[i+1] = t;
			}
		}
	}
}
/*
对一个buffer数据进行排序去除最大的和最小的滤波个数取平均值
filter_num 滤波最大和最小的个数， 相等的
*/
uint32_t kUtilsGetAverage(uint32_t *buf, uint8_t len, uint8_t filter_num) //计算平均值
{
	uint64_t temp_val = 0;
	uint8_t i;
	if (len < 2){
		return 0;
	}

	if (len <= filter_num * 2){
		filter_num = 0;
	}
	printf("\r\nbefore average = ");
	for (int8_t i= 0; i < len; i++){
		printf("%d ", buf[i]);
	}
	kArraySort(buf, len); //排序
	printf("\r\nbuffer data = ");
	for (i = filter_num; i < len - filter_num ; i++){
		emberAfCorePrint("%d ", buf[i]);
		temp_val += buf[i];
	}
	printf("");
	return temp_val / (len - 2 *filter_num);
}

//Jun  7 2021
//0123456789A
uint32_t	Get_Date_Code( uint8_t * pData, uint8_t *pStr )
{
	uint8_t	aucDate[4];
	uint8_t	i	= 0;

	switch( pData[0] )
	{
		case 'J':
			if ( pData[i+1] == 'a' )		// Jan
				aucDate[2]	= 1;
			else if ( pData[i+2] == 'n' )	// Jun
				aucDate[2]	= 6;
			else
				aucDate[2]	= 7;			// Jul
			break;
		case 'F':
			aucDate[2]		= 2;			// Feb
			break;
		case 'M':
			if ( pData[i+2] == 'r' )		// Mar
				aucDate[2]	= 3;
			else
				aucDate[2]	= 5;			// May
			break;
		case 'A':
			if ( pData[i+2] == 'r' )		// Apr
				aucDate[2]	= 4;
			else
				aucDate[2]	= 8;			// Aug
			break;
		case 'S':
			aucDate[2]		= 9;			// Sep
			break;
		case 'O':
			aucDate[2]		= 0x10;			// Oct	use hex for BCD
			break;
		case 'N':
			aucDate[2]		= 0x11;			// Nov
			break;
		case 'D':
			aucDate[2]		= 0x12;			// Dec
			break;
	}

	kUtilsStr2Hex((uint8_t*)pData + 7,(uint8_t*)aucDate,1);
	kUtilsStr2Hex((uint8_t*)pData + 9,(uint8_t*)aucDate+1,1);
	kUtilsStr2Hex((uint8_t*)pData + 4,(uint8_t*)aucDate+3,1);

	emberAfCorePrintln("\r\nbuffer data = \r\n");
	for (i = 0; i < 4 ; i++){
		emberAfCorePrint("Buffer Data %d ", aucDate[i]);
	}
	emberAfCorePrintln("\r\n");
	if ( pStr != NULL )
	{
		MEMCOPY( pStr, pData+7, 4 );			// year
		kUtilsHex2Str( aucDate[2], pStr+4 );	// month
		kUtilsHex2Str( aucDate[3], pStr+6 );	// Date
		pStr[8]		= ' ';
		MEMCOPY( pStr+9, pData+i+1, 5 );		// Hour & minute
		pStr[14]	= 0;
	}

	return	GET_U32_B(aucDate);
}


#endif
