using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.IO;
using Newtonsoft.Json;
using AutoMapper;

namespace FLY.Simulation.Blowing
{
    
    public class Blowing:INotifyPropertyChanged
    {
        #region 参数
        #region 旋转架
        /// <summary>
        /// 360° 连续旋转
        /// </summary>
        public bool Is360 { get; set; }
        /// <summary>
        /// 正向旋转
        /// </summary>
        public bool IsForw { get; set; }

        /// <summary>
        /// 旋转架复位中
        /// </summary>
        public bool IsOrg { get; set; }

        /// <summary>
        /// 旋转架启动中
        /// </summary>
        public bool IsRotationOn { get; set; }

        /// <summary>
        /// 牵引启动中
        /// </summary>
        public bool IsTractionOn { get; set; }

        /// <summary>
        /// 1圈总脉冲
        /// </summary>
        public double PosOfR { get; set; }


        /// <summary>
        /// 两个限位间的角度范围  != 旋转的总角度,限位值 °
        /// </summary>
        public double AngleRange { get; set; }

        /// <summary>
        /// 复位信号角度范围°
        /// </summary>
        public double OrgAngleRange { get; set; }
        /// <summary>
        /// 旋转的速度， min/R 1R = 360°
        /// </summary>
        public double AngleVelocity { get; set; }


        /// <summary>
        /// 加速时间 单位 s
        /// </summary>
        public double AngleAccTime { get; set; }

        /// <summary>
        /// 减速时间 单位 s
        /// </summary>
        public double AngleDecTime { get; set; }

        /// <summary>
        /// 换方向冷却时间 单位s
        /// </summary>
        public double AngleCoolTime { get; set; }
        #endregion


        #region 膜

        /// <summary>
        /// 膜泡压扁后总宽度，单位 脉冲
        /// </summary>
        public double FilmWidth { get; set; }

        /// <summary>
        /// 膜走带速度， m/min
        /// </summary>
        public double FilmVelocity { get; set; }

        /// <summary>
        /// 人字架到测厚仪的距离 23m
        /// </summary>
        public double FilmDistance { get; set; }
        /// <summary>
        /// FilmDistance+mFilmLength3D[CurrAngle]
        /// </summary>
        public double CurrFilmDistance { get; set; }
        public bool Is3D { get; set; }

        /// <summary>
        /// 辊轴承，单位mm
        /// </summary>
        [JsonProperty]
        public double RollPerimeter { get; set; }

        /// <summary>
        /// 测辊信号，信号长，单位mm
        /// </summary>
        public double RollSignLength { get; set; }
        #endregion

        #region 风环
        /// <summary>
        /// 加热棒数量
        /// </summary>
        public int ChannelCnt { get; set; }

        /// <summary>
        /// 第1根加热棒对应角度
        /// </summary>
        public double Channel1stAngle { get; set; }
        ///// <summary>
        ///// 温度影响厚度变化比例， 1厚度，对应多少加热
        ///// </summary>
        //public int Factor;//
        #endregion

        public bool IsShieldI9 { get; set; }


        #endregion
        #region 动态数据



        /// <summary>
        /// 当前人字架角度 °
        /// </summary>
        public double CurrAngle { get; private set; }
        /// <summary>
        /// 全局角度 °
        /// </summary>
        public double GlobalAngle { get; private set; }
        /// <summary>
        /// 当前速度，单位 °/s
        /// </summary>
        public double CurrAngleVelocity { get; private set; }
        /// <summary>
        /// 当前加速度, 单位 °/s^2
        /// </summary>
        public double CurrAngleAccV { get; private set; }


        /// <summary>
        /// 当前已经走到长度， 通过编码器获取 单位 m
        /// </summary>
        public double CurrFilmLength { get; private set; }
        /// <summary>
        /// 当前线速度 m/min
        /// </summary>
        public double CurrFilmVelocity { get; private set; }
        #endregion
        public HMI mHMI;
        public int Avg { get; set; }

        public double[] mFilmLength3D;
        double lastFilmDistance;
        /// <summary>
        /// 原始数据
        /// </summary>
        public ObservableCollection<int> BeforeDatas = new ObservableCollection<int>();
        /// <summary>
        /// 系统扰动后 数据
        /// </summary>
        public ObservableCollection<int> BeforeDatas2 = new ObservableCollection<int>();
        /// <summary>
        /// 系统扰动后 再 加热数据
        /// </summary>
        public ObservableCollection<int> AfterDatas = new ObservableCollection<int>();




