#include "RPC_API.h"
#include <pthread.h>


pthread_mutex_t report_mutex_lock;

void set_json_error_type(jrpc_context * ctx_p,int errorCode,char * errorMsg)
{
	ctx_p->error_code = errorCode;
	ctx_p->error_message = strdup(errorMsg);
}


static char table[]="0123456789ABCDEF";

char rpc_convert_char(char ch)
{
	if(ch>='0'&&ch<='9'){
		ch-='0';
	}else if(ch>='A' && ch<='F'){
		ch=ch-'A'+10;
	}else if(ch>='a'&&ch<='f'){
		ch=ch-'a'+10;
	}
	return ch;
}
uint8_t rpc_get_u8(char *string)
{

	if(string==NULL) return 0;

	uint8_t value;
	char valString[2]={0};
	int len = strlen(string);

	if(len<2){
		memcpy(&valString[2-len],string,len);
	}else{
		memcpy(valString,string,2);
	}
	
	//emberAfCorePrintln("\r\nstring=%s,valString=%s\r\n",string,valString);

	
	value = rpc_convert_char(valString[0])<<4;
	value|=rpc_convert_char(valString[1]);
	return value;
}

uint16_t rpc_get_u16(char *string)
{
	uint16_t value;
	value = rpc_convert_char(string[0])<<12;
	value|=(rpc_convert_char(string[1])<<8);
	value|=(rpc_convert_char(string[2])<<4);
	value|=rpc_convert_char(string[3]);
	
	return value;
}
bool rpc_get_mac(char *string,uint8_t *mac)
{
	if(string==NULL||mac==NULL) return false;

	int len = strlen(string);
	char macString[16]={0};
	if(len<16){
		memcpy(&macString[16-len],string,len);
	}else{
		memcpy(macString,string,16);
	}

	emberAfCorePrintln("\r\nlen=%d,macString=%s\r\n",len,macString);
	for(int i=0;i<EUI64_SIZE;i++){
		mac[EUI64_SIZE-1-i] = rpc_convert_char(macString[2*i])<<4;
		mac[EUI64_SIZE-1-i]|=rpc_convert_char(macString[2*i+1]);
		emberAfCorePrintln("i=%d,val=%02x",i,mac[EUI64_SIZE-1-i]);
	}
	return true;
}



EmberAfStatus ReadAttr(uint16_t node,
								uint8_t endpoint,
								EmberAfClusterId cluster,
								EmberAfAttributeId attribute,
								bool serverAttribute,
								rpc_read_attr_s *dataBuff)
{
	EmberAfStatus status;

	uint8_t data[ATTRIBUTE_LARGEST];
	uint8_t dataType;
	uint8_t length;

	emberAfCorePrint("emberAfIndexFromEndpointIncludingDisabledEndpoints!");

	uint8_t index = emberAfIndexFromEndpointIncludingDisabledEndpoints(endpoint);

	if(index==0xff){
		emberAfCorePrint("ep%d is not exsit!",endpoint);
		return EMBER_ZCL_STATUS_FAILURE;
	}
	emberAfCorePrint("%p: ep: %d, cl: 0x%2X, attr: 0x%2X",
					"read",
					endpoint,
					cluster,
					attribute);
	emberAfCorePrintln(", svr: %c", (serverAttribute ? 'y' : 'n'));

	status = emberAfReadAttribute(endpoint,
								cluster,
								attribute,
								(serverAttribute
								 ? CLUSTER_MASK_SERVER
								 : CLUSTER_MASK_CLIENT),
								data,
								sizeof(data),
								&dataType);
	if (status == EMBER_ZCL_STATUS_SUCCESS) {
		if (emberAfIsThisDataTypeAStringType(dataType)) {
			emberAfCorePrintString(data);
			length = emberAfStringLength(data);
			if(dataBuff->len < length){
				emberAfCorePrintln("buffer insufficient,\n");
			}else{
				dataBuff->len = length;
				memcpy(dataBuff->buffer,&data[1],length);
				dataBuff->AStringType = TRUE;
			}
		} else {
			length = emberAfGetDataSize(dataType);
			emberAfCorePrintBuffer(data, length, true);
			if(dataBuff->len<length){
				emberAfCorePrintln("buffer insufficient,\n");
			}else{
				dataBuff->len = length;
				memcpy(dataBuff->buffer,data,length);
				dataBuff->AStringType = FALSE;
			}
		}
		
		emberAfCorePrintln("");
	} else {
		emberAfCorePrintln("%p: read: 0x%x", "Error", status);
	}
	return status;
}


