using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Assets.lib.monolib;
using UnityEngine;

public class Session_ME : Session_Cmd, ISession
{
	public class Sender
	{
		public List<Message> sendingMessage;

		public Sender()
		{
			sendingMessage = new List<Message>();
		}

		public void AddMessage(Message message)
		{
			sendingMessage.Add(message);
		}

		public void run()
		{
			while (connected)
			{
				try
				{
					if (getKeyComplete && sysComplete)
					{
						while (sendingMessage.Count > 0)
						{
							Message message = sendingMessage[0];
							doSendMessage(message);
							if (!isSpecialMess(message))
							{
								svRecived_ClSended++;
								CRes.outz("đã gửi lên : " + message.command);
							}
							else
							{
								CRes.outz("đã gửi lên SPECIAL: " + message.command);
							}
							sendingMessage.RemoveAt(0);
						}
					}
					try
					{
						Thread.Sleep(5);
					}
					catch (Exception ex)
					{
						Cout.LogError(ex.ToString());
					}
				}
				catch (Exception)
				{
					Debug.Log("error send message! ");
				}
			}
		}
	}

	private class MessageCollector
	{
		public void run()
		{
			try
			{
				while (connected)
				{
					Message message = readMessage();
					if (message == null)
					{
						break;
					}
					try
					{
						if (message.command == -27)
						{
							getKey(message);
						}
						else if (message.command == -127)
						{
							Synchronous(message);
						}
						else
						{
							onRecieveMsg(message);
							gI().timeRecv = (gI().lastTimeRecv = mSystem.currentTimeMillis());
							gI().second = 0;
						}
					}
					catch (Exception)
					{
						Cout.println("LOI NHAN  MESS THU 1");
					}
					try
					{
						Thread.Sleep(5);
					}
					catch (Exception)
					{
						Cout.println("LOI NHAN  MESS THU 2");
					}
				}
			}
			catch (Exception ex3)
			{
				Debug.Log("error read message!");
				Debug.Log(ex3.Message.ToString());
			}
			if (!connected)
			{
				return;
			}
			if (messageHandler != null)
			{
				if (currentTimeMillis() - timeConnected > 500)
				{
					if (!isReconnectOk)
					{
						messageHandler.onDisconnected();
					}
					gI().timeDis = (gI().lasttimeDis = mSystem.currentTimeMillis());
					gI().disSecond = 0;
				}
				else if (!isReconnectOk)
				{
					messageHandler.onConnectionFail();
				}
				reconnect = false;
			}
			if (sc != null)
			{
				cleanNetwork();
			}
		}

		public void Synchronous(Message message)
		{
			try
			{
				sbyte b = message.reader().readByte();
				CRes.outz("dong bo du lieu r= " + b);
				if (b == 0)
				{
					isReconnectOk = false;
					if (mSystem.currentTimeMillis() - timeConnected > 500)
					{
						messageHandler.onDisconnected();
					}
					else
					{
						messageHandler.onConnectionFail();
					}
					gI().close();
				}
				if (b == 1)
				{
					for (int i = 0; i < vResendMessage.size(); i++)
					{
						Message message2 = (Message)vResendMessage.elementAt(i);
						CRes.outz("mss luu lai = " + message2.command);
					}
					isReconnectOk = true;
					int num = message.reader().readInt();
					int num2 = message.reader().readInt();
					CRes.outz(" 1 ..... sv nhan duoc " + num + " server tra ve " + num2);
					CRes.outz(" 2 ..... client send len " + svRecived_ClSended + " client nhan duoc " + svSended_ClRecived);
					if (num != svRecived_ClSended)
					{
						int num3 = vResendMessage.size() - (svRecived_ClSended - num);
						if (num3 < 0)
						{
							num3 = 0;
						}
						CRes.outz("index= " + num3);
						gI().resendMessageFromIndex(num3);
					}
				}
				if (b == 2)
				{
					sysComplete = true;
					svSended_ClRecived = 0;
					svRecived_ClSended = 0;
					vResendMessage.removeAllElements();
				}
				CRes.outz("reconnect ok=" + isReconnectOk);
			}
			catch (Exception ex)
			{
				Debug.Log(ex.StackTrace.ToString());
			}
		}

