package com.group.service;

import com.taurus.core.entity.ITObject;
import com.taurus.core.events.Event;
import com.taurus.core.events.EventDispatcher;
import com.taurus.core.events.IEventListener;
import com.taurus.core.util.ICallback;
import com.taurus.core.util.Logger;
import com.group.service.io.SocketEngine;

import java.util.HashMap;
import java.util.Map;


/**
 * 缃戠粶鏍稿績鍔熻兘澶勭悊绫?
 * @author daixiwei	daixiwei15@126.com
 *
 */
public class TaurusClient {
	private static final Logger	logger	= Logger.getLogger(TaurusClient.class);
	private int					_id;
	private boolean				_connect;
	private String				_gameId;
	private String				_currentIp;

	private ISocketLayer		_scoket;
	private ThreadManager		_threadManager;

	private EventDispatcher		_dispatcher;
	private Map<Message, ICallback<MessageResponse>> _responseMap;
	volatile boolean			_kill	= false;
	private static int			_tempID;
	private int _protocolCompression=100;
	
	private static int _getValidID() {
		return ++_tempID;
	}

	/**
	 * 
	 * @param host
	 * @param game
	 * @param protocol
	 */
	public TaurusClient(String host, String game, ConnectionProtocol protocol) {
		ISocketLayer socket = null;
		switch (protocol) {
		case Tcp:
			socket = new SocketEngine(this);
			break;
		case Web:
			socket = new HttpClient(host);
			_connect = true;
			break;
		default:
			socket = new SocketEngine(this);
			break;
		}
		__initialize(host, game, socket);
	}

	/**
	 * 
	 * @param host
	 * @param game
	 * @param socket
	 * @param protocol
	 */
	public TaurusClient(String host, String game, ISocketLayer socket) {
		__initialize(host, game, socket);
		
	}

	/**
	 * 娣诲姞浜嬩欢
	 * @param eventType
	 * @param listener
	 */
	public void addEventListener(String eventType, IEventListener listener) {
		_dispatcher.addEventListener(eventType, listener);
	}

	/**
	 * 绉婚櫎鎵€鏈変簨浠?
	 */
	public void removeAllListener() {
		_dispatcher.removeAllListener();
	}

	/**
	 * 绉婚櫎鎸囧畾浜嬩欢
	 * @param eventType
	 * @param listener
	 */
	public void removeEventListener(String eventType, IEventListener listener) {
		_dispatcher.removeEventListener(eventType, listener);
	}

	private void __initialize(String host, String game, ISocketLayer socket) {
		_dispatcher = new EventDispatcher();
		_responseMap = new HashMap<Message, ICallback<MessageResponse>>();
        _id = _getValidID();
        NetManager.addNetClient(this);
        _currentIp = host;
        _gameId = game;
        _threadManager = new ThreadManager();
        _threadManager.start();
        _scoket = socket;
		_scoket.setOnConnect(new ICallback<SocketCode>() {
			@Override
			public void action(SocketCode code) {
				if (code == SocketCode.Connect)
					_connect = true;
				else
					_connect = false;
				Event evt = new Event(NetClientEvent.Connect);
				evt.setParameter("code", code);
				_dispatcher.dispatchEvent(evt);
			}
		});
		_scoket.setOnEvent(new ICallback<Message>() {
			@Override
			public void action(Message msg) {
				if (_connect) {
					Event evt = new Event(NetClientEvent.OnEvent);
					evt.setParameter("msg", msg);
					_dispatcher.dispatchEvent(evt);
					if (NetManager.debug_print){
                        String str = getProtocol() == ConnectionProtocol.Web ? "WEB" : "TCP";
                        String data_str = msg.useText ? msg.textParam : (msg.param != null ? msg.param.toJson() : "null");
                        logger.debug("Event [" + str + "->" + msg.command + "] data:" + data_str);
                    }
				}
			}
		});
	}

	/**
	 * 杩炴帴鏈嶅姟鍣?
	 */
	public void connect() {
		_scoket.connect(_currentIp, _gameId);
	}

	/**
	 * Kill net connection.
	 */
	public void killConnection() {
		removeAllListener();
		_responseMap.clear();
		_threadManager.stop();
		_scoket.disconnect();
		_connect = false;
		_kill = true;
	}

