#include<stdio.h>
#include"com_api.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include "cJSON.h"
#include "kk_product.h"
#include "kk_tsl_common.h"
#include "kk_tsl_api.h"
#include "kk_dm_api.h"
#include "kk_dm_msg.h"
#include "kk_dm_mng.h"
#include "kk_log.h"
#include "kk_dm_queue.h"
#include "kk_property_db.h"


char * g_filerToPlatTable[] = 
{
	{KK_REGISTER_TOPIC_REPLY},
	{KK_ADD_TOPIC_REPLY},
	{KK_LOGIN_TOPIC_REPLY},	
	{KK_THING_SERVICE_PROPERTY_GET},	
	{KK_THING_CLOUDSTATE_MSG}, 
	{KK_THING_SERVICE_SETLOCALTIMER}, 
	{KK_THING_SERVICE_GETLOCALTIMER},
	{KK_THING_SERVICE_SETCOUNTDOWN}, 
	{KK_THING_SERVICE_GETCOUNTDOWN},	
};
static int _kk_filter_to_plat(const char* msgtype)
{
	int i = 0,num = 0;
	num = sizeof(g_filerToPlatTable)/sizeof(char *);

	for(i =0; i < num; i++){
		if(strstr(msgtype,g_filerToPlatTable[i]))
		{
			return 1;
		}
	}
	return 0;
}

