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

namespace FLY.Simulation.HeaderAndTailer
{
    public class CurveCollection : ICurveService, Misc.ISaveToXml
    {
        #region 数据文件需要保存的数据项
        CurveCorrectWay correctWay = CurveCorrectWay.OnePointIsScale;
        /// <summary>
        /// AD曲线校正方式
        /// </summary>
        public CurveCorrectWay CorrectWay
        {
            get
            {
                return correctWay;
            }
            set
            {
                if (correctWay != value)
                {
                    correctWay = value;
                    NotifyPropertyChanged("CorrectWay");
                }
            }
        }

        private CurveType flag;
        public CurveType Flag
        {
            get
            {
                return flag;
            }
            set
            {
                if (flag != value)
                {
                    flag = value;
                    NotifyPropertyChanged("Flag");
                }
            }
        }
        /// <summary>
        /// 输入的曲线, 排列顺序,Value 从 小到大
        /// </summary>
        private ObservableCollection<CurveCell> mCurves = new ObservableCollection<CurveCell>();
        public ObservableCollection<CurveCell> Curves
        {
            get
            {
                return mCurves;
            }
        }
        #endregion

        public event ActiveEventHandler ActiveEvent;

        public class ExChange : Misc.ISaveToXml
        {
            static ExChange()
            {
                Misc.SaveToXmlHepler.Regist(typeof(ExChange));
            }
            public int OrgAD { get; set; }
            public int CurrAD { get; set; }

            public string[] GetSavePropertyNames()
            {
                return new string[]{
                    "OrgAD",
                    "CurrAD"};
            }
        }
        /// <summary>
        /// 真实样品校正点
        /// </summary>
        private ObservableCollection<ExChange> mRevisingCurves = new ObservableCollection<ExChange>();
        public ObservableCollection<ExChange> RevisingCurves
        {
            get
            {
                return mRevisingCurves;
            }
        }
        private string param_path = "curve.xml";
        public CurveCollection()
        {
            SetDefault();
            ReviseCurve();
        }
        public CurveCollection(string param_path)
        {
            if (!string.IsNullOrEmpty(param_path))
                this.param_path = param_path;

            SetDefault();
            Load();
            ReviseCurve();
        }
        void SetDefault()
        {
            CorrectWay = CurveCorrectWay.OnePointIsScale;
            Flag = CurveType.E;
            Curves.Add(new CurveCell() { AD = 57564, Value = 0 });
            Curves.Add(new CurveCell() { AD = 30850, Value = 8800 });
            Curves.Add(new CurveCell() { AD = 19000, Value = 17600 });
            Curves.Add(new CurveCell() { AD = 12528, Value = 26400 });
            Curves.Add(new CurveCell() { AD = 8409, Value = 35200 });
            Curves.Add(new CurveCell() { AD = 5650, Value = 44000 });
            Curves.Add(new CurveCell() { AD = 3779, Value = 52800 });
            Curves.Add(new CurveCell() { AD = 2513, Value = 61600 });
            Curves.Add(new CurveCell() { AD = 1660, Value = 70400 });
        }
        public void Apply()
        {
            ClearExChange();
            ReviseCurve();

            if (ActiveEvent != null)
                ActiveEvent(this);
            Save();
        }
        public void Clear()
        {
            Curves.Clear();
            ClearExChange();
        }

        #region ExChange

        public void ModifyExChange(List<ExChange> list)
        {
            RevisingCurves.Clear();
            for (int i = 0; i < list.Count(); i++)
            {
                //检测RevisingCurves 正确性,避免 /0 溢出
                if ((list[i].OrgAD <= 10) || (list[i].CurrAD <= 10))
                {
                    //异常
                    continue;
                }
                var v = from rc in RevisingCurves where rc.OrgAD == list[i].OrgAD select rc;
                if (v.Count() > 0)
                {
                    //异常,重复了
                    continue;
                }
                RevisingCurves.Add(list[i]);
            }
            RevisingCurves.OrderByDescending(c => c.OrgAD);
        }


        public void ClearExChange()
        {
            RevisingCurves.Clear();
        }
        #endregion


