//+------------------------------------------------------------------+
//|                                             MetaTrader AutoHedge |
//|                          Copyright 2001-2014, KAB Software Corp. |
//|                                                http://www.kab.hk |
//+------------------------------------------------------------------+
#include "stdafx.h"
#include "Processor.h"
#include <string>
#include <direct.h>
#include "SHA1.h"
#include "csv.hpp"
#include <fstream>
using namespace std;


volatile UINT      ExtPumpingMsg = 0;
volatile UINT      ExtDealingMsg = 0;

static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";

#define WORK_BUFFER_SIZE (1024)
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

TradeTransmit::TradeTransmit()
	: m_run(false)
  {
	  m_master = "";
	  m_server_update = true;
	  m_serveraddress = "127.0.0.1";
	  m_serverport = 0;
	  memset(m_groups, 0, 256);
	  m_mt4_login = 0;
	  m_mt4_password = "";
	  m_mt4_addr = "";
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
TradeTransmit::~TradeTransmit()
  {
	 
	  m_run = false;
	  if (m_deal_msg_thread.joinable())
		  m_deal_msg_thread.join();
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void __stdcall TradeTransmit::PumpingFuncEx(int code, int type, void * data, void *param)
{
	TradeTransmit *p = (TradeTransmit*)param;
	p->DealFunEx(code, type, data);
}

void TradeTransmit::Initialize(void)
{

	Out("Initialize parameter...");
	m_factory.Init("mtmanapi.dll");
	int iRet = m_factory.WinsockStartup();
	ExtPumpingMsg = RegisterWindowMessage("MetaTrader4_Pumping_Message");
	ExtDealingMsg = RegisterWindowMessage("MetaTrader4_Dealing_Message");

	char tmp[256], *cp;
	GetModuleFileName(NULL, tmp, sizeof(tmp) - 1);
	if ((cp = strrchr(tmp, '.')) != NULL) *cp = 0;
	
	int    nPos;
	std::string spath(tmp);
	nPos = spath.rfind('\\');
	spath = spath.assign(spath, 0, nPos);
	sprintf(m_log_file, "%s\\tradeLog", spath.c_str());
	std::string csvfile = spath + "\\userinfo.csv";
	strcat(tmp, ".ini");
	if (_access(m_log_file, 0) == -1)
		_mkdir(m_log_file);
	char str[35] = { 0 };
	m_mt4_login = GetPrivateProfileInt("MT4", "Login", 27, tmp);
	if(m_mt4_login<=0)Out("mt4 login error!please check ini file");
	GetPrivateProfileString("MT4", "Addr", "maxcolive.itraderserver.com:443", str, 35, tmp);
	if(strlen(str)<=1)Out("mt4 addr error!please check ini file");
	m_mt4_addr = str;
	memset(str, 0, 25);
	GetPrivateProfileString("MT4", "PassWord", "Mjk345", str, 20, tmp);
	if (strlen(str) <= 1)Out("mt4 password error!please check ini file");
	m_mt4_password = str;
	memset(str, 0, 25);
	GetPrivateProfileString("TCP", "Addr", "0.0.0.0", str, 20, tmp);
	m_tcpserver.SetAddr(str);
	int port  = GetPrivateProfileInt("TCP", "Port", 8080, tmp);
	if (port <= 0)Out("tcp port error!please check ini file");
	m_tcpserver.SetServerPort(port);
	char symbol[1024];
	GetPrivateProfileString("MT4", "symbol", "", symbol, 1023, tmp);
	m_symbols=splitWithStl(symbol, ",");

	string line;
	ifstream file(csvfile);
	Csv csv(file);

	while (csv.getline(line) != 0 && file)
	{
		if (csv.getnfield() < 2)continue;
		USER_INFO info = { 0 };

		info.userid = csv.getfield(0);
		info.pwd = csv.getfield(1);
		m_userInfo.push_back(info);

	}
	if (file)
		file.close();
}

int TradeTransmit::Start()
{

	Out("server starting!!!");
	Initialize();
	if (m_factory.IsValid() == FALSE
		|| (m_pmanager = m_factory.Create(ManAPIVersion)) == NULL
		|| (m_pmanager_pump = m_factory.Create(ManAPIVersion)) == NULL)
	{

		return -1;
	}
	m_run = true;
	Out("connect mt4 server...");
	int iRet = ConnectManager(m_pmanager, m_mt4_addr.c_str(), m_mt4_login, m_mt4_password.c_str());
	if (iRet != RET_OK)
	{
		Sleep(500);
		iRet = ConnectManager(m_pmanager, m_mt4_addr.c_str(), m_mt4_login, m_mt4_password.c_str());
	}
	if (iRet != RET_OK)
	{
		Out("connect mt4 server fail");
		return -2;
	}
	iRet = ConnectPump(m_pmanager_pump, m_mt4_addr.c_str(), m_mt4_login, m_mt4_password.c_str());
	if (iRet != RET_OK)
	{
		Sleep(500);
		iRet = ConnectPump(m_pmanager_pump, m_mt4_addr.c_str(), m_mt4_login, m_mt4_password.c_str());
	}
	if (iRet != RET_OK)
	{
		Out("connect mt4 server fail");
		return -2;
	}
	m_trade_event = CreateEvent(NULL, FALSE, FALSE, NULL);
	m_timer.run();
	iRet=m_tcpserver.Start();
	if (iRet != 0)
	{
		Out("start tcp server fail");
		return -3;
	}
	if (!m_deal_msg_thread.joinable())
		m_deal_msg_thread = std::thread(&TradeTransmit::DealTcpMsg, this);
	if (!m_deal_mt4_thread.joinable())
		m_deal_mt4_thread = std::thread(&TradeTransmit::DealMt4Msg, this);
	m_timer.add_task([this]()
	{
		PumpHeart();
	}, 1000 * 15);
	Out("start server success!");
	/*std::string csvfliename("\\trade");
	if (m_csv_record.startflag() != true)
		m_csv_record.open(m_log_file + csvfliename, ".csv");*/
	return 0;
}


void TradeTransmit::Out(LPCSTR msg,...)
  {
   char buffer[1024];
//--- format string
   va_list arg_ptr;
   va_start(arg_ptr,msg);
   _vsnprintf(buffer,sizeof(buffer)-1,msg,arg_ptr);
   va_end(arg_ptr);

   std::cout << buffer << std::endl;
  }

void TradeTransmit::Stop()
{
	
	m_run = false;

	SetEvent(m_trade_event);
	m_tcpserver.Stop();
	m_timer.stop();
	if (m_deal_msg_thread.joinable())
		m_deal_msg_thread.join();
	if (m_deal_mt4_thread.joinable())
		m_deal_mt4_thread.join();
	if (m_pmanager_pump != NULL)
	{
		m_pmanager_pump->Release();
		m_pmanager_pump = NULL;
	}
	if (m_pmanager != NULL)
	{
		m_pmanager->Release();
		m_pmanager = NULL;
	}
	m_csv_record.stop();
}
int TradeTransmit::ConnectManager(CManagerInterface *manager, const char*  szIP, const int iUser, const char*  szPassword)
{
	int iRet = manager->Connect(szIP);
	if (iRet != RET_OK)
	{
		return iRet;
	}
	iRet = manager->Login(iUser, szPassword);
	return iRet;
}

int TradeTransmit::ConnectPump(CManagerInterface *managerpump, const char* szIP, const int iUser, const char* szPassword)
{
	int iRet = managerpump->Connect(szIP);
	if (iRet != RET_OK)
	{
		return iRet;
	}
	iRet = managerpump->Login(iUser, szPassword);
	if (iRet != RET_OK)
	{
		return iRet;
	}
	int iCount = 0;

	int flag = 0;
	while ((iRet = managerpump->PumpingSwitchEx(TradeTransmit::PumpingFuncEx, flag, this)) != 0)
	{
		if (iCount++ >= 5)
		{
			return iRet;
		}
	}
	return iRet;
}
void TradeTransmit::ReConnectPump(CManagerInterface * manager, const char * szIP, const int iUser, const char * szPassword)
{
	int iRet = m_pmanager_pump->Ping();
	if (iRet != 0)
	{
		int iRet = ConnectPump(m_pmanager_pump, m_mt4_addr.c_str(), m_mt4_login, m_mt4_password.c_str());
		if (iRet != RET_OK)
		{
			m_timer.add_task([this]()
			{
				ReConnectPump(m_pmanager_pump, m_mt4_addr.c_str(), m_mt4_login, m_mt4_password.c_str());
			}, 500);
			return;
		}

		m_timer.add_task([this]()
		{
			PumpHeart();
		}, 1000 * 15);
		Out("pump reconnect success!");
	}
}
void TradeTransmit::DealFunEx(int code, int type, void * data)
{
	switch (code)
	{
	case PUMP_START_PUMPING:
		//m_pmanager_pump->Ping();
	{
		for (int i = 0; i < m_symbols.size(); ++i)
		{
			m_pmanager_pump->SymbolAdd(m_symbols.at(i).c_str());
		}
			

	}
		break;
	case PUMP_STOP_PUMPING:
		if (m_run)
		{
			Out("PUMPING STOP");
			m_timer.add_task([this]()
			{
				ReConnectPump(m_pmanager_pump, m_mt4_addr.c_str(), m_mt4_login, m_mt4_password.c_str());
			}, 100);
		}
		break;
	case PUMP_UPDATE_BIDASK:
	{
		SymbolInfo si[32];
		int total=0;
		while (total = m_pmanager_pump->SymbolInfoUpdated(si, 32) > 0)
		{
			for (int i = 0; i < total; i++)
			{
				
				//printf("%s ask:%lf,bid:%lf", si[i].symbol, si[i].ask, si[i].bid);
				json sjson;
				sjson["type"] = 100;
				sjson["symbol"] = si[i].symbol;
				sjson["ask"] = si[i].ask;
				sjson["bid"] = si[i].bid;
				unsigned long n = 0;
				char * data = packData(sjson.dump().c_str(), &n, strlen(sjson.dump().c_str()));
				for (auto iter = m_userList.begin(); iter != m_userList.end(); ++iter)
				{
					m_tcpserver.Send(iter->dwConnID,(LPBYTE)data, n);
				}
				//delete[] data;
			}
				
			//printf("\n");
		}

	}
		break;
	case PUMP_UPDATE_SYMBOLS:

		break;
	case PUMP_UPDATE_GROUPS:

		break;
	case PUMP_UPDATE_USERS:
		break;
	case PUMP_UPDATE_ONLINE:
		break;
	case PUMP_UPDATE_TRADES:
	{
		if (data != NULL )
		{
			
		}
	}
	break;
	case PUMP_UPDATE_ACTIVATION:
		break;
	case PUMP_UPDATE_MARGINCALL:
	{
		/*if (data != NULL)
		{
			MT4_MSG msg = { 0 };
			msg.code = PUMP_UPDATE_MARGINCALL;
			memcpy(&msg.ml, (MarginLevel*)data, sizeof(MarginLevel));
			AddMt4Msg(&msg);
		}*/
	}
		break;
	case PUMP_UPDATE_REQUESTS:
	{
		/*if (data != NULL)
		{
			MT4_MSG msg = { 0 };
			msg.code = PUMP_UPDATE_REQUESTS;
			memcpy(&msg.rinfo,(RequestInfo*)data,sizeof(RequestInfo));
			AddMt4Msg(&msg);
		}*/
	}
		break;
	default: break;
	}
}
void TradeTransmit::PumpHeart()
{

	int iRet =m_pmanager_pump->Ping();
	if (iRet != 0)
	{
		Out("pump lost,reconnect!");
		ReConnectPump(m_pmanager_pump, m_mt4_addr.c_str(), m_mt4_login, m_mt4_password.c_str());
		return;
	}
	m_timer.add_task([this]()
	{
		PumpHeart();
	}, 1000*15);
}
void TradeTransmit::AddMt4Msg(MT4_MSG * mt4_msg)
{
	std::lock_guard<std::mutex> lk(m_trade_mutex);
	m_trade_list.push_back(*mt4_msg);
	SetEvent(m_trade_event);
}
bool TradeTransmit::ReadMt4Msg(MT4_MSG & mt4_msg)
{
	std::lock_guard<std::mutex> lk(m_trade_mutex);
	if (m_trade_list.size() > 0)
	{
		mt4_msg = m_trade_list.front();
		m_trade_list.pop_front();
		return true;
	}
	return false;
}
void TradeTransmit::DealTradeMsg(TradeRecord * trade,int type)
{
	if (trade == NULL)return;
	if (trade->cmd > OP_SELL_STOP ||trade->cmd < 0)return;

	float volume = trade->volume*1.00f / 100.0f;
	char _str[5] = { 0 };
	sprintf(_str, "%0.2f", volume);
	Out("trade transmit: order %d,login %d,symbol %s,volume %s", trade->order, trade->login, trade->symbol, _str);
	m_csv_record.write(tools::logger::LVNORMAL, "trade transmit,order %d,login %d,symbol %s,volume %s", trade->order, trade->login, trade->symbol, _str);

	json json_msg;
	json_msg["type"] = TCP_TRADE;
	json_msg["order"] = trade->order;
	json_msg["login"] = trade->login;
	json_msg["symbol"] = trade->symbol;
	json_msg["cmd"] = trade->cmd;
	
	json_msg["volume"] = _str;
	if(trade->open_time>0)
	{ 
		std::string date;
		StampToGmt(trade->open_time, date);
		json_msg["open_time"] = date;
	}
	else
		json_msg["open_time"] = "";

	json_msg["state"] = trade->state;
	json_msg["open_price"] = trade->open_price;
	json_msg["sl"] = trade->sl;
	json_msg["tp"] = trade->tp;
	if (trade->close_time>0)
	{
		std::string date;
		StampToGmt(trade->close_time, date);
		json_msg["close_time"] = date;
	}
	else
		json_msg["close_time"] = "";
	json_msg["close_price"] = trade->close_price;
	if (trade->cmd >= OP_BUY && trade->cmd <= OP_SELL)
	{
		if (type == TRANS_UPDATE)
		{
			if (trade->timestamp == trade->open_time)
				json_msg["transtype"] = MT4_TRADE_PENDING_ACTIVE;
			else
				json_msg["transtype"] = MT4_TRADE_UPDATE;
		}
			
		if (type == TRANS_DELETE)
			json_msg["transtype"] = MT4_TRADE_CLOSE;
	
		if (type == TRANS_ADD)
			json_msg["transtype"] = MT4_TRADE_OPEN;

	}
	if (trade->cmd > OP_SELL && trade->cmd <= OP_SELL_STOP)
	{
		if (type == TRANS_ADD)
			json_msg["transtype"] = MT4_TRADE_PENDING;
		if (type == TRANS_DELETE)
			json_msg["transtype"] = MT4_TRADE_PENDING_DELETE;
		if (type == TRANS_UPDATE)
			json_msg["transtype"] = MT4_TRADE_PENDING_UPDATE;
	}
	//m_tcpserver.BroadMsg(json_msg);
}

void TradeTransmit::DealUserMsg(UserRecord * user)
{
	if (user == NULL)return;
	json json_msg;
	json_msg["login"] = user->login;
	json_msg["group"] = user->group;
	json_msg["enable"] = user->enable;
	json_msg["name"] = user->name;
	json_msg["country"] = user->country;
	json_msg["city"] = user->city;
	json_msg["state"] = user->state;
	json_msg["zipcode"] = user->zipcode;
	json_msg["address"] = user->address;
	json_msg["phone"] = user->phone;
	json_msg["email"] = user->email;
	//m_tcpserver.BroadMsg(json_msg);
}
void TradeTransmit::DealRequestMsg(RequestInfo * info)
{
	if (info == NULL)return;
	json json_msg;
	json_msg["id"] = info->id;
	json_msg["status"] = info->status;
	json_msg["login"] = info->login;
	json_msg["time"] = info->time;
	json_msg["group"] = info->group;
	json_msg["balance"] = info->balance;
	json_msg["credit"] = info->credit;
	//m_tcpserver.BroadMsg(json_msg);
}
void TradeTransmit::DealMarginMsg(MarginLevel * ml)
{
	if (ml == NULL)return;

	json json_msg;
	json_msg["login"] = ml->login;
	json_msg["group"] = ml->group;
	json_msg["leverage"] = ml->leverage;
	json_msg["updated"] = ml->updated;
	json_msg["group"] = ml->group;
	json_msg["balance"] = ml->balance;
	json_msg["equity"] = ml->equity;
	json_msg["volume"] = ml->volume;
	json_msg["margin_free"] = ml->margin_free;
	json_msg["margin_level"] = ml->margin_level;
	json_msg["balance"] = ml->balance;
	json_msg["margin_type"] = ml->margin_type;
	//m_tcpserver.BroadMsg(json_msg);
}

void TradeTransmit::SendMsg(std::string type, vector<json> desc, time_t open_time, time_t error_time, int error_code,std::string opr)
{
	json json_msg;
	json_msg["type"] = type;
	for (unsigned int i = 0; i < desc.size(); ++i)
	{
		json_msg["desc"][i] = desc.at(i);
	}
		

	if (open_time> 0)
		json_msg["opentime"] = open_time;
	if (error_time > 0)
		json_msg["errortime"] = error_time;
	
	json_msg["status"] = error_code;

	if (opr.length() > 0)
		json_msg["opr"] = opr;
	std::string msg = json_msg.dump() + "\r\n";

}


void TradeTransmit::DealTcpMsg()
{
	while (m_run)
	{
		//m_tcpserver.WaitRecvEvent();
		if (!m_run)return;
		std::vector<string> vec;
		CONNID dwConnID;
		int flag;
		std::string ip;
		std::string u_id;
		int ilen = 0;
		while (m_tcpserver.ReadMsg(vec, dwConnID, flag, ip, u_id))
		{
			if (flag == -1)
			{
				deleteUser(dwConnID);
				continue;
			}
			for (unsigned int i = 0; i < vec.size(); i++)
			{

				if (flag == 0)
				{
					//握手
					handShake(vec.at(i).c_str(), dwConnID);
					checkUser(vec.at(i).c_str(), dwConnID);
					continue;
				}
				//解码 
				WebSocketStreamHeader header{};
				int iRead = readHeader((const unsigned char *)vec.at(i).c_str(), &header);
				if (iRead == WebSocketOpCode::ConnectionClose)
				{
					m_tcpserver.CloseConnect(dwConnID);
					continue;
				}
				if (iRead == WebSocketOpCode::Pong)
				{
					continue;
				}
			}
			vec.clear();
			dwConnID = 0;
		}
	}
}

void TradeTransmit::DealMt4Msg()
{
	while (m_run)
	{
		WaitForSingleObject(m_trade_event, INFINITE);
		if (!m_run)return;
		
		MT4_MSG msg = {0};
		while (ReadMt4Msg(msg))
		{
			switch (msg.code)
			{
			case PUMP_UPDATE_USERS:
			{
				//DealUserMsg(&msg.ur);//暂时只要交易单的转发
			}
			break;
			case PUMP_UPDATE_TRADES:
			{
				//DealTradeMsg(&msg.tr,msg.type);
			}
			break;
			case PUMP_UPDATE_ACTIVATION:
			{

			}
			break;
			case PUMP_UPDATE_MARGINCALL:
			{
				//DealMarginMsg(&msg.ml);//暂时只要交易单的转发
			}
			break;
			case PUMP_UPDATE_REQUESTS:
			{
				//DealRequestMsg(&msg.rinfo);//暂时只要交易单的转发
			}
			break;
			default:
				break;
			}
			
		}
	}
}

void TradeTransmit::StampToGmt(int stampTime,std::string &datetime)
{
	time_t t;
	struct tm *p;
	t = stampTime;
	p = gmtime(&t);
	char s[80];
	strftime(s, 80, "%Y-%m-%d %H:%M:%S", p);

	datetime = s;
}

std::vector<std::string> TradeTransmit::splitWithStl(const std::string &str, const std::string &pattern)
{
     std::vector<std::string> resVec;

     if ("" == str)
     {
         return resVec;
     }

    std::string strs = str + pattern;

    size_t pos = strs.find(pattern);
    size_t size = strs.size();

    while (pos != std::string::npos)
    {
        std::string x = strs.substr(0, pos);
        resVec.push_back(x);
        strs = strs.substr(pos + 1, size);
        pos = strs.find(pattern);
    }

    return resVec;
}

char* TradeTransmit::packData(const char * message, unsigned long * len, unsigned long n)
{
	static char * packData = new char[1024];
	memset(packData, 0, sizeof(1024));
	if (n < 126)
	{
		packData[0] = 0x81;
		packData[1] = n;
		memcpy(packData + 2, message, n);
		*len = n + 2;
	}
	else if (n < 32767)
	{
		packData[0] = 0x81;
		packData[1] = 126;
		packData[2] = (n >> 8 & 0xFF);
		packData[3] = (n & 0xFF);
		memcpy(packData + 4, message, n);
		*len = n + 4;
	}
	else
	{
		// 暂不处理超长内容  
		*len = 0;
	}
	return packData;
	//char * packData = new char[n + 4];
	//memset(packData, 0, sizeof(n + 4));
	//if (n < 126)
	//{
	//	packData[0] = 0x81;
	//	packData[1] = n;
	//	memcpy(packData + 2, message, n);
	//	*len = n + 2;
	//}
	//else if (n < 32767)
	//{
	//	packData[0] = 0x81;
	//	packData[1] = 126;
	//	packData[2] = (n >> 8 & 0xFF);
	//	packData[3] = (n & 0xFF);
	//	memcpy(packData + 4, message, n);
	//	*len = n + 4;
	//}
	//else
	//{
	//	// 暂不处理超长内容  
	//	*len = 0;
	//}
	//return packData;
}
int TradeTransmit::readHeader(const unsigned char* cData, WebSocketStreamHeader* header)
{
	if (cData == NULL)return false;

	const unsigned char *buf = cData;

	header->fin = buf[0] & 0x80;
	header->masked = buf[1] & 0x80;
	unsigned char stream_size = buf[1] & 0x7F;

	header->opcode = buf[0] & 0x0F;
	if (header->opcode == WebSocketOpCode::ContinuationFrame) {
		//连续帧  
		return WebSocketOpCode::ContinuationFrame;
		//return false;
	}
	else if (header->opcode == WebSocketOpCode::TextFrame) {
		//文本帧  
	}
	else if (header->opcode == WebSocketOpCode::BinaryFrame) {
		//二进制帧  

	}
	else if (header->opcode == WebSocketOpCode::ConnectionClose) {
		//连接关闭消息  
		return WebSocketOpCode::ConnectionClose;
		//return false;
	}
	else if (header->opcode == WebSocketOpCode::Ping) {
		//  ping  
		return WebSocketOpCode::Ping;
	}
	else if (header->opcode == WebSocketOpCode::Pong) {
		// pong  
		return WebSocketOpCode::Pong;
	}
	else {
		//非法帧  
		return -1;
	}

	if (stream_size <= 125) {
		//  small stream  
		header->header_size = 6;
		header->payload_size = stream_size;
		header->mask_offset = 2;
	}
	else if (stream_size == 126) {
		//  medium stream   
		header->header_size = 8;
		unsigned short s = 0;
		memcpy(&s, (const char*)&buf[2], 2);
		header->payload_size = ntohs(s);
		header->mask_offset = 4;
		return 100;
	}
	else if (stream_size == 127) {

		unsigned long long l = 0;
		memcpy(&l, (const char*)&buf[2], 8);

		header->payload_size = l;
		header->mask_offset = 10;
	}
	else {
		//Couldnt decode stream size 非法大小数据包  
		return -1;
	}

	if (header->payload_size > (65535 / 2)) {
		return -1;
	}

	return 0;
}
bool TradeTransmit::decodeRawData(const WebSocketStreamHeader& header, BYTE cbSrcData[], WORD wSrcLen, BYTE cbTagData[])
{
	const unsigned char *final_buf = cbSrcData;
	if (wSrcLen < header.header_size + 1) {
		return false;
	}

	char masks[4];
	memcpy(masks, final_buf + header.mask_offset, 4);
	memcpy(cbTagData, final_buf + header.mask_offset + 4, header.payload_size);

	for (INT_PTR i = 0; i < header.payload_size; ++i) {
		cbTagData[i] = (cbTagData[i] ^ masks[i % 4]);
	}
	//如果是文本包，在数据最后加一个结束字符“\0”  
	if (header.opcode == WebSocketOpCode::TextFrame)
		cbTagData[header.payload_size] = '\0';

	return true;
}

std::string TradeTransmit::base64Encode(unsigned char const* bytes_to_encode, unsigned int in_len)
{
	std::string ret;
	int i = 0;
	int j = 0;
	unsigned char char_array_3[3];
	unsigned char char_array_4[4];

	while (in_len--) {
		char_array_3[i++] = *(bytes_to_encode++);
		if (i == 3) {
			char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
			char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
			char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
			char_array_4[3] = char_array_3[2] & 0x3f;

			for (i = 0; (i <4); i++)
				ret += base64_chars[char_array_4[i]];
			i = 0;
		}
	}

	if (i)
	{
		for (j = i; j < 3; j++)
			char_array_3[j] = '\0';

		char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
		char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
		char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
		char_array_4[3] = char_array_3[2] & 0x3f;

		for (j = 0; (j < i + 1); j++)
			ret += base64_chars[char_array_4[j]];

		while ((i++ < 3))
			ret += '=';

	}

	return ret;

}

void TradeTransmit::handShake(string inMessage, CONNID &dwConnID)
{
	std::istringstream stream(inMessage);
	std::string reqType;
	std::getline(stream, reqType);
	bool ck = true;
	if (reqType.substr(0, 4) != "GET ")
	{
		ck = false;
	}

	std::string header;
	std::string::size_type pos = 0;
	std::string websocketKey;
	bool bs = false;
	std::string userId = "";
	int type = 0;
	if (ck)
	{
		while (std::getline(stream, header) && header != "\r")
		{
			header.erase(header.end() - 1);
			pos = header.find(": ", 0);
			if (pos != std::string::npos)
			{
				std::string key = header.substr(0, pos);
				std::string value = header.substr(pos + 2);
				if (key == "Sec-WebSocket-Key")
				{
					bs = true;
					websocketKey = value;
					break;
				}
			}
		}
	}

	// 填充http响应头信息  
	std::string response = "HTTP/1.1 101 Web Socket Handshake\r\n";
	response += "Upgrade: websocket\r\n";
	response += "Connection: Upgrade\r\n";
	response += "Sec-WebSocket-Accept: ";

	const std::string magicKey("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
	std::string serverKey = websocketKey + magicKey;

	std::string strKey = websocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
	SHA1 sha;
	unsigned int iDigSet[5];
	sha.Reset();
	sha << strKey.c_str();
	sha.Result(iDigSet);

	for (int i = 0; i < 5; i++)iDigSet[i] = htonl(iDigSet[i]);           //将字节转换成网络字节顺序  

	strKey = base64Encode(reinterpret_cast<const unsigned char*>(iDigSet), 20);

	response += strKey + "\r\n\r\n";
	int iLen = (int)strlen(response.c_str());
	
	m_tcpserver.Send(dwConnID, (LPBYTE)response.c_str(), iLen);
}

void TradeTransmit::checkUser(string inMessage, CONNID & dwConnID)
{
	std::istringstream stream(inMessage);
	USER_INFO ui{};
	ui.dwConnID = dwConnID;
	std::string userid="";//在这里做账号控制
	std::string pwd = "";//在这里做账号控制
	/*int id_pos = inMessage.find("UserId", 4);
	if (id_pos != string::npos)
	{
		int pos_e = inMessage.find("&", id_pos + 6);
		if (pos_e == string::npos)
			pos_e = inMessage.find(" ", id_pos + 6);
		if (pos_e != string::npos)
		{
			userid = inMessage.substr(id_pos + 7, pos_e - id_pos - 7);
			ui.userid = userid;
		}
	}
	int pos_b = inMessage.find("password", id_pos);
	if (pos_b != string::npos)
	{
		int pos_e = inMessage.find("&", pos_b + 8);
		if (pos_e == string::npos)
			pos_e = inMessage.find(" ", pos_b + 8);
		if (pos_e != string::npos)
		{
			pwd = inMessage.substr(pos_b + 9, pos_e - pos_b - 9);
			ui.pwd = pwd;
		}
	}
	auto u_iter = std::find_if(m_userInfo.begin(), m_userInfo.end(), [&userid, &pwd](USER_INFO &info) {return (userid == info.userid &&pwd== info.pwd); });
	if (u_iter == m_userInfo.end())
	{
		m_tcpserver.CloseConnect(dwConnID);
		return;
	}
	auto iter = std::find_if(m_userList.begin(), m_userList.end(), [userid](USER_INFO &info) {return (userid == info.userid); });
	if (iter != m_userList.end())
	{
		CONNID tmp = iter->dwConnID;
		iter->dwConnID = dwConnID;
		m_tcpserver.CloseConnect(tmp);
		return;
	}*/

	m_userList.push_back(ui);
}

void TradeTransmit::deleteUser(CONNID dwConnID)
{
	m_tcpserver.DeleteInfo(dwConnID);
	auto iter = std::find_if(m_userList.begin(), m_userList.end(), [dwConnID](USER_INFO &info) {return (dwConnID == info.dwConnID); });//
	if (iter != m_userList.end())
	{
		m_userList.erase(iter);
	}
}