void kk_sendData2gw(void* data, int len, char* chalMark){
    if (chalMark== NULL || strlen(chalMark) == 0){
        ERROR_PRINT(" chalMark is null");
        return;
    }

    if (kk_is_tcp_channel(chalMark) > -1){
        kk_tcp_channel_ser_send(data, len, chalMark);
    }else{
        kk_ipc_send_ex(IPC_MID2PLAT, data, len + 1, chalMark);
    }
           
}
static int kk_property_set_data_check(cJSON * payload,const char *deviceCode){
	cJSON *params = NULL;
	dm_mgr_dev_node_t *node = NULL;	
	kk_tsl_data_t *property = NULL;	
	cJSON *propertyItem = NULL;	
	int res = 0;
	int idx = 0;
	int value = 0;
	res = dm_mgr_get_device_by_devicecode(deviceCode,&node);
    if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
        return FAIL_RETURN;
    }	

	params = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
	if(params != NULL){
		for(idx = 0; idx < node->dev_shadow->property_number; idx++){
			property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
			if(property == NULL){
				continue;
			}
				
			propertyItem = cJSON_GetObjectItem(params, property->identifier);
			if(propertyItem != NULL){
				if(property->data_value.type == KK_TSL_DATA_TYPE_STRUCT){
					kk_tsl_data_value_complex_t *complex_struct = NULL;
					kk_tsl_data_t *current_data = NULL;
					int index;
					complex_struct = property->data_value.value;
					for (index = 0; index < complex_struct->size; index++) {
						current_data = (kk_tsl_data_t *)complex_struct->value + index;
						cJSON *propertyItem_1 = NULL;	
						propertyItem_1 = cJSON_GetObjectItem(propertyItem, current_data->identifier);
						if(propertyItem_1 == NULL){
							continue;
						}
						
						if(current_data->data_value.type != KK_TSL_DATA_TYPE_STRUCT){
							if(current_data->data_value.type == KK_TSL_DATA_TYPE_INT){
								value = propertyItem_1->valueint;
								if(value < current_data->data_value.mix ||value > current_data->data_value.max ){
									ERROR_PRINT("ERROR  ------------>value:%d,mix:%d,max:%d\n",value,current_data->data_value.mix,current_data->data_value.max);
									return INVALID_PARAMETER;
								}
							}
							else if(current_data->data_value.type == KK_TSL_DATA_TYPE_TEXT){
								if(strlen(propertyItem_1->valuestring) > current_data->data_value.length ){
									
									ERROR_PRINT("ERROR ------------>strlen(propertyItem_1->valuestring):%d,current_data->data_value.length:%d\n",strlen(propertyItem_1->valuestring),current_data->data_value.length);
									return INVALID_PARAMETER;
								}
							}

						}
						else{
							kk_tsl_data_value_complex_t *complex_struct_1 = NULL;
							kk_tsl_data_t *current_data_1 = NULL;
							int index_1;
							complex_struct_1 = current_data->data_value.value;
							for(index_1 = 0; index_1 < complex_struct_1->size; index_1++){
								current_data_1 = (kk_tsl_data_t *)complex_struct_1->value + index_1;
								cJSON *propertyItem_2 = NULL;	
								propertyItem_2 = cJSON_GetObjectItem(propertyItem_1, current_data_1->identifier);
								if(propertyItem_2 == NULL){
									continue;
								}
								if(current_data_1->data_value.type == KK_TSL_DATA_TYPE_INT){
									value = propertyItem_2->valueint;
									if(value < current_data_1->data_value.mix ||value > current_data_1->data_value.max ){
										ERROR_PRINT("ERROR------------>value:%d,mix:%d,max:%d\n",value,current_data_1->data_value.mix,current_data_1->data_value.max);
										return INVALID_PARAMETER;
									}
								}
								else if(current_data_1->data_value.type == KK_TSL_DATA_TYPE_TEXT){
									if(strlen(propertyItem_2->valuestring) > current_data_1->data_value.length ){
										
										ERROR_PRINT("ERROR ------------>strlen(propertyItem_2->valuestring):%d,propertyItem_2->data_value.length:%d\n",strlen(propertyItem_2->valuestring),current_data_1->data_value.length);
										return INVALID_PARAMETER;
									}
								}
							}

						}
					}

				}else if(property->data_value.type == KK_TSL_DATA_TYPE_INT){
					value = propertyItem->valueint;
					if(value < property->data_value.mix ||value > property->data_value.max ){
						ERROR_PRINT("ERROR  ------------>value:%d,mix:%d,max:%d\n",value,property->data_value.mix,property->data_value.max);
						return INVALID_PARAMETER;
					}
				}
				else if(property->data_value.type == KK_TSL_DATA_TYPE_TEXT){
					if(strlen(propertyItem->valuestring) > property->data_value.length ){
						
						ERROR_PRINT("ERROR  ------------>strlen(propertyItem->valuestring):%d,property->data_value.length:%d\n",strlen(propertyItem->valuestring),property->data_value.length );
						return INVALID_PARAMETER;
					}
				}
			}

		}
	}
	return SUCCESS_RETURN;

}
void mid_cb(void* data, int len){
	if (data != NULL){

        cJSON *json;
        cJSON *info_root,*type;
		cJSON*deviceCode;
        int res;

    	json=cJSON_Parse(data);
    	if (!json) {
            ERROR_PRINT("Error before: [%s]\n","cJSON_Parse");
        }
    	else
    	{
            info_root = cJSON_GetObjectItem(json, MSG_INFO_STR);
            if (info_root == NULL){
                ERROR_PRINT(" params [%s] can't find \n",MSG_INFO_STR);
                cJSON_Delete(json);
				return;
            }
			deviceCode = cJSON_GetObjectItem(info_root, MSG_DEVICE_CODE_STR);				
			type = cJSON_GetObjectItem(info_root, MSG_TYPE_STR);
            if (deviceCode == NULL || type == NULL){
                ERROR_PRINT(" params [%s] or [%s] can't find \n",MSG_DEVICE_CODE_STR, MSG_TYPE_STR);
                cJSON_Delete(json);
				return;
            }
			/*****属性设置需要先检测设置参数是否超出物模型给定范围*******/
			if (strcmp(type->valuestring, KK_THING_SERVICE_PROPERTY_SET)==0){
					cJSON* payload = cJSON_GetObjectItem(json, MSG_PAYLOAD_STR);
					if(payload != NULL){
						res = kk_property_set_data_check(payload,deviceCode->valuestring);
						if(res != SUCCESS_RETURN){
							return;
						}
					}
			}

			int devType = 0;
			dm_mgr_get_devicetype_by_devicecode(deviceCode->valuestring,&devType);
			//主机的device或过滤的
			if(devType == KK_DM_DEVICE_CCU ||_kk_filter_to_plat(type->valuestring)){
			    void* buf = malloc(len);
                memcpy(buf, data, len);
                res = dm_queue_msg_insert((void *)buf);
                if (res != SUCCESS_RETURN) {
                    free(buf);
                }
			}else if(devType == KK_DM_DEVICE_GATEWAY){
				kk_sendData2gw(data, strlen(data), deviceCode->valuestring);//send to gw itself
			}else if(devType == KK_DM_DEVICE_SUBDEV){
				dm_mgr_dev_node_t *gw_node = NULL;
				res = dm_mgr_get_device_by_devicecode(deviceCode->valuestring,&gw_node);
			    if (res != SUCCESS_RETURN) {
					ERROR_PRINT("res:%d\n",res);
					cJSON_Delete(json);
			        return;
			    }		
				kk_sendData2gw(data, strlen(data), gw_node->fatherDeviceCode);//send to sub device
			}
			else{
				ERROR_PRINT("wrong type\n");
			}
            cJSON_Delete(json);
            
	    }
	}
}

