using Apewer;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace Apewer.Network
{

    /// <summary>UDP 服务端。</summary>
    public class UdpServer : IDisposable
    {

        /// <summary>释放资源。</summary>
        public void Dispose() { Quit(); }

        private Thread _thread = null;
        private System.Net.Sockets.UdpClient _udp = null;

        private string _address = "0.0.0.0";
        private int _port = 0;

        /// <summary>Exception。</summary>
        public Event<Exception> Excepted { get; set; }

        /// <summary>服务端已启动。</summary>
        public Event Started { get; set; }

        /// <summary>服务端已关闭。</summary>
        public Event Quitted { get; set; }

        /// <summary>已收到客户端数据。</summary>
        public Event<SocketReceived> Received { get; set; }

        /// <summary>构造函数。</summary>
        public UdpServer()
        {
        }

        /// <summary>服务端是否正在运行。</summary>
        public bool Alive
        {
            get { return (_thread != null) ? _thread.IsAlive : false; }
        }

        /// <summary>指定监听地址,默认为 0.0.0.0。</summary>
        public string Address
        {
            get { return _address; }
            set { if (!Alive) _address = string.IsNullOrEmpty(value) ? "" : value; }
        }

        /// <summary>获取或设置服务端端口。</summary>
        public int Port
        {
            get { return _port; }
            set
            {
                int vp = value;
                if (vp < 0) vp = 0;
                if (vp > 65535) vp = 65535;
                if (!Alive) _port = vp;
            }
        }

        /// <summary>启动服务端。</summary>
        public void Start()
        {
            Quit();
            var isIP = NetworkUtility.IsIP(_address);
            if (isIP && (Port > 0))
            {
                _thread = new Thread(Listener);
                _thread.IsBackground = true;
                _thread.Start();
            }
        }

        /// <summary>关闭服务端。</summary>
        public void Quit()
        {
            if (_thread != null)
            {
                if (_thread.IsAlive) _thread.Abort();
                _thread = null;
            }
            if (_udp != null)
            {
                _udp.Close();
                _udp = null;
                Quitted?.Invoke(this);
            }
        }

        private void Listener()
        {
            try
            {
                var ep = new IPEndPoint(IPAddress.Any, Port);
                _udp = new System.Net.Sockets.UdpClient(ep);
                Started?.Invoke(this);
                while (true)
                {
                    var bytes = _udp.Receive(ref ep);
                    if ((Received != null) && (bytes.Length > 0))
                    {
                        var ip = ep.Address.ToString();
                        var port = ep.Port;
                        Received?.Invoke(this, new SocketReceived(ip, ep.Port, bytes));
                    }
                    // Thread.Sleep(1);
                }
            }
            catch (Exception ex)
            {
                if (Excepted != null) Excepted(this, ex);
            }
            Quitted.Invoke(this);
        }

    }

}