using System;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace SharpQuake
{
	internal class MsgWriter
	{
		public byte[] Data
		{
			get
			{
				return this._Buffer;
			}
		}

		public bool IsEmpty
		{
			get
			{
				return this._Count == 0;
			}
		}

		public int Length
		{
			get
			{
				return this._Count;
			}
		}

		public bool AllowOverflow { get; set; }

		public bool IsOveflowed { get; set; }

		public int Capacity
		{
			get
			{
				return this._Buffer.Length;
			}
			set
			{
				this.SetBufferSize(value);
			}
		}

		public object GetState()
		{
			object result = null;
			this.SaveState(ref result);
			return result;
		}

		public void SaveState(ref object state)
		{
			if (state == null)
			{
				state = new MsgWriter.State();
			}
			MsgWriter.State state2 = this.GetState(state);
			if (state2.Buffer == null || state2.Buffer.Length != this._Buffer.Length)
			{
				state2.Buffer = new byte[this._Buffer.Length];
			}
			Buffer.BlockCopy(this._Buffer, 0, state2.Buffer, 0, this._Buffer.Length);
			state2.Count = this._Count;
		}

		public void RestoreState(object state)
		{
			MsgWriter.State state2 = this.GetState(state);
			this.SetBufferSize(state2.Buffer.Length);
			Buffer.BlockCopy(state2.Buffer, 0, this._Buffer, 0, this._Buffer.Length);
			this._Count = state2.Count;
		}

		public void WriteChar(int c)
		{
			this.NeedRoom(1);
			byte[] buffer = this._Buffer;
			int count = this._Count;
			this._Count = count + 1;
			buffer[count] = (byte)c;
		}

		public void WriteByte(int c)
		{
			this.NeedRoom(1);
			byte[] buffer = this._Buffer;
			int count = this._Count;
			this._Count = count + 1;
			buffer[count] = (byte)c;
		}

		public void WriteShort(int c)
		{
			this.NeedRoom(2);
			byte[] buffer = this._Buffer;
			int count = this._Count;
			this._Count = count + 1;
			buffer[count] = (byte)(c & 255);
			byte[] buffer2 = this._Buffer;
			count = this._Count;
			this._Count = count + 1;
			buffer2[count] = (byte)(c >> 8);
		}

		public void WriteLong(int c)
		{
			this.NeedRoom(4);
			byte[] buffer = this._Buffer;
			int count = this._Count;
			this._Count = count + 1;
			buffer[count] = (byte)(c & 255);
			byte[] buffer2 = this._Buffer;
			count = this._Count;
			this._Count = count + 1;
			buffer2[count] = (byte)(c >> 8 & 255);
			byte[] buffer3 = this._Buffer;
			count = this._Count;
			this._Count = count + 1;
			buffer3[count] = (byte)(c >> 16 & 255);
			byte[] buffer4 = this._Buffer;
			count = this._Count;
			this._Count = count + 1;
			buffer4[count] = (byte)(c >> 24);
		}

		public void WriteFloat(float f)
		{
			this.NeedRoom(4);
			this._Val.f0 = f;
			this._Val.i0 = common.LittleLong(this._Val.i0);
			byte[] buffer = this._Buffer;
			int count = this._Count;
			this._Count = count + 1;
			buffer[count] = this._Val.b0;
			byte[] buffer2 = this._Buffer;
			count = this._Count;
			this._Count = count + 1;
			buffer2[count] = this._Val.b1;
			byte[] buffer3 = this._Buffer;
			count = this._Count;
			this._Count = count + 1;
			buffer3[count] = this._Val.b2;
			byte[] buffer4 = this._Buffer;
			count = this._Count;
			this._Count = count + 1;
			buffer4[count] = this._Val.b3;
		}

		public void WriteString(string s)
		{
			int num = 1;
			if (!string.IsNullOrEmpty(s))
			{
				num += s.Length;
			}
			this.NeedRoom(num);
			int count;
			for (int i = 0; i < num - 1; i++)
			{
				byte[] buffer = this._Buffer;
				count = this._Count;
				this._Count = count + 1;
				buffer[count] = (byte)s[i];
			}
			byte[] buffer2 = this._Buffer;
			count = this._Count;
			this._Count = count + 1;
			buffer2[count] = 0;
		}

		public void Print(string s)
		{
			if (this._Count > 0 && this._Buffer[this._Count - 1] == 0)
			{
				this._Count--;
			}
			this.WriteString(s);
		}

		public void WriteCoord(float f)
		{
			this.WriteShort((int)(f * 8f));
		}

		public void WriteAngle(float f)
		{
			this.WriteByte((int)f * 256 / 360 & 255);
		}

		public void Write(byte[] src, int offset, int count)
		{
			if (count > 0)
			{
				this.NeedRoom(count);
				Buffer.BlockCopy(src, offset, this._Buffer, this._Count, count);
				this._Count += count;
			}
		}

		public void Clear()
		{
			this._Count = 0;
		}

		public void FillFrom(Stream src, int count)
		{
			this.Clear();
			this.NeedRoom(count);
			while (this._Count < count)
			{
				int num = src.Read(this._Buffer, this._Count, count - this._Count);
				if (num == 0)
				{
					break;
				}
				this._Count += num;
			}
		}

		public void FillFrom(byte[] src, int startIndex, int count)
		{
			this.Clear();
			this.NeedRoom(count);
			Buffer.BlockCopy(src, startIndex, this._Buffer, 0, count);
			this._Count = count;
		}

		public int FillFrom(Socket socket, ref EndPoint ep)
		{
			this.Clear();
			int num = net.LanDriver.Read(socket, this._Buffer, this._Buffer.Length, ref ep);
			if (num >= 0)
			{
				this._Count = num;
			}
			return num;
		}

		public void AppendFrom(byte[] src, int startIndex, int count)
		{
			this.NeedRoom(count);
			Buffer.BlockCopy(src, startIndex, this._Buffer, this._Count, count);
			this._Count += count;
		}

		protected void NeedRoom(int bytes)
		{
			if (this._Count + bytes > this._Buffer.Length)
			{
				if (!this.AllowOverflow)
				{
					sys.Error("MsgWriter: overflow without allowoverflow set!", Array.Empty<object>());
				}
				this.IsOveflowed = true;
				this._Count = 0;
				if (bytes > this._Buffer.Length)
				{
					sys.Error("MsgWriter: Requested more than whole buffer has!", Array.Empty<object>());
				}
			}
		}

		private void SetBufferSize(int value)
		{
			if (this._Buffer != null)
			{
				if (this._Buffer.Length == value)
				{
					return;
				}
				Array.Resize<byte>(ref this._Buffer, value);
				if (this._Count > this._Buffer.Length)
				{
					this._Count = this._Buffer.Length;
					return;
				}
			}
			else
			{
				this._Buffer = new byte[value];
			}
		}

		private MsgWriter.State GetState(object state)
		{
			if (state == null)
			{
				throw new ArgumentNullException();
			}
			MsgWriter.State state2 = state as MsgWriter.State;
			if (state2 == null)
			{
				throw new ArgumentException("Passed object is not a state!");
			}
			return state2;
		}

		public MsgWriter() : this(0)
		{
		}

		public MsgWriter(int capacity)
		{
			this.SetBufferSize(capacity);
			this.AllowOverflow = false;
		}

		private byte[] _Buffer;

		private int _Count;

		private Union4b _Val = Union4b.Empty;

		private class State
		{
			public byte[] Buffer;

			public int Count;
		}
	}
}