void mid2p_cb(void* data, int len, char* chalMark){
	if (data != NULL){
		//printf("mid2plat_cb: %s RECEIVED \r\n", data);
		int res = 0;
		void* buf = NULL;
		dm_queue_msg_t *queue_msg = NULL;
		queue_msg = malloc(sizeof(dm_queue_msg_t));
		if (queue_msg == NULL){
            ERROR_PRINT("mid2p_cb malloc queue_msg failed ");
            return;
		}
		buf = malloc(len);
		if (buf == NULL){
            ERROR_PRINT("mid2p_cb malloc buf failed ");
            return;
		}
		
        memcpy(buf, data, len);
        queue_msg->data = buf;
        memset(queue_msg->chalMark, 0, sizeof(queue_msg->chalMark));
        if(chalMark != NULL){
            memcpy(queue_msg->chalMark, chalMark, strlen(chalMark));
        }
        res = dm_queue_msg_insert2((void *)queue_msg);
        if (res != SUCCESS_RETURN) {
            free(queue_msg);
            free(buf);
            return ;
        }
		
        //kk_ipc_send(IPC_MID2APP, data, len);
	}
}

void gw2mid_cb(void* data, int len, char* chalMark){
    if (data != NULL){
		printf("gw2mid_cb chalMark=%s, data: %s [%d]RECEIVED \r\n", chalMark, data,len);
		mid2p_cb(data,len,chalMark);
    }
}

