
//#include <sys/types.h>
#include <sys/socket.h>
//#include <netinet/in.h>
//#include <netdb.h>
#include <arpa/inet.h>
//#include <sys/wait.h>
//#include <signal.h>
//#include <time.h>
#include <fcntl.h>



#include "kk_ncp_common.h"



#include "kk_wlist_mng.h"
#include "com_api.h"

#include "kk_ncp_queue.h"
#include "kk_ncp_msg.h"
#include "kk_device_manager.h"
#include "kk_device_table_db.h"



#include "kk_tsl_property_report.h"








/**************************************************************/




//*************************************************************

static char g_mac[19] = {0};
char* kk_get_gw_mac(void)
{
	int cnt = 0;
	EmberEUI64 eui64;
	emberAfGetEui64(eui64);
	while(eui64[0] ==0 && eui64[1] ==0  && eui64[2] == 0 && cnt++ < 3){
		sleep(1);
	}
	if (eui64[0] ==0 && eui64[1] ==0 && eui64[2] == 0){
		printf("get gw mac error !!! \n");
		return NULL;
	}
	rpc_eui64ToString(eui64,g_mac);
	return g_mac;
}


int kk_connect_check(){
    if(strcmp(GW2CCU_PROTOCOL, "tcp") == 0){
        return kk_get_retry_num() > 20;
    }else{
        if (kk_ipc_get_senderrcnt(IPC_PLAT2MID) > 0){
            return kk_ipc_isconnect(IPC_PLAT2MID)==0?1:0;
        }
        return 0;
    }
}

