// socket.io-client-cpp_test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "sio_client.h"

#include <functional>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <string>
#include "constdef.h"
#include <chrono>
#include <stdio.h>
#include <tchar.h>

#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/prettywriter.h>

#include "jsonCommon.h"

#include <boost\locale.hpp>

#include "wsClient.h"
#include "wsClientMgr.h"
#include "wsTimerThread.h"
#include "singleton_test_class1.h"


using namespace sio;
using namespace std;
std::mutex _lock;

std::condition_variable_any _cond;
bool connect_finish = false;
bool socket_opened = false;

class connection_listener
{
public:

	connection_listener()
	{

	}
	void on_connected()
	{
		std::cout << "sio connected" << std::endl;
		_lock.lock();
		_cond.notify_all();
		connect_finish = true;
		_lock.unlock();
	}
	void on_close( client::close_reason const& reason )
	{
		std::cout << "sio closed" << std::endl;
		exit( 0 );
	}
	void on_fail()
	{
		std::cout << "sio failed" << std::endl;
		exit( 0 );
	}
	void on_socket_opened()
	{
		std::cout << "on_socket_opened" << std::endl;

		_lock.lock();
		socket_opened = true;
		_cond.notify_all();
		_lock.unlock();
	}
	void OnLogin( std::string const& name, message::ptr const& data, bool isAck, message::list &ack_resp )
	{
		int res_code = ( int ) data->get_map()["code"]->get_int();
		switch ( res_code )
		{
		case -100: //登录失败
		{
			std::cout << "sio failed to login" << std::endl;
			break;
		}
		case 0:
		{
			if ( "" == data->get_map()["code"]->get_string() )
			{ // 登录成功
				std::cout << "sio login ok" << std::endl;
			}
			else
			{ // 退出登录
				std::cout << "sio failed to login" << std::endl;
			}
			break;
		}
		default:
			break;
		}
	}
	void OnCallMessage( string const& name, message::ptr const& data, bool isAck, message::list &ack_resp )
	{
		std::cout << "OnCallMessage, name=" << name.c_str() << std::endl;

		if ( data->get_flag() == message::flag_object ) 
		{
			string cmd = data->get_map()[JSON_ROOT_KEY_CMD]->get_string();

			char szLog[1024] = { 0 };
			sprintf( szLog, "received cmd from web: %s", cmd.c_str() );
			std::cout << szLog << std::endl;
		}
	}
	void OnReConnect( unsigned, unsigned )
	{
		std::cout << "sio OnReConnect" << std::endl;

		connect_finish = false;
		socket_opened = false;
	}
};

std::unique_ptr<sio::client> ws_client( new sio::client() );

//sio::client ws_client;
connection_listener l;
socket::ptr current_socket;

std::string BuildLogin( const YA::_JS_LOGIN_& Login )
{
	rapidjson::StringBuffer sb;
	rapidjson::Writer<rapidjson::StringBuffer> writer( sb );

	rapidjson::Document doc;

	rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
	rapidjson::Value root( rapidjson::kObjectType );
	rapidjson::Value child( rapidjson::kObjectType );
	rapidjson::Value key( rapidjson::kStringType );
	rapidjson::Value value( rapidjson::kStringType );

	key.SetString( "cmd", allocator );
	value.SetString( YA::JASON_CMD_LOGIN, allocator );
	root.AddMember( key, value, allocator );

	key.SetString( "user_name", allocator );
	value.SetString( Login.user_name.c_str(), allocator );
	child.AddMember( key, value, allocator );

	key.SetString( "user_pass", allocator );
	value.SetString( Login.user_password.c_str(), allocator );
	child.AddMember( key, value, allocator );

	key.SetString( "data", allocator );
	root.AddMember( key, child, allocator );

	root.Accept( writer );

	return sb.GetString();
}

//初始化
void ws_init()
{
	ws_client->set_reconnect_attempts( 0 );
	using std::placeholders::_1;
	using std::placeholders::_2;
	using std::placeholders::_3;
	using std::placeholders::_4;
	socket::ptr sock = ws_client->socket();

	//sock->on( JSON_CMD_VALUE_USER, sio::socket::event_listener_aux( std::bind( &connection_listener::OnLogin, &l, _1, _2, _3, _4 ) ) );
	//sock->on( "code", sio::socket::event_listener_aux( std::bind( &connection_listener::OnLogin, &l, _1, _2, _3, _4 ) ) );
	sock->on( JSON_CMD_VALUE_CALL, sio::socket::event_listener_aux( std::bind( &connection_listener::OnCallMessage, &l, _1, _2, _3, _4 ) ) );

	ws_client->set_open_listener( std::bind( &connection_listener::on_connected, &l ) );
	ws_client->set_close_listener( std::bind( &connection_listener::on_close, &l, std::placeholders::_1 ) );
	ws_client->set_reconnect_listener(std::bind(&connection_listener::OnReConnect, &l, std::placeholders::_1, std::placeholders::_2));
	ws_client->set_fail_listener( std::bind( &connection_listener::on_fail, &l ) );
	ws_client->set_socket_open_listener( std::bind( &connection_listener::on_socket_opened, &l ) );
}