		private void getKey(Message message)
		{
			try
			{
				sbyte b = message.reader().readSByte();
				if (b != 0)
				{
					Session_ME.key = new sbyte[b];
					for (int i = 0; i < b; i++)
					{
						Session_ME.key[i] = message.reader().readSByte();
					}
					for (int j = 0; j < Session_ME.key.Length - 1; j++)
					{
						sbyte[] key = Session_ME.key;
						int num = j + 1;
						key[num] ^= Session_ME.key[j];
					}
					getKeyComplete = true;
					string sessionID = message.reader().readUTF();
					if (!reconnect)
					{
						gI().sessionID = sessionID;
					}
				}
				if (reconnect)
				{
					gI().sendSessionID(0);
				}
			}
			catch (Exception)
			{
			}
		}

		private Message readMessage2(sbyte cmd)
		{
			int num = 0;
			sbyte b = dis.ReadSByte();
			sbyte b2 = dis.ReadSByte();
			sbyte b3 = dis.ReadSByte();
			sbyte b4 = dis.ReadSByte();
			num = ((b & 0xFF) << 24) | ((b2 & 0xFF) << 16) | ((b3 & 0xFF) << 8) | (b4 & 0xFF);
			CRes.outz("----------SIZE = " + num + "      " + cmd);
			sbyte[] array = new sbyte[num];
			byte[] src = dis.ReadBytes(num);
			Buffer.BlockCopy(src, 0, array, 0, num);
			recvByteCount += 5 + num;
			Message message = new Message(cmd, array);
			if (!isSpecialMess(message))
			{
				svSended_ClRecived++;
			}
			return message;
		}

		private Message readMessage()
		{
			try
			{
				sbyte b = dis.ReadSByte();
				if (getKeyComplete)
				{
					b = readKey(b);
				}
				if (Session_Cmd.isBigMessage(b))
				{
					return readMessage2(b);
				}
				int num;
				if (getKeyComplete)
				{
					sbyte b2 = dis.ReadSByte();
					sbyte b3 = dis.ReadSByte();
					num = ((readKey(b2) & 0xFF) << 8) | (readKey(b3) & 0xFF);
				}
				else
				{
					sbyte b4 = dis.ReadSByte();
					sbyte b5 = dis.ReadSByte();
					num = (b4 & 0xFF00) | (b5 & 0xFF);
				}
				sbyte[] array = new sbyte[num];
				int num2 = 0;
				int num3 = 0;
				byte[] src = dis.ReadBytes(num);
				Buffer.BlockCopy(src, 0, array, 0, num);
				recvByteCount += 5 + num;
				int num4 = recvByteCount + sendByteCount;
				strRecvByteCount = num4 / 1024 + "." + num4 % 1024 / 102 + "Kb";
				if (getKeyComplete)
				{
					for (int i = 0; i < array.Length; i++)
					{
						array[i] = readKey(array[i]);
					}
				}
				Message message = new Message(b, array);
				if (!isSpecialMess(message))
				{
					svSended_ClRecived++;
				}
				return message;
			}
			catch (Exception ex)
			{
				Debug.Log(ex.StackTrace.ToString());
			}
			return null;
		}
	}

	private class RunGame
	{
		public void run()
		{
			while (true)
			{
				try
				{
					Thread.Sleep(5000);
					gI().checkConnection();
				}
				catch (Exception ex)
				{
					CRes.outz("check Connection FAILED " + ex.StackTrace.ToString());
				}
			}
		}
	}

	protected static Session_ME instance = new Session_ME();