int search_ccu(char devcode[33], char ip[16], int* port){
    
    char sendCmdFmt[] = "search_kk_ccu|deviceCode=%s;protocol=%s";
    char sendMessage[128] = {0};
    char revMessage[128] = {0};
    int sock;
    int sk_recv;
    int iSendbytes;
    int iOptval = 1;
    int flag;
    int iAddrLength;
    int recvLen = 0;
    struct sockaddr_in Addrto;
    struct sockaddr_in AddrRev;
	
    char* macString = kk_get_gw_mac();
	if (macString == NULL){
        printf("[%s] get mac fail\n",__FUNCTION__);
        return -1;
	}

    sprintf(sendMessage,sendCmdFmt,macString/*GW_DEVICE_CODE*/,GW2CCU_PROTOCOL);

    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        printf("[%s] socket fail\n",__FUNCTION__);
        return -1;
    }

    if ((sk_recv = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        printf("[%s] socket sk_recv fail\n",__FUNCTION__);
        close(sock);
        return -1;
    }
    
    if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &iOptval, sizeof(int)) < 0)
    {
        printf("[%s] setsockopt failed\n",__FUNCTION__);
        close(sock);
        close(sk_recv);
        return -1;
    }

     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &iOptval, sizeof(int)) < 0)
    {
        printf("[%s] setsockopt failed\n",__FUNCTION__);
        close(sock);
        close(sk_recv);
        return -1;
    }
    

    if (setsockopt(sk_recv, SOL_SOCKET, SO_REUSEADDR, &iOptval, sizeof(int)) < 0)
    {
        printf("[%s] setsockopt failed\n",__FUNCTION__);
        close(sock);
        close(sk_recv);
        return -1;
    }
    
    flag = fcntl(sk_recv, F_GETFL, 0);
    if (flag < 0)
    {
        printf("[%s] fcntl failed.\n",__FUNCTION__);
        close(sock);
        close(sk_recv);
        return -1;;
    }
    flag |= O_NONBLOCK;
    if (fcntl(sk_recv, F_SETFL, flag) < 0)
    {
        printf("[%s] fcntl failed.\n",__FUNCTION__);
        close(sock);
        close(sk_recv);
        return -1;
    }
    memset(&Addrto, 0, sizeof(struct sockaddr_in));
    Addrto.sin_family = AF_INET;
    Addrto.sin_addr.s_addr = inet_addr("255.255.255.255");
    Addrto.sin_port = htons(25556);

    memset(&AddrRev, 0, sizeof(struct sockaddr_in));
    AddrRev.sin_family = AF_INET;
    AddrRev.sin_addr.s_addr = INADDR_ANY;
    AddrRev.sin_port = htons(25555);
    iAddrLength = sizeof(struct sockaddr);

    
    if (bind(sk_recv, (struct sockaddr *)&AddrRev, sizeof(AddrRev)) == -1)
    {
        printf("[%s] bind failed!\n",__FUNCTION__);
        close(sock);
        close(sk_recv);
        return -1;
    }

    while (1)
    {
        if ((iSendbytes = sendto(sock, sendMessage, strlen(sendMessage)+1, 0, (struct sockaddr*)&Addrto, sizeof(struct sockaddr))) == -1)
        {
            printf("[%s] sendto fail, errno=%d\n", __FUNCTION__,errno);
            close(sock);
            close(sk_recv);
            return -1;
        }
        
        sleep(1);
        recvLen = recvfrom(sk_recv, revMessage, sizeof(revMessage), 0, (struct sockaddr *)&AddrRev, &iAddrLength);
        if (recvLen > 0){
            printf("[%s] recv:%s\n", __FUNCTION__, revMessage);
            //"search_kk_ccu_ack|deviceCode=CCU_66666;ip=192.168.36.128;port=16565"
            if (strstr(revMessage, "search_kk_ccu_ack|") != NULL){
                char* ackConnet = revMessage + strlen("search_kk_ccu_ack|");
                char* tmp = NULL;
                char* endIdx = NULL;
                int itemLen = 0;
                int itemConnetLen = 0;

                
                tmp = strstr(ackConnet, "deviceCode=");
                itemLen = strlen("deviceCode=");
                if (tmp != NULL){
                    endIdx = strstr(tmp, ";");
                    if(endIdx == NULL){
                        itemConnetLen = strlen(tmp) - itemLen;
                    }else{
                        itemConnetLen = endIdx - tmp - itemLen;
                    }
                    memcpy(devcode, tmp + itemLen,itemConnetLen);
                } 

                tmp = strstr(ackConnet, "ip=");
                itemLen = strlen("ip=");
                if (tmp != NULL){
                    endIdx = strstr(tmp, ";");
                    if(endIdx == NULL){
                        itemConnetLen = strlen(tmp) - itemLen;
                    }else{
                        itemConnetLen = endIdx - tmp - itemLen;
                    }
                    memcpy(ip, tmp + itemLen,itemConnetLen);
                } 

                tmp = strstr(ackConnet, "port=");
                itemLen = strlen("port=");
                if (tmp != NULL){
                    endIdx = strstr(tmp, ";");
                    if(endIdx == NULL){
                        itemConnetLen = strlen(tmp) - itemLen;
                    }else{
                        itemConnetLen = endIdx - tmp - itemLen;
                    }
                    char portstr[20] = {0};
                    memcpy(portstr, tmp + itemLen,itemConnetLen);
                    *port = atoi(portstr);
                } 

                
                //memcpy(ip, inet_ntoa(AddrRev.sin_addr), strlen(inet_ntoa(AddrRev.sin_addr)));
                printf(" recv deviceCode:%s ip:%s port:%d \n", devcode, ip, *port);
                break;
            }
        }
        
    }
    close(sock);
    close(sk_recv);
    return 0;
    
}