//登录
void ws_login()
{
	std::cout << "ws_login()" << std::endl;

	YA::_JS_LOGIN_ Login;
	Login.user_name = JSON_VALUE_USERNAME;
	Login.user_password = JSON_VALUE_PASSWORD;
	std::string strLogin = BuildLogin( Login );
	strLogin += "\n";
	strLogin = boost::locale::conv::to_utf<char>( strLogin, "GBK" );
	current_socket->emit( JSON_CMD_VALUE_USER, strLogin, [&]( sio::message::list const& msglist )
	{
		message::ptr msg_ptr = msglist[0];
		int n = ( int ) msg_ptr->get_map()["code"]->get_int();
		if ( 0 == n )
		{
			std::cout << "Login ok, code=" << n << std::endl;
		}
		else
		{
			std::cout << "Login failed,code=" << n << std::endl;
		}
	} );
}

void simple_test()
{
	//初始化
	ws_init();

	ws_client->connect( "ws://192.168.5.101:8086" );
	//ws_client->connect( "ws://192.168.8.175:8086" );
	//ws_client->connect( "ws://localhost:8086" );

	_lock.lock();
	if ( !connect_finish )
	{
		_cond.wait( _lock );
	}
	_lock.unlock();

	current_socket = ws_client->socket();

	_lock.lock();
	if ( !socket_opened )
	{
		_cond.wait( _lock );
	}
	_lock.unlock();

	std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );

	//登录
	ws_login();

	system( "PAUSE" );
}

//处理req_all_data命令的函数
void On_req_all_data( int ID, std::string const& name, sio::message::ptr const& data, bool need_ack, sio::message::list &ack_resp )
{
	std::cout << "[Onreq_all_data] ";
	std::cout << "{" << ID << "} ";
	string strdata = data->get_map()["data"]->get_string().c_str();
	string version = data->get_map()["version"]->get_string().c_str();
	std::cout << "data=" << strdata.c_str() << ", version=" << version.c_str() << std::endl;
}

void On_req_all_person_on_car( int ID, std::string const& name, sio::message::ptr const& data, bool need_ack, sio::message::list &ack_resp )
{
	std::cout << "[On_req_all_person_on_car] ";
	std::cout << "{" << ID << "} ";
	std::vector<message::ptr> vdata = data->get_map()["data"]->get_vector();
	std::cout << vdata[0]->get_string() << ",";
	std::cout << vdata[1]->get_int() << std::endl;
}

void wsClient_class_test()
{
	YA::wsClient client;

	std::map<std::string, YA::MSG_HANDLE_FUNC_TYPE> MsgFuncList;

	MsgFuncList.insert( std::make_pair( "req_all_data", On_req_all_data ) );
	MsgFuncList.insert( std::make_pair( "req_all_person_on_car", On_req_all_person_on_car ) );

	//初始化
	client.init( 1, "ws://192.168.5.101:8086", MsgFuncList );

	//连接服务器端
	if ( client.connect() != 0 )
	{
		std::cout << "连接服务器失败" << std::endl;
		client.close();
		return;
	}

	//登录
	client.login();
}

void wsClientMgr_class_test()
{
	//构造
	std::vector<std::string> uri_list;
	std::map<std::string, YA::MSG_HANDLE_FUNC_TYPE> MsgFuncList;

	uri_list.push_back( "ws://192.168.5.101:8086" );
	//uri_list.push_back( "ws://192.168.5.102:8086" );

	MsgFuncList.insert( std::make_pair( "req_all_data", On_req_all_data ) );
	MsgFuncList.insert( std::make_pair( "req_all_person_on_car", On_req_all_person_on_car ) );

	swsClientMgr.Build( uri_list, MsgFuncList );

	//连接服务器
	if ( swsClientMgr.connect() != 0 )
	{
		std::cout << "连接服务器失败" << std::endl;
		return;
	}

	//登录
	swsClientMgr.login();

	std::shared_ptr<YA::wsClient> pClient;
	//通过URI获得某个websocket客户端
	pClient = swsClientMgr.GetClientByURI( "ws://192.168.5.101:8086" );
	if ( pClient != NULL )
	{
		std::cout << "ID=" << pClient->GetID() << ",URI=" << pClient->get_uri().c_str() << std::endl;
	}

	//通过下标获得某个websocket客户端
	pClient = swsClientMgr[1];
	if ( pClient != NULL )
	{
		std::cout << "ID=" << pClient->GetID() << ",URI=" << pClient->get_uri().c_str() << std::endl;
	}
}

void wsTimerThread_test()
{
	YA::_THREAD_CONFIG_ Config;
	Config.SendInterval = 1;
	swsTimerThrd.Init( Config );
	swsTimerThrd.Start();

	boost::this_thread::sleep( boost::posix_time::millisec( 3000 ) );

	swsTimerThrd.Stop();
}

int main()
{
	//simple_test();
	//wsClient_class_test();
	//wsClientMgr_class_test();
	wsTimerThread_test();

	singleton_test_class1 st1;
	st1.DoSome();

	while ( true )
	{
		std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );
	}

	return 0;
}