	/**
	 * 鍙戦€佺綉缁滄秷鎭寘
	 * @param msg	娑堟伅鏁版嵁瀵硅薄
	 */
	protected void send(Message msg) {
		if (msg == null)
			return;
		if (NetManager.debug_print) {
			String str = getProtocol() == ConnectionProtocol.Web ? "WEB" : "TCP";
			String data_str = msg.useText ? msg.textParam : (msg.param != null ? msg.param.toJson() : "null");
			str = "Requst [" + str + "->" + msg.command + "] ->data:" + data_str;
			logger.debug(str);
		}
		if (msg.callback != null) {
			_responseMap.put(msg, msg.callback);
			msg.callback = new ICallback<MessageResponse>() {

				@Override
				public void action(MessageResponse response) {
					ICallback<MessageResponse> callback = _responseMap.get(response.messageData);
					if (callback == null) {
						return;
					}
					if (NetManager.debug_print){
                        String str = getProtocol() == ConnectionProtocol.Web ? "WEB" : "TCP";
                        String data_str = msg.useText ? msg.textParam : (msg.param != null ? msg.param.toJson() : "null");
                        str = "Response [" + str + "->" + msg.command + "] ->result:"+ response.returnCode + " param:" + data_str;
                        logger.debug(str);
                    }
					_responseMap.remove(response.messageData);
					callback.action(response);
				}

			};
		}

		_threadManager.enqueueSend(new ICallback<Message>() {
			@Override
			public void action(Message msg) {
				sendData(msg);
			}
		}, msg);
	}

	
	/**
	 * 鍙戦€佺綉缁滄秷鎭寘
	 * @param cmd 		缃戠粶鍗忚鎸囦护Key
	 * @param param		鍙傛暟
	 * @param callback	缃戠粶娑堟伅鍥炶皟
	 * @return
	 */
	public Message send(String cmd, ITObject param, ICallback<MessageResponse> callback) {
		Message msg = new Message();
		msg.useText = false;
		msg.command = cmd;
		msg.param = param;
		msg.callback = callback;
		this.send(msg);
		return msg;
	}
	
	/**
	 * 鍙戦€佺綉缁滄秷鎭寘
	 * @param cmd 		缃戠粶鍗忚鎸囦护Key
	 * @param text		JSON 鏂囨湰
	 * @param callback	缃戠粶娑堟伅鍥炶皟
	 * @return
	 */
	public Message sendText(String cmd, String text, ICallback<MessageResponse> callback) {
		Message msg = new Message();
		msg.command = cmd;
		msg.textParam = text;
		msg.callback = callback;
		msg.useText = true;
		this.send(msg);
		return msg;
	}

	/**
	 * 鍙戦€佹暟鎹嚎绋嬫柟娉?
	 * @param message
	 */
	private void sendData(Message msg) {
		_scoket.write(msg);
	}

	/**
	 * 澶勭悊浜嬩欢
	 */
	void processEvent() {
		if(_scoket!=null) {
			_scoket.processEvent();
		}
	}

	/**
	 * 娓呯悊鍝嶅簲鍥炶皟
	 */
	public void clearResponse() {
		_responseMap.clear();
	}

	/**
	 * The net client id
	 * @return
	 */
	public int getId() {

		return _id;

	}

	/**
	 * The curren ip
	 * @return
	 */
	public String getCurrentIp() {
		return _currentIp;
	}

	/**
	 * The curren Game ID
	 * @return
	 */
	public String getGameID() {
		return _gameId;
	}

	/**
	 * 缃戠粶鏄惁宸茶繛鎺?
	 * @return
	 */
	public boolean isConnected() {
		return _connect;
	}

	/**
	 * 褰撳墠缃戠粶绫诲瀷
	 * @return
	 */
	public ConnectionProtocol getProtocol() {
		return _scoket.getProtocol();
	}

	/**
	 * 缃戠粶寤舵椂
	 * @return
	 */
	public int getAveragePingTime() {
		return _scoket.getAveragePingTime();
	}

	/**
	 * 鑾峰彇鏈嶅姟鍣⊿ession瀛楃
	 * @return
	 */
	public String getSession() {
		return _scoket.getSession();
	}

	/**
	 * 璁剧疆鏈嶅姟鍣⊿ession瀛楃
	 * @param session
	 */
	public void setSession(String session) {
		_scoket.setSession(session);
	}
	
	/**
	 * 璁剧疆鍘嬬缉闃€鍊?
	 * @param protocolCompression
	 */
	public void setProtocolCompression(int protocolCompression) {
		_protocolCompression = protocolCompression;
	}

	/**
	 * 鑾峰彇鍘嬬缉闃€鍊?
	 * 
	 * @return
	 */
	public int getProtocolCompression() {
		return _protocolCompression;
	}
    

	public static enum ConnectionProtocol {
		Tcp, Web,
	}

	public static class NetClientEvent {
		public static final String	Connect	= "connect";

		public static final String	OnEvent	= "onevent";
	}
}
