// Tencent is pleased to support the open source community by making Mars available.
// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.

// Licensed under the MIT License (the "License"); you may not use this file except in 
// compliance with the License. You may obtain a copy of the License at
// http://opensource.org/licenses/MIT

// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions and
// limitations under the License.

#ifndef __MOCK_SERVER_CONTROL_UTILS_H__
#define __MOCK_SERVER_CONTROL_UTILS_H__
#include <string>
#include <vector>
class ServerStatusItem
{
  public:
	std::string strIP;
	uint16_t nPort;
	bool isRunning;
	ServerStatusItem(const char* ip, uint16_t port, bool isRunning)
	{
		strIP =  ip;
		nPort = port;
		this->isRunning = isRunning;
	}
	ServerStatusItem(const char* ip, uint16_t port)
	{
		strIP =  ip;
		nPort = port;
		this->isRunning = false;
	}
};

static std::vector<ServerStatusItem>  sg_ServerStatusTable;
class MockServerControlUtils
{
	//startxxxϵ�к�������������server������status��־λ     killXXXϵ�к����ǹر�server���������־λ    stopXXXϵ�к����Ƿ���8888 TASK�� �������־λ
public:
static void setServerStatus(std::string _ip, uint16_t _port, bool& _isRunning)//_isRunning������������� ���Ϊserver��oldStatus
{
	bool oldStatus = false;
	std::vector<ServerStatusItem>::iterator iter = sg_ServerStatusTable.begin();
	for(;iter!=sg_ServerStatusTable.end();++iter)
	{
		if(iter->strIP==_ip && iter->nPort==_port)
		{
			oldStatus = iter->isRunning;
			iter->isRunning = _isRunning;
			break;
		}
	}

	if(iter == sg_ServerStatusTable.end())
	{
		ServerStatusItem tempItem(_ip.c_str(), _port, _isRunning);
		sg_ServerStatusTable.push_back(tempItem);
	}

	_isRunning = oldStatus;
}
//����һ��server������sg_ServerStatusTable���ö�Ӧ��־λ
static bool startNormalEcho(const IPPortItem& _ipPortItem)
{
	char tmpCmd[1024] = {0};
	snprintf(tmpCmd, sizeof(tmpCmd), START_NORMAL_ECHO_CMD, _ipPortItem.strIP.c_str(), _ipPortItem.nPort);
	bool isRunning = true;
	setServerStatus( _ipPortItem.strIP, _ipPortItem.nPort, isRunning);
	if(isRunning)
	{
		printf("server(%s:%u) is already running\n",_ipPortItem.strIP.c_str(), _ipPortItem.nPort);
		return true;
	}
	printf("line:%d,tempCmd=%s\n",__LINE__, tmpCmd);
	FILE* f = _popen(tmpCmd , "rt");
	if(NULL == f)   
	{
		printf("popen error!\n");
		return false;

	}
	return true;
}
//�ر�һ��server�� ����sg_ServerStatusTable�����Ӧ��־λ, ����ֵ��ʾ�Ƿ�رճɹ�
static bool killNormalEcho(const IPPortItem& _ipPortItem)
{
	char KILL_MSG[16] = "kill";
	bool isRunning = false;
	setServerStatus( _ipPortItem.strIP, _ipPortItem.nPort, isRunning);
	if(!isRunning)
	{
		printf("stopping server(%s:%u) is not running\n",_ipPortItem.strIP.c_str(), _ipPortItem.nPort);
		return true;
	}
	SOCKET sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	bool bRet = false;
	do 
	{
		if(sockfd<0)
		{
			isRunning = true;
			setServerStatus( _ipPortItem.strIP, _ipPortItem.nPort, isRunning);//û�������ص�  �ָ�statusΪ running
			printf("^^^^^^^^^^^^^close server(%s:%u) failed^^^^^<sockfd=%d, socket_errno:%d>^^^^^^^\n", _ipPortItem.strIP.c_str(), _ipPortItem.nPort, sockfd, WSAGetLastError());
			bRet = false;
			break;
		}
		struct sockaddr_in addr={0};
		addr.sin_family = AF_INET;
		addr.sin_addr.s_addr =inet_addr(_ipPortItem.strIP.c_str());
		addr.sin_port = (uint16_t)htons(_ipPortItem.nPort);

		int ret = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
		if(ret < 0)
		{
			isRunning = true;
			setServerStatus( _ipPortItem.strIP, _ipPortItem.nPort, isRunning);//û�������ص�  �ָ�statusΪ running
			printf("close echo_nomal server error.\n");
			printf("^^^^^^^^^^^^^close server(%s:%u) failed^^^^^<connect failed>^^^^^^^\n", _ipPortItem.strIP.c_str(), _ipPortItem.nPort);
			bRet = false;
			break;
		}
		else
		{
			std::string closeMsg(KILL_MSG);
			int sendSize = send(sockfd, closeMsg.c_str(), closeMsg.size(), 0);
			if(sendSize != closeMsg.size())
			{
				isRunning = true;
				setServerStatus( _ipPortItem.strIP, _ipPortItem.nPort, isRunning);//û�������ص�  �ָ�statusΪ running
				printf("sendSize=%d, closeMsg.size=%d, is not equal!\n", sendSize, closeMsg.size());
				printf("^^^^^^^^^^^^^close server(%s:%u) failed^^^^^<send failed>^^^^^^^\n", _ipPortItem.strIP.c_str(), _ipPortItem.nPort);
				bRet = false;
				break;
			}
			else
			{
				printf("^^^^^^^^^^^^^close server(%s:%u) success^^^^^^^^^^^^\n", _ipPortItem.strIP.c_str(), _ipPortItem.nPort);
				bRet = true;
				break;
			}
		}
	} while (false);
	
	if(sockfd!=INVALID_SOCKET)
	{
		::closesocket(sockfd);
		sockfd = INVALID_SOCKET;
	}
	return bRet;
}
static int startNormalEchoServer(const char* ip)
{
	int succCount = 0;
	IPPortItem tempItem;
	tempItem.strIP = ip;
	tempItem.nPort = 80;
	if(startNormalEcho(tempItem))
		succCount++;
	tempItem.nPort = 443;
	if(startNormalEcho(tempItem))
		succCount++;

	return succCount;
}
static int killNormalEchoServer(const char* ip)
{
	int succCount = 0;
	IPPortItem tempItem;
	tempItem.strIP = ip;
	tempItem.nPort = 80;
	if(killNormalEcho(tempItem))
		succCount++;
	tempItem.nPort = 443;
	if(killNormalEcho(tempItem))
		succCount++;

	return succCount;
}
static int startNormalEchoServerList(const std::vector<IPPortItem>& _serverList)
{
	int succCount = 0;
	std::vector<IPPortItem>::const_iterator iter = _serverList.begin();
	for(; iter!=_serverList.end(); ++iter)
	{
		bool isSucc = startNormalEcho(*iter);
		if(isSucc)
			succCount++;
	}
	return succCount++;
}
static int killNormalEchoServerList(const std::vector<IPPortItem>& _serverList)
{
	int succCount = 0;
	std::vector<IPPortItem>::const_iterator iter = _serverList.begin();
	for(; iter!=_serverList.end(); ++iter)
	{
		bool isSucc = killNormalEcho(*iter);
		if(isSucc)
			succCount++;
	}
	return succCount++;
}
static void startAllMainIdcServer()
{
	char* IPs[3] = {"127.0.51.1", "127.0.51.2", "127.0.51.3"};
	unsigned int ports[2] = {80, 443};
	for(int i=0; i<2; ++i)
	{
		for(int j=0; j<3; ++j)
		{
			IPPortItem ipPortItem;
			ipPortItem.strIP =  IPs[j];
			ipPortItem.nPort = ports[i];
			startNormalEcho(ipPortItem);
		}
	}
}
static void killAllMainIdcServer()
{
	char* IPs[3] = {"127.0.51.1", "127.0.51.2", "127.0.51.3"};
	unsigned int ports[2] = {80, 443};
	for(int i=0; i<2; ++i)
	{
		for(int j=0; j<3; ++j)
		{
			IPPortItem ipPortItem;
			ipPortItem.strIP =  IPs[j];
			ipPortItem.nPort = ports[i];
			killNormalEcho(ipPortItem);
		}
	}
}
static void startAllSatelliteIdcServer()
{
	char* IPs[3] = {"127.0.50.1", "127.0.50.2", "127.0.50.3"};
	unsigned int ports[2] = {80, 443};
	for(int i=0; i<2; ++i)
	{
		for(int j=0; j<3; ++j)
		{
			IPPortItem ipPortItem;
			ipPortItem.strIP =  IPs[j];
			ipPortItem.nPort = ports[i];
			startNormalEcho(ipPortItem);
		}
	}
}
static void killAllSatelliteIdcServer()
{
	char* IPs[3] = {"127.0.50.1", "127.0.50.2", "127.0.50.3"};
	unsigned int ports[2] = {80, 443};
	for(int i=0; i<2; ++i)
	{
		for(int j=0; j<3; ++j)
		{
			IPPortItem ipPortItem;
			ipPortItem.strIP =  IPs[j];
			ipPortItem.nPort = ports[i];
			killNormalEcho(ipPortItem);
		}
	}
}
/*
static void startEchoServer(const IPPortItem& _ipPortItem)
{
	char tmpCmd[1024] = {0};
	snprintf(tmpCmd, sizeof(tmpCmd), ECHO_NOOPING_RESP_THREE, _ipPortItem.strIP.c_str(), _ipPortItem.nPort);
	printf("line:%d,tempCmd=%s, ip=%s\n",__LINE__, tmpCmd, _ipPortItem.strIP.c_str());
	FILE* f = _popen(tmpCmd , "rt");
	if(NULL == f)   
	{
		printf("popen error!\n");

	}

}
static void startEchoServer(const std::string& ip, unsigned int port)
{
	IPPortItem ipPortItem;
	ipPortItem.strIP =  ip;
	ipPortItem.nPort = port;
	startEchoServer(ipPortItem);
}
*/
static bool isAllServerClosed()
{
	bool isAllClosed = true;
	std::vector<ServerStatusItem>::iterator iter = sg_ServerStatusTable.begin();
	for(;iter!=sg_ServerStatusTable.end();++iter)
	{
		if(true == iter->isRunning)
		{
			isAllClosed = false;
			break;
		}
	}
	return isAllClosed;
}

//�ر�����server�������sg_ServerStatusTable
static bool killAllServer()
{
	bool isStopAllServerSucc = true;
	std::vector<ServerStatusItem>::iterator iter = sg_ServerStatusTable.begin();
	for(;iter!=sg_ServerStatusTable.end();++iter)
	{
		if(true == iter->isRunning)
		{
			printf("line=%d, server(%s:%d) is running, stop it!\n",__LINE__, iter->strIP.c_str(), iter->nPort);
			IPPortItem tempItem;
			tempItem.strIP = iter->strIP;
			tempItem.nPort = iter->nPort;
			isStopAllServerSucc = killNormalEcho(tempItem);
			if(!isStopAllServerSucc)
			{
				printf("error: stop server failed\n");
			}
		}
	}
	if(isStopAllServerSucc)
		sg_ServerStatusTable.clear();

	return isStopAllServerSucc;
}
};


#define startNormalEcho				    MockServerControlUtils::startNormalEcho
#define killNormalEcho				    MockServerControlUtils::killNormalEcho
#define startNormalEchoServer		    MockServerControlUtils::startNormalEchoServer
#define killNormalEchoServer		    MockServerControlUtils::killNormalEchoServer
#define startNormalEchoServerList		MockServerControlUtils::startNormalEchoServerList
#define killNormalEchoServerList		MockServerControlUtils::killNormalEchoServerList
#define startAllMainIdcServer			MockServerControlUtils::startAllMainIdcServer
#define startAllSatelliteIdcServer		MockServerControlUtils::startAllSatelliteIdcServer
#define killAllSatelliteIdcServer		MockServerControlUtils::killAllSatelliteIdcServer
#define startEchoServer				    MockServerControlUtils::startEchoServer
#define killAllServer				    MockServerControlUtils::killAllServer



#endif