using FLY.Thick.Base.Common;
using FLY.Thick.Base.IService;
using FlyADBase;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;

namespace FLY.Thick.Base.Server
{
    /// <summary>
    /// 膜位置检测;
    /// 通过辊接近开关，或者编码器2
    /// </summary>
    public class FilmPositionDetect : IFilmPositionDetectService
    {
        #region 输入口定义
        /// <summary>
        /// 纵向边界
        /// </summary>
        const int InIdxOfVSensor = 12;
        /// <summary>
        /// 控制主轴脉冲启动计数
        /// </summary>
        const int OutIdxOfPosition2OnOff = 3;
        /// <summary>
        /// 控制主轴脉冲启动计数输入， o3 接 i11;
        /// i11 为 0 计数停止
        /// </summary>
        const int InIdxOfPosition2OnOff = 11;
        /// <summary>
        /// 辊速度 
        /// </summary>
        const int InIdxOfRound = 11;
        #endregion

        #region 状态
        /// <summary>
        /// 线速度 m/min
        /// </summary>
        public double FilmVelocity { get; private set; }

        /// <summary>
        /// 膜位置， m
        /// </summary>
        public double FilmPosition { get; private set; }

        /// <summary>
        /// 工作中
        /// </summary>
        public bool IsRunning { get; private set; } = true;

        /// <summary>
        /// 当前正在使用的 与机头测厚仪偏移，单位m
        /// </summary>
        public double VDistanceWithHeaderInUsed { get; private set; }

        /// <summary>
        /// 当前正在使用的 激光探头与 X光的偏移，单位m
        /// </summary>
        public double VSensorOffsetInUsed { get; private set; }

        /// <summary>
        /// 已经重新开始测量
        /// </summary>
        public bool HasReset { get; private set; }
        #endregion

        #region 参数
        /// <summary>
        /// 线速度阀值，低于阀值，速度直接变为0
        /// </summary>
        public double FilmVThreshold { get; set; } = 2;

        /// <summary>
        /// 线速度来源
        /// </summary>
        public FilmVSRC FilmVSrc { get; set; } = FilmVSRC.ROUND;

        /// <summary>
        /// 线速度:编码器2 mm/pulse
        /// </summary>
        public double Encoder2_mmpp { get; set; } = 0.1;

        /// <summary>
        /// 线速度:1圈多少mm
        /// </summary>
        public double MmOfR { get; set; } = 377;

        /// <summary>
        /// 本测厚仪探头与机头测厚仪探头距离单位m
        /// 修改此值，会改变纵向偏移
        /// </summary>
        public double VDistanceWithHeader { get; set; } = 0;

        /// <summary>
        /// 激光探头与 X光的偏移，单位m;
        /// 激光探头 为与 X光的后面， 为正数;
        /// 激光探头 为与 X光的前面， 为负数;
        /// 当主轴脉冲修正后， 当前轨迹 比 机头轨迹要滞后，应该增大VSensorOffset。增大指数值，如原来是-0.200m， 发现滞后了0.010m，那现在应该为 -0.190m;
        /// </summary>
        public double VSensorOffset { get; set; } = 0;

        #endregion
        /// <summary>
        /// 
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>
        /// 主轴激光传感器检测到 1->0 变化 事件
        /// </summary>
        public event FilmPosAt01EventHandler FilmPosAt01Event;

        FlyAD7 flyAd;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="flyAd"></param>
        public void Init(FlyAD7 flyAd)
        {
            this.flyAd = flyAd;


            //------------------------------------------------------------------------------------------------------------------------------------
            //线速度------------------------------------------------------------------------------------------------------------------------------
            this.flyAd.PropertyChanged += FlyAd_PropertyChanged;

            //------------------------------------------------------------------------------------------------------------------------------------
            //辊信号生成线速度-----------------------------------------------------------------------------------------------------------------------------
            InitRoundFilmVelocity();

            flyAd.IStatusChangedEvent += mFlyAD_IStatusChangedEvent;

            this.PropertyChanged += FilmPositionDetect_PropertyChanged;

            updateIsRunning();

            VDistanceWithHeaderInUsed = VDistanceWithHeader;
            VSensorOffsetInUsed = VSensorOffset;
        }

        void updateIsRunning() 
        {
            if (FilmVSrc == FilmVSRC.EN2)
            {
                IsRunning = Misc.MyBase.CHECKBIT(flyAd.OStatus, OutIdxOfPosition2OnOff - 1);
            }
        }
        private void FlyAd_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (FilmVSrc != FilmVSRC.EN2)
                return;

            if (e.PropertyName == "Speed2")
            {
                double speed = Pos2ToFilmPos(flyAd.Speed2);// m/s
                speed *= 60;//m/min
                FilmVelocity = speed;
            }
            else if (e.PropertyName == "Position2")
            {
                double filmPos = Pos2ToFilmPos(flyAd.Position2);
                FilmPosition = filmPos;
            }
            else if(e.PropertyName == "OStatus") 
            {
                updateIsRunning();
            }
        }

