using System;
using System.Threading;
using System.Threading.Tasks;

namespace PlaneGcsSdk.Contract.DtuClient
{
    public partial class EhNetLoginMgr
    {
        #region Fields
        private AutoResetEvent _loginEnNet;
        private AutoResetEvent _sendRndCodeSignal;
        private AutoResetEvent _sendBindCopterIDSignal;
        private AutoResetEvent _sendUpdHandshakeSignal;
        private AutoResetEvent _requestCopterListSignal;
        private const string Protocol_SendRandCode = "J001";        //表示向服务器请求“发送随机码”的协议号
        private const string Protocol_SendRandCode_Reply = "J002";  //表示服务端返回“请求发送随机码”的应答协议号
        private const string Protocol_BindCopterID = "J003";        //表示向服务器请求“绑定飞机”的协议号
        private const string Protocol_BindCopterID_Reply = "J004";  //表示服务端返回“请求绑定飞机”的应答协议号
        private const string Protocol_RequestCopterList = "J007";   //表示向服务器请求“飞机列表”的请求协议号
        private const string Protocol_ReceivedCopterItem = "J008";  //表示服务端返回“飞机列表中的一个飞机”的推送协议号
        private const string Protocol_RecievedCopterInvailed = "J206";//表示由服务端通告“您所绑定的飞机已无效”的推送协议好
                                                                    
        private string _errorCode;                                  //请求过程由服务端返回的错误码的缓存变量
        private string _errorCodeForRequestCopterList;              //专为缓存“请求飞机列表”结果的错误号变量
        private const string ErrorCode_Succeed = "0000";            //表示执行成功的错误码
        private const string ErrorCode_EndCopterList = "0003";      //表示服务端返回“飞机列表完毕”的协议号
        private CopterEntity _nextCopter;                           //当前请求的飞机实体
        private string _usersname;                                  //当前登录的账号
        private const string DtuServerUsername = "10000";           // 在PLNet登陆体系里Dtu服务端的用户名
        #endregion

        #region Properties
        /// <summary>
        /// 在PLNet登陆体系里的用户别名
        /// </summary>
        public string NickName { get; protected set; }

        /// <summary>
        /// PLNet服务端的IP
        /// </summary>
        public string ServerIp { get; set; }
        /// <summary>
        /// PLNet服务端的监听端口
        /// </summary>
        public int ServerPort { get; set; }
        /// <summary>
        /// 表示当前所处的PLNet-Dtu连接状态（比如已登录PLNet，但没有建立Dtu透传管道）
        /// </summary>
        public ProcessStep ProcessSetp { get; protected set; }
        /// <summary>
        /// 登陆后获得的随机码
        /// </summary>
        public int RandCode { get; protected set; }
        /// <summary>
        /// 用于建立透传管道的Udp端口。
        /// </summary>
        public const int DTU_USER_PORT = 5250;
        #endregion

        /// <summary>
        /// 当前已绑定的飞机变为无效状态的事件
        /// </summary>
        public event EventHandler CopterLost;

        public EhNetLoginMgr()
        {
            _loginEnNet = new AutoResetEvent(false);
            _sendBindCopterIDSignal = new AutoResetEvent(false);
            _sendRndCodeSignal = new AutoResetEvent(false);
            _sendUpdHandshakeSignal = new AutoResetEvent(false);
            _requestCopterListSignal = new AutoResetEvent(false);

            InstanceEhNetObject();
            _PLNet.CommandArrival += _ehNet_CommandArrival;
            _PLNet.Disconnect += _ehNet_Disconnect;
            _PLNet.DiscoveredOneUser += _ehNet_DiscoveredOneUser;
            //_ehNet.ExceptionThrown += _ehNet_ExceptionThrown;
            _PLNet.Login += _ehNet_Login;
        }

        public void Dispose()
        {
            _PLNet.CommandArrival -= _ehNet_CommandArrival;
            _PLNet.Disconnect -= _ehNet_Disconnect;
            _PLNet.DiscoveredOneUser -= _ehNet_DiscoveredOneUser;
            //_ehNet.ExceptionThrown -= _ehNet_ExceptionThrown;
            _PLNet.Login -= _ehNet_Login;
        }