	private static NetworkStream dataStream;

	private static BinaryReader dis;

	private static BinaryWriter dos;

	public static IMessageHandler messageHandler;

	private static TcpClient sc;

	public static bool connected;

	public static bool connecting;

	private static Sender sender = new Sender();

	public static Thread initThread;

	public static Thread collectorThread;

	public static Thread sendThread;

	public static int sendByteCount;

	public static int recvByteCount;

	private static bool getKeyComplete;

	private static bool sysComplete = true;

	public static sbyte[] key = null;

	private static sbyte curR;

	private static sbyte curW;

	private bool firstTimeConnect;

	private bool firstTimeOpenGame = true;

	private static int timeConnected;

	public static string strRecvByteCount = string.Empty;

	public static int svSended_ClRecived;

	public static int svRecived_ClSended;

	private int reconnectTurn;

	public static bool isCancel;

	private string host;

	private int port;

	private int lastPort;

	private string lastHost;

	public static MyVector vResendMessage = new MyVector();

	public string sessionID;

	public static MyVector recieveMsg = new MyVector();

	public static bool reconnect;

	public static bool isReconnectOk = true;

	public long timeRecv = mSystem.currentTimeMillis();

	public long lastTimeRecv = mSystem.currentTimeMillis();

	public long timeDis = mSystem.currentTimeMillis();

	public long lasttimeDis = mSystem.currentTimeMillis();

	public int second;

	public int disSecond;

	public static bool bRun;

	public Session_ME()
	{
		Debug.Log("init Session_ME");
		new Thread(new RunGame().run).Start();
	}

	public void clearSendingMessage()
	{
		sender.sendingMessage.Clear();
	}

	public static Session_ME gI()
	{
		if (instance == null)
		{
			instance = new Session_ME();
		}
		return instance;
	}

	public bool isConnected()
	{
		return connected;
	}

	public void setHandler(IMessageHandler msgHandler)
	{
		messageHandler = msgHandler;
	}

	public void connect(string host, int port)
	{
		Debug.Log("connect ...!" + connected + "  ::  " + connecting);
		if (!connected && !connecting)
		{
			this.host = host;
			this.port = port;
			Debug.Log("connecting...!");
			Debug.Log("host: " + host);
			Debug.Log("port: " + port);
			initThread = new Thread(NetworkInit);
			initThread.Start();
			lastHost = host;
			lastPort = port;
		}
	}

	public void reConnect(string host, int port)
	{
		reconnectTurn++;
		connect(host, port);
		CRes.outz("message chưa gửi = " + sender.sendingMessage.Count);
	}

	private void NetworkInit()
	{
		isCancel = false;
		connecting = true;
		Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;
		connected = true;
		try
		{
			doConnect(host, port);
			messageHandler.onConnectOK();
			firstTimeOpenGame = false;
			reconnectTurn = 0;
		}
		catch (Exception)
		{
			if (messageHandler != null)
			{
				close();
				if (!isReconnectOk || !firstTimeConnect)
				{
					messageHandler.onConnectionFail();
				}
			}
		}
	}

	public void doConnect(string host, int port)
	{
		sc = new TcpClient();
		sc.Connect(host, port);
		dataStream = sc.GetStream();
		dis = new BinaryReader(dataStream, new UTF8Encoding());
		dos = new BinaryWriter(dataStream, new UTF8Encoding());
		new Thread(sender.run).Start();
		MessageCollector messageCollector = new MessageCollector();
		Cout.LogError("new -----");
		collectorThread = new Thread(messageCollector.run);
		collectorThread.Start();
		timeConnected = currentTimeMillis();
		connecting = false;
		Message m = new Message(-27);
		doSendMessage(m);
	}

	private static bool isSpecialMess(Message message)
	{
		return message.command == -27 || message.command == -127 || message.command == -102;
	}