        private void FilmPositionDetect_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "VDistanceWithHeader") //滞后,应该增大
            {
                int pos2 = FilmPosToPos2(VDistanceWithHeader - VDistanceWithHeaderInUsed);

                flyAd.SetPos2Offset(-pos2);//提前
                VDistanceWithHeaderInUsed = VDistanceWithHeader;
            }
            else if (e.PropertyName == "VSensorOffset") //滞后,应该增大
            {
                int pos2 = FilmPosToPos2(VSensorOffset - VSensorOffsetInUsed);
                flyAd.SetPos2Offset(pos2);//提前
                VSensorOffsetInUsed = VSensorOffset;
            }
        }

        void mFlyAD_IStatusChangedEvent(object sender, IStatusChangedEventArgs e)
        {
            if (Misc.MyBase.CHECKBIT(e.IChanged, InIdxOfVSensor - 1))
            {
                if (Misc.MyBase.CHECKBIT(e.IStatus, InIdxOfVSensor - 1))
                {
                    if (FilmPosAt01Event != null)
                    {
                        //减去偏移
                        double filmPos = Pos2ToFilmPos(e.Position2);
                        filmPos -= VSensorOffset;
                        FilmPosAt01Event(this, new FilmPosAt01EventArgs() { filmPos = filmPos });
                    }
                }
            }
        }

        #region 辊信号生成 线速度
        DispatcherTimer round_t;
        DateTime dtRound;

        int RCnt = 0;
        double BaseFilmPosition = 0;
        void InitRoundFilmVelocity()
        {
            round_t = new DispatcherTimer();
            round_t.Interval = TimeSpan.FromSeconds(1);
            round_t.Tick += new EventHandler(round_t_Tick);
            flyAd.IStatusChangedEvent += mFlyAD_IStatusChangedEvent_round;
        }


        void mFlyAD_IStatusChangedEvent_round(object sender, IStatusChangedEventArgs e)
        {
            if (FilmVSrc != FilmVSRC.ROUND)
                return;

            if (!Misc.MyBase.CHECKBIT(e.IChanged, InIdxOfRound - 1))
                return;
            
            if (Misc.MyBase.CHECKBIT(e.IStatus, InIdxOfRound - 1))
                return;
            
            //1->0
            DateTime dt = e.Time;
            if (dt <= dtRound)
                return;
            if (dtRound != DateTime.MinValue)
            {
                double v = MmOfR / 1000.0 / (dt - dtRound).TotalMinutes;
                if (v < 2)//太慢了
                {
                    dt = DateTime.MinValue;
                    v = 0;
                }
                FilmVelocity = v;
                if (v > 0)
                {
                    RCnt++;
                    FilmPosition = RCnt * MmOfR / 1000.0 + BaseFilmPosition;
                }
            }

            dtRound = dt;

            if (dtRound != DateTime.MinValue)
            {
                if (!round_t.IsEnabled)
                    round_t.Start();
            }
        }

        void round_t_Tick(object sender, EventArgs e)
        {
            if (FilmVSrc != FilmVSRC.ROUND)
            {
                round_t.Stop();
                return;
            }

            if (dtRound == DateTime.MinValue)
            {
                round_t.Stop();
                return;
            }

            //1->0
            DateTime dt = DateTime.Now;
            if (dt <= dtRound)
                return;

            double v = MmOfR / 1000.0 / (dt - dtRound).TotalMinutes;

            if (v < (FilmVelocity - 1))
            {
                if (v < 2)
                {
                    dtRound = DateTime.MinValue;
                    v = 0;
                }
                FilmVelocity = v;
            }
            
            double p1 = RCnt * MmOfR / 1000.0;
            double p2 = (dt - dtRound).TotalMinutes * FilmVelocity;
            if (p2 > MmOfR / 1000.0)
                p2 = MmOfR / 1000.0;
            p1 += p2;
            if (FilmPosition < p1)
                FilmPosition = p1;
            
            if (dtRound == DateTime.MinValue)
            {
                round_t.Stop();
                return;
            }
        }
         
        #endregion


        /// <summary>
        /// 设置膜位置为某值
        /// </summary>
        /// <param name="filmPos">极片位置m</param>
        public void Reset(double filmPos)
        {
            if (FilmVSrc == FilmVSRC.EN2)
            {
                int pos2 = (int)(filmPos * 1000.0 / Encoder2_mmpp);
                flyAd.Position2 = pos2;
            }
            else
            {
                RCnt = 0;
                BaseFilmPosition = filmPos;
                FilmPosition = BaseFilmPosition;
            }
            HasReset = true;
        }

        /// <summary>
        /// 把膜位置设置为 -VDistanceWithHeader
        /// </summary>
        public void Reset() 
        {
            Reset(-VDistanceWithHeader);
        }

        /// <summary>
        /// 清除 hasReset标志位
        /// </summary>
        public void ClearResetState() 
        {
            HasReset = false;
        }

        /// <summary>
        /// 服务器 从 机头得到的 0->1 事件，给机尾
        /// </summary>
        /// <param name="filmPos">极片位置m</param>
        public void SetFilmPosAt01(double filmPos) 
        {
            //加上偏移
            filmPos += VSensorOffset;
            int pos2 = FilmPosToPos2(filmPos);
            flyAd.SetPos2At01(pos2, false);
        }
        int FilmPosToPos2(double filmPos) 
        {
            return (int)(filmPos * 1000.0 / Encoder2_mmpp);
        }
        double Pos2ToFilmPos(int pos2) 
        {
            return pos2 * Encoder2_mmpp / 1000.0;
        }
        /// <summary>
        /// 停止测量
        /// </summary>
        public void Stop() 
        {
            if (FilmVSrc == FilmVSRC.EN2) 
                flyAd.SetOutputBit(OutIdxOfPosition2OnOff - 1, false);
            IsRunning = false;
        }

        /// <summary>
        /// 启动测量
        /// </summary>
        public void Start() 
        {
            if (FilmVSrc == FilmVSRC.EN2)
                flyAd.SetOutputBit(OutIdxOfPosition2OnOff - 1, true);
            IsRunning = true;
        }
    }

}
