/**
* @brief
websocket客户端类

* @version
  V 1.0.0

* @author
  王益俊

* @date
  创建时间:  2018-08-14\n

* @note
  2018-08-14  创建类。\n

* @warning

* @bug
  
*/

#pragma once

#include <string>
#include <mutex>
#include <condition_variable>
#include <map>

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

#include <boost/function.hpp>
#include <boost/bind.hpp>

#include "sio_client.h"
#include "jsonBuilder.h"

namespace YA
{
	//消息处理函数类型
	typedef boost::function<void( int, std::string const&, sio::message::ptr const&, bool, sio::message::list & )> MSG_HANDLE_FUNC_TYPE;

	class wsClient
	{
	private:
		sio::client __wsclient;//websocket客户端
		int __ID;//唯一标识
		std::string __uri;//连接字符串
		bool __Connected;//是否连接上服务器端
		bool __SktOpened;//Socket是否已打开
		bool __Logined;//是否已登录成功
		std::condition_variable_any __cond;//条件变量
		std::mutex __lock;//锁(配合__cond)
		std::string __LastError;//最新错误
		std::map<std::string, MSG_HANDLE_FUNC_TYPE> __MsgFuncList;//消息处理函数列表(key是命令,value是处理函数)
		std::recursive_mutex __send_lock;//发送锁
		jsonBuilder __jsBuilder;//json构造器
	protected:
		/**
		* @brief
		重置状态函数。

		* @param  无\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void _reset();
		/**
		* @brief
		连接成功回调函数。

		* @param  无\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void _on_connected();
		/**
		* @brief
		连接关闭回调函数。

		* @param  [in] sio::client::close_reason const& reason 关闭的原因\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void _on_close( sio::client::close_reason const& reason );
		/**
		* @brief
		重连回调函数。

		* @param  [in] unsigned p1 ???\n
		* @param  [in] unsigned p2 ???\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void _on_reconnect( unsigned p1, unsigned p2 );
		/**
		* @brief
		失败回调函数。

		* @param  无\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void _on_fail();
		/**
		* @brief
		socket打开成功回调函数。

		* @param  无\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void _on_socket_opened();
		/**
		* @brief
		收到服务器端CALL命令回调函数。

		* @param  [in] std::string const& name  触发的名字\n
		* @param  [in] sio::message::ptr const& data  收到的消息数据\n
		* @param  [in] bool need_ack  是否需要应答\n
		* @param  [in] sio::message::list &ack_resp  应答消息数据\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void _OnCallMessage( std::string const& name, sio::message::ptr const& data, bool need_ack, sio::message::list &ack_resp );
		/**
		* @brief
		收到服务器端登录应答命令回调函数。

		* @param  [in] std::string const& name  触发的名字\n
		* @param  [in] sio::message::ptr const& data  收到的消息数据\n
		* @param  [in] bool need_ack  是否需要应答\n
		* @param  [in] sio::message::list &ack_resp  应答消息数据\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void _OnLoginResponse( std::string const& name, sio::message::ptr const& data, bool need_ack, sio::message::list &ack_resp );
	public:
		wsClient();
		~wsClient();
		/**
		* @brief
		初始化函数。

		* @param  [in] int ID  当前客户端的唯一标识\n
		* @param  [in] const std::string & uri  连接串\n
		* @param  [in] const std::map<std::string, MSG_HANDLE_FUNC_TYPE>& MsgFuncList  消息处理函数\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void init( int ID, const std::string & uri, const std::map<std::string, MSG_HANDLE_FUNC_TYPE>& MsgFuncList );
		/**
		* @brief
		获得连接字符串函数。

		* @param  无\n

		* @return 获得的连接字符串\n

		* @note

		* @warning

		* @bug

		*/
		std::string get_uri();
		/**
		* @brief
		；连接函数。

		* @param  [in] int time_out  超时(单位：秒),默认是3秒\n

		* @return 连接服务器是否成功\n
		* @retval  0  成功\n
        * @retval  -1  失败\n

		* @note

		* @warning

		* @bug

		*/
		int connect( int time_out = 3 );
		/**
		* @brief
		；登录函数。

		* @param  无\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void login();
		/**
		* @brief
		发送数据函数。

		* @param  [in] const std::string & Cmd  要发送的命令\n
		* @param  [in] const std::string& Data  要发送的数据\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void send( const std::string & Cmd, const std::string & Data );
		/**
		* @brief
		获得ID函数。

		* @param  无\n

		* @return 获得的ID\n

		* @note

		* @warning

		* @bug

		*/
		int GetID();
		/**
		* @brief
		获得是否已连接服务器端函数。

		* @param  无\n

		* @return 是否已连接服务器\n

		* @note

		* @warning

		* @bug

		*/
		bool IsConnected();
		/**
		* @brief
		获得Socket是否已打开函数。

		* @param  无\n

		* @return Socket是否已打开\n

		* @note

		* @warning

		* @bug

		*/
		bool IsSktOpened();
		/**
		* @brief
		获得是否已登录成功函数。

		* @param  无\n

		* @return 是否已登录成功\n

		* @note

		* @warning

		* @bug

		*/
		bool IsLogined();
		/**
		* @brief
		关闭函数。

		* @param  无\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		void close();
		/**
		* @brief
		获得最新错误函数。

		* @param  无\n

		* @return 无\n

		* @note

		* @warning

		* @bug

		*/
		std::string GetLastError();
	};
}