        class PositionAngleInfo
        {
            /// <summary>
            /// 时间点
            /// </summary>
            public DateTime dt;
            /// <summary>
            /// 测厚仪所在位置 已经跑了的膜长度位置
            /// </summary>
            public double position;
            /// <summary>
            /// 这个时刻的角度
            /// </summary>
            public double angle;
            /// <summary>
            /// 膜距离，应该找为N米前 PositionAngleInfo.angle 得出厚度信息
            /// </summary>
            public double filmDistance;

            /// <summary>
            /// position+filmDistance
            /// </summary>
            public double pos24m => position + filmDistance;
        }



        /// <summary>
        /// 10ms 1个记录点
        /// </summary>
        List<PositionAngleInfo> mPositionAngleList = new List<PositionAngleInfo>();

        int ListCap = 30000;//300s

        public Blowing()
        {

            //撞了限位后，限位信号一直在。。。。
            PosOfR = 50000;
            OrgAngleRange = 5;//复位信号角度°
            AngleRange = 350;//两个限位间的角度范围350°
            AngleVelocity = 6;//出限位 到 撞另一个限位的时间 8min/ 360°
            AngleAccTime = 1;//加速时间1s
            AngleDecTime = 5;//减速时间5s
            AngleCoolTime = 5;//正反转延迟时间5s 
            
            FilmWidth = 2.3;//膜宽2.3m
    
            FilmVelocity = 20;//线速度m/min
            FilmDistance = 26;//膜距离m


            RollPerimeter = 314;//辊周长mm
            RollSignLength = 30;//辊信号长度mm


            ChannelCnt = 88;//加热棒数量
            Channel1stAngle = 100;//第1根加热棒对应角度

            if (!Load())
                Save();

            //整个膜片1000个数据
            int[] datas = OrgData.GetData(1000);
            for(int i=0;i<1000;i++)
            {
                BeforeDatas.Add(datas[i]);//原始数据
                BeforeDatas2.Add(datas[i]);//系统扰动后数据
                AfterDatas.Add(datas[i]);//系统扰动后 再 加热数据
            }
            //3d膜距离
            mFilmLength3D = FilmLength3D.GetData();


            mAirRing = new AirRing(ChannelCnt);//88支加热棒
            mAirRing.Init(BeforeDatas, BeforeDatas2, 0);


            mAirRing2 = new AirRing(ChannelCnt);//88支加热棒;
            mAirRing2.Init(BeforeDatas2, AfterDatas, (int)(1000*Channel1stAngle/360));//加热偏移了 

            mAirRing2.AfterDatasUpdateEvent += new Action<ObservableCollection<int>>(mAirRing2_AfterDatasUpdateEvent);
            Avg = (int)(BeforeDatas.Average());//原始平均值

            TestPos = 500;
            UpdateTestHeat();

            //AfterDatas.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(AfterDatas_CollectionChanged);
            PropertyChanged += new PropertyChangedEventHandler(Blowing_PropertyChanged);

            mHMI = new HMI();
            mHMI.mAirRing = mAirRing2;



            Is360 = false;

            IsForw = true;
            IsOrg = false;
            IsRotationOn = true;
            IsTractionOn = true;
        }

        void mAirRing2_AfterDatasUpdateEvent(ObservableCollection<int> obj)
        {
            NotifyPropertyChanged(nameof(AfterDatas));
        }
        

        public int TestPos { get; set; }

        public int TestHeat { get; set; }

        public void Test()
        {
            int idx = mAirRing.ChannelCnt * TestPos / BeforeDatas.Count();

            int offset = TestHeat - mAirRing.Heats[idx];

            mAirRing.Test(idx, offset);

            mAirRing2.HeatApply();
        }
        
        public class AirRing 
        {
            /// <summary>
            /// 加热通过
            /// </summary>
            public int ChannelCnt;
            /// <summary>
            /// 加热量， 数据量为 ChannelCnt
            /// </summary>
            public int[] Heats;
            /// <summary>
            /// 第1个加热棒，对应的 数据序号， 数据量为 1000， BeforeData.Count
            /// </summary>
            public int Channel1stIndex;
            /// <summary>
            /// 加热 对 厚度的影响
            /// </summary>
            public double Factor;