cJSON *rpc_ReadAttr(jrpc_context * ctx, cJSON * params, cJSON *id)
{
	cJSON *item;
	cJSON *item_node;
	cJSON *item_endpoint;
	cJSON *item_cluster;
	cJSON *item_attribute;
	cJSON *item_serverAttribute;
	EmberStatus status;

	item = rpc_cJSON_CreateObject();

	if(params == NULL){
		set_json_error_type(ctx,JRPC_INVALID_PARAMS,MSG_INVALID_PARAMS);
		kk_print_debug("params is NULL\n");
		goto error_return;
	}else if(params->type == cJSON_Object){
		item_node = cJSON_GetObjectItem(params, "node");
		item_endpoint = cJSON_GetObjectItem(params, "endpoint");
		item_cluster = cJSON_GetObjectItem(params, "cluster");
		item_attribute = cJSON_GetObjectItem(params, "attribute");
		item_serverAttribute = cJSON_GetObjectItem(params, "serverAttribute");
	}else if(params->type == cJSON_Array){
		item_node = cJSON_GetArrayItem(params, 0);
		item_endpoint = cJSON_GetArrayItem(params, 1);
		item_cluster = cJSON_GetArrayItem(params, 2);
		item_attribute = cJSON_GetArrayItem(params, 3);
		item_serverAttribute = cJSON_GetArrayItem(params, 4);
	}else{
		set_json_error_type(ctx,JRPC_INVALID_PARAMS,MSG_INVALID_PARAMS);
		kk_print_debug("params->type is %d\n",params->type);
		goto error_return;
	}

	if(item_node==NULL ||
		item_endpoint==NULL ||
		item_cluster==NULL ||
		item_attribute==NULL ||
		item_serverAttribute == NULL){
		set_json_error_type(ctx,JRPC_INVALID_PARAMS,MSG_INVALID_PARAMS);
		//kk_print_debug("1.....\n");
		goto error_return;
	}
	if(item_node->type!=cJSON_String ||
		item_endpoint->type!=cJSON_String ||
		item_cluster->type!=cJSON_String ||
		item_attribute->type!=cJSON_String ||
		(item_serverAttribute->type!=cJSON_True &&
			item_serverAttribute->type!=cJSON_False)){
		set_json_error_type(ctx,JRPC_INVALID_PARAMS,MSG_INVALID_PARAMS);
		//kk_print_debug(".2....\n");
		goto error_return;
	}
	if(strlen(item_node->valuestring)!=4 ||
		strlen(item_endpoint->valuestring)!=2 ||
		strlen(item_cluster->valuestring)!=4 ||
		strlen(item_attribute->valuestring)!=4){
		set_json_error_type(ctx,JRPC_INVALID_PARAMS,MSG_INVALID_PARAMS);
		//kk_print_debug("3[%d,%d,%d,%d]\n",strlen(item_node->valuestring),strlen(item_endpoint->valuestring),strlen(item_cluster->valuestring),strlen(item_attribute->valuestring));
		goto error_return;
	}

	kk_print_debug("node=%s\n",item_node->valuestring);
	kk_print_debug("endpoint=%s\n",item_endpoint->valuestring);
	kk_print_debug("cluster=%s\n",item_cluster->valuestring);
	kk_print_debug("attribute=%s\n",item_attribute->valuestring);
	
	uint16_t node= rpc_get_u16(item_node->valuestring);
	uint8_t endpoint= rpc_get_u8(item_endpoint->valuestring);
	uint16_t cluster= rpc_get_u16(item_cluster->valuestring);
	uint16_t attribute= rpc_get_u16(item_attribute->valuestring);

	bool serverAttribute = (item_serverAttribute->type==cJSON_True)?TRUE:FALSE;
	kk_print_debug("read node=0x%04X,EP=%d,clu=0x%04X,attr=0x%04X\n",
					node,endpoint,cluster,attribute);

	rpc_read_attr_s *dataBuff;
	kk_print_debug("111\r\n");
	uint8_t buffer[ATTRIBUTE_LARGEST];
	kk_print_debug("2222\r\n");
	uint8_t TempBuff[100];
	kk_print_debug("333\r\n");
	dataBuff->buffer = buffer;
	kk_print_debug("444\r\n");
	dataBuff->len = ATTRIBUTE_LARGEST;
	kk_print_debug("555\r\n");

	status = ReadAttr(node,endpoint,cluster,attribute,serverAttribute,dataBuff);
	kk_print_debug("666\r\n");

	if(status == EMBER_ZCL_STATUS_SUCCESS){
		kk_print_debug("read suc.\r\n");
		
		if(dataBuff->AStringType==TRUE){
			kk_print_debug("data:%s.\r\n",dataBuff->len);
			rpc_cJSON_AddStringToObject(item, "Attr",dataBuff->buffer);
		}else{
			kk_print_debug("dataBuff->len=%d.\r\n",dataBuff->len);
			for(int i=0;i<dataBuff->len;i++){
				sprintf(&TempBuff[3*i],"%02X ",dataBuff->buffer[i]);
			}
			rpc_cJSON_AddStringToObject(item, "Attr","ojbk");
		}
	}else{
		kk_print_debug("read fail!status=0x%02X\r\n",status);
		set_json_error_type(ctx,JRPC_INVALID_PARAMS,"read fail!");
		goto error_return;
	}

	return item;
	
	error_return:
	return rpc_cJSON_CreateNull();
	


}


