using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.ComponentModel;
using FObjBase;
using Misc;
using System.Collections.ObjectModel;
namespace FlyADBase
{
    public interface IFlyAD : INotifyPropertyChanged
    {
        IPEndPoint LocalEP { get; set; }
        /// <summary>
        /// 从flyad7 获取 的systick 转换的时间
        /// </summary>
        DateTime Now { get; }


        //POS & AD
        int Position { get; }
        int Speed { get; }
        int AD { get; }/*1000ms从AD卡获取(或推送)1个AD值。此AD值只用于调试,定点*/
        int ADMax { get; }//AD值最大值 ,恒定返回65535
        //IO
        UInt16 IStatus { get; }/*input read*/
        UInt16 OStatus { get; }/*output read*/
        /// <summary>
        /// Out0 = 0, SetOutput(0x0001,0x0000);
        /// Out0 = 1, Out1 = 0, SetOutput(0x0003,0x0001);
        /// </summary>
        /// <param name="mask"></param>
        /// <param name="enable"></param>
        void SetOutput(UInt16 mask, UInt16 enable); 

        /// <summary>
        /// 读取参数, 全部!!!!
        /// </summary>
        void UpdateParam();

        #region 配置参数
        void SetSysParam(UInt16 posOfGrid, MOTORTYPE motortype, UInt16 ratio01, UInt16 ratio02);
        MOTORTYPE MotorType { set; get; }
        UInt16 PosOfGrid { set; get; }// 单位 pulse/grid
        UInt16 Ratio01 { get; set; }
        UInt16 Ratio02 { get; set; }

        #endregion

        Int16 PosOffset { set; get; }//脉冲平移
        UInt32 JogVelocity { set; get; }

        #region 速度
        UInt32 Velocity { set; get; }
        UInt32 SVelocity { set; get; }
        UInt32 ATime { set; get; }
        UInt32 DTime { set; get; }
        UInt32 HVelocity1 { set; get; }
        UInt32 HVelocity2 { set; get; }
        void SetPosParam(UInt32 velocity, UInt32 sv, UInt32 atime, UInt32 dtime, UInt32 hspeed1, UInt32 hspeed2);
        #endregion

        #region 密码

        AREA_STATUS AreaStatus { get; }
        AREA_ERR AreaRet { get; }
        /// <summary>
        /// 序列码byte[6]
        /// </summary>
        byte[] Code { get; }
        /// <summary>
        /// 系统剩余时间
        /// </summary>
        int Surplus { get; }
        /// <summary>
        /// 系统授权码access[8]
        /// </summary>
        byte[] Access { get; }
        /// <summary>
        /// 输入系统授权码
        /// </summary>
        /// <param name="access"></param>
        void SetAccess(byte[] access);
        /// <summary>
        /// 初始化系统信息区
        /// </summary>
        void InitArea();

        #endregion


        //grid
        void GetGrid(DIRECTION direction, int grid_start, int grid_len, out int[] dat);
        void GetGrid(DIRECTION direction, out int[] dat);

        event TimeGridEventHandler TimeGridEvent;
        event MiniGridEventHandler MiniGridEvent;
        event IStatusChangedEventHandler IStatusChangedEvent;
        event MiniGridEventHandler GridEvent;



        #region 运行
        void Runto(int to);
        void Origin();
        void Stop();
        void Backward();
        void Forward();
        #endregion

        DRIVE_MAN_ORDER DriveOrder { get; }
        DRIVE_MAN_STATUS DriveStatus { get; }