            //需要别人赋值
            /// <summary>
            /// 原始数据！！ 数据量为1000
            /// </summary>
            public ObservableCollection<int> BeforeDatas;
            /// <summary>
            /// 加热后的数据！！！！ 数据量为BeforeDatas.Count
            /// </summary>
            public ObservableCollection<int> AfterDatas;


            double[] p;// 一个凸起来的数组  0 1 4 9 16 9 4 1 0
            void p_init()
            {
                int size = ChannelCnt / 10;
                p = new double[size];
                for (int i = 0; i < size; i++)
                {
                    int index1 = i;
                    int index2 = size - 1 - i;
                    double d = i * i;
                    p[index1] = d;
                    p[index2] = d;
                    if (Math.Abs(index2-index1)<=1)
                        break;
                }
                double sum_p = p.Max();
                for (int i = 0; i < size; i++)
                {
                    p[i] = p[i] / sum_p;
                }
            }
            public AirRing(int channelcnt)
            {
                SetChannelCnt(channelcnt);
                p_init();
                Factor = 5;
            }
            public void Init(ObservableCollection<int> before_datas, ObservableCollection<int> after_datas, int channel1stIndex)
            {
                BeforeDatas = before_datas;
                AfterDatas = after_datas;
                Channel1stIndex = channel1stIndex;

            }
            public void SetChannelCnt(int channelcnt)
            {
                ChannelCnt = channelcnt;
                Heats = new int[ChannelCnt];
                Array.Clear(Heats, 0, ChannelCnt);
            }
            public event Action<ObservableCollection<int>> AfterDatasUpdateEvent;
            public void HeatApply() 
            {
                int boltcnt = BeforeDatas.Count();
                double b_c = (double)(boltcnt)/ChannelCnt;
                int b = Channel1stIndex;
                double beforeavg = BeforeDatas.Average();
                int[] datas = new int[boltcnt];
                for (int i = 0; i < ChannelCnt; i++) 
                {
                    int heat = Heats[i];
                    int e = (int)((i+1) * b_c)+ Channel1stIndex;

                    if (e >= boltcnt)
                        e -= boltcnt;
                    else if (e < 0)
                        e += boltcnt;
                        
                    int j=b;
                    while (j != e)
                    {
                        datas[j] = (int)(BeforeDatas[j] - beforeavg * heat / Factor/100);

                        j++;
                        if (j >= boltcnt)
                            j -= boltcnt;
                    }
                    b = e;
                }
                double afteravg = datas.Average();

                for (int j = 0; j < boltcnt; j++)
                {
                    AfterDatas[j] = (int)(beforeavg * datas[j] / afteravg);
                }
                if (AfterDatasUpdateEvent != null)
                {
                    AfterDatasUpdateEvent(AfterDatas);
                }
            }
            
            public void Test(int idx,int offset) 
            {
                idx -= p.Count() / 2;
                if (idx < 0)
                    idx += ChannelCnt;
                else if (idx >= ChannelCnt)
                    idx -= ChannelCnt;

                for (int i = 0; i < p.Count(); i++) 
                {
                    int index = idx+i;
                    
                    if (index < 0)
                        index += ChannelCnt;
                    else if (index>= ChannelCnt)
                        index -= ChannelCnt;


                    int heat = Heats[index] + (int)(offset * p[i]);
                    if (heat > 100)
                        heat = 100;
                    else if (heat < 0)
                        heat = 0;
                    Heats[index] = heat;
                }
                HeatApply();
            }
        }
        /// <summary>
        /// 1级加热, 模拟系统扰动
        /// </summary>
        private AirRing mAirRing;
        /// <summary>
        /// 2级加热, 通过HMI 控制的加热
        /// </summary>
        public AirRing mAirRing2;