extern uint64_t s_start_time;
void kk_platMsg_handle(void* data, char* chalMark){
    
    char *out;
    int res = 0;
    cJSON *json;
	cJSON *info;
    cJSON *info_dcode;
    cJSON *params;
    cJSON *jsonPay;
    cJSON *msgType;
    cJSON *proCode;
	cJSON *devCode;
    cJSON *mac;
	cJSON *payload;
    
    json=cJSON_Parse(data);
	if (!json) {
        WARNING_PRINT("Error before: [%s]\n","cJSON_Parse");
    }
	else{
        info = cJSON_GetObjectItem(json, MSG_INFO_STR);
		payload = cJSON_GetObjectItem(json, MSG_PAYLOAD_STR);
		if (info == NULL || payload == NULL){
            ERROR_PRINT("info or payload params error\n");
            goto error;
		}

		msgType = cJSON_GetObjectItem(info, MSG_TYPE_STR);
		info_dcode = cJSON_GetObjectItem(info, MSG_DEVICE_CODE_STR);

        jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
        
		if (msgType == NULL || info_dcode == NULL || jsonPay == NULL){
            ERROR_PRINT("msgType info_dcode or jsonPay params are error\n");
            goto error;
		}

        if (chalMark != NULL){
		    dm_mgr_update_timestamp_by_devicecode(chalMark,HAL_UptimeMs()-s_start_time);
		}

        dm_mgr_update_timestamp_by_devicecode(info_dcode->valuestring,HAL_UptimeMs()-s_start_time);
		
        if (strcmp(msgType->valuestring, KK_THING_TOPO_ADD_MSG)==0){
            proCode = cJSON_GetObjectItem(jsonPay, MSG_PRODUCT_CODE_STR);
            devCode = cJSON_GetObjectItem(jsonPay, MSG_DEVICE_CODE_STR);
			mac = cJSON_GetObjectItem(jsonPay, "mac");
            if (proCode == NULL || devCode == NULL || mac == NULL){
                ERROR_PRINT("productCode, deviceCode mac params are error\n");
                goto error;
            }
			INFO_PRINT("deviceCode productCode mac: [%s][%s] [%s] \n",devCode->valuestring, proCode->valuestring, mac->valuestring);
			//判断网关还是子设备
			if (strcmp(info_dcode->valuestring, devCode->valuestring) == 0){
			    char ccu_deviceCode[DEVICE_CODE_MAXLEN] = {0};
                HAL_GetDevice_Code(ccu_deviceCode);
                kk_mid_subdev_add(KK_DM_DEVICE_GATEWAY,proCode->valuestring,devCode->valuestring, mac->valuestring,ccu_deviceCode);
			}else{
                kk_mid_subdev_add(KK_DM_DEVICE_SUBDEV,proCode->valuestring,devCode->valuestring, mac->valuestring,info_dcode->valuestring);
			}
			dm_mgr_update_timestamp_by_devicecode(devCode->valuestring,HAL_UptimeMs()-s_start_time);
                
        }else if (strstr(msgType->valuestring, KK_THING_TOPO_BATCH_ADD_MSG) != NULL){
        	kk_ipc_send(IPC_MID2APP,data,strlen(data));
			cJSON *devices = cJSON_GetObjectItem(jsonPay, MSG_TOPO_CHANGE_DEVICES_STR);
			cJSON * item = devices->child;
			while(item != NULL){
				char *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR)->valuestring;
				char *productCode = cJSON_GetObjectItem(item,MSG_PRODUCT_CODE_STR)->valuestring;
				char *mac_s = cJSON_GetObjectItem(item,MSG_DEVICE_MAC)->valuestring;	
				char *fatherMac = cJSON_GetObjectItem(item,MSG_DEVICE_PARENTCODE)->valuestring;	
				kk_mid_subdev_batch_add(productCode,deviceCode,mac_s,fatherMac);
				item = item->next;
			}
            
        }else if (strstr(msgType->valuestring, KK_THING_PROPERTY_POST) != NULL){
            INFO_PRINT("save property and send to cloud \n");
            char* outstr = cJSON_Print(payload);
			kk_tsl_t *dev_shadow = NULL;
			dm_mgr_get_device_shadow_by_devicecode(info_dcode->valuestring,&dev_shadow);
            kk_tsl_property_set_by_shadow(dev_shadow, outstr, strlen(outstr)+1);
			dm_msg_thing_property_post_by_identify(info_dcode->valuestring,jsonPay);
            free(outstr);
            
        }else if(strstr(msgType->valuestring, KK_THING_TOPO_DELETE_MSG) != NULL){
			INFO_PRINT("kk_platMsg_handle data: handle delete\n");
			devCode = cJSON_GetObjectItem(jsonPay, MSG_DEVICE_CODE_STR);
			kk_ipc_send(IPC_MID2APP,data,strlen(data)+1);
			dm_mgr_subdev_delete(devCode->valuestring);
			
		}else if(strstr(msgType->valuestring, KK_THING_EVENT_MESSAGE) != NULL && \
			strstr(msgType->valuestring, KK_THING_EVENT_POST) != NULL){
			kk_tsl_t *dev_shadow = NULL;
			int idx = 0;
			kk_tsl_event_t *eventItem =NULL;
			char tmpStr[128] = {0};
			res = dm_mgr_get_device_shadow_by_devicecode(info_dcode->valuestring,&dev_shadow);
			if (res < SUCCESS_RETURN) {
		        goto error;
		    }
			for(idx = 0; idx < dev_shadow->event_number; idx++){
				eventItem = dev_shadow->events + idx;
				if(eventItem != NULL){
					if(strcmp(eventItem->identifier,MSG_PROPERTY_STR) != 0 &&
						eventItem->output_data_number > 0){
						int index = 0;
						kk_tsl_data_t *itemData = NULL;
						cJSON * itemStr = NULL;
						for(index = 0; index < eventItem->output_data_number;index++){
							itemStr = cJSON_GetObjectItem(jsonPay, eventItem->identifier);
							itemData = eventItem->output_datas + index;
							if(itemStr != NULL){
								 
								memset(tmpStr,0x0,sizeof(tmpStr));
								sprintf(tmpStr,"%s.%s",eventItem->identifier,itemData->identifier);
								#if 0
								if(strcmp(itemData->identifier,"Battery") == 0)
{
									double batteryValue = 0;
									kk_tsl_get_value(kk_tsl_get_property_value,dev_shadow,itemData->identifier,&batteryValue,NULL);
									kk_tsl_set_value(kk_tsl_set_event_output_value,dev_shadow,tmpStr,&batteryValue,NULL);	

								}
								else{
									
									kk_tsl_set_value(kk_tsl_set_event_output_value,dev_shadow,tmpStr,&itemStr->valueint,NULL);	

								}
								#else
								kk_tsl_set_value(kk_tsl_set_event_output_value,dev_shadow,tmpStr,&itemStr->valueint,NULL);	
								#endif
								INFO_PRINT("kk_platMsg_handle data: event post\n");
								dm_msg_thing_event_post(info_dcode->valuestring,eventItem->identifier);
							}							
						}
						
					}
				}
			}
		}else if(strstr(msgType->valuestring, KK_THING_TOPO_BATCH_DELETE_MSG) != NULL){
			kk_ipc_send(IPC_MID2APP,data,strlen(data));
			cJSON *devices = cJSON_GetObjectItem(jsonPay, MSG_TOPO_CHANGE_DEVICES_STR);
			cJSON * item = devices->child;
			while(item != NULL){
				char *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR)->valuestring;
				dm_mgr_subdev_delete(deviceCode);
				item = item->next;
			}			
			
		}else{
            INFO_PRINT("kk_platMsg_handle data: don't handle it [%s]\n",data);
        
        }
    error:
        cJSON_Delete(json);
   }
}

