using System;
using System.IO;

namespace WS
{
    ///<summary>解析器状态</summary>
    public enum ParserState
	{
		///<summary>解析头</summary>
		PacketSize,
		///<summary>解析体</summary>
		PacketBody
	}

	///<summary>解析器</summary>
	public static class Packet
	{
		///<summary>包头的长度 2</summary>
		public const int PacketSizeLength2 = 3;//int16(2个字节)
		///<summary>包头的长度 4</summary>
		public const int PacketSizeLength4 = 5;//int32(4个字节)
		///<summary>包体最小长度</summary>
		public const int MinPacketSize = 2;
		public const int OpcodeIndex = 0;
		///<summary>协议编号的长度</summary>
		public const int MessageIndex = 1;
	}

	///<summary>网络消息包解析器</summary>
	public class PacketParser
    {
		/// <summary>数据</summary>
		private readonly CircularBuffer buffer;
		/// <summary>包体的长度</summary>
		private int packetSize;
		/// <summary>解析器状态状态</summary>
		private ParserState state;
		/// <summary>流操作</summary>
		public MemoryStream memoryStream;
		///<summary>是否成功</summary>
		private bool isOK;
		/// <summary>包头长度</summary>
		private readonly int packetSizeLength;

		/// <summary>构造函数</summary>
		/// <param name="packetSizeLength">包头长度</param>
		/// <param name="buffer">数据</param>
		/// <param name="memoryStream">流操作</param>
		public PacketParser(int packetSizeLength, CircularBuffer buffer, MemoryStream memoryStream)
		{
			this.packetSizeLength = packetSizeLength;
			this.buffer = buffer;
			this.memoryStream = memoryStream;
		}

		///<summary>解析</summary>
		public bool Parse()
		{
			if (isOK) return isOK;

			bool finish = false;//完成？
			while (!finish)
			{
				switch (state)
				{
					case ParserState.PacketSize://解头
						if (buffer.Length < packetSizeLength)//buffer的长度是否小于包头的长度
						{
							finish = true;
						}
						else
						{
							memoryStream.Seek(Packet.OpcodeIndex, SeekOrigin.Begin);
							memoryStream.SetLength(packetSizeLength);
							buffer.Read(memoryStream.GetBuffer(), 0, packetSizeLength);//buffer的数据写到memoryStream

							switch (packetSizeLength)//判断包头长度
							{
								case Packet.PacketSizeLength4://int32
									memoryStream.Seek(Packet.MessageIndex, SeekOrigin.Begin);
									packetSize = memoryStream.ReadInt();//读取包头，并且赋值 packetSize
									if (packetSize > ushort.MaxValue * 16)//判断包头是否异常 
									{
										throw new Exception($"recv packet size error, 可能是外网探测端口: {packetSize}");
									}
									break;
								case Packet.PacketSizeLength2://int16
									memoryStream.Seek(Packet.MessageIndex, SeekOrigin.Begin);
									packetSize = memoryStream.ReadUShort();//读取包头，并且赋值 packetSize
									if (packetSize > ushort.MaxValue)//判断包头是否异常
									{
										throw new Exception($"recv packet size error:, 可能是外网探测端口: {packetSize}");
									}
									break;
								default:
									throw new Exception("packet size byte count must be 2 or 4!");
							}
							state = ParserState.PacketBody;//切换到解包体状态
						}
						break;
					case ParserState.PacketBody://解包体
						if (buffer.Length < packetSize)
						{
							finish = true;
						}
						else
						{
							memoryStream.Seek(Packet.OpcodeIndex, SeekOrigin.Begin);//指定流的开始位置
							memoryStream.SetLength(packetSize + 1);//把流的长度设为 packetSize 的值
							byte[] bytes = memoryStream.GetBuffer();
							buffer.Read(bytes, Packet.MessageIndex, packetSize);//将数据读取到 memoryStream 中
							isOK = true;
							state = ParserState.PacketSize;
							finish = true;
							memoryStream.Seek(Packet.OpcodeIndex, SeekOrigin.Begin);
						}
						break;
				}
			}
			return isOK;
		}

		///<summary>获取流操作</summary>
		public MemoryStream GetPacket()
		{
			isOK = false;
			return memoryStream;
		}
	}
}