using Plane.Communication;
using Plane.Geography;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using static Plane.Copters.Constants;
namespace Plane.Copters
{
    /// 
    /// 虚拟的  实现。
    /// 
    [DebuggerDisplay("Name={Name}")]
    public partial class FakeCopter : CopterImplSharedPart, IFakeCopter
    {
        /// 
        /// 心跳间隔,单位为毫秒。
        /// 
        private const int HEARTBEAT_INTERVAL = 200;
        /// 
        /// 更新虚拟飞行器状态的时间间隔,单位为毫秒。
        /// 
        static private int UPDATE_INTERVAL =50;  //默认100, i7电脑 150可以跑1000架 100可以跑500架 50可以200-300架 
        /// 
        /// 在一个更新间隔中的最大移动距离。
        /// 
        private float MAX_MOVE_IN_INTERVAL = MAX_VEL * UPDATE_INTERVAL / 1000;
        /// 
        /// 高速模式下,在一个更新间隔中的最大移动距离。
        /// 
        private  float MAX_MOVE_IN_INTERVAL_FAST = MAX_VEL * UPDATE_INTERVAL / 1000 * 4;  //MAX_MOVE_IN_INTERVAL*4
        // private int _UPDATE_INTERVAL = 50;
        /// 
        /// 对飞行器的模拟是否正在运行。
        /// 
        private bool _isRunning = false;
        /// 
        /// 上次计算速度时的位置。
        /// 
        private ILocation _lastCalcSpeedPoint;
        /// 
        /// 上次计算速度的时间。
        /// 
        private DateTime _lastCalcSpeedTime;
        /// 
        /// 高速模式下,按比例缩放过的在一个更新间隔中的最大移动距离。
        /// 
        private float _scaledFastMaxMoveInInterval = MAX_VEL * UPDATE_INTERVAL / 1000 * 4;  //MAX_MOVE_IN_INTERVAL_FAST
        /// 
        /// 按比例缩放过的在一个更新间隔中的最大移动距离。
        /// 
        private float _scaledMaxMoveInInterval = MAX_VEL *  UPDATE_INTERVAL / 1000;  //MAX_MOVE_IN_INTERVAL
        /// 
        /// 速度缩放比例。
        /// 
        private float _speedScale = 1;
        /// 
        /// 自动起飞的目标高度。
        /// 
        private int _takeOffTargetAltitude;
        /// 
        /// FlyTo 的目标高度。
        /// 
        private float _targetAlt;
        /// 
        /// FlyTo 的目标纬度。
        /// 
        private double _targetLat;
        /// 
        /// FlyTo 的目标经度。
        /// 
        private double _targetLng;
        /// 
        /// FlyTo 的目标经度。
        /// 
        private bool _ShowLED;
        /// 
        /// 使用  创建  实例。
        /// 
        public FakeCopter() : this(SynchronizationContext.Current)
        {
        }
        new public int  sim_update_int
        {
            get { return UPDATE_INTERVAL; }
            set
            {
                //最大移动距离
                MAX_MOVE_IN_INTERVAL = MAX_VEL * value / 1000;
                //快速模式最大移动距离
                MAX_MOVE_IN_INTERVAL_FAST = MAX_MOVE_IN_INTERVAL * 4;
                //速度缩放后快速速度距离
                _scaledFastMaxMoveInInterval = MAX_MOVE_IN_INTERVAL_FAST* _speedScale;
                //速度缩放后速度距离
                _scaledMaxMoveInInterval = MAX_MOVE_IN_INTERVAL* _speedScale;
                Set(nameof(sim_update_int), ref UPDATE_INTERVAL, value);
            }
        }
        public Task DoCommandAckAsync(ushort command, byte result)
        {
            return TaskUtils.CompletedTask;
        }
        /// 
        /// 创建  实例。
        /// 
        /// UI 线程的同步上下文。
        /// 自动起飞时的目标高度。
        /// 速度缩放比例。
        public FakeCopter(SynchronizationContext uiSyncContext, int takeOffTargetAltitude = 10, float speedScale = 1, IConnection connection = null)
            : base(uiSyncContext)
        {
            Latitude = 23.155382266268134;
            Longitude = 113.45038586296141;
            Elevation = 20;
            this.PropertyChanged += (sender, e) =>
            {
                switch (e.PropertyName)
                {
                    case nameof(Altitude):
                        Elevation = Altitude + 20;
                        break;
                    case nameof(IsUnlocked):
                        if (IsUnlocked)
                        {
                            // 王海, 20151029, 在解锁时上次计算速度点、上次计算速度时刻。
                            _lastCalcSpeedPoint = new PLLocation { Latitude = Latitude, Longitude = Longitude, Altitude = Altitude };
                            _lastCalcSpeedTime = DateTime.Now;
                        }
                        break;
                }
            };
            _takeOffTargetAltitude = takeOffTargetAltitude;
            _speedScale = speedScale;
            _scaledMaxMoveInInterval = MAX_MOVE_IN_INTERVAL * _speedScale;
            _scaledFastMaxMoveInInterval = MAX_MOVE_IN_INTERVAL_FAST * _speedScale;
            this.Connection = connection ?? EmptyConnection.Instance;
            _isRunning = true;
            // 持续计算并更新虚拟飞行器的状态。
            // Task.Run(async () =>
             Task.Factory.StartNew(async () =>
             {
                while (_isRunning)
                {
                    Update();
                    await TaskUtils.Delay(UPDATE_INTERVAL).ConfigureAwait(false);
                }
            }
             , TaskCreationOptions.LongRunning
             );
          
           
            ++HeartbeatCount;
            GpsFixType = GpsFixType.Fix3D;
            GpsHdop = 1;
            IsGpsAccurate = true;
            HasSwitchedToGpsMode = true;
            /*
            // 持续假装收到飞行器发来的心跳。
            Task.Run(async () =>
            {
                while (true)
                {
                    if (_isRunning)
                    {
                        ++HeartbeatCount;
                        IsCheckingConnection = false;
                        if (HeartbeatCount >= 10)
                        {
                            // 收到若干个心跳之后,设置一下 GPS 相关属性。
                            GpsFixType = GpsFixType.Fix3D;
                            GpsHdop = 1;
                            IsGpsAccurate = true;
                            HasSwitchedToGpsMode = true;
                        }
                        _uiSyncContext.Post(() => RaiseHeartbeatReceived(new HeartbeatReceivedEventArgs(HeartbeatCount)));
                    }
                    await TaskUtils.Delay(HEARTBEAT_INTERVAL).ConfigureAwait(false);
                }
            });
            */
        }
        public IConnection Connection { get; set; }
        public string Id { get; set; }
        private int ReturnToLaunchAltitude { get { return _takeOffTargetAltitude; } }
        public Task ConnectAsync()
        {
            IsConnected = true;
            _isRunning = true;
            IsCheckingConnection = true;
            return TaskUtils.CompletedTask;
        }
        public Task DisconnectAsync()
        {
            IsConnected = false;
            _isRunning = false;
            IsCheckingConnection = false;
            return TaskUtils.CompletedTask;
        }
        protected override Task FlyToCoreAsync(double lat, double lng, float alt)
        {
            if (!IsEmergencyHoverActive)
            {
                _targetLat = lat;
                _targetLng = lng;
                _targetAlt = alt;
                Mode = FlightMode.GUIDED;
            }
            return TaskUtils.CompletedTask;
        }
        public Task GetCopterDataAsync()
        {
            return TaskUtils.CompletedTask;
        }
        public Task GetParamAsync(string paramName, int millisecondsTimeout = Timeout.Infinite)
        {
            // TODO: 王海, 20150806, 实现仿真的 GetParamAsync。
            return Task.FromResult(0f);
        }
        public Task LockAsync()
        {
            if (IsUnlocked)
            {
                IsUnlocked = false;
            }
            return TaskUtils.CompletedTask;
        }
        public Task LEDAsync()
        {
            return TaskUtils.CompletedTask;
        }
        public Task MotorTestAsync(int motor)
        {
            return TaskUtils.CompletedTask;
        }
        public override Task SetChannelsAsync()
        {
            Channel1 = DesiredChannel1 ?? Channel1;
            Channel2 = DesiredChannel2 ?? Channel2;
            Channel3 = DesiredChannel3 ?? Channel3;
            Channel4 = DesiredChannel4 ?? Channel4;
            Channel5 = DesiredChannel5 ?? Channel5;
            Channel6 = DesiredChannel6 ?? Channel6;
            Channel7 = DesiredChannel7 ?? Channel7;
            Channel8 = DesiredChannel8 ?? Channel8;
            return TaskUtils.CompletedTask;
        }
        public override Task SetMobileControlAsync()
        {
            Channel1 = DesiredChannel1 ?? Channel1;
            Channel2 = DesiredChannel2 ?? Channel2;
            Channel3 = DesiredChannel3 ?? Channel3;
            Channel4 = DesiredChannel4 ?? Channel4;
            Channel5 = DesiredChannel5 ?? Channel5;
            Channel6 = DesiredChannel6 ?? Channel6;
            Channel7 = DesiredChannel7 ?? Channel7;
            Channel8 = DesiredChannel8 ?? Channel8;
            Yaw = DesiredYaw ?? Yaw;
            Heading = (short)Yaw;
            return TaskUtils.CompletedTask;
        }
        //得到收到的总数据量
        public void GetCommunicationNumber(out int recnumber, out int sendnumber)
        {
            recnumber = 0;
            sendnumber = 0;
        }
        //重设数据量
        public void ResetCommunicationNumber()
        {
        }
        public async Task DoCommandAsync(int actionid, float p1, float p2, float p3, float p4, float p5, float p6, float p7)
        {
            await Task.Delay(50).ConfigureAwait(false);
           
        }
        public Task SetParamAsync(string paramName, float value, int millisecondsTimeout = Timeout.Infinite)
        {
            // TODO: 王海, 20150807, 实现仿真的 SetParamAsync。
            return TaskUtils.CompletedTask;
        }
        public bool GetShowLEDAsync()
        {
            return _ShowLED;
        }             
        public Task SetShowLEDAsync(bool Ledon)
        {
            _ShowLED = Ledon;
            RaiseLocationChanged();
            return TaskUtils.CompletedTask;
        }
        public Task SetShowRGBLEDAsync(int RedValue, int GreenValue, int BlueValue)
        {
            return TaskUtils.CompletedTask;
        }
        public Task SetShowLEDFlashAsync(int Flashtype, int millisecondsTime)
        {
            bool Ledison;
            Ledison = GetShowLEDAsync();
            if (!Ledison)
            {
                 SetShowLEDAsync(true);
                 Task.Delay(millisecondsTime).ConfigureAwait(false);
                 SetShowLEDAsync(false);
            }
            else
            {
                 SetShowLEDAsync(false);
                 Task.Delay(millisecondsTime).ConfigureAwait(false);
                 SetShowLEDAsync(true);
            }
           
            return TaskUtils.CompletedTask;
        }
        public void SetProperties(
            string id = null,   //"Junqing's Drone",
            double? latitude = null,   //23.14973333,
            double? longitude = null,   //113.40974166,
            float? altitude = null,   //0,
            string name = null,   //"王海的飞行器",
            byte? batteryPer = null,   //10,
            short? heading = null,   //33,
            bool? isConnected = null,   //true,
            float? pitch = null,   //-70,
            float? roll = null,   //28,
            byte? satCount = null,   //6,
            float? airSpeed = null,   //3.333,
            double? flightDistance = null,   //100.388,
            double? flightDistance2D = null, // 100.88,
            TimeSpan? flightTimeSpan = null)
        {
            if (id != null) Id = id;
            if (name != null) Name = name;
            if (latitude != null) Latitude = latitude.Value;
            if (longitude != null) Longitude = longitude.Value;
            if (altitude != null) Altitude = altitude.Value;
            if (batteryPer != null) BatteryPer = batteryPer.Value;
            if (heading != null) Heading = heading.Value;
            if (isConnected != null) IsConnected = isConnected.Value;
            if (pitch != null) Pitch = pitch.Value;
            if (roll != null) Roll = roll.Value;
            if (satCount != null) SatCount = satCount.Value;
            if (airSpeed != null) AirSpeed = airSpeed.Value;
            if (flightDistance != null) FlightDistance = flightDistance.Value;
            if (flightDistance2D != null) FlightDistance2D = flightDistance2D.Value;
            if (flightTimeSpan != null) FlightTimeSpan = flightTimeSpan.Value;
        }
        public Task StartPairingAsync()
        {
            RaisePairingCompleted(new PairingCompletedEventArgs(true, 0, 0));
            return TaskUtils.CompletedTask;
        }
        public Task StopPairingAsync()
        {
            return TaskUtils.CompletedTask;
        }
        public async Task TakeOffAsync(float alt)
        {
            await UnlockAsync().ConfigureAwait(false);
            _takeOffTargetAltitude = (int)alt;
            await TakeOffAsync().ConfigureAwait(false);
        }
        public Task MissionStartAsync(int hour_utc, int minute_utc, int second_utc, double Missionlng, double Missionlat)
        {
            return TaskUtils.CompletedTask;
        }
        public async Task UnlockAsync()
        {
            if (!IsUnlocked)
            {
                await SetChannelsAsync(
                    ch1: 1500,
                    ch2: 1500,
                    ch3: 1100,
                    ch4: 1500
                ).ConfigureAwait(false);
                if (await SetModeAsync(FlightMode.ALT_HOLD).ConfigureAwait(false))
                {
                    IsUnlocked = true;
                }
            }
        }
        /// 
        /// 无论在不在紧急悬停状态下都可用的切换模式方法。
        /// 
        /// 模式。
        /// 超时。
        /// 成功与否。
        internal override Task SetModeCoreAsync(FlightMode mode, int millisecondsTimeout = 5000)
        {
            Mode = mode;
            return Task.FromResult(true);
        }
        protected override void UpdateFlightDataIfNeeded()
        {
            //计算飞机距离,没必要
            /*
            if (!TakeOffPoint.IsNullOrEmpty())
            {
                FlightDistance = TakeOffPoint.CalcDistance(this);
                FlightDistance2D = TakeOffPoint.CalcDistance2D(this);
            }
           
            if (FlightTimeSpan.TotalSeconds > 0)
            {
                if (_lastCalcSpeedPoint.IsNullOrEmpty())
                {
                    if (!this.IsNullOrEmpty())
                    {
                        _lastCalcSpeedPoint = new PLLocation(this);
                        _lastCalcSpeedTime = DateTime.Now;
                    }
                }
                else
                {
                    var movedDistance = _lastCalcSpeedPoint.CalcDistance(this);
                    var movedTime = DateTime.Now - _lastCalcSpeedTime;
                    if (movedDistance >= 3 || movedTime.TotalSeconds >= 3)
                    {
                        var airSpeed = movedDistance / movedTime.TotalSeconds;
                        if (airSpeed < 100)  // 王海, 20151023, 速度过大时不正常,经纬度可能有错误。
                        {
                            AirSpeed = (float)airSpeed;
                        }
                        //Windows.Messages.Message.Show(AirSpeed.ToString());
                        GroundSpeed = AirSpeed;
                        _lastCalcSpeedPoint = new PLLocation(this);
                        _lastCalcSpeedTime = DateTime.Now;
                    }
                }
            }
            */
        }
        private void MoveToPointImmediately(double lat, double lng, float alt)
        {
            Latitude = lat;
            Longitude = lng;
            Altitude = alt;
            Roll = 0;
            Pitch = 0;
        }
        public Task InjectGpsDataAsync(byte[] data, ushort length)
        {
            return TaskUtils.CompletedTask;
        }
        private bool ReachedDestination(double destLat, double destLng, float destAlt) => this.CalcDistance(destLat, destLng, destAlt) < 0.1;
        /// 
        /// 计算并更新虚拟飞行器状态。
        /// 
        private void Update()
        {
            if (IsUnlocked)
            {
                // 飞行器接触地面(只判断 Altitude <= 0)后,如果处于 LAND 模式或者保持 Channel3 < MIN_HOVER_CHANNEL,在一段时间后自动锁定。
                if ((Mode == FlightMode.LAND || Channel3 < MIN_HOVER_CHANNEL) && Altitude <= 0)
                {
                    Task.Run(async () =>
                    {
                        for (int i = 0; i < 4000 / 20; i++)
                        {
                            await TaskUtils.Delay(20).ConfigureAwait(false);
                            if ((Mode != FlightMode.LAND && Channel3 >= MIN_HOVER_CHANNEL) || !IsUnlocked)
                            {
                                return;
                            }
                        }
                        IsUnlocked = false;
                    });
                }
                else
                {
                    switch (Mode)
                    {
                        case FlightMode.ACRO:
                            break;
                        case FlightMode.AUTO:
                            // 暂时只管起飞。以最大速度上升,直到达到目标高度。
                            if (Altitude < _takeOffTargetAltitude)
                            {
                                Altitude += _scaledMaxMoveInInterval;
                            }
                            else
                            {
                                Mode = FlightMode.LOITER;
                            }
                            break;
                        case FlightMode.GUIDED:
                            // 王海, 20160317, 指点时也能体感控制若干通道。
                            //考虑不更新这个,好像没必要-xu
                            //UpdateWithChannels();
                            UpdateWithDestination(_targetLat, _targetLng, _targetAlt);
                            break;
                        case FlightMode.STABILIZE:
                        case FlightMode.ALT_HOLD:
                        case FlightMode.LOITER:
                            UpdateWithChannels();
                            break;
                        case FlightMode.RTL:
                            if (Altitude < ReturnToLaunchAltitude && !ReachedDestination(Latitude, Longitude, ReturnToLaunchAltitude))
                            {
                                UpdateWithDestination(Latitude, Longitude, ReturnToLaunchAltitude);
                            }
                            else if (Altitude > ReturnToLaunchAltitude && !ReachedDestination(TakeOffPoint.Latitude, TakeOffPoint.Longitude, Altitude))
                            {
                                UpdateWithDestination(TakeOffPoint.Latitude, TakeOffPoint.Longitude, Altitude);
                            }
                            else
                            {
                                UpdateWithDestination(TakeOffPoint.Latitude, TakeOffPoint.Longitude, ReturnToLaunchAltitude);
                            }
                            break;
                        case FlightMode.CIRCLE:
                            break;
                        case FlightMode.POSITION:
                            break;
                        case FlightMode.LAND:
                            // 王海, 20160317, 降落时也能体感控制若干通道。
                            UpdateWithChannels();
                            // 以最大速度降落,直到高度为 0。
                            if (Altitude > 0)
                            {
                                if (Altitude > _scaledMaxMoveInInterval)
                                {
                                    Altitude -= _scaledMaxMoveInInterval;
                                }
                                else
                                {
                                    Altitude = 0;
                                }
                                Roll = 0;
                                Pitch = 0;
                            }
                            break;
                        case FlightMode.OF_LOITER:
                            break;
                        case FlightMode.TOY:
                            break;
                        default:
                            break;
                    }
                    UpdateFlightDataIfNeeded();
                }
            }
            else
            {
                // TODO: 王海, 20151228, 模拟空中锁定。
                // 锁定时直接把速度设为 0。
                AirSpeed = 0;
            }
            _uiSyncContext.Post(() =>
            {
                //位置变化需要在UI刷新
                RaiseLocationChangedIfNeeded();
                //高度变化需要在UI刷新
               // RaiseAltitudeChangedIfNeeded();
                //GPS数据用于显示
              //  RaiseDataStreamReceived(PDataStreamType.GPS_RAW_INT);
                //不考虑姿态
             //   RaiseAttitudeChanged();
            });
        }
        /// 
        /// 根据各个通道值来更新位置、姿态等状态。
        /// 
        private void UpdateWithChannels()
        {
            var maxMove = Mode == FlightMode.LOITER ? _scaledMaxMoveInInterval : _scaledFastMaxMoveInInterval;
            var ch3Delta = Channel3 > MAX_HOVER_CHANNEL ? Channel3 - MAX_HOVER_CHANNEL : Channel3 < MIN_HOVER_CHANNEL ? Channel3 - MIN_HOVER_CHANNEL : 0;
            if (ch3Delta != 0)
            {
                // 更新相对高度。
                Altitude = Math.Max(0, Altitude + maxMove * ch3Delta / MAX_CHANNEL_DELTA);
            }
            var yawRad = Yaw.DegToRad();
            var metersToLocalLng = GeographyUtils.CalcMetersToLngSpan(Latitude);
            var ch1Delta = Channel1 > MAX_HOVER_CHANNEL ? Channel1 - MAX_HOVER_CHANNEL : Channel1 < MIN_HOVER_CHANNEL ? Channel1 - MIN_HOVER_CHANNEL : 0;
            var xDistance = maxMove * ch1Delta / MAX_CHANNEL_DELTA;
            if (ch1Delta != 0)
            {
                // 更新横滚方向的纬度和经度。
                Latitude -= xDistance * Math.Sin(yawRad) * GeographyUtils.METERS_TO_LAT_SPAN;
                Longitude += xDistance * Math.Cos(yawRad) * metersToLocalLng;
                // 更新横滚姿态。
                Roll = MAX_TILT_IN_FLIGHT * ch1Delta / MAX_CHANNEL_DELTA;
            }
            else
            {
                Roll = 0;
            }
            var ch2Delta = Channel2 > MAX_HOVER_CHANNEL ? Channel2 - MAX_HOVER_CHANNEL : Channel2 < MIN_HOVER_CHANNEL ? Channel2 - MIN_HOVER_CHANNEL : 0;
            var yDistance = maxMove * ch2Delta / MAX_CHANNEL_DELTA;
            if (ch2Delta != 0)
            {
                // 更新俯仰方向的纬度和经度。
                Latitude -= yDistance * Math.Cos(yawRad) * GeographyUtils.METERS_TO_LAT_SPAN;
                Longitude -= yDistance * Math.Sin(yawRad) * metersToLocalLng;
                // 更新俯仰姿态。
                Pitch = MAX_TILT_IN_FLIGHT * ch2Delta / MAX_CHANNEL_DELTA;
            }
            else
            {
                Pitch = 0;
            }
        }
        /// 
        /// 根据目的地来更新位置、姿态等状态。
        /// 
        private void UpdateWithDestination(ILocation loc)
        {
            UpdateWithDestination(loc.Latitude, loc.Longitude, loc.Altitude);
        }
        /// 
        /// 根据目的地来更新位置、姿态等状态。
        /// 
        private void UpdateWithDestination(double lat, double lng, float alt)
        {
            // 与目标点之间的距离。
            var distance = this.CalcDistance(lat, lng, alt);
            // 距离已经很近,直接移动到目标点。
            if (distance < _scaledMaxMoveInInterval)
            {
                MoveToPointImmediately(lat, lng, alt);
                return;
            }
            // 在空间中的移动距离。
            var move = _scaledMaxMoveInInterval;
            // 竖直方向的移动距离。
            var altDelta = (float)(move * (alt - Altitude) / distance);
            // 更新高度。
            Altitude += altDelta;
            // 目标点相对于当前位置的方向。
             var direction = this.CalcDirection2D(lat, lng);
            // 水平面上的移动距离。
            var moveInHorizontalPlane = Math.Sqrt(move * move - altDelta * altDelta);
            if (double.IsNaN(moveInHorizontalPlane))
            {
                MoveToPointImmediately(lat, lng, alt);
                return;
            }
            // 更新纬度。
            Longitude += moveInHorizontalPlane * Math.Sin(direction) * GeographyUtils.CalcMetersToLngSpan(Latitude);
            // 更新经度。
            Latitude += moveInHorizontalPlane * Math.Cos(direction) * GeographyUtils.METERS_TO_LAT_SPAN;
        }
    }
}