        void Blowing_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(Avg)) 
            {
                int avg = (int)(BeforeDatas.Average());
                int offset = Avg - avg;
                if (offset != 0)
                {
                    for (int i = 0; i < BeforeDatas.Count(); i++)
                    {
                        BeforeDatas[i] += offset;
                    }
                }
            }
            else if (e.PropertyName == nameof(TestPos))
            {
                UpdateTestHeat();
            }
        }
        void UpdateTestHeat() 
        {
            int idx = mAirRing.ChannelCnt * TestPos / BeforeDatas.Count();
                TestHeat = mAirRing.Heats[idx];
        }


        /// <summary>
        ///  找到一个时间点，它的位置+膜距离=输入的纵向位置， 返回对应的时间点的角度
        /// </summary>
        /// <param name="position"></param>
        /// <param name="angle"></param>
        /// <returns></returns>
        bool SearchAngleFromPositionList24m(double position, out double angle)
        {
            for (int i = 1; i < mPositionAngleList.Count; i++)
            {
                int idx1 = i;
                int idx0 = i - 1;
                double pos24m1 = mPositionAngleList[idx1].pos24m;
                double pos24m0 = mPositionAngleList[idx0].pos24m;
                double angle1 = mPositionAngleList[idx1].angle;
                double angle0 = mPositionAngleList[idx0].angle;

                if (pos24m1 >= position )
                {
                    //刚过了，就是它与上一个之间的值
                    

                    double percent = (position - pos24m0) / (pos24m1 - pos24m0);
                    if (percent < 0)
                    {
                        angle = 0;
                        return true;
                    }
                    //找到了
                    angle = (angle1 - angle0) * percent + angle0;
                    return true;
                }
            }
            angle = 0;
            return true;
        }

        /// <summary>
        /// 通过纵向位置，查找角度
        /// </summary>
        /// <param name="position"></param>
        /// <param name="angle"></param>
        /// <returns></returns>
        bool SearchAngleFromPositionList(double position, out double angle)
        {
            for (int i = 1; i < mPositionAngleList.Count; i++)
            {
                int idx1 = i;
                int idx2 = i - 1;
                if ((mPositionAngleList[idx1].position >= position))
                {

                    double percent = (position - mPositionAngleList[idx2].position) / (mPositionAngleList[idx1].position - mPositionAngleList[idx2].position);
                    if (percent < 0)
                    {
                        angle = 0;
                        return true;
                    }
                    //找到了
                    angle = (mPositionAngleList[idx1].angle - mPositionAngleList[idx2].angle) * percent + mPositionAngleList[idx2].angle;
                    return true;
                }
            }
            angle = 0;
            return true;
        }
        /// <summary>
        /// 给定相对于膜横向位置， 输出当前对应的厚度
        /// </summary>
        /// <param name="pos_m"></param>
        /// <returns></returns>
        public FilmData GetData(double pos_m)
        {
            //double ago_filmlength = CurrFilmLength - CurrFilmDistance;
            double angle;

            if (!SearchAngleFromPositionList24m(CurrFilmLength, out angle))
                return null;

            //从膜位置列表找时间
            //if (!SearchAngleFromPositionList(ago_filmlength, out angle))
            //    return null;

            return GetData(pos_m, angle);

        }
        double GetValidAngle(double a) {
            while (a >= 360)
                a -= 360;
            while (a < 0)
                a += 360;
            return a;
        }
        /// <summary>
        /// 获取膜泡数据
        /// </summary>
        /// <param name="position">相对于膜泡位置，横向</param>
        /// <param name="angle">人字架角度</param>
        /// <returns></returns>
        FilmData GetData(double position, double angle)
        {
            if ((position < 0) || (position > FilmWidth))
            {
                return null;
            }
            //与0°的偏移
            double a = position / FilmWidth * 180;
            //压扁对面的角度
            double a_other = 360 - a;

            a = GetValidAngle( a + angle );
            a_other = GetValidAngle(a_other + angle);

            int dat_idx1 = (int)(a / 360 * AfterDatas.Count());
            int dat_idx2 = (int)(a_other / 360 * AfterDatas.Count());

            FilmData fd = new FilmData()
            {
                angle1 = a,
                angle2 = a_other,
                data1 = AfterDatas[dat_idx1],
                data2 = AfterDatas[dat_idx2]
            };
            return fd;
        }

        /// <summary>
        /// 1.28ms 1次
        /// </summary>
        public void OnPoll(DateTime now)
        {
           
            UpdatePositionAndAngle(now);
        }


        enum STATE 
        {
            /// <summary>
            /// 加速
            /// </summary>
            Acc,
            /// <summary>
            /// 减速
            /// </summary>
            Dec,
            /// <summary>
            /// 恒速
            /// </summary>
            Constant,
            /// <summary>
            /// 方向交换，冷却期
            /// </summary>
            Wrap
        }
        STATE mState;
        DateTime mDTLast = DateTime.MinValue;
        /// <summary>
        /// 停下来的时间
        /// </summary>
        DateTime mDTWrap = DateTime.MinValue;


        /// <summary>
        /// 更新旋转
        /// </summary>
        /// <param name="now"></param>
        /// <param name="ts"></param>
        void UpdateAngleV(DateTime now, TimeSpan ts)
        {
            if (IsOrg) {
                IsRotationOn = false;

                UpdateAngleV_Org(now, ts);
                return;
            }

            if (IsRotationOn) {
                if (Is360)
                {
                    UpdateAngleV_360(now, ts);
                }
                else {
                    UpdateAngleV_ForwBackw(now, ts);
                }
            }
        }



        /// <summary>
        /// 正反向旋转
        /// </summary>
        /// <param name="now"></param>
        /// <param name="ts"></param>
        void UpdateAngleV_ForwBackw(DateTime now, TimeSpan ts) 
        {
            double angle = CurrAngle + CurrAngleVelocity * ts.TotalSeconds;

            switch (mState)
            {
                case STATE.Constant:
                    if (((CurrAngleVelocity > 0) && (angle >= AngleRange / 2)) ||
                        ((CurrAngleVelocity < 0) && (angle <= (-AngleRange / 2))))
                    {
                        mState = STATE.Dec;
                        double dv = 0 - CurrAngleVelocity;
                        CurrAngleAccV = dv / AngleDecTime;
                    } break;
                case STATE.Dec:
                    {
                        bool isForw = false;
                        if (CurrAngleVelocity > 0)
                            isForw = true;
                        CurrAngleVelocity += CurrAngleAccV * ts.TotalSeconds;
                        if (((isForw) && (CurrAngleVelocity < 0)) ||
                            ((!isForw) && (CurrAngleVelocity > 0)))
                        {
                            CurrAngleVelocity = 0;
                            mState = STATE.Wrap;
                            mDTWrap = now;
                        }
                    } break;
                case STATE.Wrap:
                    {
                        if ((now - mDTWrap).TotalSeconds >= AngleCoolTime)
                        {
                            //冷静完
                            mState = STATE.Acc;
                            double anglev = 360.0 / (AngleVelocity * 60);
                            if (angle >= AngleRange / 2)
                            {
                                //反转
                                anglev = -anglev;
                                IsForw = false;
                            }
                            else {
                                IsForw = true;
                            }
                            CurrAngleAccV = anglev / AngleAccTime;
                        }
                    } break;
                case STATE.Acc:
                    {
                        CurrAngleVelocity += CurrAngleAccV * ts.TotalSeconds;

                        double anglev = 360.0 / (AngleVelocity * 60);
                        if (CurrAngleAccV > 0)
                        {
                            if (CurrAngleVelocity >= anglev)
                            {
                                CurrAngleVelocity = anglev;
                                mState = STATE.Constant;
                            }
                        }
                        else
                        {
                            if (CurrAngleVelocity <= -anglev)
                            {
                                CurrAngleVelocity = -anglev;
                                mState = STATE.Constant;
                            }
                        }
                    } break;
            }
            double delta = angle - CurrAngle;
            GlobalAngle += delta;
            CurrAngle = angle;
        }


        /// <summary>
        /// 连续旋转
        /// </summary>
        /// <param name="now"></param>
        /// <param name="ts"></param>
        void UpdateAngleV_360(DateTime now, TimeSpan ts)
        {
            double anglev = 360.0 / (AngleVelocity * 60);
            if (IsForw)
                CurrAngleVelocity = anglev;
            else
                CurrAngleVelocity = -anglev;

            double angle = CurrAngle + CurrAngleVelocity * ts.TotalSeconds;
            double delta = angle - CurrAngle;
            GlobalAngle += delta;

            while (angle >= 360)
                angle -= 360;
            while (angle < 0)
                angle +=360;

            CurrAngle = angle;

        }

        /// <summary>
        /// 复位
        /// </summary>
        /// <param name="now"></param>
        /// <param name="ts"></param>
        void UpdateAngleV_Org(DateTime now, TimeSpan ts)
        {
            double anglev = 360.0 / (AngleVelocity * 60);

            if (CurrAngle > 0){
                CurrAngleVelocity = -anglev;
            }
            else if (CurrAngle < 0) 
            { 
                CurrAngleVelocity = anglev;
            }
            else {
                CurrAngleVelocity = 0;
                IsOrg = false;
                return;
            }

            double angle = CurrAngle + CurrAngleVelocity * ts.TotalSeconds;
            double delta = angle - CurrAngle;

            if (((CurrAngle > 0) && (angle <= 0))||
                ((CurrAngle < 0) && (angle >= 0)))
            {
                delta = 0 - CurrAngle;
                CurrAngle = 0;
                CurrAngleVelocity = 0;
                IsOrg = false;
                return;
            }
            GlobalAngle += delta;
            CurrAngle = angle;
        }
        
        
        
        /// <summary>
        /// 驱动器，根据时间，更新angle，
        /// </summary>
        /// <param name="now"></param>
        void UpdatePositionAndAngle(DateTime now)
        {
            if (mDTLast == DateTime.MinValue)
            {
                //提前把膜距离耗完，不用等
                double position = FilmDistance;
                DateTime time = now;
                while (position > 0)
                {
                    mPositionAngleList.Insert(0,
                        new PositionAngleInfo()
                        {
                            dt = time,
                            position = position,
                            angle = 0
                        });
                    TimeSpan ts1 = TimeSpan.FromMilliseconds(10);
                    time -= ts1;
                    position -= FilmVelocity * ts1.TotalMinutes;
                }

                mDTLast = now;
                CurrFilmLength = FilmDistance;
                CurrFilmDistance = FilmDistance;
                lastFilmDistance = CurrFilmDistance;
                CurrAngle = 0;//在中间

                mState = STATE.Constant;
                double anglev = 360.0 / (AngleVelocity * 60);
                CurrAngleVelocity = anglev;


                return;
            }

            DateTime dt = now;

            TimeSpan ts = dt.Subtract(mDTLast);
            if (ts.TotalMilliseconds < 10)
                return;

            mDTLast = dt;
            //线速度。。。。

            UpdateAngleV(dt, ts);
            if (Is3D && !Is360)//立体旋转架，肯定不是360°连续旋转的
            {
                double index1_5 = CurrAngle + 180;
                
                //提高精度。 线性插值
                int index1 = (int)Math.Floor(index1_5);
                int index2 = (int)Math.Ceiling(index1_5);
                while (index1 < 0)
                    index1 = 0;
                while (index1 >= 360)
                    index1 = 360 - 1;
                while (index2 < 0)
                    index2 = 0;
                while (index2 >= 360)
                    index2 = 360 - 1;
                double filmLength3d;
                if (index2 == index1)
                    filmLength3d = mFilmLength3D[index1];

                else if (index1 <= index1_5 && index1_5 <= index2)
                {
                    filmLength3d = (index1_5-index1)/(index2- index1) * (mFilmLength3D[index2]- mFilmLength3D[index1])+ mFilmLength3D[index1];

                }
                else 
                {
                    filmLength3d = mFilmLength3D[index1];
                }
                CurrFilmDistance = FilmDistance + filmLength3d;
            }

            if (IsTractionOn)//启动牵引
            {
                //膜距离增量 膜长了，2牵引速度要降
                double d = CurrFilmDistance - lastFilmDistance;
                lastFilmDistance = CurrFilmDistance;
                //2牵引速度
                double fv2 = FilmVelocity - d / ts.TotalMinutes;
                CurrFilmVelocity = fv2;
                CurrFilmLength += CurrFilmVelocity * ts.TotalMinutes;
            }
            


            mPositionAngleList.Add(
                new PositionAngleInfo()
                {
                    dt = mDTLast,
                    angle = CurrAngle,
                    position = CurrFilmLength,
                    filmDistance = CurrFilmDistance
                });

            if (mPositionAngleList.Count > ListCap)
                mPositionAngleList.RemoveAt(0);
        }
        public bool CheckOrg() 
        {
            if (CurrAngle <= OrgAngleRange / 2 && CurrAngle >= -OrgAngleRange / 2)
                return true;
            else
                return false;
        }
        public bool CheckLimit1() 
        {
            if (Is360)
            {
                if (CurrAngleVelocity < 0)
                    return true;
                else
                    return false;
            }
            else
            {
                if (CurrAngle >= AngleRange / 2)
                    return true;
                else
                    return false;
            }
        }
        public bool CheckLimit0()
        {
            if (Is360)
            {
                if (CurrAngleVelocity > 0)
                    return true;
                else
                    return false;
            }
            else
            {
                if (CurrAngle <= (-AngleRange / 2))
                    return true;
                else
                    return false;
            }
        }
        public bool CheckRoll() 
        {
            int rollcnt = (int)(CurrFilmLength*1000 / RollPerimeter);
            double p = CurrFilmLength*1000 - rollcnt * RollPerimeter;
            if (p <= RollSignLength)
                return true;
            else
                return false;
        }
        protected void NotifyPropertyChanged(string propertyname) 
        {
            if (PropertyChanged != null) 
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        private string param_path = "simulation_blowing.json";
        public bool Save() 
        {
            return JsonDbHelper<Blowing, BlowingJsonDb>.Save(this, param_path);

        }
        bool Load() 
        {
            return JsonDbHelper<Blowing, BlowingJsonDb>.Load(this, param_path);
        }
    }
    public class FilmData
    {
        public double angle1;
        public double angle2;
        public int data1;
        public int data2;
    }


    public class BlowingJsonDb 
    {
        #region 参数
        #region 旋转架
        /// <summary>
        /// 360° 连续旋转
        /// </summary>
        public bool Is360 { get; set; }

        /// <summary>
        /// 1圈总脉冲
        /// </summary>
        public double PosOfR { get; set; }


        /// <summary>
        /// 两个限位间的角度范围  != 旋转的总角度,限位值 °
        /// </summary>
        public double AngleRange { get; set; }

        /// <summary>
        /// 复位信号角度范围°
        /// </summary>
        public double OrgAngleRange { get; set; }
        /// <summary>
        /// 旋转的速度， min/R 1R = 360°
        /// </summary>
        public double AngleVelocity { get; set; }


        /// <summary>
        /// 加速时间 单位 s
        /// </summary>
        public double AngleAccTime { get; set; }

        /// <summary>
        /// 减速时间 单位 s
        /// </summary>
        public double AngleDecTime { get; set; }

        /// <summary>
        /// 换方向冷却时间 单位s
        /// </summary>
        public double AngleCoolTime { get; set; }
        #endregion


        #region 膜
        /// <summary>
        /// 膜走带速度， m/min
        /// </summary>
        public double FilmVelocity { get; set; }

        /// <summary>
        /// 人字架到测厚仪的距离 23m
        /// </summary>
        public double FilmDistance { get; set; }

        /// <summary>
        /// 立体收卷
        /// </summary>
        public bool Is3D { get; set; }

        /// <summary>
        /// 辊轴承，单位mm
        /// </summary>
        public double RollPerimeter { get; set; }

        /// <summary>
        /// 测辊信号，信号长，单位mm
        /// </summary>
        public double RollSignLength { get; set; }
        #endregion

        #region 风环
        /// <summary>
        /// 加热棒数量
        /// </summary>
        public int ChannelCnt { get; set; }

        /// <summary>
        /// 第1根加热棒对应角度
        /// </summary>
        public double Channel1stAngle { get; set; }
        #endregion


        #endregion
    }

    public static class JsonDbHelper<TSource,TDestination>
    {
        static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c => {
            c.CreateMap<TSource, TDestination>().ReverseMap();
        }));

        public static bool Save(TSource src, string filePath)
        {
            try
            {
                var jsondb = Mapper.Map<TDestination>(src);
                string json = Newtonsoft.Json.JsonConvert.SerializeObject(jsondb, Formatting.Indented);
                File.WriteAllText(filePath, json);
                return true;
            }
            catch
            {

                return false;
            }
        }
        public static bool Load(TSource src, string filePath)
        {
            if (!File.Exists(filePath))
                return false;
            try
            {
                string json = File.ReadAllText(filePath);

                var jsondb = Newtonsoft.Json.JsonConvert.DeserializeObject<TDestination>(json);
                Mapper.Map(jsondb, src);
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}