void kk_platMsg_dispatch(void)
{
    int count = 0;
    void *data = NULL;

    while (CONFIG_DISPATCH_QUEUE_MAXLEN == 0 || count++ < CONFIG_DISPATCH_QUEUE_MAXLEN) {

        if (dm_queue_msg_next2(&data) == SUCCESS_RETURN) {
            dm_queue_msg_t *msg = (dm_queue_msg_t *)data;
            //INFO_PRINT("kk_handle_platMsg_dispatch get call \n");
            if (kk_platMsg_handle) {
                kk_platMsg_handle(msg->data,msg->chalMark);
            }

            if (msg->data != NULL){
                free(msg->data);
            }
            free(data);
            data = NULL;
        } else {
            break;
        }
    }
}


time_t getSysTime(){
    time_t t;  
    t = time(NULL);  
    return t;

}

typedef struct {
    int auto_add_subdev;
    int master_devid;
    int cloud_connected;
    int master_initialized;
    int subdev_index;
    int permit_join;
    void *g_mid_dispatch_thread;
    void *g_ota_dispatch_thread;
    void *g_ccuProChg_dispatch_thread;	
	void *g_udp_dispatch_thread;
    int g_mid_dispatch_thread_running;
    int g_ota_dispatch_thread_running;
    int g_ccuProChg_dispatch_thread_running;	
	int g_udp_dispatch_thread_running;
} mid_ctx_t;
#define MID_YIELD_TIMEOUT_MS (200)


static mid_ctx_t g_mid_ctx;

static mid_ctx_t *kk_mid_get_ctx(void)
{
    return &g_mid_ctx;
}

extern void IOT_Linkkit_Yield(int timeout_ms);
void *mid_dispatch_yield(void *args)
{
    mid_ctx_t *mid_ctx = kk_mid_get_ctx();

    while (mid_ctx->g_mid_dispatch_thread_running) {
        IOT_Linkkit_Yield(MID_YIELD_TIMEOUT_MS);
    }

    return NULL;
}

void *ota_dispatch_yield(void *args)
{
    mid_ctx_t *mid_ctx = kk_mid_get_ctx();

    while (mid_ctx->g_ota_dispatch_thread_running) {
        dm_ota_yield(MID_YIELD_TIMEOUT_MS);
    }

    return NULL;
}


#define UDP_LAN_PORT 25556
#define UDP_LAN_PORT_HOST 25555
#define test_

