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

namespace FLY.Simulation.Coating
{

    public class Coating : INotifyPropertyChanged, Misc.ISaveToXml
    {
        public CoatingCtrl hmi_cc;
        public CoatingCtrl inner_cc;
        public HMI hmi;

        private FLY.Simulation.Coating.CoatingCtrl.COATINGMODE coatingmode = CoatingCtrl.COATINGMODE.Extrusion;
        /// <summary>
        /// 涂布类型
        /// </summary>
        public FLY.Simulation.Coating.CoatingCtrl.COATINGMODE CoatingMode 
        {
            get {
                return coatingmode;
            }
            set {
                if (coatingmode != value) 
                {
                    coatingmode = value;
                    hmi_cc.CoatingMode = value;
                    inner_cc.CoatingMode = value;
                }
            }
        }

        public int Port { get; set; } = 502;


        public class DataInfo
        {
            /// <summary>
            /// 上光纤是亮
            /// </summary>
            public bool IsLight;
            /// <summary>
            /// 下光纤是亮
            /// </summary>
            public bool IsLight2;
            /// <summary>
            /// 厚度值
            /// </summary>
            public int Thick;
        }
        
        //当前数据
        public List<DataInfo> Datas_Vertical = new List<DataInfo>();//纵向数据
        public List<DataInfo> Datas_Horizontal = new List<DataInfo>();//横向数据
        int datas_horizontal_avg = 0;
        int datas_vertical_position=0;


        //30m 后的数据
        public List<DataInfo> Datas_Vertical_30m = new List<DataInfo>();//纵向数据
        public List<DataInfo> Datas_Horizontal_30m = new List<DataInfo>();//横向数据
        int datas_vertical_30m_position=0;


        /// <summary>
        /// 膜宽
        /// </summary>
        public int FilmWidth => Datas_Horizontal.Count();


        /// <summary>
        /// 膜速度 m/min
        /// </summary>
        public double FilmVelocity { get; set; } = 12;


        /// <summary>
        /// 辊周长 mm
        /// </summary>
        public double MmOfR=120*3.14;

        /// <summary>
        /// 辊信号长度 mm
        /// </summary>
        public double MmOfRSignal = 10;

        /// <summary>
        /// 当前辊位置 mm
        /// </summary>
        double RPosition = 0;


        /// <summary>
        /// 膜已经跑了的长度。m
        /// </summary>
        public double FilmLength { get; set; }

        /// <summary>
        /// 烘箱长度 30m
        /// </summary>
        public double OvenLength = 30;
        /// <summary>
        /// 辊信号 
        /// </summary>
        public bool RSignal;
        /// <summary>
        /// 上纵向信号
        /// </summary>
        public bool VSignal;
        /// <summary>
        /// 下纵向信号
        /// </summary>
        public bool VSignal2;
        /// <summary>
        /// 上横向信号
        /// </summary>
        public bool HSignal;
        /// <summary>
        /// 下横向信号
        /// </summary>
        public bool HSignal2;

        public bool DeviceState { get; set; }


        public double Avg { get; set; }

        void Load_Vertical()
        {
            Datas_Vertical.Clear();
            using (StreamReader sr = new StreamReader(@"coating\datas_vertical.csv"))
            {
                string header = sr.ReadLine();//标题 , 位置(mm), 纵向信号,厚度

                while (!sr.EndOfStream)
                {
                    string s = sr.ReadLine();
                    string[] ss = s.Split(',');

                    int pos_mm = int.Parse(ss[0]);
                    bool isLight = bool.Parse(ss[1]);
                    bool isLight2 = bool.Parse(ss[2]);
                    int thick = (int)(double.Parse(ss[3]) * 100);

                    Datas_Vertical.Add(new DataInfo() { IsLight = isLight, IsLight2 = isLight2, Thick = thick });
                    Datas_Vertical_30m.Add(new DataInfo() { IsLight = isLight, IsLight2 = isLight2, Thick = thick });
                }
                sr.Close();
            }
        }
        void Load_Horizontal()
        {
            Datas_Horizontal.Clear();
            using (StreamReader sr = new StreamReader(@"coating\datas_horizontal.csv"))
            {
                string header = sr.ReadLine();//标题 , 位置(mm), 厚度

                while (!sr.EndOfStream)
                {
                    string s = sr.ReadLine();
                    string[] ss = s.Split(',');

                    int pos_mm = int.Parse(ss[0]);
                    bool isLight = bool.Parse(ss[1]);
                    bool isLight2 = bool.Parse(ss[2]);
                    int thick = (int)(double.Parse(ss[3]) * 100.0);

                    Datas_Horizontal.Add(new DataInfo() { IsLight = isLight, IsLight2 = isLight2, Thick = thick });
                    Datas_Horizontal_30m.Add(new DataInfo() { IsLight = isLight, IsLight2 = isLight2, Thick = thick });
                }
                sr.Close();
            }
        }