void _cb(void* data, int len, char* chlmark){
	if (data != NULL){
		printf("plat_cb: %s [%d]RECEIVED \r\n", data,len); 
		cJSON *root;
		char *end_ptr = NULL;

		if ((root = rpc_cJSON_Parse_Stream(data, &end_ptr)) != NULL) {

			if (root->type == cJSON_Object) {
                cJSON* info = rpc_cJSON_GetObjectItem(root, "info"); 
                
			    if (info!=NULL&&strstr(rpc_cJSON_GetObjectItem(info, "msgType")->valuestring,KK_THING_OTA_DEVICE_UPGRADE) != NULL){
			         
                    kk_ota_process(root);
			    }else{
			    	ncp_queue_enqueue(REV_MSG,(void *)root);
				    //eval_request(&my_server, root);
				}
			}
			//shift processed request, discarding it

			//rpc_cJSON_Delete(root);
		} else {
            if (1) {
				printf("INVALID JSON Received:\n---\n%s\n---\n",
						data);
			}
			/*
            send_error_resp(JRPC_PARSE_ERROR,
					strdup(
							"Parse error. Invalid JSON was received by the server."),
					NULL);*/

		}
	}
}








static void kk_rpc_send_message(cJSON *data,char *msgtype,char *method,EmberEUI64 mac)
{
	static uint16_t msgid;
	char msgIdString[10]= {0};
	char macString[19] = {0};
	int res = 0;
	kk_device_table_s *dev =NULL;

	rpc_eui64ToString(mac,macString);	
	dev = kk_device_find_by_mac(mac);
	if (dev == NULL) {
		printf("[%s][%d]kk_rpc_send_message error!!!\n",__FUNCTION__,__LINE__);
		return; 
	}	

	cJSON *info = rpc_cJSON_CreateObject();
	if(info != NULL){
		rpc_cJSON_AddStringToObject(info, "msgType",msgtype);
		rpc_cJSON_AddStringToObject(info, "productCode",dev->productCode);
		rpc_cJSON_AddStringToObject(info, "deviceCode",macString);	
	}
	cJSON *payload = rpc_cJSON_CreateObject();
	if(payload != NULL){
		sprintf(msgIdString,"%d",++msgid);
		rpc_cJSON_AddStringToObject(payload, "msgId",msgIdString);
		rpc_cJSON_AddStringToObject(payload, "version", KK_IPC_VERSION);
		rpc_cJSON_AddStringToObject(payload, "method",method);
		rpc_cJSON_AddItemToObject(payload, "params", data);		
	}
	cJSON *root = rpc_cJSON_CreateObject();
	if(root != NULL){
		rpc_cJSON_AddItemToObject(root, "info", info);	
		rpc_cJSON_AddItemToObject(root, "payload", payload);	
	}

	char* p = rpc_cJSON_Print(root);
	emberAfAppPrintln("send json:\n%s\n",p);
	free(p);
	kk_tsl_send_msg(root);	
	rpc_cJSON_Delete(root);	
}
void kk_rpc_report_devices(cJSON *data,EmberEUI64 mac)
{
	kk_rpc_send_message(data,KK_REPORT_DEVICE_JOINED_TYPE,KK_REPORT_DEVICE_JOINED_METHOD,mac);
}
void kk_rpc_report_left_devices(cJSON *data,EmberEUI64 mac)
{
	kk_rpc_send_message(data,KK_REPORT_DEVICE_LEFT_TYPE,KK_REPORT_DEVICE_LEAVE_METHOD,mac);
}

void kk_rpc_report_status(cJSON *data,EmberEUI64 mac)
{

	kk_rpc_send_message(data,KK_REPORT_ATTRIBUTE_TYPE,KK_REPORT_ATTRIBUTE_METHOD,mac);
}




cJSON* rpc_reportDeviceState(char *state,EmberEUI64 eui64)
{
	char euiString[RPC_EUI64_STRING_LENGTH] = { 0 };
	cJSON* stateJSON;

	rpc_eui64ToString(eui64, euiString);

	stateJSON = rpc_cJSON_CreateObject();
	rpc_cJSON_AddStringToObject(stateJSON, "mac", euiString);
	rpc_cJSON_AddStringToObject(stateJSON, "status", state);
	return stateJSON;
}

