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

namespace FLY.Thick.FilmCasting.Server
{
    /// <summary>
    /// 膜位置检测;
    /// 通过辊接近开关，或者编码器2;
    /// 可以用于2台测厚仪同步主轴位置
    /// </summary>
    public class FilmPositionDetect2 :INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        #region 状态
        /// <summary>
        /// 线速度 m/min
        /// </summary>
        public double FilmVelocity { get; private set; }

        /// <summary>
        /// 膜位置， m
        /// </summary>
        public double FilmPosition { 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; } = 314;

        /// <summary>
        /// 辊信号
        /// </summary>
        public int InNo_Roll { get; set; } = 11 - 1;
        #endregion


        /// <summary>
        /// 
        /// </summary>
        double reset_filmPos;

        /// <summary>
        /// 复位时，对应的pos2脉冲
        /// </summary>
        int reset_pos2;

        FlyAD7 flyAd;

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


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

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


            //复位
            Misc.BindingOperations.SetBinding(this.flyAd, nameof(this.flyAd.IsReady), () =>
            {
                //刚连接上，复位
                Reset(0);
            });
        }


        private void FlyAd_PropertyChanged_EN2(object sender, PropertyChangedEventArgs e)
        {
            if (FilmVSrc != FilmVSRC.EN2)
                return;

            if (e.PropertyName == nameof(flyAd.Speed2))
            {
                double speed = flyAd.Speed2 * Encoder2_mmpp / 1000.0;// m/s
                speed *= 60;//m/min
                FilmVelocity = speed;
            }
            else if (e.PropertyName == nameof(flyAd.Position2))
            {
                FilmPosition = Pos2ToFilmPos(flyAd.Position2);
            }
        }

        class DateTimeUnit
        {
            public DateTime dt { get; set; }
            public int data;
        }
        List<DateTimeUnit> pos2Pool = new List<DateTimeUnit>();
        void AddPos2(DateTime time, int pos2)
        {
            pos2Pool.Add(new DateTimeUnit() { dt = time, data = pos2 });
            if (pos2Pool.Last().dt - pos2Pool.First().dt > TimeSpan.FromMinutes(1))
            {
                pos2Pool.RemoveAt(0);
            }
        }
        bool FindPos2(DateTime time, out int pos2)
        {
            pos2 = 0;
            var unit = pos2Pool.Find(u => u.dt == time);
            if (unit == null)
                return false;
            pos2 = unit.data;
            return true;
        }


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


        /// <summary>
        /// 用于实时信号
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void mFlyAD_IStatusChangedEvent_round(object sender, IStatusChangedEventArgs e)
        {
            if (FilmVSrc != FilmVSRC.ROUND)
                return;

            if (!Misc.MyBase.CHECKBIT(e.IChanged, InNo_Roll))
                return;
            if (Misc.MyBase.CHECKBIT(e.IStatus, InNo_Roll))
                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 < FilmVThreshold)//太慢了
                {
                    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();
            }
        }

        /// <summary>
        /// 用于长时间没信号
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        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 = flyAd.Now;
            if (dt <= dtRound)
                return;

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

            if (v >= (FilmVelocity - 1))
                return;

            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 (FilmVelocity <= FilmVThreshold)
            {
                dtRound = DateTime.MinValue;
                FilmVelocity = 0;
                round_t.Stop();
                return;
            }
        }

        #endregion




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



        double Pos2ToFilmPos(int pos2)
        {
            int distance_p = pos2 - reset_pos2;

            double distance_m = distance_p * Encoder2_mmpp / 1000.0;

            double filmPos = distance_m + reset_filmPos;

            if (Math.Abs(distance_p) > 1000000)//不让它太大，不然乘法会溢出
            {
                //当距离很远，需要复位一下
                reset_pos2 = pos2;
                reset_filmPos = filmPos;
            }
            return filmPos;
        }
    }
}