        #region 同步
        /// <summary>
        /// 同步用标示
        /// </summary>
        Int32 Marker { get; }
        #region 横向脉冲
        /// <summary>
        /// 逻辑横向脉冲偏移  Pos1 + Pos1LCShift = Pos1LC
        /// </summary>
        int Pos1LCShift { get; set; }
        #endregion
        #region 主轴脉冲
        /// <summary>
        /// 纵向脉冲,也叫主轴脉冲
        /// </summary>
        int Position2 { get; set; }
        /// <summary>
        /// 纵向速度
        /// </summary>
        int Speed2 { get; }
        /// <summary>
        /// 纵向偏移,这个是相对量
        /// </summary>
        void SetPos2Offset(int offset);
        /// <summary>
        /// 纵向值补偿系数,补偿时,先乘除后加减
        /// </summary>
        float Pos2Comp { get; set; }
        /// <summary>
        /// 纵向同步事件,0-1事件
        /// </summary>
        /// <param name="pos2"></param>
        /// <param name="immediately">只要是 01,就立刻修正</param>
        void SetPos2At01(int pos2, bool immediately);
     
        #endregion
        #region 同步控制 同步状态转换规则
        /// <summary>
        /// 进入同步状态
        /// </summary>
        /// <param name="pos2"></param>
        void SyncBegin(int pos2);
        /// <summary>
        /// 进入同步状态
        /// </summary>
        void SyncBegin();
        /// <summary>
        /// 退出同步状态
        /// </summary>
        void SyncEnd();
        /// <summary>
        /// 清空同步指令
        /// </summary>
        void SyncClear();
        /// <summary>
        /// 清空POS2同步列表
        /// </summary>
        void SyncPos2Clear();
        #endregion
        #region 同步扫描 脚本指令
        //同步扫描至
        //D+0xE0+开始主轴位置+结束主轴位置+结束横向脉冲位置(逻辑位置)+脉冲开关(1B)+命令识标号(4B)
        void SyncRunAtLC(int pos2_begin, int pos2_end, int pos1lc, bool hasDataGrid, Int32 marker);

        //位于队列头时运行,归零
        //D+0xE1+命令识标号(4B)
        void SyncOrigin(Int32 marker);


        //位于队列头时运行,以速度运行至物理位置
        //D+0xE2+横向脉冲位置(4B:int32,物理位置)+速度(4B:int32)+脉冲开关(1B)+命令识标号(4B)
        void SyncRunTo(int pos1, UInt32 velocity, bool hasDataGrid, Int32 marker);

        //位于队列头时运行,以速度运行至逻辑位置
        //D+0xE3+横向脉冲位置(4B:int32,逻辑位置)+速度(4B:int32)+脉冲开关(1B)+命令识标号(4B)
        void SyncRunToLC(int pos1lc, UInt32 velocity, bool hasDataGrid, Int32 marker);


        //等待,ms
        //D+0xE4+毫秒数(4B:int32)+命令识标号(4B)
        void SyncWait(int ms, Int32 marker);

        #endregion
        #endregion
    }
    public interface IFlyADClient : IFlyAD
    {
        bool IsConnected { get; }
        int ConnectCnt { get; }
        CorrectADsHandler CorrectADs { get; set; }
        bool HasCRC { get; set; }
        /// <summary>
        /// grid 滤波
        /// </summary>
        int GridSmooth { get; set; }
        int InBufLen { get; }

        /// <summary>
        /// Ratio02 / Ratio01
        /// </summary>
        double Speed1Scale { get; }

        void Connect();
        void Connect(IPEndPoint ep);
        void ReConnect();

        int PosLen { get; set; }
        void RuntoMin();
        void RuntoMax();

        int LastPos2At01 { get; }
        bool IsSync { get; }

        void SetOutputBit(int index, bool is1);

        #region 滞后处理
        /// <summary>
        /// ad滞后修正  单位ms
        /// </summary>
        int ADLag { get; set; }
        event GridAdvEventHandler GridAdvEvent;
        #endregion

        #region runto 推送 istatus 变化
        void GridIStatusEventAdd(int istatus_no, GridIStatusEventHander func);
        void GridIStatusEventDel(int istatus_no, GridIStatusEventHander func);
        #endregion

        #region 同步

        /// <summary>
        /// 同步列表,完成后,会删除
        /// </summary>
        ObservableCollection<SyncOrder> SyncOrders { get; }
        #endregion
    }



