using System;

namespace SharpQuake
{
	internal class net_loop : INetDriver
	{
		public string Name
		{
			get
			{
				return "Loopback";
			}
		}

		public bool IsInitialized
		{
			get
			{
				return this._IsInitialized;
			}
		}

		public void Init()
		{
			if (client.cls.state == cactive_t.ca_dedicated)
			{
				return;
			}
			this._IsInitialized = true;
		}

		public void Listen(bool state)
		{
		}

		public void SearchForHosts(bool xmit)
		{
			if (!server.sv.active)
			{
				return;
			}
			net.HostCacheCount = 1;
			if (net.HostName == "UNNAMED")
			{
				net.HostCache[0].name = "local";
			}
			else
			{
				net.HostCache[0].name = net.HostName;
			}
			net.HostCache[0].map = server.sv.name;
			net.HostCache[0].users = net.ActiveConnections;
			net.HostCache[0].maxusers = server.svs.maxclients;
			net.HostCache[0].driver = net.DriverLevel;
			net.HostCache[0].cname = "local";
		}

		public qsocket_t Connect(string host)
		{
			if (host != "local")
			{
				return null;
			}
			this._LocalConnectPending = true;
			if (this._Client == null)
			{
				this._Client = net.NewSocket();
				if (this._Client == null)
				{
					Con.Print("Loop_Connect: no qsocket available\n", Array.Empty<object>());
					return null;
				}
				this._Client.address = "localhost";
			}
			this._Client.ClearBuffers();
			this._Client.canSend = true;
			if (this._Server == null)
			{
				this._Server = net.NewSocket();
				if (this._Server == null)
				{
					Con.Print("Loop_Connect: no qsocket available\n", Array.Empty<object>());
					return null;
				}
				this._Server.address = "LOCAL";
			}
			this._Server.ClearBuffers();
			this._Server.canSend = true;
			this._Client.driverdata = this._Server;
			this._Server.driverdata = this._Client;
			return this._Client;
		}

		public qsocket_t CheckNewConnections()
		{
			if (!this._LocalConnectPending)
			{
				return null;
			}
			this._LocalConnectPending = false;
			this._Server.ClearBuffers();
			this._Server.canSend = true;
			this._Client.ClearBuffers();
			this._Client.canSend = true;
			return this._Server;
		}

		public int GetMessage(qsocket_t sock)
		{
			if (sock.receiveMessageLength == 0)
			{
				return 0;
			}
			int num = (int)sock.receiveMessage[0];
			int num2 = (int)sock.receiveMessage[1] + ((int)sock.receiveMessage[2] << 8);
			net.Message.Clear();
			net.Message.FillFrom(sock.receiveMessage, 4, num2);
			num2 = this.IntAlign(num2 + 4);
			sock.receiveMessageLength -= num2;
			if (sock.receiveMessageLength > 0)
			{
				Array.Copy(sock.receiveMessage, num2, sock.receiveMessage, 0, sock.receiveMessageLength);
			}
			if (sock.driverdata != null && num == 1)
			{
				((qsocket_t)sock.driverdata).canSend = true;
			}
			return num;
		}

		public int SendMessage(qsocket_t sock, MsgWriter data)
		{
			if (sock.driverdata == null)
			{
				return -1;
			}
			qsocket_t qsocket_t = (qsocket_t)sock.driverdata;
			if (qsocket_t.receiveMessageLength + data.Length + 4 > 8192)
			{
				sys.Error("Loop_SendMessage: overflow\n", Array.Empty<object>());
			}
			int num = qsocket_t.receiveMessageLength;
			qsocket_t.receiveMessage[num++] = 1;
			qsocket_t.receiveMessage[num++] = (byte)(data.Length & 255);
			qsocket_t.receiveMessage[num++] = (byte)(data.Length >> 8);
			num++;
			Buffer.BlockCopy(data.Data, 0, qsocket_t.receiveMessage, num, data.Length);
			qsocket_t.receiveMessageLength = this.IntAlign(qsocket_t.receiveMessageLength + data.Length + 4);
			sock.canSend = false;
			return 1;
		}

		public int SendUnreliableMessage(qsocket_t sock, MsgWriter data)
		{
			if (sock.driverdata == null)
			{
				return -1;
			}
			qsocket_t qsocket_t = (qsocket_t)sock.driverdata;
			if (qsocket_t.receiveMessageLength + data.Length + 1 + 2 > 8192)
			{
				return 0;
			}
			int num = qsocket_t.receiveMessageLength;
			qsocket_t.receiveMessage[num++] = 2;
			qsocket_t.receiveMessage[num++] = (byte)(data.Length & 255);
			qsocket_t.receiveMessage[num++] = (byte)(data.Length >> 8);
			num++;
			Buffer.BlockCopy(data.Data, 0, qsocket_t.receiveMessage, num, data.Length);
			qsocket_t.receiveMessageLength = this.IntAlign(qsocket_t.receiveMessageLength + data.Length + 4);
			return 1;
		}

		public bool CanSendMessage(qsocket_t sock)
		{
			return sock.driverdata != null && sock.canSend;
		}

		public bool CanSendUnreliableMessage(qsocket_t sock)
		{
			return true;
		}

		public void Close(qsocket_t sock)
		{
			if (sock.driverdata != null)
			{
				((qsocket_t)sock.driverdata).driverdata = null;
			}
			sock.ClearBuffers();
			sock.canSend = true;
			if (sock == this._Client)
			{
				this._Client = null;
				return;
			}
			this._Server = null;
		}

		public void Shutdown()
		{
			this._IsInitialized = false;
		}

		private int IntAlign(int value)
		{
			return value + 3 & -4;
		}

		private bool _IsInitialized;

		private bool _LocalConnectPending;

		private qsocket_t _Client;

		private qsocket_t _Server;
	}
}