        void Load() 
        {
            Load_Vertical();
            Load_Horizontal();

            datas_horizontal_avg = (int)(Datas_Horizontal.Average((d) => { return d.Thick; }));
            Misc.SaveToXmlHepler.Load("simulation_coating.xml", this);
        }
        public void Save() 
        {
            Misc.SaveToXmlHepler.Save("simulation_coating.xml", this);
        }
        public Coating() 
        {
            hmi_cc = new CoatingCtrl(this);
            inner_cc = new CoatingCtrl(this);
            DeviceState = true;
            Load();
            hmi = new HMI(this, hmi_cc, Port);

            this.PropertyChanged += new PropertyChangedEventHandler(Coating_PropertyChanged);
        }

        void Coating_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "CoatingMode")
                Save();
        }

        /// <summary>
        /// 获取30m后的数据
        /// </summary>
        /// <param name="mm"></param>
        /// <returns></returns>
        public int GetData30m(int mm) 
        {
            if (mm < 0)
                return 0;
            if (mm >= FilmWidth)
                return 0;

            return (int)(Datas_Vertical_30m[datas_vertical_position].Thick * ((double)Datas_Horizontal_30m[mm].Thick) / datas_horizontal_avg);
        }
        public int GetData(int mm) 
        {
            if (mm < 0)
                return 0;
            if (mm >= FilmWidth)
                return 0;

            return (int)(Datas_Vertical[datas_vertical_position].Thick * ((double)Datas_Horizontal[mm].Thick) / datas_horizontal_avg);
        }
        /// <summary>
        /// 上一个时间点
        /// </summary>
        DateTime dtLast = DateTime.MinValue;
        
        public void OnPoll(DateTime now) 
        {
            if (dtLast == DateTime.MinValue)
            {
                dtLast = now;
                return;
            }
            TimeSpan ts= now - dtLast;
            dtLast = now;

            if (!DeviceState)//没有涂布
                return;

            double filmMove = ts.TotalMinutes * FilmVelocity;
            FilmLength += filmMove;//膜位置

            int p1 = (int)(FilmLength * 1000 % Datas_Vertical.Count());
            if (p1 != datas_vertical_position)
            {
                datas_vertical_position = p1;
                Avg = Datas_Vertical[datas_vertical_position].Thick / 100.0;
                if (AvgChanged != null) 
                {
                    AvgChanged(FilmLength, (int)(Avg*100));
                }
            }
            

            datas_vertical_30m_position = (int)((FilmLength - OvenLength) * 1000 % Datas_Vertical.Count());
            if (datas_vertical_30m_position < 0)
                datas_vertical_30m_position += Datas_Vertical.Count();


            //更新纵向信号
            VSignal = Datas_Vertical[datas_vertical_position].IsLight;
            VSignal2 = Datas_Vertical[datas_vertical_position].IsLight2;



            //更新辊信号
            RPosition += filmMove * 1000;
            RPosition = RPosition % MmOfR;
            if (RPosition < MmOfRSignal)
                RSignal = true;
            else
                RSignal = false;


            hmi_cc.OnPoll(filmMove);
            inner_cc.OnPoll(filmMove);
        }

        /// <summary>
        /// 每1mm更新一次
        /// </summary>
        public event Action<double, int> AvgChanged;
        public event Action DatasChanged;
        public event Action Datas30mChanged;
        public void NotifyDatasChanged() 
        {
            if (DatasChanged != null) 
            {
                DatasChanged();
            }
        }
        public void NotifyDatas30mChanged()
        {
            if (Datas30mChanged != null)
            {
                Datas30mChanged();
            }
        }
        protected void NotifyPropertyChanged(string propertyname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        public string[] GetSavePropertyNames()
        {
            return new string[] { 
                "Port",
                "CoatingMode"
            };
        }
    }

    /// <summary>
    /// 涂布控制量
    /// </summary>
    public class CoatingCtrlElement:INotifyPropertyChanged
    {
        /// <summary>
        /// 控制的时间
        /// </summary>
        public DateTime Time = DateTime.Now;

        private double pump;
        public double Pump
        {
            get
            {
                return pump;
            }
            set
            {
                if (pump != value)
                {
                    pump = value;
                    NotifyPropertyChanged("Pump");
                }
            }
        }
        private double left;
        public double LeftDis
        {
            get
            {
                return left; ;
            }
            set
            {
                if (left != value)
                {
                    left = value;
                    NotifyPropertyChanged("LeftDis");
                }
            }
        }
        private double right;
        public double RightDis
        {
            get
            {
                return right;
            }
            set
            {
                if (right != value)
                {
                    right = value;
                    NotifyPropertyChanged("RightDis");
                }
            }
        }

        /// <summary>
        /// 膜移动的距离
        /// </summary>
        public double FilmMove=0;

        protected void NotifyPropertyChanged(string propertyname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }


    public class CoatingCtrl : INotifyPropertyChanged
    {
        Coating mCoating;

        #region 参数
        public enum COATINGMODE
        {
            /// <summary>
            /// 挤压涂布
            /// </summary>
            Extrusion,
            /// <summary>
            /// 转移涂布
            /// </summary>
            Transfer
        }

        /// <summary>
        /// 涂布类型
        /// </summary>
        public COATINGMODE CoatingMode = COATINGMODE.Extrusion;

        /// <summary>
        /// 泵速因子  1 个 面密度 = N个泵速, 只有挤压涂布有效
        /// </summary>
        public double PumpFactor = 0.5;

        /// <summary>
        /// 左右刀因子 1个面密度 = N个左右刀
        /// </summary>
        public double LeftRightFactor = 1;

        /// <summary>
        /// 当前涂布控制量
        /// </summary>
        public CoatingCtrlElement NowCtrl;
        CoatingCtrlElement NowCtrl_30m;
        #endregion



        /// <summary>
        /// 控制量
        /// </summary>
        List<CoatingCtrlElement> mCtrlElement = new List<CoatingCtrlElement>();

        public CoatingCtrl(Coating coating) 
        {
            mCoating = coating;
            NowCtrl = new CoatingCtrlElement() { FilmMove = 0, Pump = 90, LeftDis = 200, RightDis = 210 };
            NowCtrl_30m = new CoatingCtrlElement() { FilmMove = 0, Pump = 90, LeftDis = 200, RightDis = 210 };
        }


        public void OnPoll(double filmMove)
        {
            for (int i = 0; i < mCtrlElement.Count(); i++)
            {
                if (mCtrlElement[i].FilmMove<mCoating.OvenLength)
                {
                    mCtrlElement[i].FilmMove += filmMove;
                }
            }

            for (int i = 0; i < mCtrlElement.Count(); i++)
            {
                if (mCtrlElement[i].FilmMove>=mCoating.OvenLength)
                {
                    CoatingAction(NowCtrl_30m, mCtrlElement[i], mCoating.Datas_Vertical_30m, mCoating.Datas_Horizontal_30m, mCoating.NotifyDatas30mChanged);
                    mCtrlElement.RemoveAt(i);
                    i--;
                }
                else
                    break;
            }
        }

        /// <summary>
        /// 控制量生效
        /// </summary>
        /// <param name="element"></param>
        /// <param name="datas_vertical"></param>
        /// <param name="datas_horizontal"></param>
        void CoatingAction(CoatingCtrlElement now, CoatingCtrlElement element, List<Coating.DataInfo> datas_vertical, List<Coating.DataInfo> datas_horizontal, Action NotifyDatasChanged)
        {
            if (CoatingMode == COATINGMODE.Extrusion)
            {
                double d_left = element.LeftDis - now.LeftDis;
                double d_right = element.RightDis - now.RightDis;
                double d = (d_right - d_left) / LeftRightFactor * 100;

                for (int i = 0; i < datas_horizontal.Count(); i++)
                {
                    datas_horizontal[i].Thick += (int)(d * i / (datas_horizontal.Count() - 1) - d / 2);
                }


                double d_pump = element.Pump - now.Pump;
                d = (d_pump / PumpFactor) * 100;
                for (int i = 0; i < datas_vertical.Count(); i++)
                {
                    FLY.Simulation.Coating.Coating.DataInfo vi = datas_vertical[i];
                    vi.Thick += (int)d;
                    datas_vertical[i] = vi;
                }
            }
            else
            {
                double d_left = element.LeftDis - now.LeftDis;
                double d_right = element.RightDis - now.RightDis;
                double d = (d_right - d_left) / LeftRightFactor * 100;

                for (int i = 0; i < datas_horizontal.Count(); i++)
                {
                    datas_horizontal[i].Thick += (int)(d * i / (datas_horizontal.Count() - 1) - d / 2);
                }

                d = (d_left + d_right) / 2 / LeftRightFactor * 100;
                for (int i = 0; i < datas_vertical.Count(); i++)
                {
                    FLY.Simulation.Coating.Coating.DataInfo vi = datas_vertical[i];
                    vi.Thick += (int)d;
                    datas_vertical[i] = vi;
                }
            }

            now.Pump = element.Pump;
            now.LeftDis = element.LeftDis;
            now.RightDis = element.RightDis;
            now.Time = element.Time;
            NotifyDatasChanged();
        }


        public void SetCoatingCtrl(double pump, double left, double right)
        {
            CoatingCtrlElement element = new CoatingCtrlElement() { Pump = pump, LeftDis = left, RightDis = right };
            mCtrlElement.Add(element);
            CoatingAction(NowCtrl, element, mCoating.Datas_Vertical, mCoating.Datas_Horizontal, mCoating.NotifyDatasChanged);
            
        }




        protected void NotifyPropertyChanged(string propertyname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;


    }
}