    public enum SyncOrderState
    {
        Waiting,
        Doing,
        Finish
    }
    public abstract class SyncOrder : INotifyPropertyChanged
    {

        private SyncOrderState state = SyncOrderState.Waiting;
        public SyncOrderState State
        {
            get { return state; }

            set {
                if (state != value) 
                {
                    state = value;
                    NotifyPropertyChanged("State");
                }
            }
        }
        public Int32 Marker { get; set; }

        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
    public class SyncOrder_SyncRunAtLC : SyncOrder
    {
        public int Pos2Begin { get; set; }
        public int Pos2End { get; set; }
        public int Pos1LC { get; set; }
        public bool HasDataGrid { get; set; }
        public override string ToString()
        {
            string s;
            if (State == SyncOrderState.Waiting)
                s = "_ ";
            else if (State == SyncOrderState.Doing)
                s = "√ ";
            else// if (State == SyncOrderState.Finish)
                s = "x ";

            return s+"SyncRunAtLC( " +
                "Pos2Begin=" + Pos2Begin.ToString() + ", " +
                "Pos2End=" + Pos2End.ToString() + ", " +
                "Pos1LC=" + Pos1LC.ToString() + ", " +
                "HasDataGrid=" + HasDataGrid.ToString() + ", " +
                "Marker=" + Marker.ToString() + ")";
        }
    }
    public class SyncOrder_SyncOrigin : SyncOrder
    {
        public override string ToString()
        {
            string s;
            if (State == SyncOrderState.Waiting)
                s = "_ ";
            else if (State == SyncOrderState.Doing)
                s = "√ ";
            else// if (State == SyncOrderState.Finish)
                s = "x ";

            return s + "SyncOrigin( " +
                "Marker=" + Marker.ToString() + ")";
        }

    }
    public class SyncOrder_SyncRunTo : SyncOrder
    {
        public int Pos1 { get; set; }
        public UInt32 Velocity { get; set; }
        public bool HasDataGrid { get; set; }
        public override string ToString()
        {
            string s;
            if (State == SyncOrderState.Waiting)
                s = "_ ";
            else if (State == SyncOrderState.Doing)
                s = "√ ";
            else// if (State == SyncOrderState.Finish)
                s = "x ";

            return s + "SyncRunTo( " +
                "Pos1=" + Pos1.ToString() + ", " +
                "Velocity=" + Velocity.ToString() + ", " +
                "HasDataGrid=" + HasDataGrid.ToString() + ", " +
                "Marker=" + Marker.ToString() + ")";
        }

    }
    public class SyncOrder_SyncRunToLC : SyncOrder
    {
        public int Pos1 { get; set; }
        public UInt32 Velocity { get; set; }
        public bool HasDataGrid { get; set; }
        public override string ToString()
        {
            string s;
            if (State == SyncOrderState.Waiting)
                s = "_ ";
            else if (State == SyncOrderState.Doing)
                s = "√ ";
            else// if (State == SyncOrderState.Finish)
                s = "x ";

            return s + "SyncRunToLC( " +
                "Pos1=" + Pos1.ToString() + ", " +
                "Velocity=" + Velocity.ToString() + ", " +
                "HasDataGrid=" + HasDataGrid.ToString() + ", " +
                "Marker=" + Marker.ToString() + ")";
        }
    }
    public class SyncOrder_SyncWait : SyncOrder
    {
        public int MS { get; set; }
        public override string ToString()
        {
            string s;
            if (State == SyncOrderState.Waiting)
                s = "_ ";
            else if (State == SyncOrderState.Doing)
                s = "√ ";
            else// if (State == SyncOrderState.Finish)
                s = "x ";

            return s + "SyncWait( " +
                "MS=" + MS.ToString() + ", " +
                "Marker=" + Marker.ToString() + ")";
        }
    }


