using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

using FlyADBase;
using FLY.Thick.Base.Common;
using FLY.Thick.Base.IService;
using System.Diagnostics;

namespace FLY.Thick.Base.Server
{
    public abstract class GM_Base : IGageMode, INotifyErrorArisen
    {
        /// <summary>
        /// 启动时出错，已经在运行了
        /// </summary>
        public const byte ERRNO_StartUp_IsRunning = 1;
        /// <summary>
        /// 启动时出错，AD卡连接断开
        /// </summary>
        public const byte ERRNO_StartUp_FlyADNoConnected = 2;
        /// <summary>
        /// 参数异常
        /// </summary>
        public const byte ERRNO_StartUp_Param = 3;
        /// <summary>
        /// 参数异常
        /// </summary>
        public const byte ERRNO_Running_Manual = 4;

        protected FlyAD7 mFlyAD;
        protected FObjBase.PollModule.PollHandler onpoll_func;
        #region IGageMode 接口

        public CTRL_STATE GMState { get; protected set; }

        /// <summary>
        /// 运行中
        /// </summary>
        public bool IsRunning { get; protected set; }

        public event ErrorArisenEventHander ErrorArisenEvent;
        protected void NotifyError(byte errno) 
        {
            ErrorArisenEvent?.Invoke(this, new ErrorArisenEventArgs() { Errno = errno });
        }
        #endregion

        public GM_Base(FlyAD7 flyad)
        {
            mFlyAD = flyad;
            onpoll_func = new FObjBase.PollModule.PollHandler(OnPoll);
        }
        protected virtual void OnPoll()
        {
            if (mFlyAD.IsFinish)
            {
                Stop();
            }
        }
        #region IGageMode 接口
        public virtual bool Start()
        {
            if (IsRunning)
            {
                NotifyError(ERRNO_StartUp_IsRunning);
                return false;
            }
            if (!mFlyAD.IsConnected)
            {
                NotifyError(ERRNO_StartUp_FlyADNoConnected);
                return false;
            }
            IsRunning = true;
            FObjBase.PollModule.Current.Poll_Config(onpoll_func);
            return true;
        }
        public virtual void Stop()
        {
            FObjBase.PollModule.Current.Poll_Config(
                FObjBase.PollModule.POLL_CONFIG.REMOVE,
                onpoll_func);

            IsRunning = false;
        }

        #endregion
        
        #region IGageMode 接口
        protected void NotifyPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        #endregion

        /// <summary>
        /// 等待停止; 
        /// 正常停止返回true，没有停止及异常停止返回false
        /// </summary>
        /// <returns></returns>
        protected bool WaitFinish()
        {
            switch (mFlyAD.DriveStatus)
            {
                case DRIVE_MAN_STATUS.STOP://完成任务
                case DRIVE_MAN_STATUS.LIMIT:
                    {
                        return true;
                    }
                case DRIVE_MAN_STATUS.STOP_MANUAL://异常
                    {
                        NotifyError(ERRNO_Running_Manual);
                        Stop(); return false;
                    }
            }
            return false;
        }
    }

    public class GM_Goto : GM_Base
    {
        /// <summary>
        /// 扫描速度
        /// </summary>
        public UInt32 Velocity
        {
            get;
            set;
        }

        public GM_Goto(FlyAD7 flyad):base(flyad)
        {
            GMState = CTRL_STATE.RUNNING;
            Velocity = 5000;
        }
        public override bool Start()
        {
            return Start(1000);
        }
        public bool Start(int pos) 
        {
            bool b = base.Start();
            if (!b)
                return false;
            mFlyAD.SetVelocity(Velocity);
            mFlyAD.Runto(pos);
            return true;
        }
    }

    public class GM_Forward : GM_Base 
    {
        /// <summary>
        /// 扫描速度
        /// </summary>
        public UInt32 Velocity
        {
            get;
            set;
        }
        public GM_Forward(FlyAD7 flyad)
            :base(flyad)
        {
            GMState = CTRL_STATE.FORW;
            Velocity = 5000;
        }
        public override bool Start()
        {
            bool b = base.Start();
            if (!b)
                return false;
            mFlyAD.SetVelocity(Velocity);
            mFlyAD.RuntoMax();
            return true;
        }
    }

    public class GM_Backward : GM_Base 
    {
        /// <summary>
        /// 扫描速度
        /// </summary>
        public UInt32 Velocity
        {
            get;
            set;
        }
        public GM_Backward(FlyAD7 flyad)
            : base(flyad)
        {
            GMState = CTRL_STATE.BACKW;
            Velocity = 5000;
        }
        public override bool Start()
        {
            bool b = base.Start();
            if (!b)
                return false;
            mFlyAD.SetVelocity(Velocity);
            mFlyAD.RuntoMin();
            return true;
        }
    }

    public class GM_Origin : GM_Base
    {
        public GM_Origin(FlyAD7 flyad)
            : base(flyad)
        {
            GMState = CTRL_STATE.ORG;
        }
        public override bool Start()
        {
            bool b =base.Start();
            if (!b)
                return false;
            mFlyAD.Origin();
            return true;
        }
    }

    public class GM_Stop : GM_Base
    {
        public GM_Stop(FlyAD7 flyad)
            : base(flyad)
        {
            GMState = CTRL_STATE.STOP;
        }
        public override bool Start()
        {
            bool b = base.Start();
            if (!b)
                return false;
            mFlyAD.Stop();
            return true;
        }
    }

