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

namespace WS
{
	[ObjectSystem]
	public class SessionAwake : AwakeSystem<Session, AChannel>
	{
		public override void Awake(Session self, AChannel a)
		{
			self.Awake(a);
		}
	}

	///<summary>Session Socket链接代理</summary>
	public class Session : WSComponent
	{
		private AChannel channel;

		///<summary>Network</summary>
		public NetworkComponent Network { get { return GetParent<NetworkComponent>(); } }

		public int Error
		{
			get { return channel.Error; }
			set { channel.Error = value; }
		}

		public void Awake(AChannel aChannel)
		{
			channel = aChannel;
			long id = InstanceId;
			channel.LinkCallback += () =>
			{
#if !SERVER
				Log.LogDebug("链接服务器成功");
				OnLinkCallback?.Invoke();
#endif
			};
			channel.ErrorCallback += (c, e) =>
			{
				Log.LogError($"Socket链接错误,错误ID:{e}");
				OnErrorCallback?.Invoke(e);
				Network.Remove(id);
			};
			channel.ReadCallback += OnRead;
		}

        public override void Dispose()
		{
			Network.Remove(InstanceId);
			base.Dispose();
			channel.Dispose();
			OnLinkCallback = null;
			OnErrorCallback = null;
		}

        public void Start()
		{
			channel.Start();
		}

		public IPEndPoint RemoteAddress { get { return channel.RemoteAddress; } }

		public ChannelType ChannelType { get { return channel.ChannelType; } }

		public MemoryStream Stream { get { return channel.Stream; } }

		///<summary>链接成功</summary>
		public Action OnLinkCallback;

		///<summary>网络错误回调</summary>
		public Action<int> OnErrorCallback;

		///<summary>接收到网络消息的回调</summary>
		public void OnRead(MemoryStream memoryStream)
		{
			try
			{
				Run(memoryStream);
			}
			catch (Exception e)
			{
				Log.LogError(e);
			}
		}

		///<summary>接收消息</summary>
		private void Run(MemoryStream memoryStream)
		{
			try
			{
				memoryStream.Seek(Packet.OpcodeIndex, SeekOrigin.Begin);
				byte opcode = (byte)memoryStream.ReadByte();
				IProto proto = Network.Proto.GetReceiveProto(opcode);
				if (proto != null)
				{
					memoryStream.Seek(Packet.MessageIndex, SeekOrigin.Begin);
					proto.Read(memoryStream);
#if !SERVER
					Network.Event.Dispatch(opcode, proto);//发送消息
#else
					Network.Event.Dispatch(opcode, this, proto);//发送消息
#endif
					memoryStream.Seek(Packet.OpcodeIndex, SeekOrigin.Begin);//将流的位置归0
				}
				else
				{
					Log.LogError($"协议:{opcode} 未找到");
					Error = ErrorCode.ERR_PacketParserError;
				}
			}
			catch (Exception e)
			{
				Log.LogError(e);
				Error = ErrorCode.ERR_PacketParserError;
			}
		}

		///<summary>发送消息</summary>
		public void Send(IProto proto)
		{
			MemoryStream stream = Stream;
			stream.Seek(Packet.OpcodeIndex, SeekOrigin.Begin);//设置流的开始位置
			stream.WriteByte(proto.Opcode);//写入协议编号
			stream.Seek(Packet.PacketSizeLength4, SeekOrigin.Begin);//设置流到包体开始位置
			int count = proto.Write(stream);//将包体写入流
			stream.SetLength(count);
			stream.Seek(Packet.MessageIndex, SeekOrigin.Begin);//设置流的位置到包体长度的位置
			stream.WriteInt(count - Packet.PacketSizeLength4);//将包体的长度写入流
			stream.Seek(Packet.OpcodeIndex, SeekOrigin.Begin);//将流的位置归0
			Send(stream);
#if SERVER
			ProtoComponent component = (ProtoComponent)proto;
			component.Dispose();
#endif
		}

		///<summary>启用代理发送消息</summary>
		private void Send(MemoryStream stream)
		{
			channel.Send(stream);
		}
	}
}