static void kk_reportDeviceStateChange(EmberEUI64 eui64,uint8_t state)
{
	char euiString[RPC_EUI64_STRING_LENGTH] = { 0 };
	cJSON* stateChangeJson;

	rpc_eui64ToString(eui64, euiString);

	stateChangeJson = rpc_cJSON_CreateObject();
	rpc_cJSON_AddStringToObject(stateChangeJson, "mac", euiString);
	rpc_cJSON_AddNumberToObject(stateChangeJson, "deviceState", state);
	rpc_printfJSON("devicestatechange",stateChangeJson);
}

void emberAfPluginDeviceTableStateChangeCallback(EmberNodeId nodeId,
																	uint8_t state)
{
	EmberEUI64 nodeEui64;
	emberAfDeviceTableGetEui64FromNodeId(nodeId, nodeEui64);
	kk_reportDeviceStateChange(nodeEui64, state);
}



void kk_IasZoneClusterZoneStatusChangeNotificationCallback(uint16_t zoneStatus,
																				uint8_t extendedStatus,
																				uint8_t zoneId,
																				uint16_t delay)
{
	EmberEUI64 nodeEui64;
	EmberNodeId nodeId = emberAfCurrentCommand()->source;
	UTIL_LOG_INFO("\n======================NotificationCallback======================\n");
	emberAfDeviceTableGetEui64FromNodeId(nodeId, nodeEui64);
	kk_tsl_report_alarm(nodeEui64,zoneStatus,extendedStatus,zoneId,delay);
}
#define ATTRIBUTE_BUFFER_ATTRIBUTEID_ID				1
#define ATTRIBUTE_BUFFER_REPORT_DATA_TYPE			2
#define ATTRIBUTE_BUFFER_REPORT_DATA_VALUE			3
																				
																				// Attribute reading buffer location definitions
#define ATTRIBUTE_BUFFER_ATTRIBUTEID_LOW_BITS  0
#define ATTRIBUTE_BUFFER_ATTRIBUTEID_HIGH_BITS 1
#define ATTRIBUTE_BUFFER_SUCCESS_CODE        2
#define ATTRIBUTE_BUFFER_DATA_TYPE           3
#define ATTRIBUTE_BUFFER_DATA_START          4

