/*
 * kk_connect.cpp
 *
 *  Created on: 2020年10月1日
 *      Author: hj
 */

#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include "json/reader.h"
#include "json/writer.h"
#include "json/value.h"
#include "EH_ToolKit.h"
#include "EH_FindCCU.h"
#include "kk_connect.h"
#include "LSC_Logger.h"

#include "MQ_CCU_Adapter.h"

kk_connect* kk_connect::ms_instance = NULL;

kk_connect* kk_connect::GetInstance() {
	if (ms_instance == NULL) {
		ms_instance = new kk_connect();
	}
	return ms_instance;
}
kk_connect::kk_connect() {
	
}

void* kk_connect::run0(void* opt) {
	kk_connect* client = (kk_connect*) opt;
	return client->run(opt);
}
//
int kk_connect::init(string ccuId, string accessKey, bool autoDestroyHandler) {
	this->ccuId = ccuId;
	this->accessKey = accessKey;
	this->ccuServerPort = SERVER_LISTEN_PORT;
	this->autoDestroyHandler = autoDestroyHandler;
#ifdef NOT_X86
	this->ccuLocalIP  = string(EH_ToolKit::GetLocalIP("eth1"));
#else
	this->ccuLocalIP  = string(EH_ToolKit::GetLocalIP());
#endif
	this->ccuSn = EH_ToolKit::GetMacNoSpace();
	LOGI(" ccuLocalIP:%s.\n", ccuLocalIP.c_str());
	ccuServerIp = ccuLocalIP;
	ccuServerPort = 6768;

	findCCU = new EH_FindCCU();
	// findCCU->init(ccuId, this,ccuLocalIP);
	findCCU->init(ccuId,ccuLocalIP);
	pthread_t tid;
	pthread_create(&tid, NULL, run0, this);

	return 0;
}

string kk_connect::sendLoginReq(string msg) {
	string loginReq = "";
	string logingwsn = ccuSn;
	EH::Json::Reader reader;
    EH::Json::Value buf;
    if (!reader.parse(msg, buf) || !buf.isObject()) {
       LOGW("Message format is wrong. msg is: %s\n",msg.c_str());
       return "-1";
    }
	try{
    	EH::Json::Value arg;
    	arg["method"] = "bind";
		arg["gw_id"] = buf["gw_id"];
		arg["client_id"] = buf["client_id"];
		arg["device_name"] = buf["device_name"];

		//错误类型
		//网关ID不符result=3  ；
		if(logingwsn != buf["gw_id"].asString()){
	//		arg["gw_id"] = logingwsn;
			arg["result"] = "3";
			loginReq = arg.toStyledString();
			return loginReq;
		}
		//网关未联网result=2
		//进行网络校验
		if (EH_ToolKit::Ping(string("114.114.114.114"))!= true) {
			arg["result"] = "2";
			loginReq = arg.toStyledString();
			return loginReq;
		}
		//网关已被绑定result=1（如需绑定，请先解除绑定）
		EH::Json::Value connectStateInfo = KK_HwDevManager::GetInstance()->loadConnectState();//获取绑定信息
		if(connectStateInfo["result"] == "0"){ //0为未绑定
			EH::Json::Value newconnectInfo;
			newconnectInfo["result"] = "1";
			newconnectInfo["client_id"] = buf["client_id"];
			newconnectInfo["device_name"] = buf["device_name"];
			int saveok = KK_HwDevManager::GetInstance()->saveConnectState(newconnectInfo);//获取绑定信息
			LOGI("saves :%d.\n",saveok);
			//保存成功就会进行连接Roma程序启动。void MQ_CCU_Adapter::oninitmqttsdk() 
			arg["result"] = "0"; //绑定成功result=0,
			loginReq = arg.toStyledString();
			return loginReq;
		}else{
			arg["result"] = "1"; //网关已被绑定result=1
			loginReq = arg.toStyledString();
			return loginReq;
		}
	} catch (exception &e) {
		LOGW("%s.\n", e.what());
	}
	return "-1";
}
//
void* kk_connect::run(void* opt) {
	//定义用于连接，和接收的socket
	// bind
	try{

		int socket_fd,accept_fd;
		sockaddr_in myserver, remote_addr;
		if(( socket_fd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0 ){
			LOGW("socket() failed!.\n");
		}
		memset(&myserver,0,sizeof(myserver));
		myserver.sin_family = AF_INET;
		myserver.sin_addr.s_addr = htonl(INADDR_ANY);
		myserver.sin_port = htons(6768);

		//使用端口复用，在bind之前先设置好socket的选线，让其可以绑定在已经正在被别的socket使用的端口上。
		setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,(const void*)&opt,sizeof(1));

		if( bind(socket_fd,(sockaddr*) &myserver,sizeof(myserver)) < 0 ) {
			LOGW("bind() failed!.\n");
		}
		// listen
		if( listen(socket_fd,50) < 0 ) {
			LOGW("listen() failed!.\n");
		}
		LOGI("Step3: 侦听.\n");
		//  while(!destroyed) {
		while(true) {
			socklen_t sin_size = sizeof(struct sockaddr_in);
			if(( accept_fd = accept(socket_fd,(struct sockaddr*) &remote_addr,&sin_size)) == -1 ){
				LOGI("收发数据%d.\n",accept_fd);
				LOGW("Accept error!.\n");
				continue;
			}
			LOGI("收发数据%d.\n",accept_fd);
			LOGI("Received a connection from %s\n",(char*) inet_ntoa(remote_addr.sin_addr));
			if(!fork() ) {
				char buffer[RECV_MSG_SIZE];
				memset(buffer,0,RECV_MSG_SIZE);
				if((read(accept_fd,buffer,RECV_MSG_SIZE)) < 0) {
					LOGW("Accept error!.\n");
					throw("Read() error!");
				} else {
					LOGI("收到的消息: %s\n",buffer);
					string sendbuffer = buffer;
					string loginReq = sendLoginReq(sendbuffer);
					int loginReq_Len = loginReq.length();
					//对下面进行封装，达到发送信息的要求
					if(loginReq != "-1"){
						LOGI("发送的消息: %s\n",loginReq.c_str());
						send(accept_fd, (void *)loginReq.c_str(), loginReq_Len, 0);
					}
				}
			}
			close(accept_fd);
			// close(socket_fd);
		}
		delete this;

	} catch (exception &e) {
		LOGW("%s.\n", e.what());
	}
	return NULL;
}

void kk_connect::destroy() {
	// destroyed = true;
	// close(connectToCcuFd);
	LOGI("destroy:%s.\n", ccuId.c_str());
}

kk_connect::~kk_connect() {
	// close(connectToCcuFd);

	if (findCCU) {
		findCCU->destroy();
		findCCU = NULL;
	}

	LOGI("~EH_Client:%p.\n", this);
}

