using System;
using System.Collections.Concurrent;
using System.Text;
using System.Threading.Tasks;

namespace Plane.Communication
{
    /// <summary>
    /// （通过DTU服务端的Udp透传管道）与飞机进行通信的连接器。
    /// </summary>
    public partial class UdpThroughDtuServiceConnection : ExceptionThrownEventSource, IConnection
    {
        #region Fields
        private byte[] _currentByteArray;
        private int _currentIndex;
#if LOG_PACKETS
        private System.Text.StringBuilder _log = new System.Text.StringBuilder();
#endif
        private ConcurrentQueue<byte[]> _inputQueue = new ConcurrentQueue<byte[]>();
        /// <summary>
        /// 表示向DTU服务端飞控透传通道握手的协议头
        /// </summary>
        protected string FLAG_DTU_HANDSHAKE_HEAD = "*#$";
        /// <summary>
        /// 表示向DTU服务端的Udp飞控透传管道建立申请的结果状态
        /// </summary>
        protected enum DTUHandShakeResult
        {
            Unknown = 0,
            Successful = 1,
            NotExisted,
            Occupied,
        }
        #endregion

        #region Properties
        /// <summary>
        /// 希望连接到哪台飞机
        /// </summary>
        public string CopterIDToBind { get; set; }

        public bool IsOpen { get; private set; }

        /// <summary>
        /// 获取即将或正在与服务端连接的服务端IP
        /// </summary>
        public string DtuServiceIP { get; set; }

        /// <summary>
        /// 获取即将或正在与服务端连接的服务端端口
        /// </summary>
        public int DtuServicePort { get; set; }
        #endregion

        public virtual async Task<int> ReadAsync(byte[] buffer, int offset, int size)
        {
            if (!IsOpen)
            {
                return 0;
            }
            try
            {
                var indexLessThan = offset + size;
                for (int i = offset; i < indexLessThan; i++, _currentIndex++)
                {
                    while (_currentByteArray == null || _currentIndex >= _currentByteArray.Length)
                    {
                        while (_inputQueue.Count <= 0)
                        {
                            if (!IsOpen)
                            {
                                return 0;
                            }
                            await Task.Delay(5).ConfigureAwait(false);
                        }
                        while (!_inputQueue.TryDequeue(out _currentByteArray))
                        {
                            if (!IsOpen)
                            {
                                return 0;
                            }
                            await Task.Delay(5).ConfigureAwait(false);
                        }
                        _currentIndex = 0;
                    }
                    buffer[i] = _currentByteArray[_currentIndex];
                }
                return size;
            }
            catch (Exception ex)
            {
                RaiseExceptionThrown(ex);
                return 0;
            }
        }

        public virtual async Task WriteAsync(byte[] buffer, int offset, int count)
        {
            if (IsOpen)
            {
                try
                {
                    if (offset == 0)
                    {
                        await SendAsync(buffer, count);
                    }
                    else
                    {
                        var data = new byte[count];
                        for (int i = 0, j = offset; i < count; i++, j++)
                        {
                            data[i] = buffer[j];
                        }
                        await SendAsync(data, count);
                    }
                }
                catch (Exception ex)
                {
                    Close();
                    RaiseExceptionThrown(ex);
                }
            }
        }

        internal void EnqueueDatagram(byte[] datagram)
        {
            if (datagram != null && IsOpen)
            {
#if LOG_PACKETS
                _log.AppendLine("------------");
                for (int i = 0; i < datagram.Length; i++)
                {
                    _log.Append(datagram[i]).Append(" ");
                }
                _log.AppendLine();
#endif
                _inputQueue.Enqueue(datagram);
            }
        }

        /// <summary>
        /// 构建用于发向DTU服务端的握手包
        /// </summary>
        /// <returns></returns>
        protected virtual byte[] ConstructHandShakeDatagramToDTUService()
        {
            var str = string.Format("{0}{1}", FLAG_DTU_HANDSHAKE_HEAD, CopterIDToBind??string.Empty);
            return Encoding.ASCII.GetBytes(str);
        }

        /// <summary>
        /// 分析由DTU服务端返回的我握手包
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        protected virtual DTUHandShakeResult AnalyzeHandShakeDatagramFromDTUService(byte[] buffer)
        {
            var strResult = Encoding.ASCII.GetString(buffer);//返回的格式为“*#$xxxx|0”
            if (strResult.StartsWith(FLAG_DTU_HANDSHAKE_HEAD))
            {
                var strList = strResult.Substring(FLAG_DTU_HANDSHAKE_HEAD.Length).Split('|');
                var copterID = strList[0];
                int iValue;
                int.TryParse(strList[1], out iValue);
                return (DTUHandShakeResult)iValue;
            }
            return DTUHandShakeResult.Unknown;
        }
    }
}