void *udp_dispatch_yield(void *args){  
    

    INFO_PRINT("udp_dispatch_yield udp thread create\n");    

    // 绑定地址 
    struct sockaddr_in addrto; 
    bzero(&addrto, sizeof(struct sockaddr_in)); 
    addrto.sin_family = AF_INET; 
    addrto.sin_addr.s_addr = htonl(INADDR_ANY); 
    addrto.sin_port = htons(UDP_LAN_PORT); 

     // 发送地址
    struct sockaddr_in addrto_host; 
    bzero(&addrto_host, sizeof(struct sockaddr_in)); 
    addrto_host.sin_family = AF_INET; 
    addrto_host.sin_addr.s_addr = htonl(INADDR_ANY); 
    //addrto_host.sin_port = htons(UDP_LAN_PORT); 
 
    // 接收到的广播地址 
    struct sockaddr_in from; 
    bzero(&from, sizeof(struct sockaddr_in)); 
   
    
    int sock = -1; 
     int sock_host = -1; 
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 
    { 
        ERROR_PRINT("socket error\n"); 
    } 

     if ((sock_host = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 
    { 
        ERROR_PRINT("socket error\n"); 
    } 
    
    if(bind(sock,(struct sockaddr *)&(addrto), sizeof(struct sockaddr_in)) == -1) 
    { 
        ERROR_PRINT("bind error...\n"); 
    } 
 
    socklen_t len = sizeof(struct sockaddr_in); 
    cJSON* json = NULL;
    cJSON* info = NULL;
    cJSON* payload = NULL;
    cJSON* infoObj = NULL;
    cJSON* payloadObj = NULL;
    cJSON* msgtype = NULL;
    cJSON* proCode = NULL;
    cJSON* devCode = NULL;
    cJSON* params = NULL;
    cJSON* macstr = NULL;
    char szOut[128] = {0};
    char szDec[1024] = {0}; 
    char host_ip[32] = {0};
    char mac[32] = {0};
    char device_code[DEVICE_CODE_LEN] = {0};
    int devId = 0;
    kk_prop_raw_struct_t ipList[10] = {0};
    int idx = 0;
    
    kk_property_db_get_rawdata("IPAddress",4, ipList, sizeof(ipList));
    for(; idx < 10; idx++){
        DEBUG_PRINT("ipList[%d][%s][%s] \n", idx, ipList[idx].deviceCode, ipList[idx].raw);
        if (strlen(ipList[idx].deviceCode)>0 && strlen(ipList[idx].raw)>0){
            kk_set_tcp_channel_by_idx(idx, ipList[idx].deviceCode, ipList[idx].raw);
        }
    }
    kk_TCP_channel_init(gw2mid_cb);
    
    while(1) 
    { 
            
        
        //从广播地址接受消息 
        memset(szDec, 0 , sizeof(szDec));
        int size=recvfrom(sock, szDec, sizeof(szDec), 0, (struct sockaddr*)&from,(socklen_t*)&len); 
        if(size<=0) 
        { 
            WARNING_PRINT("read error....\n"); 
        } 
        else 
        { 
                
            DEBUG_PRINT("lan recmsg: %s\n", szDec); 
            //DEBUG_PRINT("udp client ip:%s ,port is :%d htons(UDP_LAN_PORT)=%d \n",inet_ntoa(from.sin_addr),from.sin_port, htons(UDP_LAN_PORT)); 
#ifdef test_
            //"search_kk_ccu|deviceCode=1122334455667788;protocol=tcp"
            if(strstr(szDec, "search_kk_ccu|") != NULL){

                char* getConnet = szDec + strlen("search_kk_ccu|");
                char* tmp = NULL;
                char* endIdx = NULL;
                int itemLen = 0;
                int itemConnetLen = 0;
                char gwDevCode[DEVICE_CODE_LEN] = {0};
                char proto[10] = {0};

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

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

                DEBUG_PRINT("gwDevCode =%s proto=%s \n",gwDevCode,proto);
                if(strcmp(proto,"tcp") == 0){
                    //
                    
                    kk_set_tcp_channel(gwDevCode,inet_ntoa(from.sin_addr));
                }

                memset(host_ip, 0, sizeof(host_ip));
                memset(mac, 0, sizeof(mac));
                memset(szOut, 0, sizeof(szOut));
                HAL_Get_IP(host_ip,NULL);
                HAL_GetDevice_Code(device_code);
                
                sprintf(szOut,"search_kk_ccu_ack|deviceCode=%s;ip=%s;port=%d",device_code,host_ip,16565);
                DEBUG_PRINT("szOut:%s\n",szOut); 
                DEBUG_PRINT("udp client ip:%s ,port is :%d \n",inet_ntoa(from.sin_addr),from.sin_port); 
                //sendto(sock, szOut, strlen(szOut), 0, (struct sockaddr*)&from,len); 

                addrto_host.sin_addr.s_addr = inet_addr(inet_ntoa(from.sin_addr)); 
                addrto_host.sin_port = htons(UDP_LAN_PORT_HOST); 
                //addrto_host.sin_port = from.sin_port; 
                //if(strcmp(host_ip,inet_ntoa(from.sin_addr)) == 0)
                //{
                    sendto(sock_host, szOut, strlen(szOut), 0, (struct sockaddr*)&addrto_host,sizeof(addrto_host)); 
                //}
                //else
                //{
                //    DEBUG_PRINT("udp client is not local ip  , refused send ack to it\n");
                //}
            }
#else
            json=cJSON_Parse(szDec);
        	if (!json) {
                ERROR_PRINT("Error before: [%s]\n","cJSON_Parse");
            }
        	else
        	{
                
                infoObj = cJSON_GetObjectItem(json, "info");
                payloadObj = cJSON_GetObjectItem(json, "payload");
                
                if (infoObj != NULL && payloadObj != NULL){

                    msgtype = cJSON_GetObjectItem(infoObj, "msgtype");
                    if (msgtype == NULL || strstr(msgtype->valuestring, "/thing/topo/add") == NULL){
                        ERROR_PRINT("msgtype parameter is error \n");
                        cJSON_Delete(json);
                        continue;
                    }

                    proCode = cJSON_GetObjectItem(infoObj, "productCode");
                    devCode = cJSON_GetObjectItem(infoObj, "deviceCode");
                    params = cJSON_GetObjectItem(payloadObj, "params");
                    if (proCode == NULL || devCode == NULL || params == NULL){
                        ERROR_PRINT("productType productCode deviceCode params parameters are error \n");
                        cJSON_Delete(json);
                        continue;
                    }
                    
                    macstr = cJSON_GetObjectItem(params, "mac");

                    if (macstr == NULL){
                        ERROR_PRINT("mac parameter is error \n");
                        cJSON_Delete(json);
                        continue;
                    }
                    
                    INFO_PRINT(" productCode deviceCode mac: [%s][%s][%s] \n", proCode->valuestring,
                                devCode->valuestring, macstr->valuestring);
                    char device_code[DEVICE_CODE_LEN] = {0};            
                    HAL_GetDevice_Code(device_code);
                    int res = kk_mid_subdev_add(KK_DM_DEVICE_GATEWAY, proCode->valuestring, devCode->valuestring,macstr->valuestring, device_code);
                	if (res != SUCCESS_RETURN) {
                        WARNING_PRINT("dm_mgr_gw_create error");
                	}
                    
                    //kk_ipc_send(IPC_MID2APP, szDec, size);

                    memset(host_ip, 0, sizeof(host_ip));
                    memset(mac, 0, sizeof(mac));
                    memset(szOut, 0, sizeof(szOut));
                    HAL_Get_IP(host_ip,"ens33");
                    HAL_Get_mac(mac);
                    
                    sprintf(szOut,"/thing/topo/add_reply|mac=%s;ip=%s",mac,host_ip);
                    DEBUG_PRINT("szOut:%s\n",szOut); 
                    DEBUG_PRINT("udp client ip:%s ,port is :%d \n",inet_ntoa(from.sin_addr),from.sin_port); 
                    //sendto(sock, szOut, strlen(szOut), 0, (struct sockaddr*)&from,len); 

                    addrto_host.sin_addr.s_addr = inet_addr(inet_ntoa(from.sin_addr)); 
                    addrto_host.sin_port = htons(UDP_LAN_PORT_HOST); 
                    //addrto_host.sin_port = from.sin_port; 
                    if(strcmp(host_ip,inet_ntoa(from.sin_addr)) == 0)
                    {
                        sendto(sock_host, szOut, strlen(szOut), 0, (struct sockaddr*)&addrto_host,sizeof(addrto_host)); 
                    }
                    else
                    {
                        DEBUG_PRINT("udp client is not local ip  , refused send ack to it\n");
                    }
                    
                }else{
                    INFO_PRINT("error format json: [%s]\n",szDec);
                
                }
                
                cJSON_Delete(json);
                
            }
#endif
             
        }
        usleep(100000); 
    } 

            
    close(sock);
    close(sock_host);
}
void *ccu_property_monitor(void *args)
{
    mid_ctx_t *mid_ctx = kk_mid_get_ctx();
 	char s_IP[NETWORK_ADDR_LEN];
	char s_IP_TSL[NETWORK_ADDR_LEN] = {0};
	int res = 0;
	int needReport  = 0;
	int time_second = 60;
	dm_mgr_dev_node_t *node = NULL;
	dm_mgr_search_dev_by_devid(KK_DM_DEVICE_CCU_DEVICEID,&node);

    while (mid_ctx->g_ccuProChg_dispatch_thread_running) {
		if(kk_get_cloud_recv_status() == 0){
			iotx_dm_ccu_cloud_check();
			sleep(10);
			continue;
		}
        
		HAL_Get_IP(s_IP,NULL);	
		res = kk_tsl_get_value(kk_tsl_get_property_value,node->dev_shadow,KK_TSL_CCU_WANIP_IDENTIFIER,s_IP_TSL,NULL);
		if(res != SUCCESS_RETURN){
			ERROR_PRINT("kk_tsl_get_value Failed\n");
		}
		else{
			if(strcmp(s_IP,s_IP_TSL)){
				kk_tsl_set_value(kk_tsl_set_property_value,node->dev_shadow,KK_TSL_CCU_WANIP_IDENTIFIER,NULL,s_IP);
				INFO_PRINT("current ip:%s,before ip:%s\n",s_IP,s_IP_TSL);
				kk_property_db_update("CCU_66666");
				needReport  = 1;
			}
		}		
		
		if(needReport&&(kk_get_cloudstatus() == 1)){
			needReport = 0;
			char *postStr = kk_tsl_get_post_property_str(node->dev_shadow,NULL);
			if(postStr != NULL){
				dm_mgr_upstream_thing_property_post(node->devid, postStr, strlen(postStr),0);
				free(postStr);
				postStr = NULL;
			}
		}
		sleep(time_second);
    }
    return NULL;
}


int main(const int argc, const char **argv)
{

        int res = 0;
		char *tsl_str;
		int i;
		kk_tsl_t *dev_shadow[30] = {NULL};
        mid_ctx_t *mid_ctx = kk_mid_get_ctx();
    
		open("midware",LOG_PID,LOG_USER);
        memset(mid_ctx, 0, sizeof(mid_ctx_t));
		
        kk_tsl_api_init();
        kk_ipc_init(IPC_MID2APP, mid_cb, NULL, NULL);
        kk_ipc_init(IPC_MID2PLAT, mid2p_cb, NULL, "*");
		
        kk_init_dmproc();
		kk_subDb_init();
		kk_heartbeat_init();
		kk_area_init();	
        mid_ctx->g_mid_dispatch_thread_running = 1;
        res = pthread_create(&mid_ctx->g_mid_dispatch_thread, NULL, mid_dispatch_yield, NULL);
        if (res < 0) {
            ERROR_PRINT("HAL_ThreadCreate mid Failed\n");
            //IOT_Linkkit_Close(mid_ctx->master_devid);
            return -1;
        }
        mid_ctx->g_ota_dispatch_thread_running = 1;
        res = pthread_create(&mid_ctx->g_ota_dispatch_thread, NULL, ota_dispatch_yield, NULL);
        if (res < 0) {
            ERROR_PRINT("HAL_ThreadCreate ota Failed\n");
            //IOT_Linkkit_Close(mid_ctx->master_devid);
            return -1;
        }
        
        // recv gateway add cmd and ack to gateway
        res = pthread_create(&mid_ctx->g_udp_dispatch_thread, NULL, udp_dispatch_yield, NULL);
        if (res < 0) {
            ERROR_PRINT("HAL_ThreadCreate udp Failed\n");
            //IOT_Linkkit_Close(mid_ctx->master_devid);
            return -1;
        }
		
		mid_ctx->g_ccuProChg_dispatch_thread_running = 1;
        res = pthread_create(&mid_ctx->g_ccuProChg_dispatch_thread, NULL, ccu_property_monitor, NULL);
        if (res < 0) {
            ERROR_PRINT("HAL_ThreadCreate Failed\n");
            return -1;
        }		

        int ct = 0;
		for (;;) {
                usleep(200000);
                kk_platMsg_dispatch();
                /*if (ct == 0){
                    ct =1;
                    void* buf = "{\
                            \"info\": {\
                                    \"msgtype\":      \"/thing/topo/add\",\
                                     \"productType\":  \"gw\",\
                                     \"productCode\":  \"2\",\
                                    \"deviceCode\":   \"1122334455667788\"\
                                },\
                            \"payload\":      {\
                                    \"msgId\":        \"1\",\
                                     \"version\":      \"1.0\",\
                                    \"params\":       {\
                                        \"deviceCode\":   \"588E81FFFED3834A\",\
                                         \"productCode\":  \"24\",\
                                        \"mac\":  \"588E81FFFED3834A\"\
                                     }\
                            }\
                        }";
                    
                    kk_platMsg_handle(buf, "1122334455667788");
                    //kk_set_tsl_by_productKey("a1OYuSallan","model.json");
                    //kk_mid_subdev_add("a1OYuSallan","allanWno8yDdsjCX15iq","","aabbccddeeff1122");
                }*/

        }
}