bool kk_ReportAttributesCallback(EmberAfClusterId clusterId,
												uint8_t * buffer,
												uint16_t bufLen)
{
	EmberEUI64 nodeEui64;
	EmberAfAttributeId attributeId;
	EmberNodeId nodeId = emberAfCurrentCommand()->source;
	uint8_t ep = emberAfCurrentCommand()->apsFrame->sourceEndpoint;
	emberAfDeviceTableGetEui64FromNodeId(nodeId, nodeEui64);
	uint8_t * bufferTemp;
	uint8_t * bufferPtr = buffer;
	uint8_t i, bufferSize,typeSize;
	
	uint8_t dataLen,dataType;
	uint8_t *dataPtr;

	printf("\n********************report callback**********************\n");
	emberAfAppPrint("[ ");
	emberAfAppPrintBuffer(buffer,bufLen,true);
	emberAfAppPrint("]\n");

	if (bufLen == 0) {
		emberAfAppPrintln("Report attributes callback: zero length buffer");
		return false;
	}

	printf("\nmac:");
	emberAfPrintBigEndianEui64(nodeEui64);
	emberAfAppPrintln(",EP=%d,cluster=0x%04X\n",ep,clusterId);


	for (i = 0; i < bufLen - 3; ) {
		dataType = bufferPtr[ATTRIBUTE_BUFFER_REPORT_DATA_TYPE];
		if(emberAfIsStringAttributeType(dataType)){
			dataLen = bufferPtr[ATTRIBUTE_BUFFER_REPORT_DATA_VALUE ];
			typeSize = 1;
		}else if(emberAfIsLongStringAttributeType(dataType)){
			dataLen = HIGH_LOW_TO_INT(bufferPtr[ATTRIBUTE_BUFFER_REPORT_DATA_TYPE + 2],
										bufferPtr[ATTRIBUTE_BUFFER_REPORT_DATA_TYPE + 1]);
			typeSize = 2;
		}else {
			typeSize = 0;
			dataLen = emberAfGetDataSize(
							bufferPtr[ATTRIBUTE_BUFFER_REPORT_DATA_TYPE]);
		}
		dataPtr = &bufferPtr[ATTRIBUTE_BUFFER_REPORT_DATA_VALUE];
		
		bufferSize = ATTRIBUTE_BUFFER_REPORT_DATA_VALUE + dataLen + typeSize;
		bufferTemp = (uint8_t*)malloc(bufferSize);
		memcpy(bufferTemp, bufferPtr, bufferSize);

		bufferPtr +=bufferSize;
		i +=bufferSize;
		
		emberAfAppPrintln("i=%d,bufferSize=%d\n",i,bufferSize);

		emberAfAppPrintln("Reported attribute: 0x%02X%02X, Type: %02X",
							bufferTemp[ATTRIBUTE_BUFFER_ATTRIBUTEID_HIGH_BITS],
							bufferTemp[ATTRIBUTE_BUFFER_ATTRIBUTEID_LOW_BITS],
							bufferTemp[ATTRIBUTE_BUFFER_REPORT_DATA_TYPE]);

	
		attributeId = HIGH_LOW_TO_INT(bufferTemp[ATTRIBUTE_BUFFER_ATTRIBUTEID_HIGH_BITS],bufferTemp[ATTRIBUTE_BUFFER_ATTRIBUTEID_LOW_BITS]);
		emberAfAppPrintln("attributeId=0x%x",attributeId);

		if(emberAfDeviceTableGetEui64FromNodeId(nodeId,nodeEui64)){
			emberAfAppPrintln("nodeId=0x%x",nodeId);
			kk_tsl_report_attribute(nodeEui64,ep,clusterId,attributeId,dataType,dataLen,dataPtr);
		}

	
		free(bufferTemp);
	}

	return false;
}

