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


using Misc;
using FlyADBase;
using FLY.Thick.Base.Common;
using System.Diagnostics;
using FLY.OBJComponents.Server;

namespace FLY.Thick.Base.Server
{
    public delegate void EndEventHandler(object obj, MiniGridEventArgs e);
    /// <summary>
    /// 只是来回走的逻辑，不包含数据处理
    /// </summary>
    public abstract class GM_ScanMotion : GM_Base
    {
        #region 成员变量
        protected GSample gsample;
        protected WarningSystem2 warningSystem;

        /// <summary>
        /// 归0开始时间点，用于计算什么时候需要归0
        /// </summary>
        private TimeSpan orgStartTime;

        /// <summary>
        /// 使用timer.Elapsed 代替 DateTime.Now 使用
        /// </summary>
        private Stopwatch timer = new Stopwatch();

        /// <summary>
        /// 归原点间隔
        /// </summary>
        public int OrgInterval { get; set; }


        /// <summary>
        /// 扫描开始位置
        /// </summary>
        public int ScanStart { get; set; }

        /// <summary>
        /// 扫描结束位置
        /// </summary>
        public int ScanEnd { get; set; }


        public event EndEventHandler DataPosEvent;
        public event EndEventHandler EndEvent;

        public event EventHandler StartEvent;
        public event EventHandler FinishEvent;

        enum CTRLST
        {
            INIT = 0,//判断进入阶段

            #region 归0 及 样品采集阶段
            ORIGINWAIT = 2,//正在归0
            FORWARD = 3,//前进到样品，或扫描结束位置
            FORWAIT_1 = 4,//前进等待
            FORWAIT_2 = 5,//前进结束，等待获取grid
            BACKWARD = 8,//后退到温修，或扫描开始位置
            BACKWAIT_1 = 9,//后退等待
            BACKWAIT_2 = 10,//后退结束，等待获取grid
            FORWAIT_SAMPLE = 11,//前进取样中
            FORW_SAMPLE = 12,//前进取样
            BACKWAIT_SAMPLE = 13,//后退取样中
            BACKW_SAMPLE = 14,//后退取样
            #endregion

            #region 正常扫描阶段
            SCAN_FORW = 20,//前进扫描
            SCAN_FORWAIT = 21,//前进等待
            SCAN_BACKW = 22,//后退扫描
            SCAN_BACKWAIT = 23,//后退等待
            #endregion


        }
        CTRLST state;
        #endregion

        public UInt32 Velocity { get; set; }

        public GM_ScanMotion()
        {
            GMState = CTRL_STATE.SCAN;

            ScanStart = -1;
            ScanEnd = -1;

        }
        public virtual void Init(IFlyADClientAdv flyad, GSample gsample, WarningSystem2 warningSystem)
        {
            base.Init(flyad);
            this.gsample = gsample;
            this.warningSystem = warningSystem;

            flyad.MiniGridEvent += (s, e) =>
            {
                if ((state == CTRLST.FORWAIT_1)
                || (state == CTRLST.BACKWAIT_1)
                || (state == CTRLST.SCAN_FORWAIT)
                || (state == CTRLST.SCAN_BACKWAIT))
                {
                    DataPosEvent?.Invoke(this, e);
                }
            };
        }

        protected virtual bool Start2(int start, int end)
        {
            ScanStart = start;
            ScanEnd = end;

            timer.Restart();
            orgStartTime = TimeSpan.FromMinutes(-OrgInterval);
            state = CTRLST.INIT;
            reInitCnt = 0;
            warningSystem.Remove(ERRNOs.ERRNO_SCAN_FATAL);

            if (gsample != null)
                gsample.Reset(ScanStart, ScanEnd);

            StartEvent?.Invoke(this, null);
            return true;
        }

        public override void Stop()
        {
            timer.Stop();
            FinishEvent?.Invoke(this, null);
            base.Stop();
        }
        /// <summary>
        /// 由于NoMove，重试的次数。
        /// </summary>
        int reInitCnt = 0;