    public class GM_Disconnected: GM_Base
    {
        GM_AutoScan mGMAutoScan;
        DynArea mDynArea;
        Stopwatch stopwatch = new Stopwatch();
        bool isReadyToAutoScan = false;

        public GM_Disconnected(FlyAD7 flyad)
            : base(flyad)
        {
            GMState = CTRL_STATE.DISCONNECTED;
            
        }
        public void Init(DynArea dynarea, GM_AutoScan gmAutoScan) 
        {
            mDynArea = dynarea;
            mGMAutoScan = gmAutoScan;
            mDynArea.PropertyChanged += new PropertyChangedEventHandler(mDynArea_PropertyChanged);
        }

        void mDynArea_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(mDynArea.FLYADIsConnect))
            {
                if (!mDynArea.FLYADIsConnect)
                {
                    //AD卡已经断开

                    if (mDynArea.ControllerState == CTRL_STATE.SCAN || 
                        mDynArea.ControllerState == CTRL_STATE.AUTOSCAN)
                    {
                        //之前在扫描中
                        isReadyToAutoScan = true;
                        stopwatch.Restart();
                    }
                    else {
                        isReadyToAutoScan = false;
                        stopwatch.Stop();
                    }
                    Start();
                }
                else
                {
                    //AD盒已经重新连接上
                    if (IsRunning)//还在 CTRL_STATE.DISCONNECTED
                    {
                        if (isReadyToAutoScan)
                        {
                            //需要自动扫描
                            if (stopwatch.Elapsed > TimeSpan.FromMinutes(3))
                            {
                                isReadyToAutoScan = false;
                                stopwatch.Stop();
                                //断开连接，到现在重新连上，只过了3min，重新执行扫描
                                mGMAutoScan.Start(5);
                            }
                            else
                            {
                                Stop();
                            }
                        }
                        else 
                        {
                            Stop();
                        }
                    }
                }
            }
        }
        public override bool Start()
        {
            IsRunning = true;
            return true;
        }
        public override void Stop()
        {
            IsRunning = false;
            isReadyToAutoScan = false;
            stopwatch.Stop();
        }
    }

    public class GM_AutoScan : GM_Base
    {
        public int Delay { get; set; }

        public int Counter { get; set; } = 5;

        Action ReScan;
        DateTime dtLast = DateTime.MinValue;
        public GM_AutoScan(FlyAD7 flyad)
            : base(flyad)
        {
            GMState = CTRL_STATE.AUTOSCAN;
            Delay = 5;
            Counter = Delay;
        }
        public void Init(Action reScan) 
        {
            ReScan = reScan;
        }
        protected override void OnPoll()
        {
            if ((DateTime.Now - dtLast).TotalSeconds >= 1)
            {
                dtLast = DateTime.Now;
                if (Counter > 0)
                    Counter--;

                if (Counter <= 0)
                {
                    Stop();
                    ReScan();
                }
            }
        }
        public bool Start(int delay) 
        {
            Delay = delay;
            return Start();
        }
        public override bool Start()
        {
            IsRunning = true;
            Counter = Delay;
            dtLast = DateTime.Now;
            FObjBase.PollModule.Current.Poll_Config(onpoll_func);
            return true;
        }
    }
    
    public class GM_Pause : GM_Base
    {
        public int Delay
        {
            get;
            set;
        }
        public bool Enable
        {
            get;
            set;
        }
        DynArea mDynArea;
        GM_AutoScan mGMAutoScan;
        enum STATE 
        {
            WAIT_ORG,
            WAIT_RESCAN
        }
        STATE mState;


        public GM_Pause(FlyAD7 flyad)
            : base(flyad)
        {
            GMState = CTRL_STATE.PAUSE;
            Enable = false;
            this.PropertyChanged += new PropertyChangedEventHandler(GM_Pause_PropertyChanged);
        }

        void GM_Pause_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(Enable)) 
            {
                if (Enable)
                {
                    update_datavalid();
                }
                else 
                {
                    if(IsRunning)
                        Stop();
                }
            }
        }
        public void Init(DynArea dynarea, GM_AutoScan gmAutoScan)
        {
            mDynArea = dynarea;
            mGMAutoScan = gmAutoScan;
            mDynArea.PropertyChanged+=new PropertyChangedEventHandler(mDynArea_PropertyChanged);
        }
        void update_datavalid() 
        {
            if (mDynArea.DataValid)
            {
                switch(mDynArea.ControllerState)
                {
                    case CTRL_STATE.FIX:
                    case CTRL_STATE.PAUSE:
                        mGMAutoScan.Start(Delay);
                        break;
                }
            }
            else
            {
                switch (mDynArea.ControllerState)
                {
                    case CTRL_STATE.SCAN:
                    case CTRL_STATE.AUTOSCAN:
                        Start();
                        break;
                    default:
                        mGMAutoScan.Stop();
                        break;
                }
            }
        }
        void mDynArea_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(mDynArea.DataValid)) 
            {
                if(Enable)
                    update_datavalid();
            }
        }
        protected override void OnPoll()
        {
            switch (mState) 
            {
                case STATE.WAIT_ORG:
                    if (mFlyAD.IsFinish)
                    {
                        mState = STATE.WAIT_RESCAN;
                    }
                    break;
                case STATE.WAIT_RESCAN:
                    break;
            }
        }
        public override bool Start()
        {
            bool b = base.Start();
            if (!b)
                return false;
            mState = STATE.WAIT_ORG;
            mFlyAD.Origin();
            return true;
        }

    }
}