void rpcBufferPrint(void)
{
	uint8_t cmdIndex = (appZclBuffer[0] & ZCL_MANUFACTURER_SPECIFIC_MASK) ? 4 : 2;

	emberAfCorePrintln("Msg: clus 0x%2x, cmd 0x%x, len %d",
							globalApsFrame.clusterId,
							appZclBuffer[cmdIndex],
							appZclBufferLen);
	emberAfCorePrintBuffer(appZclBuffer, appZclBufferLen, true);
	emberAfCorePrintln("");
}

EmberStatus rpcSendCommand(uint16_t destination,uint8_t srcEndpoint,uint8_t dstEndpoint,bool multicast)
{

	EmberStatus status;
	uint8_t label;

	emAfApsFrameEndpointSetup(srcEndpoint, dstEndpoint);



	if (multicast == true) {
		label = 'M';
		status = emberAfSendMulticast(destination,
									&globalApsFrame,
									appZclBufferLen,
									appZclBuffer);
	} else if (destination >= EMBER_BROADCAST_ADDRESS) {
		label = 'B';
		status = emberAfSendBroadcast(destination,
									&globalApsFrame,
									appZclBufferLen,
									appZclBuffer);
	} else {
		label = 'U';
		status = emberAfSendUnicast(EMBER_OUTGOING_DIRECT,
									destination,
									&globalApsFrame,
									appZclBufferLen,
									appZclBuffer);
	}
	


	if (status != EMBER_SUCCESS) {
		emberAfCorePrintln("Error: CLI Send failed, status: 0x%X", status);
	}
	
	emberAfCorePrintln("T%4x:TX (%p) %ccast 0x%x%p",
						emberAfGetCurrentTime(),
						"CLI",
						label,
						status,
						((globalApsFrame.options & EMBER_APS_OPTION_ENCRYPTION)
						? " w/ link key" : ""));
	emberAfCorePrintln("TX buffer: [");
	emberAfCoreFlush();
	emberAfCorePrintBuffer(appZclBuffer, appZclBufferLen, true);
	emberAfCorePrintln("]");
	emberAfCoreFlush();

	mfgSpecificId = EMBER_AF_NULL_MANUFACTURER_CODE;
	disableDefaultResponse = 0;

	return status;
}



void rpc_PreCommandReceivedCallback(EmberAfClusterCommand* cmd)
{
	EmberAfClusterId clusterId = cmd->apsFrame->clusterId;
	uint8_t zclCmd = cmd->commandId;
	uint8_t *message = cmd->buffer;
	uint16_t msgLen = cmd->bufLen;
	uint16_t msgIndex = cmd->payloadStartIndex;
	uint8_t clientServerMask = (cmd->direction == ZCL_DIRECTION_CLIENT_TO_SERVER
								? CLUSTER_MASK_SERVER
								: CLUSTER_MASK_CLIENT);
	
	if(cmd->apsFrame->profileId!=0x0104) return;
	emberAfAppPrint("@@@@@@@@@@@@@@@@@@@@@zclCmd=0X%X\n",zclCmd);

	if(cmd->clusterSpecific==false){//global
		switch(zclCmd){
			case ZCL_READ_ATTRIBUTES_RESPONSE_COMMAND_ID:{
				uint16_t attribute = HIGH_LOW_TO_INT(message[msgIndex + 1], message[msgIndex]);
				uint8_t attr_status = message[msgIndex + 2];
				uint8_t type = message[msgIndex + 3];
				uint8_t len = msgLen - (msgIndex + 3);
				//ep ,mac
				kk_print_debug("[read response]clu=0x%04X,attr=0x%04X,status=0x%02X,type=0x%02X\r\n",
								clusterId,attribute,attr_status,type);
				emberAfCorePrintBuffer(&message[4],len,true);
				}
			break;
			default:break;
		}
	}else{//cluster

	}
}