        /// <summary>
        /// 等待停止; 
        /// 正常停止返回true，没有停止及异常停止返回false
        /// </summary>
        /// <returns></returns>
        bool WaitFinish()
        {
            switch (mFlyAD.DriveStatus)
            {
                case DRIVE_MAN_STATUS.STOP://完成任务
                case DRIVE_MAN_STATUS.LIMIT://撞了限位，也算运行完成
                    {
                        reInitCnt = 0;
                        warningSystem.Remove(ERRNOs.ERRNO_SCAN_FATAL);
                        return true;
                    }
                case DRIVE_MAN_STATUS.STOP_MANUAL://异常
                    {
                        if (mFlyAD.Is10sNoMove)
                        {
                            //重新运作整个流程，试试
                            reInitCnt++;
                            warningSystem.Update(ERRNOs.ERRNO_SCAN_FATAL, accessory: $"NoMove{reInitCnt}");
                            if (reInitCnt < 3)
                            {
                                state = CTRLST.INIT;
                            }
                            else
                            {
                                //3次都失败
                                Stop();
                            }
                        }
                        else
                        {
                            warningSystem.Update(ERRNOs.ERRNO_SCAN_FATAL,accessory: "ManualStop");
                            Stop(); 
                        }
                        return false;
                    }
            }
            return false;
        }