        #region Public Methods
        /// <summary>
        /// 登陆到PLNet网络（第三个参数决定是否在登陆成功后发起获取飞机列表的请求）。
        /// </summary>
        /// <param name="username"></param>
        /// <param name="pwd"></param>
        /// <param name="gotCopterCallBack">获得得到的飞机事件</param>
        public async Task Login(string username, string pwd, string ehNetServerIp,
            Action<CopterEntity> gotCopterCallBack = null)
        {
            if (CheckIfLogined())
            {
                return;
            }
            _usersname = username;
            await Task.Run(async () =>
            {
                await EhNetStart(ehNetServerIp, username, pwd);
                if (!_loginEnNet.WaitOne(TimeSpan.FromSeconds(10)))
                {
                    throw new Exception("登陆无响应失败！");
                }
                ProcessSetp = ProcessStep.EhNetLogin;
                if (!string.IsNullOrEmpty(_PLNet.MyRND))
                {
                    int value;
                    int.TryParse(_PLNet.MyRND, out value);
                    RandCode = value;
                    //发送随机码到Dtu服务端
                    await SendCommandToDtuServer($"{Protocol_SendRandCode};{username};{_PLNet.MyRND}");
                    if (!_sendRndCodeSignal.WaitOne(TimeSpan.FromSeconds(10)))
                    {
                        throw new Exception("发送随机码超时！");
                    }
                    else if (_errorCode != ErrorCode_Succeed)
                    {
                        throw new Exception("发送随机码失败:" + _errorCode);
                    }
                    ProcessSetp = ProcessStep.SendRandCode;
                }

                if (gotCopterCallBack != null)
                {
                    int index = 0;
                    while (true)
                    {
                        await SendCommandToDtuServer($"{Protocol_RequestCopterList};{username};{index}");
                        if (_requestCopterListSignal.WaitOne(TimeSpan.FromSeconds(10)))
                        {
                            if (_errorCodeForRequestCopterList == ErrorCode_Succeed)
                            {
                                if (_nextCopter != null)
                                {
                                    gotCopterCallBack.Invoke(_nextCopter);
                                }
                                //加1后继续请求
                                index++;
                            }
                            else if (_errorCodeForRequestCopterList == ErrorCode_EndCopterList)
                            {
                                //正常结束请求
                                break;
                            }
                            else
                            {
                                throw new Exception($"请求获取飞机列表错误：{_errorCode}！");
                            }
                        }
                        else
                        {
                            throw new Exception("请求获取飞机列表超时！");
                        }
                    }
                }
            }).ConfigureAwait(false);
        }

        /// <summary>
        /// 退出PLNet网络
        /// </summary>
        public void Logout()
        {
            _PLNet.Close();
            ResetLoginStatus();
            ProcessSetp = ProcessStep.None;
        }

        /// <summary>
        /// 获取飞机列表
        /// </summary>
        public async Task GetCopterList(Action<CopterEntity> gotCopterCallBack)
        {
            await Task.Run(async () =>
           {
               int index = 0;
               while (true)
               {
                   await SendCommandToDtuServer($"{Protocol_RequestCopterList};{_usersname};{index}");
                   if (_requestCopterListSignal.WaitOne(TimeSpan.FromSeconds(10)))
                   {
                       if (_errorCodeForRequestCopterList == ErrorCode_Succeed)
                       {
                           if (_nextCopter != null)
                           {
                               gotCopterCallBack.Invoke(_nextCopter);
                           }
                           //加1后继续请求
                           index++;
                       }
                       else if (_errorCodeForRequestCopterList == ErrorCode_EndCopterList)
                       {
                           //正常结束请求
                           break;
                       }
                       else
                       {
                           //throw new Exception($"请求获取飞机列表错误：{_errorCode}！");
                       }
                   }
                   else
                   {
                       //throw new Exception("请求获取飞机列表超时！");
                   }
               }
           }).ConfigureAwait(false);
        }

        /// <summary>
        /// 申请绑定飞机
        /// </summary>
        public async Task AssignBindingCopter(string copterID)
        {
            //向Dtu服务端申请绑定飞机
            await SendCommandToDtuServer($"{Protocol_BindCopterID};{_usersname};{copterID}");
            if (!_sendBindCopterIDSignal.WaitOne(TimeSpan.FromSeconds(10)))
            {
                throw new Exception("申请绑定超时！");
            }
            else if (_errorCode != ErrorCode_Succeed)
            {
                throw new Exception("申请绑定失败:" + _errorCode);
            }
            ProcessSetp = ProcessStep.AssignCopter;
        }
        #endregion

        #region Private Methods
        private void AcceptProtocolCommand(string userIDFrom, string msg)
        {
            if (!string.IsNullOrEmpty(msg) && userIDFrom == DtuServerUsername)
            {
                var strList = msg.Split(';');
                if (strList.Length >= 3)
                {
                    switch (strList[0])
                    {
                        case Protocol_SendRandCode_Reply:
                            _errorCode = strList[2];
                            _sendRndCodeSignal.Set();
                            break;

                        case Protocol_BindCopterID_Reply:
                            _errorCode = strList[2];
                            _sendBindCopterIDSignal.Set();
                            break;

                        case Protocol_ReceivedCopterItem:
                            _errorCodeForRequestCopterList = strList[2];
                            if (strList.Length >= 5)
                            {
                                _nextCopter = new CopterEntity { ID = strList[3], Name = strList[4] };
                            }
                            else
                            {
                                _nextCopter = null;
                            }
                            _requestCopterListSignal.Set();
                            break;

                        case Protocol_RecievedCopterInvailed:
                            CopterLost?.Invoke(this, EventArgs.Empty);
                            break;
                    }
                }
            }
        }
        #endregion
    }
}