    public static class SyncOrderExtention
    {
        public static void Add(this SyncOrder order, IFlyAD flyad) 
        {
            if (order is SyncOrder_SyncRunAtLC) 
            {
                ((SyncOrder_SyncRunAtLC)order).Add(flyad);
            }
            else if (order is SyncOrder_SyncOrigin) 
            {
                ((SyncOrder_SyncOrigin)order).Add(flyad);
            }
            else if (order is SyncOrder_SyncRunTo)
            {
                ((SyncOrder_SyncRunTo)order).Add(flyad);
            }
            else if (order is SyncOrder_SyncRunToLC)
            {
                ((SyncOrder_SyncRunToLC)order).Add(flyad);
            }
            else if (order is SyncOrder_SyncWait)
            {
                ((SyncOrder_SyncWait)order).Add(flyad);
            }
        }
        public static void Add(this SyncOrder_SyncRunAtLC order, IFlyAD flyad)
        {
            flyad.SyncRunAtLC(order.Pos2Begin, order.Pos2End, order.Pos1LC, order.HasDataGrid, order.Marker);
        }
        public static void Add(this SyncOrder_SyncOrigin order, IFlyAD flyad)
        {
            flyad.SyncOrigin(order.Marker);
        }
        public static void Add(this SyncOrder_SyncRunTo order, IFlyAD flyad)
        {

            flyad.SyncRunTo(
                order.Pos1, order.Velocity, order.HasDataGrid, order.Marker);

        }
        public static void Add(this SyncOrder_SyncRunToLC order, IFlyAD flyad)
        {

            flyad.SyncRunToLC(
                order.Pos1, order.Velocity, order.HasDataGrid, order.Marker);

        }
        public static void Add(this SyncOrder_SyncWait order, IFlyAD flyad)
        {
            flyad.SyncWait(order.MS, order.Marker);
        }
    }


    public class IStatusChangedEventArgs : EventArgs
    {
        public IStatusChangedEventArgs(DateTime time, UInt16 istatus, UInt16 ichanged, int pos, int pos2)
        {
            Time = time;
            IStatus = istatus;
            IChanged = ichanged;
            Position = pos;
            Position2 = pos2;
        }

        /// <summary>
        /// 开始时间点
        /// </summary>
        public DateTime Time;
        /// <summary>
        /// 输入口状态
        /// </summary>
        public UInt16 IStatus;
        /// <summary>
        /// 变化量
        /// </summary>
        public UInt16 IChanged;
        /// <summary>
        /// 变化时的脉冲1
        /// </summary>
        public int Position;
        /// <summary>
        /// 变化时的脉冲2
        /// </summary>
        public int Position2;

    }
    public delegate void IStatusChangedEventHandler(object sender, IStatusChangedEventArgs e);

    public class TimeGridEventArgs : EventArgs
    {
        public TimeGridEventArgs()
        {

        }
        public TimeGridEventArgs(DateTime time, TimeSpan tspan, int[] data)
        {
            //Ts = new TimeSpan((long)(TimeSpan.TicksPerMillisecond * 1.28));
            Time = time;
            Ts = tspan;
            Data = data;
        }
        /// <summary>
        /// 数据
        /// </summary>
        public int[] Data
        {
            get;
            set;
        }
        /// <summary>
        /// 单数据时间间隔
        /// </summary>
        public TimeSpan Ts
        {
            get;
            set;
        }
        /// <summary>
        /// 开始时间点
        /// </summary>
        public DateTime Time
        {
            get;
            set;
        }
    }
    public delegate void TimeGridEventHandler(object sender, TimeGridEventArgs e);

    public class MiniGridEventArgs : EventArgs
    {
        public Misc.DIRECTION direction;
        public int posOfGrid;
        public int grid_start;
        public int[] buf;
        public Int32 marker;//扫描标记
    }
    public delegate void MiniGridEventHandler(object sender, MiniGridEventArgs e);

    public delegate void CorrectADsHandler(Misc.DIRECTION direction, int start_grid, int[] dat);