        /// <summary>
        /// 等待停止; 
        /// 正常停止返回true，没有停止及异常停止返回false
        /// </summary>
        /// <returns></returns>
        bool WaitFinish_Home()
        {
            switch (mFlyAD.DriveStatus)
            {
                case DRIVE_MAN_STATUS.STOP://完成任务
                    {
                        reInitCnt = 0;
                        warningSystem.Remove(ERRNOs.ERRNO_SCAN_FATAL);
                        return true;
                    }
                    break;
                case DRIVE_MAN_STATUS.LIMIT://撞了限位，也算运行完成
                    {
                        reInitCnt = 0;
                        warningSystem.Update(ERRNOs.ERRNO_SCAN_FATAL,accessory: "LimitAtHome");
                    }
                    break;
                case DRIVE_MAN_STATUS.STOP_MANUAL://异常
                    {
                        if (mFlyAD.Is10sNoMove)
                        {
                            //重新运作整个流程，试试
                            reInitCnt++;
                            warningSystem.Update(ERRNOs.ERRNO_SCAN_FATAL, accessory: $"NoMove{reInitCnt}AtHome");
                            if (reInitCnt < 3)
                            {
                                state = CTRLST.INIT;
                            }
                            else
                            {
                                //3次都失败
                                Stop();
                            }
                        }
                        else
                        {
                            warningSystem.Update(ERRNOs.ERRNO_SCAN_FATAL,accessory: "ManualStopAtHome");
                            Stop();
                        }
                    }break;
            }
            return false;
        }
        protected override void OnPoll()
        {
            switch (state)
            {
                case CTRLST.INIT:
                    {
                        if (IsOrging())
                        {
                            mFlyAD.Origin();
                            state = CTRLST.ORIGINWAIT;
                        }
                        else
                        {
                            state = CTRLST.SCAN_FORW;
                        }
                    }
                    break;
                case CTRLST.ORIGINWAIT:
                    {
                        if (!WaitFinish_Home())
                            break;

                        state = CTRLST.FORWARD;
                    }
                    break;
                case CTRLST.FORWARD:
                    {
                        int to = ScanEnd;

                        if (gsample.GetSampleRange(Misc.DIRECTION.FORWARD, out int b, out int e))
                        {
                            FlyADBase.MOTORTYPE motorType = mFlyAD.MotorType;

                            if (motorType == FlyADBase.MOTORTYPE.VF0)
                            {
                                //直接去到取样的位置
                                to = e;
                            }
                            else//要变速，分开两段
                            {
                                to = b;
                            }
                        }

                        mFlyAD.SetVelocity(Velocity);
                        mFlyAD.Runto(to);
                        state = CTRLST.FORWAIT_1;
                    }
                    break;
                case CTRLST.FORWAIT_1:
                    {
                        if (!WaitFinish())
                            break;
                        
                        FlushAD(DIRECTION.FORWARD);
                        state = CTRLST.FORWAIT_2;
                    }
                    break;
                case CTRLST.FORWAIT_2:
                    {
                        state = CTRLST.BACKWARD;

                        if (gsample.GetSampleRange(Misc.DIRECTION.FORWARD, out int b, out int e))
                        {
                            FlyADBase.MOTORTYPE motorType = mFlyAD.MotorType;

                            if (motorType == FlyADBase.MOTORTYPE.VF0)
                            {
                                //直接去到取样的位置
                                state = CTRLST.FORW_SAMPLE;
                            }
                            else//要变速，分开两段
                            {
                                mFlyAD.SetVelocity(gsample.Velocity);
                                mFlyAD.Runto(e);
                                state = CTRLST.FORWAIT_SAMPLE;
                            }
                        }
                    }
                    break;
                case CTRLST.FORWAIT_SAMPLE:
                    {
                        if (!WaitFinish())
                            break;
                        state = CTRLST.FORW_SAMPLE;
                    }
                    break;
                case CTRLST.FORW_SAMPLE:
                    {
                        gsample.Do(Misc.DIRECTION.FORWARD);
                        state = CTRLST.BACKWARD;
                    }
                    break;
                case CTRLST.BACKWARD:
                    {
                        int to = ScanStart;

                        if (gsample.GetSampleRange(Misc.DIRECTION.BACKWARD, out int b, out int e))
                        {
                            FlyADBase.MOTORTYPE motorType = mFlyAD.MotorType;

                            if (motorType == FlyADBase.MOTORTYPE.VF0)
                            {
                                //直接去到取样的位置
                                to = b;
                            }
                            else//要变速，分开两段
                            {
                                to = e;
                            }
                        }

                        mFlyAD.SetVelocity(Velocity);
                        mFlyAD.Runto(to);
                        state = CTRLST.BACKWAIT_1;
                    }
                    break;
                case CTRLST.BACKWAIT_1:
                    {
                        if (!WaitFinish())
                            break;
                        
                        FlushAD(DIRECTION.BACKWARD);
                        state = CTRLST.BACKWAIT_2;
                    }
                    break;
                case CTRLST.BACKWAIT_2:
                    {
                        if (gsample.GetSampleRange(Misc.DIRECTION.BACKWARD, out int b, out int e))
                        {
                            FlyADBase.MOTORTYPE motorType = mFlyAD.MotorType;

                            if (motorType == FlyADBase.MOTORTYPE.VF0)
                            {
                                //直接去到取样的位置
                                state = CTRLST.BACKW_SAMPLE;
                            }
                            else//要变速，分开两段
                            {
                                mFlyAD.SetVelocity(gsample.Velocity);
                                mFlyAD.Runto(b);
                                state = CTRLST.BACKWAIT_SAMPLE;
                            }
                        }
                        else
                        {
                            //完成一次周期
                            if (!gsample.IsFailure())
                                orgStartTime = timer.Elapsed;
                            state = CTRLST.INIT;
                        }
                    }
                    break;
                case CTRLST.BACKWAIT_SAMPLE:
                    {
                        if (!WaitFinish())
                            break;
                        state = CTRLST.BACKW_SAMPLE;
                    }
                    break;
                case CTRLST.BACKW_SAMPLE:
                    {
                        gsample.Do(Misc.DIRECTION.BACKWARD);
                        //完成一次周期
                        if (!gsample.IsFailure())
                            orgStartTime = timer.Elapsed;
                        state = CTRLST.INIT;
                    }
                    break;


                case CTRLST.SCAN_FORW:
                    {
                        int to = ScanEnd;
                        mFlyAD.SetVelocity(Velocity);
                        mFlyAD.Runto(to);
                        state = CTRLST.SCAN_FORWAIT;
                    }
                    break;
                case CTRLST.SCAN_FORWAIT:
                    {
                        if (!WaitFinish())
                            break;
                        
                        FlushAD(DIRECTION.FORWARD);
                        state = CTRLST.SCAN_BACKW;
                    }
                    break;
                case CTRLST.SCAN_BACKW:
                    {
                        int to = ScanStart;
                        mFlyAD.SetVelocity(Velocity);
                        mFlyAD.Runto(to);
                        state = CTRLST.SCAN_BACKWAIT;
                    }
                    break;
                case CTRLST.SCAN_BACKWAIT:
                    {
                        if (!WaitFinish())
                            break;
                        
                        FlushAD(DIRECTION.BACKWARD);
                        state = CTRLST.INIT;
                    }
                    break;
            }
        }

        private bool IsOrging()
        {
            if (OrgInterval > 0)
            {

                if (timer.Elapsed >= (orgStartTime + TimeSpan.FromMinutes(OrgInterval)))
                    return true;
            }

            return false;
        }

        private void FlushAD(Misc.DIRECTION direction)
        {
            int pos1, pos2;

            pos1 = ScanStart;
            pos2 = ScanEnd;
            int start_grid = pos1 / mFlyAD.PosOfGrid;
            int end_grid = pos2 / mFlyAD.PosOfGrid;

            if (start_grid < 0)
                start_grid = 0;

            int len = end_grid - start_grid + 1;
            int[] dat;
            mFlyAD.GetGrid(direction, start_grid, len, out dat);

            if (EndEvent != null)
            {
                EndEvent(this, new MiniGridEventArgs()
                {
                    grid_start = start_grid,
                    direction = direction,
                    posOfGrid = mFlyAD.PosOfGrid,
                    buf = dat
                });
            }
        }
    }


}