        public static bool CheckRevisingPointValid(int ad)
        {
            if (ad < 3)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 根据样品值,修正曲线,只支持2个样品
        /// </summary>
        /// <returns></returns>
        public bool ReviseCurve()
        {
            if (RevisingCurves.Count < 1)//没数据
            {
                foreach (CurveCell c in Curves)
                {
                    c.RevisedAD = c.AD;
                }
                return false;
            }

            if (RevisingCurves.Count == 1)//只有一个校正点
            {
                switch (CorrectWay)
                {
                    case CurveCorrectWay.OnePointIsScale:
                        {
                            double ux = ((double)RevisingCurves[0].CurrAD) / RevisingCurves[0].OrgAD;

                            foreach (CurveCell c in Curves)
                            {
                                c.RevisedAD = (int)(c.AD * ux);
                            }
                        } break;
                    default:
                        //case CurveCorrectWay.OnePointIsOffset:
                        {
                            int x = RevisingCurves[0].CurrAD - RevisingCurves[0].OrgAD;

                            foreach (CurveCell c in Curves)
                            {
                                c.RevisedAD = c.AD + x;
                            }
                        } break;
                }

                return true;
            }
            else
            {
                int adh = RevisingCurves[0].OrgAD;
                int adl = RevisingCurves[1].OrgAD;
                double uh = ((double)RevisingCurves[0].CurrAD) / adh;
                double ul = ((double)RevisingCurves[1].CurrAD) / adl;

                for (int i = 0, j = 1; i < Curves.Count; i++)
                {
                    double ux = uh - (adh - Curves[i].AD) * (uh - ul) / (adh - adl);
                    Curves[i].RevisedAD = (int)(Curves[i].AD * ux);
                }
                return true;
            }
        }

        #region E

        int AD2Value_E(int ad, AD2ValueFlag flag)
        {
            int i;
            int thick;

            if (Curves.Count < 1) return -1;
            if (ad < 0) return -1;
            if (ad == 0) ad = 1;
            if (flag == AD2ValueFlag.NoRevised)
            {
                for (i = 0; i < Curves.Count; i++)
                {
                    if (ad < Curves[i].AD)
                        continue;
                    else
                        break;
                }
            }
            else
            {
                for (i = 0; i < Curves.Count; i++)
                {
                    if (ad < Curves[i].RevisedAD)
                        continue;
                    else
                        break;
                }
            }
            if (i >= Curves.Count) i = Curves.Count - 1;

            if (i == 0) i = 1;
            if (flag == AD2ValueFlag.NoRevised)
            {
                double u;

                u = Math.Log((double)Curves[i - 1].AD / Curves[i].AD, Math.E) * 100 / (Curves[i].Value - Curves[i - 1].Value);
                thick = (int)(Math.Log((double)Curves[i - 1].AD / ad, Math.E) * 100 / u + Curves[i - 1].Value);
            }
            else
            {
                double u;

                u = Math.Log((double)Curves[i - 1].RevisedAD / Curves[i].RevisedAD, Math.E) * 100 / (Curves[i].Value - Curves[i - 1].Value);
                thick = (int)(Math.Log((double)Curves[i - 1].RevisedAD / ad, Math.E) * 100 / u + Curves[i - 1].Value);

            }
            //if (thick < 0)
            //    return 0;

            return thick;
        }

        int Value2AD_E(int value)
        {
            int i;
            int ad;

            if (Curves.Count < 1) return -1;
            if (value < 0) return -1;


            for (i = 0; i < Curves.Count; i++)
            {
                if (value > Curves[i].Value)
                    continue;
                else
                    break;
            }
            
            if (i >= Curves.Count) i = Curves.Count - 1;

            if (i == 0) i = 1;

            double u;

            u = (Math.Log(Curves[i - 1].AD) - Math.Log(Curves[i].AD)) / (Curves[i - 1].Value - Curves[i].Value);
            ad = (int)Math.Exp((value - Curves[i - 1].Value) * u + Math.Log(Curves[i - 1].AD));

            return ad;
        }
        #endregion
        #region 线性
        int AD2Value_Line(int ad, AD2ValueFlag flag)
        {
            int i;
            int thick;

            if (Curves.Count < 2) return -1;
            if (ad < 0) return -1;
            if (ad == 0) ad = 1;
            bool isDescending = true;//降序排列
            if (Curves[0].AD < Curves[1].AD)
                isDescending = false;
            //找 ad0<ad<adi

            if (flag == AD2ValueFlag.NoRevised)
            {
                if (isDescending)//降序排列
                {
                    for (i = 0; i < Curves.Count; i++)
                    {
                        if (ad < Curves[i].AD)
                            continue;
                        else
                            break;
                    }
                }
                else
                {
                    for (i = 0; i < Curves.Count; i++)
                    {
                        if (ad > Curves[i].AD)
                            continue;
                        else
                            break;
                    }
                }
                if (i >= Curves.Count) i = Curves.Count - 1;
                if (i == 0) i = 1;

                double adi_ad0 = Curves[i].AD - Curves[i - 1].AD;
                double vi_v0 = Curves[i].Value - Curves[i - 1].Value;
                double a = vi_v0 / adi_ad0;
                double b = Curves[i - 1].Value - Curves[i - 1].AD * a;

                thick = (int)(ad * a + b);
                return thick;
            }
            else
            {
                if (isDescending)//降序排列
                {
                    for (i = 0; i < Curves.Count; i++)
                    {
                        if (ad < Curves[i].RevisedAD)
                            continue;
                        else
                            break;
                    }
                }
                else
                {
                    for (i = 0; i < Curves.Count; i++)
                    {
                        if (ad > Curves[i].RevisedAD)
                            continue;
                        else
                            break;
                    }
                }
                if (i >= Curves.Count) i = Curves.Count - 1;
                if (i == 0) i = 1;

                double adi_ad0 = Curves[i].RevisedAD - Curves[i - 1].RevisedAD;
                double vi_v0 = Curves[i].Value - Curves[i - 1].Value;
                double a = vi_v0 / adi_ad0;
                double b = Curves[i - 1].Value - Curves[i - 1].RevisedAD * a;

                thick = (int)(ad * a + b);
                return thick;
            }
        }

        int Value2AD_Line(int thick)
        {
            int i;
            int ad;

            if (Curves.Count < 2) return -1;

            bool isDescending = true;//降序排列
            if (Curves[0].Value < Curves[1].Value)
                isDescending = false;
            //找 value0<thick<value1


                if (isDescending)//降序排列
                {
                    for (i = 0; i < Curves.Count; i++)
                    {
                        if (thick < Curves[i].Value)
                            continue;
                        else
                            break;
                    }
                }
                else
                {
                    for (i = 0; i < Curves.Count; i++)
                    {
                        if (thick > Curves[i].Value)
                            continue;
                        else
                            break;
                    }
                }
                if (i >= Curves.Count) i = Curves.Count - 1;
                if (i == 0) i = 1;

                double vi_v0 = Curves[i].Value - Curves[i - 1].Value;
                double adi_ad0 = Curves[i].AD - Curves[i - 1].AD;
                double a = vi_v0 / adi_ad0;
                double b = Curves[i - 1].Value - Curves[i - 1].AD * a;

                ad = (int)((thick - b)/a);
                return ad;
            }
        
        #endregion

        public int AD2Value(int ad, AD2ValueFlag flag)
        {
            switch (Flag)
            {
                case CurveType.Line:
                    return AD2Value_Line(ad, flag);
                default:
                    return AD2Value_E(ad, flag);
            }
        }

        public int ValueAD(int value)
        {
            switch (Flag)
            {
                case CurveType.Line:
                    return Value2AD_Line(value);
                default:
                    return Value2AD_E(value);
            }
        }
        #region ITDParam 成员
        public bool Load()
        {
            bool ret = Misc.SaveToXmlHepler.Load("curve.xml", this);
            RevisingCurves.Clear();
            Curves.OrderBy(c => c.Value);

            return ret;
        }
        public void Save()
        {
            Misc.SaveToXmlHepler.Save("curve.xml", this);
        }
        #endregion

        #region ISaveToXml 成员

        public string[] GetSavePropertyNames()
        {
            return new string[]{
                "CorrectWay",
                "Flag",
                "Curves"};
        }

        #endregion

        #region INotifyPropertyChanged 成员

        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

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

        #endregion
    }
}