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


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

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

        int autoOriginCount;//归原点累计(多少次扫描一个归原点的累计)

        int orgInterval;//归原点间隔
        public int OrgInterval
        {
            get { return orgInterval; }
            set
            {
                if (orgInterval != value)
                {
                    orgInterval = value;
                    NotifyPropertyChanged("OrgInterval");
                }
            }
        }

        int scanStart, scanEnd;//扫描范围
        public int ScanStart
        {
            get { return scanStart; }
            set
            {
                if (scanStart != value)
                {
                    scanStart = value;
                    NotifyPropertyChanged("ScanStart");
                }
            }
        }
        public int ScanEnd
        {
            get { return scanEnd; }
            set
            {
                if (scanEnd != value)
                {
                    scanEnd = value;
                    NotifyPropertyChanged("ScanEnd");
                }
            }
        }

        public event EndEventHandler DataPosEvent;
        public event EndEventHandler EndEvent;

        public event EventHandler StartEvent;
        public event EventHandler FinishEvent;

        enum CTRLST
        {
            SORIGIN = 1,//判断是否归0
            SORIGINWAIT = 2,//正在归0
            SFORWARD = 3,//前进到样品，或扫描结束位置
            SFORWAIT_1 = 4,//前进等待
            SFORWAIT_2 = 5,//前进结束，等待获取grid
            SBACKWARD = 8,//后退到温修，或扫描开始位置
            SBACKWAIT_1 = 9,//后退等待
            SBACKWAIT_2 = 10,//后退结束，等待获取grid
            SFORWAIT_SAMPLE = 11,//前进取样中
            SFORW_SAMPLE = 12,//前进取样
            SBACKWAIT_SAMPLE = 13,//后退取样中
            SBACKW_SAMPLE = 14//后退取样
        }
        CTRLST state;
        #endregion

        public UInt32 Velocity { get; set; }

        public GM_ScanMotion(FlyAD7 flyad, GSample gsample)
            : base(flyad)
        {
            GMState = CTRL_STATE.SCAN;

            this.gsample = gsample;
            ScanCnt = -1;//无限次扫描

            ScanStart = -1;
            ScanEnd = -1;

            state = CTRLST.SORIGIN;

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

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

            autoOriginCount = 0;
            state = CTRLST.SORIGIN;
            if (ScanCnt >= 0)
            {
                OrgInterval = ScanCnt + 1;//禁止自动归原点
            }

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

            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.SORIGIN:
                    {
                        state = CTRLST.SFORWARD;

                        //if( scanCnt == -1 )
                        {
                            if (IsOrgEnable() && (autoOriginCount > 0))
                                autoOriginCount--;

                            if (IsOrging())
                            {
                                autoOriginCount = OrgInterval;
                                mFlyAD.Origin();
                                state = CTRLST.SORIGINWAIT;
                                break;
                            }
                        }
                    } break;
                case CTRLST.SORIGINWAIT:
                    {
                        WaitFinish(ref state, CTRLST.SFORWARD);
                    } break;
                case CTRLST.SFORWARD:
                    {
                        int to = ScanEnd;

                        if (scanCnt == -1)
                        {
                            if (gsample != null && gsample.Check())
                            {
                                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.SetPosParam(Velocity, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
                        mFlyAD.Runto(to);
                        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;

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

                        if (scanCnt == 0)
                        {
                            //扫描完成
                            Stop(); return;
                        }

                        if (scanCnt == -1)
                        {
                            if (gsample != null && gsample.Check())
                            {
                                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.SFORW_SAMPLE;
                                    }
                                    else//要变速，分开两段
                                    {
                                        mFlyAD.SetPosParam((UInt32)gsample.Velocity, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
                                        mFlyAD.Runto(e);
                                        state = CTRLST.SFORWAIT_SAMPLE;
                                    }
                                }
                            }
                        }
                    } break;
                case CTRLST.SFORWAIT_SAMPLE:
                    {
                        WaitFinish(ref state, CTRLST.SFORW_SAMPLE);
                    } break;
                case CTRLST.SFORW_SAMPLE:
                    {
                        gsample.Do(Misc.DIRECTION.FORWARD);
                        state = CTRLST.SBACKWARD;
                    } break;
                case CTRLST.SBACKWARD:
                    {
                        int to = ScanStart;
                        if (scanCnt == -1)
                        {
                            if (gsample.Check())
                            {
                                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.SetPosParam(Velocity, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
                        mFlyAD.Runto(to);
                        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.SORIGIN;

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

                        if (scanCnt == 0)
                        {
                            //扫描完成
                            Stop(); return;
                        }
                        if (scanCnt == -1)
                        {
                            if (gsample.Check())
                            {
                                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.SBACKW_SAMPLE;
                                    }
                                    else//要变速，分开两段
                                    {
                                        mFlyAD.SetPosParam((UInt32)gsample.Velocity, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
                                        mFlyAD.Runto(b);
                                        state = CTRLST.SBACKWAIT_SAMPLE;
                                    }

                                }
                            }
                        }
                    } break;
                case CTRLST.SBACKWAIT_SAMPLE:
                    {
                        WaitFinish(ref state, CTRLST.SBACKW_SAMPLE);
                    } break;
                case CTRLST.SBACKW_SAMPLE:
                    {
                        gsample.Do(Misc.DIRECTION.BACKWARD);
                        state = CTRLST.SORIGIN;
                    } break;
            }
        }

        private bool IsOrging()
        {
            if ((autoOriginCount == 0) && (OrgInterval > 0))
                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.SetPosParam(Velocity, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
                        mFlyAD.Runto(0);
                        state = CTRLST.READY_BACKWAIT;
                    } break;
                case CTRLST.READY_BACKWAIT:
                    {
                        WaitFinish(ref state, CTRLST.SFORWARD);
                    } break;
                case CTRLST.SFORWARD:
                    {
                        int to = mFlyAD.PosLen;
                        mFlyAD.SetPosParam(Velocity, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
                        mFlyAD.Runto(to);
                        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.SetPosParam(Velocity, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
                        mFlyAD.Runto(0);
                        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
                });
            }
        }
    }
}
