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


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

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;

        /// <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; }

        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(FlyAD7 flyad, GSample gsample)
            : base(flyad)
        {
            GMState = CTRL_STATE.SCAN;

            this.gsample = gsample;

            ScanStart = -1;
            ScanEnd = -1;
            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;

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

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

        public override void Stop()
        {
            timer.Stop();
            FinishEvent?.Invoke(this, null);
            base.Stop();
        }
        bool WaitFinish(ref CTRLST src, CTRLST next)
        {
            switch (mFlyAD.DriveStatus)
            {
                case DRIVE_MAN_STATUS.STOP://完成任务
                case DRIVE_MAN_STATUS.LIMIT:
                    {
                        src = next;
                        return true;
                    } break;
                case DRIVE_MAN_STATUS.STOP_MANUAL://异常
                    {
                        NotifyError(ERRNO_Running_Manual);
                        Stop(); return false;
                    } 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:
                    {
                        WaitFinish(ref state, CTRLST.FORWARD);
                    } break;
                case CTRLST.FORWARD:
                    {
                        int to = ScanEnd;

                        int b, e;
                        if (gsample.GetSampleRange(Misc.DIRECTION.FORWARD, out b, out 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(ref state, CTRLST.FORWAIT_2))
                            FlushAD(DIRECTION.FORWARD);

                    } break;
                case CTRLST.FORWAIT_2:
                    {
                        state = CTRLST.BACKWARD;

                        int b, e;
                        if (gsample.GetSampleRange(Misc.DIRECTION.FORWARD, out b, out 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:
                    {
                        WaitFinish(ref state, CTRLST.FORW_SAMPLE);
                    } break;
                case CTRLST.FORW_SAMPLE:
                    {
                        gsample.Do(Misc.DIRECTION.FORWARD);
                        state = CTRLST.BACKWARD;
                    } break;
                case CTRLST.BACKWARD:
                    {
                        int to = ScanStart;

                        int b, e;
                        if (gsample.GetSampleRange(Misc.DIRECTION.BACKWARD, out b, out 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(ref state, CTRLST.BACKWAIT_2))
                            FlushAD(DIRECTION.BACKWARD);
                    } break;
                case CTRLST.BACKWAIT_2:
                    {
                        int b, e;
                        if (gsample.GetSampleRange(Misc.DIRECTION.BACKWARD, out b, out 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.OK())
                                orgStartTime = timer.Elapsed;
                            state = CTRLST.INIT;
                        }
                    } break;
                case CTRLST.BACKWAIT_SAMPLE:
                    {
                        WaitFinish(ref state, CTRLST.BACKW_SAMPLE);
                    } break;
                case CTRLST.BACKW_SAMPLE:
                    {
                        gsample.Do(Misc.DIRECTION.BACKWARD);
                        //完成一次周期
                        if (gsample.OK())
                            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(ref state, CTRLST.SCAN_BACKW))
                            FlushAD(DIRECTION.FORWARD);
                    }
                    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(ref state, CTRLST.INIT))
                            FlushAD(DIRECTION.BACKWARD);
                    }
                    break;
            }
        }

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

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

            return false;
        }

        private bool IsOrgEnable()
        {
            if (OrgInterval > 0)
                return true;
            else
                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
                });
            }
        }
    }

    /// <summary>
    /// 只是来回走的逻辑，不包含数据处理 
    /// 0~posLen
    /// </summary>
    public abstract class GM_ScanMotion2 : GM_Base
    {
        #region 成员变量

       
        int scanCnt;//扫描次数， 当为-1时，无限次扫描，>0时，有限次扫描
        protected int ScanCnt
        {
            get
            {
                return scanCnt;
            }
            set
            {
                if (scanCnt != value)
                {
                    scanCnt = value;
                    NotifyPropertyChanged("ScanCnt");
                }
            }
        }

        public event EndEventHandler DataPosEvent;
        public event EndEventHandler EndEvent;

        public event EventHandler StartEvent;
        public event EventHandler FinishEvent;

        enum CTRLST
        {
            /// <summary>
            /// 准备动作:归0
            /// </summary>
            READY_ORIGIN = 1,
            /// <summary>
            /// 准备动作:正在归0
            /// </summary>
            READY_ORIGINWAIT = 2,
            /// <summary>
            /// 准备动作:后退到 0 脉冲
            /// </summary>
            READY_BACKW = 3,
            /// <summary>
            /// 准备动作:正在后退
            /// </summary>
            READY_BACKWAIT = 4,
            /// <summary>
            /// 前进到 机架总长
            /// </summary>
            SFORWARD = 5,
            /// <summary>
            /// 前进等待
            /// </summary>
            SFORWAIT_1 = 6,
            /// <summary>
            /// 前进结束，等待获取grid
            /// </summary>
            SFORWAIT_2 = 7,
            /// <summary>
            /// 后退到 0 脉冲
            /// </summary>
            SBACKWARD = 8,
            /// <summary>
            /// 后退等待
            /// </summary>
            SBACKWAIT_1 = 9,
            /// <summary>
            /// 后退结束，等待获取grid
            /// </summary>
            SBACKWAIT_2 = 10,
        }
        CTRLST state;
        #endregion

        public UInt32 Velocity { get; set; }

        public GM_ScanMotion2(FlyAD7 flyad)
            : base(flyad)
        {
            GMState = CTRL_STATE.SCAN;

            ScanCnt = -1;//无限扫描

            state = CTRLST.READY_ORIGIN;

            flyad.MiniGridEvent += (s, e) =>
            {
                if ((state == CTRLST.SFORWAIT_1) || (state == CTRLST.SBACKWAIT_1))
                {
                    if (DataPosEvent != null)
                        DataPosEvent(this, e);
                }
            };
        }

        protected virtual bool Start2()
        {

            state = CTRLST.READY_ORIGIN;

            if (StartEvent != null)
                StartEvent(this, null);
            return true;
        }

        public override void Stop()
        {
            if (FinishEvent != null)
                FinishEvent(this, null);
            base.Stop();
        }
        bool WaitFinish(ref CTRLST src, CTRLST next)
        {
            switch (mFlyAD.DriveStatus)
            {
                case DRIVE_MAN_STATUS.STOP://完成任务
                case DRIVE_MAN_STATUS.LIMIT:
                    {
                        src = next;
                        return true;
                    } break;
                case DRIVE_MAN_STATUS.STOP_MANUAL://异常
                    {
                        NotifyError(ERRNO_Running_Manual);
                        Stop(); return false;
                    } break;
            }
            return false;
        }
        protected override void OnPoll()
        {
            switch (state)
            {
                case CTRLST.READY_ORIGIN:
                    {
                        mFlyAD.Origin();
                        state = CTRLST.READY_ORIGINWAIT;
                    } break;
                case CTRLST.READY_ORIGINWAIT:
                    {
                        WaitFinish(ref state, CTRLST.READY_BACKW);
                    }break;
                case CTRLST.READY_BACKW:
                    {

                        mFlyAD.SetVelocity(Velocity);
                        mFlyAD.RuntoMin();
                        state = CTRLST.READY_BACKWAIT;
                    } break;
                case CTRLST.READY_BACKWAIT:
                    {
                        WaitFinish(ref state, CTRLST.SFORWARD);
                    } break;
                case CTRLST.SFORWARD:
                    {
                        mFlyAD.SetVelocity(Velocity);
                        mFlyAD.RuntoMax();
                        state = CTRLST.SFORWAIT_1;
                    } break;
                case CTRLST.SFORWAIT_1:
                    {
                        if (WaitFinish(ref state, CTRLST.SFORWAIT_2))
                            FlushAD(DIRECTION.FORWARD);
                    } break;
                case CTRLST.SFORWAIT_2:
                    {
                        state = CTRLST.SBACKWARD;
                    } break;
                case CTRLST.SBACKWARD:
                    {
                        mFlyAD.SetVelocity(Velocity);
                        mFlyAD.RuntoMin();
                        state = CTRLST.SBACKWAIT_1;
                    } break;
                case CTRLST.SBACKWAIT_1:
                    {
                        if (WaitFinish(ref state, CTRLST.SBACKWAIT_2))
                            FlushAD(DIRECTION.BACKWARD);
                    } break;
                case CTRLST.SBACKWAIT_2:
                    {
                        state = CTRLST.SFORWARD;

                        //扫描次数
                        if (ScanCnt > 0)
                            ScanCnt--;

                        if (ScanCnt == 0)
                        {
                            //扫描完成
                            Stop(); return;
                        }
                    } break;
            }
        }
        private void FlushAD(Misc.DIRECTION direction)
        {
            int start_grid = 0;
            int end_grid = mFlyAD.PosLen / mFlyAD.PosOfGrid;

            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
                });
            }
        }
    }
}