char* rpc_createTwoByteHexString(uint16_t value)
{
	char* outputString = (char *) malloc(7);

	sprintf(outputString, "0x%04X", value);
	return outputString;
}



void rpc_printfJSON(char* str,cJSON* item)
{
	char* json = rpc_cJSON_Print(item);
	emberAfAppPrintln("%s:\n%s\n",str,json);
	free(json);
}




void rpc_eui64ToString(EmberEUI64 eui, char* euiString)
{
	sprintf(euiString, "%02X%02X%02X%02X%02X%02X%02X%02X",
			eui[7],
			eui[6],
			eui[5],
			eui[4],
			eui[3],
			eui[2],
			eui[1],
			eui[0]);
}

void rpc_nodeIdToString(EmberNodeId nodeId, char* nodeIdString)
{
	sprintf(nodeIdString, "0x%04X", nodeId);
}
void rpc_clusterIdToString(EmberAfClusterId clusterId, char* clusterIdString)
{
	sprintf(clusterIdString, "0x%04X", clusterId);
}
void rpc_attributeIdToString(EmberAfAttributeId attributeId, char* attributeIdString)
{
	sprintf(attributeIdString, "0x%04X", attributeId);
}
void rpc_cJSON_AddMACToObject(cJSON *item,EmberEUI64 nodeEui64)
{
	char macString[RPC_EUI64_STRING_LENGTH];
	rpc_eui64ToString(nodeEui64,macString);
	rpc_cJSON_AddStringToObject(item, "mac", macString);
}
void rpc_cJSON_AddNodeToObject(cJSON *item,EmberNodeId nodeId)
{
	char nodeString[RPC_NODEID_STRING_LENGTH];
	rpc_nodeIdToString(nodeId,nodeString);
	rpc_cJSON_AddStringToObject(item, "node", nodeString);
}
void rpc_cJSON_AddEndpointToObject(cJSON *item,uint8_t endpoint)
{
	char endpointString[RPC_ENDPOINT_STRING_LENGTH];
	sprintf(endpointString, "%d",endpoint);
	rpc_cJSON_AddStringToObject(item, "endpoint",endpointString);
}
void rpc_cJSON_AddClusterToObject(cJSON *item,EmberAfClusterId clusterId)
{
	char clusterString[RPC_CLUSTERID_STRING_LENGTH];
	rpc_clusterIdToString(clusterId,clusterString);
	rpc_cJSON_AddStringToObject(item, "clusterId", clusterString);
}
void rpc_cJSON_AddAttributeToObject(cJSON *item,EmberAfAttributeId attributeId)
{
	char attributeString[RPC_ATTRIBUTE_STRING_LENGTH];
	rpc_attributeIdToString(attributeId,attributeString);
	rpc_cJSON_AddStringToObject(item, "attributeId", attributeString);
}

void rpc_cJSON_AddDataTypeToObject(cJSON *item, uint8_t type)
{
	char dataTypeString[RPC_DATATYPE_STRING_LENGTH];
	sprintf(dataTypeString, "0x%02X",type);
	rpc_cJSON_AddStringToObject(item, "DataType", dataTypeString);
}
void rpc_cJSON_AddLengthToObject(cJSON *item, uint8_t length)
{
	char lengthString[RPC_LENGTH_STRING_LENGTH];
	sprintf(lengthString, "0x%02X",length);
	rpc_cJSON_AddStringToObject(item, "length", lengthString);
}
void rpc_cJSON_AddDataToObject(cJSON *item,uint8_t *data,uint8_t length)
{
	int i=0;
	char *dataString = (char *)malloc(length*2+1);
	
	for(;i<length;i++){
		sprintf(&dataString[2*i],"%02X",data[i]);
	}
	dataString[2*i]='\0';
	rpc_cJSON_AddStringToObject(item, "data", dataString);
	free(dataString);
}
void rpc_cJSON_AddStatusToObject(cJSON *item, uint8_t status)
{
	char statusString[RPC_STATUS_STRING_LENGTH];
	sprintf(statusString, "0x%02X",status);
	rpc_cJSON_AddStringToObject(item, "Status", statusString);
}

void rpc_cJSON_AddAppVersionToObject(cJSON *item,uint8_t ver)
{
	char VerString[RPC_APPVERSION_STRING_LENGTH];
	sprintf(VerString, "%02X",ver);
	rpc_cJSON_AddStringToObject(item, "AppVersion", VerString);
}