    public enum MOTORTYPE
    {
        NULL = 0,
        VF0 = 1,
        SERVO = 2
    }
    public enum AREA_STATUS
    {
        /// <summary>
        /// 没有读过密码区
        /// </summary>
        NOTLOAD = 0,
        /// <summary>
        /// 读出错
        /// </summary>
        RDERR = 1,
        /// <summary>
        /// 非有效密码区 没有0xAA55 或 0x5A5A 标志
        /// </summary>
        NOTVALID = 2,
        /// <summary>
        /// 写出错
        /// </summary>
        WRERR = 3,
        /// <summary>
        /// 有效密码区
        /// </summary>
        VALID = 4,
        /// <summary>
        /// 有效密码区,应回写EEPROM
        /// </summary>
        VALID_DIRTY = 5,
        /// <summary>
        /// 有效密码区,但回写EEPROM失败
        /// </summary>
        VALID_WRERR = 6
    }

    public enum AREA_ERR
    {
        NO_ERR = 0, // 没有错误
        DUP_ACCESS = 1,//  重复使用码 
        ERR_ACCESS = 2//无效使用码
    }
    public enum DRIVE_MAN_STATUS
    {
        /// <summary>
        /// 正常运行结束
        /// </summary>
        STOP = 0,
        /// <summary>
        /// 正在运行
        /// </summary>
        RUNNING = 1,
        /// <summary>
        /// 指令结束(收到停止指令)
        /// </summary>
        STOP_MANUAL = 2,
        /// <summary>
        /// 运行结束,限位开关闭合
        /// </summary>
        LIMIT = 3
    }
    public enum DRIVE_MAN_ORDER
    {
        IDLE = 'I',
        /// <summary>
        /// 运行到
        /// </summary>
        RUNTO = 'R',
        /// <summary>
        /// 归原点
        /// </summary>
        ORIGIN = 'O',
        /// <summary>
        /// 后退
        /// </summary>
        BACKWORD = 'B',
        /// <summary>
        /// 前进
        /// </summary>
        FORWORD = 'F',
        /// <summary>
        /// 停止
        /// </summary>
        STOP = 'S',
        /// <summary>
        /// 同步
        /// </summary>
        SYNC = 'D',

        /// <summary>
        /// 未知状态
        /// </summary>
        SYNC2 = 'P'
    }


    /// <summary>
    /// 同步状态
    /// </summary>
    public enum SYNC_STATUS
    {
        SYNCST_NO = 0,
        SYNCST_PENDING1 = 1,
        SYNCST_PENDING2 = 2,
        SYNCST_PENDING3 = 3,
        SYNCST_TEMP_OUT = 4,
        SYNCST_WAIT_TO_PENDING = 5,
        SYNCST_RESUME = 6,
        SYNCST_YES = 10,

    }




    public class GridAdvUnit
    {
        public DateTime dt;
        public int ad;
        public int pos;
        public UInt16 istatus;
        public override string ToString()
        {
            return dt.Ticks.ToString() + " |" +
                ad.ToString() + " |" +
                pos.ToString() + " |" +
                istatus.ToString("X2");
        }
    } 
    public class GridAdvEventArgs : EventArgs
    {
        public Misc.DIRECTION direction;
        public int pos_start;
        public int pos_len;
        public Int32 marker;//扫描标记
        public List<GridAdvUnit> dt_data;
        
    }
    public delegate void GridAdvEventHandler(object sender, GridAdvEventArgs e);


    public class GridIStatusEventArgs : EventArgs
    {
        public Misc.DIRECTION direction;
        /// <summary>
        /// 输入口 1~12
        /// </summary>
        public int istatus_no;
        public Int32 marker;//扫描标记
        /// <summary>
        /// 扫描开始点
        /// </summary>
        public int pos_start;
        /// <summary>
        /// 扫长度
        /// </summary>
        public int pos_len;
        /// <summary>
        /// 输入口 信号为0, 的范围段
        /// </summary>
        public List<Range> data_0;
        /// <summary>
        /// 输入口 信号为1, 的范围段
        /// </summary>
        public List<Range> data_1;
    }
    public delegate void GridIStatusEventHander(object sender, GridIStatusEventArgs e);

}