	public void sendMessage(Message message)
	{
		sender.AddMessage(message);
		if (vResendMessage.size() < 200)
		{
			if (!isSpecialMess(message))
			{
				vResendMessage.addElement(message);
			}
		}
		else
		{
			vResendMessage.removeElementAt(0);
		}
	}

	public void resendMessageFromIndex(int index)
	{
		try
		{
			for (int i = index; i < vResendMessage.size(); i++)
			{
				Message message = (Message)vResendMessage.elementAt(i);
				doSendMessage(message);
				CRes.outz("gui lai message " + message.command);
			}
			sendSessionID(2);
		}
		catch (Exception ex)
		{
			CRes.outz(ex.StackTrace.ToString());
		}
		vResendMessage.removeAllElements();
	}

	public void recevieSessionID(string sessionID)
	{
		this.sessionID = sessionID;
		CRes.outz("nhan session " + sessionID);
	}

	public void sendSessionID(sbyte type)
	{
		CRes.outz("sendSession" + sessionID);
		if (sessionID == null)
		{
			sysComplete = true;
			getKeyComplete = true;
			return;
		}
		try
		{
			Message message = new Message((sbyte)(-127));
			message.writer().write(type);
			if (type == 0)
			{
				message.writer().writeUTF(sessionID);
				message.writer().writeInt(svRecived_ClSended);
				message.writer().writeInt(svSended_ClRecived);
				doSendMessage(message);
			}
			CRes.outz("gui len server da send= " + svSended_ClRecived + " da nhan = " + svRecived_ClSended);
		}
		catch (IOException ex)
		{
			Debug.Log(ex.StackTrace.ToString());
		}
	}

	private static void doSendMessage(Message m)
	{
		sbyte[] data = m.getData();
		try
		{
			if (getKeyComplete)
			{
				sbyte value = writeKey(m.command);
				dos.Write(value);
			}
			else
			{
				dos.Write(m.command);
			}
			if (data != null)
			{
				int num = data.Length;
				if (getKeyComplete)
				{
					int num2 = writeKey((sbyte)(num >> 8));
					dos.Write((sbyte)num2);
					int num3 = writeKey((sbyte)(num & 0xFF));
					dos.Write((sbyte)num3);
				}
				else
				{
					dos.Write((ushort)num);
				}
				if (getKeyComplete)
				{
					for (int i = 0; i < data.Length; i++)
					{
						sbyte value2 = writeKey(data[i]);
						dos.Write(value2);
					}
				}
				else if (m.command == -27)
				{
					if (!reconnect)
					{
						dos.Write((sbyte)(-1));
					}
					else
					{
						dos.Write((sbyte)0);
					}
				}
				sendByteCount += 5 + data.Length;
			}
			else
			{
				if (getKeyComplete)
				{
					int num4 = 0;
					int num5 = writeKey((sbyte)(num4 >> 8));
					dos.Write((sbyte)num5);
					int num6 = writeKey((sbyte)(num4 & 0xFF));
					dos.Write((sbyte)num6);
				}
				else
				{
					dos.Write((ushort)0);
				}
				sendByteCount += 5;
			}
			dos.Flush();
		}
		catch (Exception ex)
		{
			Debug.Log(ex.StackTrace);
		}
	}

	public static sbyte readKey(sbyte b)
	{
		sbyte result = (sbyte)((key[curR++] & 0xFF) ^ (b & 0xFF));
		if (curR >= key.Length)
		{
			curR %= (sbyte)key.Length;
		}
		return result;
	}

	public static sbyte writeKey(sbyte b)
	{
		sbyte result = (sbyte)((key[curW++] & 0xFF) ^ (b & 0xFF));
		if (curW >= key.Length)
		{
			curW %= (sbyte)key.Length;
		}
		return result;
	}

	public static void onRecieveMsg(Message msg)
	{
		if (Thread.CurrentThread.Name == Main.mainThreadName)
		{
			messageHandler.onMessage(msg);
		}
		else
		{
			recieveMsg.addElement(msg);
		}
	}

