
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "kk_findccu_handle.h"
#include "kk_hal.h"
#include "cJSON.h"


static int kk_findccu_ack(int sockfd,struct sockaddr_in *addr){
	cJSON *json = NULL,*args = NULL;
	cJSON *ccu = NULL;
	char *out = NULL;
	char *tmpBuf = NULL;
	char s_IP[NETWORK_ADDR_LEN] = {0};
	if(addr == NULL || sockfd < 0){
		return -1;
	}
	char ccuid[32] = {0};
	kk_lan_get_ccuid(ccuid);
	json=cJSON_CreateObject();
	if(json){
		args = cJSON_CreateObject();
		if(args){
			cJSON_AddItemToObject(json, "arg", args);

			cJSON_AddStringToObject(args, "zkid", &ccuid[4]);

			cJSON_AddStringToObject(args, "zk", KK_CCU_NAME);
			HAL_Get_IP(s_IP,NULL);			
			cJSON_AddStringToObject(args, "ip", s_IP); 
			cJSON_AddBoolToObject(args, "ssl", FALSE);
		}
		cJSON_AddStringToObject(json, "nodeid", "*");
		cJSON_AddStringToObject(json, "opcode", FINDCCU_OPCODE);
		cJSON_AddStringToObject(json, "status", "success");
		out=cJSON_Print(json);
		cJSON_Minify((char*)out);
		tmpBuf = calloc(strlen(out) + 4,1);
		if(tmpBuf == NULL){
			cJSON_Delete(json);
			free(out);
			return -1;
		}
		strcat(tmpBuf,"!");
		strcat(tmpBuf,out);
		strcat(tmpBuf,"$");
		INFO_PRINT("tmpBuf:%s\n",tmpBuf);
		sendto(sockfd, tmpBuf, strlen(tmpBuf), 0, (struct sockaddr*)addr, sizeof(struct sockaddr_in));
		cJSON_Delete(json);
		free(out);
		free(tmpBuf);
	}
	return 0;
}
void *kk_findccu_handle(void *data)
{
	int sockfd;
	struct sockaddr_in saddr;
	int r;
	int ret = 0;
	char recvline[1025] = {0};
	char recvline_tmp[1025] = {0};
	struct sockaddr_in presaddr;
	socklen_t len;
	cJSON *json;
	cJSON *opcode;
	struct timeval time_out;	
	char *pStart = NULL,*pEnd = NULL;
	fd_set server_fd_set;
	int yes = 1;
	while(1){
		sockfd = socket(AF_INET, SOCK_DGRAM, 0);
		bzero(&saddr, sizeof(saddr));
		setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes ,sizeof(int));// 允许IP地址复用
		saddr.sin_family = AF_INET;
		saddr.sin_addr.s_addr = htonl(INADDR_ANY);
		saddr.sin_port = htons(FINDCCU_LOCAL_PORT);
		if(bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) 
		{
			ERROR_PRINT("bind error...\n"); 
		}
		while (1)
		{
			FD_ZERO(&server_fd_set);
			FD_SET(sockfd,&server_fd_set);
			time_out.tv_sec = 1;//select会更改timeout的值，所以需要重新初始化超时时间
			time_out.tv_usec = 0;		
			ret = select(sockfd + 1, &server_fd_set,NULL, NULL, &time_out );
			if(ret <  0){
				DEBUG_PRINT("UDP receiving error......\n");
				close(sockfd);
				sockfd = -1;
				break;
			}else if(ret == 0){

			}else{
				if (FD_ISSET(sockfd, &server_fd_set))
				{
					r = recvfrom(sockfd, recvline, sizeof(recvline), 0 , (struct sockaddr*)&presaddr, &len);
					if (r <= 0){
						WARNING_PRINT("read error....\n"); 
						close(sockfd);
						sockfd = -1;
						break;		
					}else{
						DEBUG_PRINT("findccu recmsg: %s\n", recvline); 
						WARNING_PRINT("findccu from ip: %s\n", inet_ntoa(presaddr.sin_addr));
						pStart = strstr(recvline, "!");
						pEnd = strstr(recvline, "$");
						if(pStart != NULL && pEnd != NULL){
							memset(recvline_tmp,0x0,sizeof(recvline_tmp));
							memcpy(recvline_tmp,pStart+1,(pEnd - pStart - 1));
							json=cJSON_Parse(recvline_tmp);
							if (!json) {
								WARNING_PRINT("Error before: [%s]\n","cJSON_Parse");
							}else{
								opcode = cJSON_GetObjectItem(json, OPCODE_STRING);
								if(opcode != NULL){
									if(strcmp(opcode->valuestring,FINDCCU_OPCODE) == 0){
										kk_findccu_ack(sockfd,&presaddr);
									}
								}
								cJSON_Delete(json);
							}
						}else{
							WARNING_PRINT("data error....\n"); 
						}
					}
				}
			}

		}
	}
	return NULL;
}

int kk_findccu_handle_init(void)
{
	int rc = 0;
	size_t s = 1500;
	pthread_t findccu_thread_handle;
	pthread_attr_t findccu_thread_attr;
	//pthread_mutex_init(&s_data_mutex, NULL);
	/*创建线程*/
	pthread_attr_init(&findccu_thread_attr);
	pthread_attr_setstacksize(&findccu_thread_attr, s);
	pthread_attr_setdetachstate(&findccu_thread_attr, PTHREAD_CREATE_DETACHED);
	rc = pthread_create(&findccu_thread_handle, &findccu_thread_attr, kk_findccu_handle, (void *)NULL);   //收数据
	if (rc)
	{
		WARNING_PRINT("Error : unable to create thread udp_recv \r\n");
		return -1;
	}
	pthread_attr_destroy(&findccu_thread_attr);
	return 0;
}