bool kk_ReadAttributesResponseCallback(EmberAfClusterId clusterId,
														uint8_t *buffer,
														uint16_t bufLen)
{
	EmberEUI64 nodeEui64;
	EmberNodeId nodeId = emberAfCurrentCommand()->source;
	uint8_t ep = emberAfCurrentCommand()->apsFrame->sourceEndpoint;
	emberAfDeviceTableGetEui64FromNodeId(nodeId, nodeEui64);
	uint8_t * bufferTemp;
	uint8_t * bufferPtr = buffer;
	uint8_t i, bufferSize,typeSize;
	uint8_t dataType;
	EmberAfAttributeId attributeId;
	uint8_t cnt=1;
	uint8_t Status;
	printf("\n********************read attributes response callback**********************\n");
	emberAfAppPrint("[ ");
	emberAfAppPrintBuffer(buffer,bufLen,true);
	emberAfAppPrint("]\n");

	if (bufLen == 0) {
		emberAfAppPrintln("read attributes response callback: zero length buffer");
		return false;
	}

	printf("\nmac:");
	emberAfPrintBigEndianEui64(nodeEui64);
	emberAfAppPrintln(",EP=%d,cluster=0x%04X\n",ep,clusterId);

	cJSON *item  = rpc_cJSON_CreateObject();
	cJSON *array_attr = rpc_cJSON_CreateObject();

	rpc_cJSON_AddMACToObject(item,nodeEui64);
	rpc_cJSON_AddNodeToObject(item,nodeId);
	rpc_cJSON_AddEndpointToObject(item,ep);
	rpc_cJSON_AddClusterToObject(item,clusterId);

	array_attr = rpc_cJSON_CreateArray();
	rpc_cJSON_AddItemToObject(item,"attributes",array_attr);

	cJSON *item_attr = rpc_cJSON_CreateObject();
	rpc_cJSON_AddItemToArray(array_attr,item_attr);

	//todo:check
	for (i = 0; i < bufLen; ) {
		Status = bufferPtr[2];

		
		if(Status == EMBER_ZCL_STATUS_SUCCESS){
			dataType = bufferPtr[3];
			if(emberAfIsStringAttributeType(dataType)){
				bufferSize = bufferPtr[4];
				typeSize = 1;
			}else if(emberAfIsLongStringAttributeType(dataType)){
				bufferSize = HIGH_LOW_TO_INT(bufferPtr[5], bufferPtr[4]);
				typeSize = 2;
			}else {
				typeSize = 0;
				bufferSize = emberAfGetDataSize(dataType);
			}
			bufferSize = bufferSize + 4 + typeSize;
			bufferTemp = (uint8_t*)malloc(bufferSize);
			memcpy(bufferTemp, bufferPtr, bufferSize);

			bufferPtr = bufferPtr + bufferSize;
			
			emberAfAppPrintln("i=%d,bufferSize=%d\n",i,bufferSize);

			emberAfAppPrintln("Read attribute Response: 0x%02X%02X, Type: %02X",
							  bufferTemp[ATTRIBUTE_BUFFER_ATTRIBUTEID_HIGH_BITS],
							  bufferTemp[ATTRIBUTE_BUFFER_ATTRIBUTEID_LOW_BITS],
							  bufferTemp[ATTRIBUTE_BUFFER_REPORT_DATA_TYPE]);

			attributeId = HIGH_LOW_TO_INT(bufferTemp[ATTRIBUTE_BUFFER_ATTRIBUTEID_HIGH_BITS],bufferTemp[ATTRIBUTE_BUFFER_ATTRIBUTEID_LOW_BITS]);


			rpc_cJSON_AddStatusToObject(item_attr,Status);
			
			rpc_cJSON_AddAttributeToObject(item_attr,attributeId);
			
			rpc_cJSON_AddDataTypeToObject(item_attr,bufferTemp[3]);
			
			int dataLen = bufferSize-4-typeSize;
			rpc_cJSON_AddLengthToObject(item_attr,dataLen);
			uint8_t *dataPtr = &bufferTemp[ATTRIBUTE_BUFFER_REPORT_DATA_TYPE+1+1+typeSize];
			rpc_cJSON_AddDataToObject(item_attr,dataPtr,dataLen);

			UTIL_LOG_INFO("\nkk_device_config_item_report~~~~~~~~~~~~~~~~~~~~\n");
			kk_device_config_item_report(nodeEui64,ep,clusterId,attributeId,dataType,dataLen,dataPtr);

			kk_read_attr_response(nodeId,
									ep,
									clusterId,
									attributeId,
									EMBER_ZCL_STATUS_SUCCESS,
									bufferPtr[3],
									dataLen,
									dataPtr);
			free(bufferTemp);
		}else{
			rpc_cJSON_AddStatusToObject(item_attr,Status);
			bufferSize += 3;
			emberAfAppPrintln("Status=0x%X\n",Status);
			attributeId = HIGH_LOW_TO_INT(bufferPtr[ATTRIBUTE_BUFFER_ATTRIBUTEID_HIGH_BITS],bufferPtr[ATTRIBUTE_BUFFER_ATTRIBUTEID_LOW_BITS]);
			kk_read_attr_response(nodeId,
									ep,
									clusterId,
									attributeId,
									Status,
									0,
									0,
									NULL);
		}
		i = i + bufferSize;
	}


	return false;
}








void emberAfMainTickCallback(void)
{

	static unsigned int last_time;
	unsigned int time = halCommonGetInt32uMillisecondTick();
	kk_sub_dev_manage();
	

	if((time-last_time)>=3000){
		last_time = time;
		kk_productCode_tick();
		//printf("kk_productCode_tick!\n");
	}
}