	public static void update()
	{
		while (recieveMsg.size() > 0)
		{
			Message message = (Message)recieveMsg.elementAt(0);
			if (MessageHandler.isStopReadMessage)
			{
				break;
			}
			if (message == null)
			{
				recieveMsg.removeElementAt(0);
				break;
			}
			messageHandler.onMessage(message);
			recieveMsg.removeElementAt(0);
		}
	}

	public void close()
	{
		recieveMsg.removeAllElements();
		cleanNetwork();
	}

	public void checkConnection()
	{
		try
		{
			if (firstTimeOpenGame)
			{
				return;
			}
			if (isConnected() && !connecting)
			{
				lastTimeRecv = mSystem.currentTimeMillis();
				second = (int)(lastTimeRecv - timeRecv) / 1000;
				if (second <= 15)
				{
					return;
				}
				close();
				sysComplete = false;
				if (messageHandler == null)
				{
					return;
				}
				if (mSystem.currentTimeMillis() - timeConnected > 500)
				{
					if (!isReconnectOk)
					{
						messageHandler.onDisconnected();
					}
					timeDis = (lasttimeDis = mSystem.currentTimeMillis());
					disSecond = 0;
				}
				else if (!isReconnectOk)
				{
					messageHandler.onConnectionFail();
				}
			}
			else
			{
				if (connecting)
				{
					return;
				}
				lastTimeRecv = (timeRecv = mSystem.currentTimeMillis());
				if (reconnect)
				{
					return;
				}
				lasttimeDis = mSystem.currentTimeMillis();
				disSecond = (int)(lasttimeDis - timeDis) / 1000;
				if (disSecond >= 5)
				{
					reconnect = true;
					disSecond = 0;
					sysComplete = false;
					if (reconnectTurn >= 4)
					{
						close();
						sysComplete = true;
						sessionID = null;
						firstTimeConnect = false;
						reconnect = false;
						connect(lastHost, lastPort);
					}
					else if (!isConnected())
					{
						reConnect(lastHost, lastPort);
					}
				}
			}
		}
		catch (Exception ex)
		{
			CRes.outz(ex.StackTrace.ToString());
		}
	}

	private static void cleanNetwork()
	{
		CRes.outz("mat ket noi da gui len tong cong " + svRecived_ClSended + " nhan ve tong cong " + svSended_ClRecived);
		curR = 0;
		curW = 0;
		gI().timeDis = (gI().lasttimeDis = mSystem.currentTimeMillis());
		gI().timeRecv = (gI().lastTimeRecv = mSystem.currentTimeMillis());
		try
		{
			getKeyComplete = false;
			key = null;
			reconnect = false;
			connected = false;
			connecting = false;
			if (sc != null)
			{
				sc.Close();
				sc = null;
			}
			if (dataStream != null)
			{
				dataStream.Close();
				dataStream = null;
			}
			if (dos != null)
			{
				dos.Close();
				dos = null;
			}
			if (dis != null)
			{
				dis.Close();
				dis = null;
			}
			sendThread = null;
			collectorThread = null;
		}
		catch (Exception)
		{
		}
	}

	public static int currentTimeMillis()
	{
		return Environment.TickCount;
	}

	public static byte convertSbyteToByte(sbyte var)
	{
		if (var > 0)
		{
			return (byte)var;
		}
		return (byte)(var + 256);
	}

	public static byte[] convertSbyteToByte(sbyte[] var)
	{
		byte[] array = new byte[var.Length];
		for (int i = 0; i < var.Length; i++)
		{
			if (var[i] > 0)
			{
				array[i] = (byte)var[i];
			}
			else
			{
				array[i] = (byte)(var[i] + 256);
			}
		}
		return array;
	}

	public void clearReconnect()
	{
		sessionID = null;
		reconnect = false;
	}
}
