using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms.DataVisualization.Charting;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace FLY.ControlLibrary
{
    /// <summary>
    /// GraphScan.xaml 的交互逻辑
    /// </summary>
    public partial class GraphScan4 : UserControl, INotifyPropertyChanged
    {
        //设定数据统计范围
        #region IGraphBase
        #region 附加属性
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(GraphScan4), new PropertyMetadata("Title"));
        public string Title
        {
            get
            {
                return GetValue(TitleProperty) as string;
            }
            set
            {
                if (value != Title)
                {
                    SetValue(TitleProperty, value);
                    NotifyPropertyChanged("Title");
                }
            }
        }
        public static readonly DependencyProperty Title2Property =
            DependencyProperty.Register("Title2", typeof(string), typeof(GraphScan4), new PropertyMetadata(""));
        public string Title2
        {
            get
            {
                return GetValue(Title2Property) as string;
            }
            set
            {
                if (value != Title2)
                {
                    SetValue(Title2Property, value);
                    NotifyPropertyChanged("Title2");
                }
            }
        }

        public static readonly DependencyProperty IsValidProperty =
            DependencyProperty.Register("IsValid", typeof(bool), typeof(GraphScan4), new PropertyMetadata(true));
        public bool IsValid
        {
            get
            {
                return (bool)GetValue(IsValidProperty);
            }
            set
            {
                if (value != IsValid)
                {
                    SetValue(IsValidProperty, value);
                    NotifyPropertyChanged("IsValid");
                }
            }
        }
        /// <summary>
        /// 计算结果
        /// </summary>
        public static readonly DependencyProperty CalStateProperty =
            DependencyProperty.Register("CalState", typeof(string), typeof(GraphScan4), new PropertyMetadata(
                "Max:null Min:null Avg:null 2σ:null",
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                })));
        public string CalState
        {
            get
            {
                return (string)GetValue(CalStateProperty);
            }
            set
            {
                SetValue(CalStateProperty, value);
            }
        }


        /// <summary>
        /// 空的数据，定义某个值为空，默认为 99999998
        /// </summary>
        public static readonly DependencyProperty EmptyValueProperty =
            DependencyProperty.Register("EmptyValue", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                99999998,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                })));
        public int EmptyValue
        {
            get
            {
                return (int)GetValue(EmptyValueProperty);
            }
            set
            {
                SetValue(EmptyValueProperty, value);
            }
        }
        /// <summary>
        /// 放大倍数, 目标值= Target/放大倍数
        /// </summary>
        public static readonly DependencyProperty MultiProperty =
            DependencyProperty.Register("Multi", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                100,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                })));

        public int Multi
        {
            get
            {
                return (int)GetValue(MultiProperty);
            }
            set
            {
                SetValue(MultiProperty, value);
            }
        }



        /// <summary>
        /// 目标值
        /// </summary>
        public static readonly DependencyProperty TargetProperty =
            DependencyProperty.Register("Target", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                3000,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                    (d as GraphScan4).NotifyPropertyChanged("Target");
                })));
        public int Target
        {
            get
            {
                return (int)GetValue(TargetProperty);
            }
            set
            {
                SetValue(TargetProperty, value);
            }
        }

        private int autotarget;
        public int AutoTarget
        {
            get { return autotarget; }
            set
            {
                if (autotarget != value)
                {
                    autotarget = value;
                    NotifyPropertyChanged("AutoTarget");
                }
            }
        }


        /// <summary>
        /// 自动目标值
        /// </summary>
        public static readonly DependencyProperty IsAutoTargetProperty =
            DependencyProperty.Register("IsAutoTarget", typeof(bool), typeof(GraphScan4), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                    (d as GraphScan4).NotifyPropertyChanged("IsAutoTarget");
                })));
        public bool IsAutoTarget
        {
            get
            {
                return (bool)GetValue(IsAutoTargetProperty);
            }
            set
            {
                SetValue(IsAutoTargetProperty, value);
            }
        }


        /// <summary>
        /// 获取或设置指示是否将轴反转的标志
        /// </summary>
        public static readonly DependencyProperty IsReversedProperty =
            DependencyProperty.Register("IsReversed", typeof(bool), typeof(GraphScan4), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("IsReversed");
                })));
        public bool IsReversed
        {
            get
            {
                return (bool)GetValue(IsReversedProperty);
            }
            set
            {
                SetValue(IsReversedProperty, value);
            }
        }


        /// <summary>
        /// 获取或设置 左右标示是否反转 的标志
        /// </summary>
        public static readonly DependencyProperty LeftRightIsReversedProperty =
            DependencyProperty.Register("LeftRightIsReversed", typeof(bool), typeof(GraphScan4), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("LeftRightIsReversed");
                })));
        /// <summary>
        /// 左右标示 反转
        /// </summary>
        public bool LeftRightIsReversed
        {
            get
            {
                return (bool)GetValue(LeftRightIsReversedProperty);
            }
            set
            {
                SetValue(LeftRightIsReversedProperty, value);
            }
        }

        /// <summary>
        /// 左右标示 可见
        /// </summary>
        public static readonly DependencyProperty LeftRightIsVisableProperty =
            DependencyProperty.Register("LeftRightIsVisable", typeof(bool), typeof(GraphScan4), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                    (d as GraphScan4).NotifyPropertyChanged("LeftRightIsVisable");
                })));

        /// <summary>
        /// 左右标示 反转
        /// </summary>
        public bool LeftRightIsVisable
        {
            get
            {
                return (bool)GetValue(LeftRightIsVisableProperty);
            }
            set
            {
                SetValue(LeftRightIsVisableProperty, value);
            }
        }

        /// <summary>
        /// %显示
        /// </summary>
        public static readonly DependencyProperty IsPercentProperty =
            DependencyProperty.Register("IsPercent", typeof(bool), typeof(GraphScan4), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                    (d as GraphScan4).NotifyPropertyChanged("IsPercent");
                })));
        public bool IsPercent
        {
            get
            {
                return (bool)GetValue(IsPercentProperty);
            }
            set
            {
                SetValue(IsPercentProperty, value);
            }
        }

        /// <summary>
        /// 报警值
        /// </summary>
        public static readonly DependencyProperty AlarmProperty =
            DependencyProperty.Register("Alarm", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                1000,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("Alarm");
                })));
        public int Alarm
        {
            get
            {
                return (int)GetValue(AlarmProperty);
            }
            set
            {
                SetValue(AlarmProperty, value);
            }

        }
        /// <summary>
        /// Y轴是 Alarm 的N倍 默认3倍
        /// </summary>
        public static readonly DependencyProperty YRangePercentProperty =
            DependencyProperty.Register("YRangePercent", typeof(double), typeof(GraphScan4), new PropertyMetadata(
            3.0,
            new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
            {

                (d as GraphScan4).NotifyPropertyChanged("YRangePercent");
            })));
        public double YRangePercent
        {
            get
            {
                return (double)GetValue(YRangePercentProperty);
            }
            set
            {
                SetValue(YRangePercentProperty, value);
            }
        }
        /// <summary>
        /// 控制线
        /// </summary>
        public static readonly DependencyProperty HasCtrlLineProperty =
            DependencyProperty.Register("HasCtrlLine", typeof(bool), typeof(GraphScan4), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("HasCtrlLine");
                })));
        public bool HasCtrlLine
        {
            get
            {
                return (bool)GetValue(HasCtrlLineProperty);
            }
            set
            {
                SetValue(HasCtrlLineProperty, value);
            }

        }

        /// <summary>
        /// 控制线
        /// </summary>
        public static readonly DependencyProperty CtrlLineProperty =
            DependencyProperty.Register("CtrlLine", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                1000,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("CtrlLine");
                })));
        public int CtrlLine
        {
            get
            {
                return (int)GetValue(CtrlLineProperty);
            }
            set
            {
                SetValue(CtrlLineProperty, value);
            }

        }


        /// <summary>
        /// 第一个分区号
        /// </summary>
        public static readonly DependencyProperty FirstBoltNoProperty =
            DependencyProperty.Register("FirstBoltNo", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                0,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("FirstBoltNo");
                })));

        public int FirstBoltNo
        {
            get
            {
                return (int)GetValue(FirstBoltNoProperty);
            }
            set
            {
                SetValue(FirstBoltNoProperty, value);
            }
        }



        /// <summary>
        /// 
        /// </summary>
        public static readonly DependencyProperty FirstIndexProperty =
            DependencyProperty.Register("FirstIndex", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                0,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("FirstIndex");

                })));
        public int FirstIndex
        {
            get
            {
                return (int)GetValue(FirstIndexProperty);
            }
            set
            {
                SetValue(FirstIndexProperty, value);
            }
        }


        /// <summary>
        /// 
        /// </summary>
        public static readonly DependencyProperty LastIndexProperty =
            DependencyProperty.Register("LastIndex", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                49,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("LastIndex");
                })));

        public int LastIndex
        {
            get
            {
                return (int)GetValue(LastIndexProperty);
            }
            set
            {
                SetValue(LastIndexProperty, value);
            }
        }

        /// <summary>
        /// 数据统计的开始
        /// </summary>
        public static readonly DependencyProperty DataFirstProperty =
            DependencyProperty.Register("DataFirst", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                0,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("DataFirst");

                })));

        public int DataFirst
        {
            get
            {
                return (int)GetValue(DataFirstProperty);
            }
            set
            {
                SetValue(DataFirstProperty, value);
            }
        }

        /// <summary>
        /// 数据统计的结束
        /// </summary>
        public static readonly DependencyProperty DataLastProperty =
            DependencyProperty.Register("DataLast", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                49,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("DataLast");
                })));

        public int DataLast
        {
            get
            {
                return (int)GetValue(DataLastProperty);
            }
            set
            {
                SetValue(DataLastProperty, value);
            }
        }


        #endregion

        #region IGraphBase3
        /// <summary>
        /// mm/分区
        /// </summary>
        public static readonly DependencyProperty MmOfBoltProperty =
            DependencyProperty.Register("MmOfBolt", typeof(double), typeof(GraphScan4), new PropertyMetadata(
                10.0,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("MmOfBolt");
                })));
        /// <summary>
        /// mm/分区
        /// </summary>
        public double MmOfBolt
        {
            get
            {
                return (double)GetValue(MmOfBoltProperty);
            }
            set
            {
                if (value != MmOfBolt)
                {
                    SetValue(MmOfBoltProperty, value);
                    NotifyPropertyChanged("MmOfBolt");
                }
            }
        }


        /// <summary>
        /// X轴间隔 单位分区
        /// </summary>
        public static readonly DependencyProperty XIntervalProperty =
            DependencyProperty.Register("XInterval", typeof(int), typeof(GraphScan4), new PropertyMetadata(
                5,
                new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan4).NotifyPropertyChanged("XInterval");
                })));
        /// <summary>
        /// X轴间隔 单位分区
        /// </summary>
        public int XInterval
        {
            get
            {
                return (int)GetValue(XIntervalProperty);
            }
            set
            {

                if (value != XInterval)
                {
                    SetValue(XIntervalProperty, value);
                    NotifyPropertyChanged("XInterval");
                }
            }
        }
        #endregion
        /// <summary>
        /// 数据源
        /// </summary>
        private ObservableCollection<GraphScan4Data> _datasource;
        /// <summary>
        /// 数据源
        /// </summary>
        public virtual ObservableCollection<GraphScan4Data> DataSource
        {
            get
            {
                return _datasource;
            }
            set
            {
                if (_datasource != null)
                    _datasource.CollectionChanged -= dataSource_CollectionChanged;

                _datasource = value;

                _datasource.CollectionChanged += dataSource_CollectionChanged;
                mRefresh.UpdateData = true;
            }
        }

        public event EventHandler ShowSettingDialogEvent;
        public event EventHandler TitleClickEvent;



        #endregion

        #region 刷新率控制
        protected class Refresh
        {
            /// <summary>
            /// 控制刷新率
            /// </summary>
            System.Windows.Threading.DispatcherTimer timer;
            bool updatedata_flag = false;
            bool updatey_flag = false;
            bool updatex_flag = false;
            bool updatecalx_flag = false;


            /// <summary>
            /// 最快0.1s 刷新一次
            /// </summary>
            TimeSpan REFRESH_RATE = TimeSpan.FromSeconds(0.1);

            public Refresh(GraphScan4 graph)
            {
                timer = new System.Windows.Threading.DispatcherTimer();
                timer.Tick += new EventHandler(delegate (object sender, EventArgs e)
                {
                    if (UpdateData)
                    {
                        UpdateData = false;
                        graph.DataBindAll_all();
                    }
                    if (UpdateY)
                    {
                        UpdateY = false;
                        graph.UpdateAxisY();
                    }
                    if (UpdateX)
                    {
                        UpdateX = false;
                        graph.UpdateXRange();
                    }
                    if (UpdateCalX)
                    {
                        UpdateCalX = false;
                        graph.UpdateDataCalRange();
                        graph.UpdateCalState_all();
                    }
                    timer.Stop();
                });

                timer.Interval = REFRESH_RATE;
                timer.Start();
            }

            public bool UpdateData
            {
                get { return updatedata_flag; }
                set
                {
                    updatedata_flag = value;
                    if (value)
                    {
                        if (!timer.IsEnabled)
                            timer.Start();
                    }
                }
            }
            public bool UpdateY
            {
                get { return updatey_flag; }
                set
                {
                    updatey_flag = value;
                    if (value)
                    {
                        if (!timer.IsEnabled)
                            timer.Start();
                    }
                }
            }
            public bool UpdateX
            {
                get { return updatex_flag; }
                set
                {
                    updatex_flag = value;
                    if (value)
                    {
                        if (!timer.IsEnabled)
                            timer.Start();
                    }
                }
            }
            public bool UpdateCalX
            {
                get { return updatecalx_flag; }
                set
                {
                    updatecalx_flag = value;
                    if (value)
                    {
                        if (!timer.IsEnabled)
                            timer.Start();
                    }
                }
            }

        }
        protected Refresh mRefresh;
        #endregion



        public GraphScan4()
        {

            InitializeComponent();
            InitializeComponent2();
            grid_title.DataContext = this;
            PropertyChanged += new PropertyChangedEventHandler(GraphScan_PropertyChanged);

            mRefresh = new Refresh(this);

            SetDefault();


            //Test();

        }

        void GraphScan_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            //if (e.PropertyName == "AutoTarget")
            //{
            //    if (IsAutoTarget)
            //    {
            //        mRefresh.UpdateY = true;
            //        mRefresh.UpdateData = true;
            //    }
            //}
            if ((e.PropertyName == "Target") ||
                (e.PropertyName == "Alarm") ||
                (e.PropertyName == "YRangePercent") ||
                (e.PropertyName == "IsAutoTarget") ||
                (e.PropertyName == "IsPercent") ||
                (e.PropertyName == "AutoTarget"))
            {
                mRefresh.UpdateY = true;
                mRefresh.UpdateData = true;
            }
            else if (e.PropertyName == "FirstBoltNo")
            {
                mRefresh.UpdateCalX = true;
                mRefresh.UpdateX = true;
                mRefresh.UpdateData = true;

            }
            else if (e.PropertyName == "FirstIndex" || e.PropertyName == "LastIndex")
            {
                mRefresh.UpdateX = true;
            }
            else if (e.PropertyName == "DataFirst" || e.PropertyName == "DataLast")
            {
                mRefresh.UpdateCalX = true;
            }
            else if (e.PropertyName == "IsReversed")
            {
                chart1.ChartAreas[0].AxisX.IsReversed = IsReversed;
            }
            else if ((e.PropertyName == "HasCtrlLine") || (e.PropertyName == "CtrlLine"))
            {
                UpdateCtrlLine();
            }
            if (e.PropertyName == "MmOfBolt")
            {
                mRefresh.UpdateData = true;
            }
            else if (e.PropertyName == "XInterval")
            {
                mRefresh.UpdateX = true;
            }
        }

        public void SetDefault()
        {
            NotifyPropertyChanged("Target");
            NotifyPropertyChanged("TAlarm");
            NotifyPropertyChanged("YRangePercent");
            NotifyPropertyChanged("ChartType");
            NotifyPropertyChanged("FirstBoltNo");
            NotifyPropertyChanged("FirstIndex");
            NotifyPropertyChanged("LastIndex");
            NotifyPropertyChanged("DataFirst");
            NotifyPropertyChanged("DataLast");

            AutoTarget = Target;
        }

        void InitializeComponent2()
        {
            System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
            System.Windows.Forms.DataVisualization.Charting.Series series_sigma = new System.Windows.Forms.DataVisualization.Charting.Series();
            System.Windows.Forms.DataVisualization.Charting.Series series_avg = new System.Windows.Forms.DataVisualization.Charting.Series();

            chart1.Name = "chart1";
            chart1.BackColor = System.Drawing.Color.Transparent;

            // 
            // chart1
            //---------------------------------------------------------------------------------------
            chartArea1.Name = "chartArea1";
            chartArea1.AxisX.LabelStyle.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold);
            chartArea1.AxisX.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
            chartArea1.AxisX.MajorGrid.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
            chartArea1.AxisX.IsMarksNextToAxis = false;
            chartArea1.AxisX.IsLabelAutoFit = true;
            chartArea1.AxisX.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont;
            chartArea1.AxisX.IntervalAutoMode = System.Windows.Forms.DataVisualization.Charting.IntervalAutoMode.VariableCount;

            chartArea1.AxisY.LabelStyle.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold);
            chartArea1.AxisY.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
            chartArea1.AxisY.MajorGrid.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));

            chartArea1.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
            chartArea1.BorderDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;



            //chartArea1.Position.Height = 100;// 42F;
            //chartArea1.Position.Width = 100;// 88F;
            //chartArea1.Position.X = 0;// 3F;
            //chartArea1.Position.Y = 0;// 10F;

            chart1.ChartAreas.Add(chartArea1);

            //---------------------------------------------------------------------------------------
            series_sigma.Name = "series_sigma";
            series_sigma.ChartArea = chartArea1.Name;

            series_sigma.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Range;
            series_sigma.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240)))));


            series_sigma.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105)))));
            series_sigma.BorderWidth = 2;

            //series_sigma.ShadowColor = System.Drawing.Color.Black;
            //series_sigma.ShadowOffset = 2;
            series_sigma.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32;
            series_sigma.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
            chart1.Series.Add(series_sigma);

            //---------------------------------------------------------------------------------------
            series_avg.Name = "series_avg";
            series_avg.ChartArea = chartArea1.Name;

            series_avg.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Spline;
            series_avg.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240)))));
            series_avg.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105)))));
            series_avg.BorderWidth = 3;
            series_avg.ShadowColor = System.Drawing.Color.Black;
            series_avg.ShadowOffset = 2;
            series_avg.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32;
            series_avg.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
            chart1.Series.Add(series_avg);

            //chart1.PrePaint += new EventHandler<ChartPaintEventArgs>(Chart1_PrePaint);

            this.chart1.PrePaint += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs>(Chart1_PrePaint);
        }

        protected virtual void SetCustomLabel(Axis axisY, double p, GridTickTypes gt, System.Drawing.Color c, bool ispercent, string message)
        {
            double r = axisY.Maximum - axisY.Minimum;
            double f, t;
            f = p + r / 2;
            t = p - r / 2;
            double target = (axisY.Maximum + axisY.Minimum) / 2;

            CustomLabel customLabel;
            string str;
            if (!ispercent)
            {
                str = p.ToString("N1");
            }
            else
            {
                //百分比模式！！！！！！！
                if (target == p)
                {
                    str = p.ToString("N1");
                }
                else
                {
                    double percent;

                    percent = ((p - target) / target) * 100;
                    str = percent.ToString("N1") + "%";
                }
            }
            if (!string.IsNullOrEmpty(message))
                str = message + " " + str;

            customLabel = axisY.CustomLabels.Add(f, t, str);

            customLabel.GridTicks = gt;
            customLabel.ForeColor = c;
        }


        /// <summary>
        /// 获取实际应用的目标值，公差
        /// </summary>
        /// <param name="target"></param>
        /// <param name="alarm"></param>
        /// <param name="yrange"></param>
        /// <param name="ispercent"></param>
        protected void GetActualTargetAlarm(out double target, out double alarm, out double yrange, out bool ispercent)
        {
            double multi = Multi;
            if (IsAutoTarget)
                target = AutoTarget / multi;//AutoTarget 计算得到的平均值
            else
                target = Target / multi;

            ispercent = IsPercent;
            if ((ispercent) && (Target <= 0) || (Alarm < 0) || (target <= 0))
                ispercent = false;

            if (ispercent)
            {
                alarm = target * Alarm / Target;
            }
            else
            {
                alarm = Alarm / multi;
            }
            yrange = alarm * YRangePercent;

            if ((alarm < 0.1) || (yrange < 0.3))
            {
                alarm = 0.1;
                yrange = 0.3;
            }
        }
        /// <summary>
        /// 与 Multi,Target,YRange,Alarm 相关
        /// </summary>
        public virtual void UpdateAxisY()
        {
            double alarm;
            double yrange;
            double target;
            bool ispercent;
            GetActualTargetAlarm(out target, out alarm, out yrange, out ispercent);

            Axis axisY = chart1.ChartAreas[0].AxisY;

            axisY.Crossing = target;

            // Set manual minimum and maximum values.
            axisY.Minimum = target - yrange;
            axisY.Maximum = target + yrange;

            axisY.CustomLabels.Clear();
            //中间目标值,肯定不以%显示
            SetCustomLabel(axisY, target, GridTickTypes.All, System.Drawing.Color.Green, false, null);

            //上下限
            SetCustomLabel(axisY, target + alarm, GridTickTypes.All, System.Drawing.Color.DarkGoldenrod, ispercent, null);
            SetCustomLabel(axisY, target - alarm, GridTickTypes.All, System.Drawing.Color.DarkGoldenrod, ispercent, null);

            //2倍上下限
            SetCustomLabel(axisY, target + alarm * 2, GridTickTypes.All, System.Drawing.Color.Red, ispercent, null);
            SetCustomLabel(axisY, target - alarm * 2, GridTickTypes.All, System.Drawing.Color.Red, ispercent, null);

            //显示范围数值
            if ((yrange != alarm) && (yrange != 2 * alarm))
            {
                SetCustomLabel(axisY, axisY.Minimum, GridTickTypes.TickMark, System.Drawing.Color.Black, ispercent, null);
                SetCustomLabel(axisY, axisY.Maximum, GridTickTypes.TickMark, System.Drawing.Color.Black, ispercent, null);
            }

            //显示范围太小，多加纵坐标
            if (yrange <= alarm)
            {
                SetCustomLabel(axisY, target - yrange / 2, GridTickTypes.All, System.Drawing.Color.Black, ispercent, null);
                SetCustomLabel(axisY, target + yrange / 2, GridTickTypes.All, System.Drawing.Color.Black, ispercent, null);
            }



        }

        /// <summary>
        /// 与 FirstBoltNo,DataFirst,DataLast 相关
        /// </summary>
        public virtual void UpdateDataCalRange()
        {
            int firstBoltNo = FirstBoltNo;
            int datafirst = DataFirst;
            int datalast = DataLast;
            if (datafirst > datalast)
            {
                int swap = datalast;
                datalast = datafirst;
                datafirst = swap;
            }

            System.Windows.Forms.DataVisualization.Charting.Axis axisX = chart1.ChartAreas[0].AxisX;

            axisX.CustomLabels.Clear();

            System.Windows.Forms.DataVisualization.Charting.CustomLabel customlabel
                = new System.Windows.Forms.DataVisualization.Charting.CustomLabel(
                    datafirst + firstBoltNo, datalast + firstBoltNo, CalState, 1,
                System.Windows.Forms.DataVisualization.Charting.LabelMarkStyle.LineSideMark);

            axisX.CustomLabels.Add(customlabel);
        }

        /// <summary>
        /// 与 FirstBoltNo,FirstIndex,LastIndex 相关
        /// </summary>
        public virtual void UpdateXRange()
        {
            int firstBoltNo = FirstBoltNo;
            int first = FirstIndex;
            int last = LastIndex;
            if (first > last)
            {
                //交换
                int swap = last;
                last = first;
                first = swap;
            }
            else if (first == last)
            {
                last = first + 10;
            }
            // Set manual minimum and maximum values.
            Axis axis = chart1.ChartAreas[0].AxisX;

            axis.Minimum = firstBoltNo + first;
            axis.Maximum = firstBoltNo + last;
            axis.Interval = XInterval;
            //0必须在 写着0mm

            axis.IntervalOffset = (0 - axis.Minimum) % XInterval;
        }

        public virtual void UpdateCtrlLine()
        {
            chart1.Invalidate();
        }

        protected virtual void Chart1_PrePaint(object sender, System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs e)
        {
            if (e.ChartElement is ChartArea)
            {
                ChartArea area = (ChartArea)e.ChartElement;
                //if (area.Name == "Default")
                {
                    if (!HasCtrlLine)
                        return;
                    double c1 = ((double)(Target + CtrlLine)) / Multi;
                    double c2 = ((double)(Target - CtrlLine)) / Multi;

                    if (c1 > area.AxisY.Maximum || c2 < area.AxisY.Minimum)
                        return;

                    // Take Graphics object from chart
                    Graphics graph = e.ChartGraphics.Graphics;

                    // Convert X and Y values to screen position
                    c1 = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.Y, c1);
                    c2 = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.Y, c2);

                    double XMin = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.X, area.AxisX.Minimum);
                    double XMax = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.X, area.AxisX.Maximum);

                    // Draw Maximum trangle
                    System.Drawing.Pen darkPen = new System.Drawing.Pen(System.Drawing.Color.LightPink, 1);

                    System.Drawing.PointF[] points = new System.Drawing.PointF[2];
                    points[0].X = (float)XMin;
                    points[1].X = (float)XMax;
                    points[0].Y = points[1].Y = (float)c1;

                    // Convert relative coordinates to absolute coordinates.
                    points[0] = e.ChartGraphics.GetAbsolutePoint(points[0]);
                    points[1] = e.ChartGraphics.GetAbsolutePoint(points[1]);

                    graph.DrawLine(darkPen, points[0], points[1]);

                    points[0].X = (float)XMin;
                    points[1].X = (float)XMax;
                    points[0].Y = points[1].Y = (float)c2;

                    // Convert relative coordinates to absolute coordinates.
                    points[0] = e.ChartGraphics.GetAbsolutePoint(points[0]);
                    points[1] = e.ChartGraphics.GetAbsolutePoint(points[1]);

                    graph.DrawLine(darkPen, points[0], points[1]);
                }
            }
        }




        protected virtual void UpdateOnePoint_all(int index)
        {
            double multi = Multi;
            int emptyvalue = EmptyValue;
            DataPoint point_sigma;
            DataPoint point_avg;
            
            double avg;
            double upper;
            double lower;

            if ((DataSource[index].Avg == emptyvalue) || (DataSource[index].Sigma == emptyvalue))
            {
                avg = double.NaN;
                upper = double.NaN;
                lower = double.NaN;
            }
            else
            {
                double sigma2 = 2 * DataSource[index].Sigma / multi;
                avg = DataSource[index].Avg / multi;
                upper = avg + sigma2;
                lower = avg - sigma2;
            }


            if (index >= chart1.Series["series_sigma"].Points.Count)
            {
                chart1.Series["series_sigma"].Points.AddXY(
                    FirstBoltNo + index,
                    upper, lower);

                point_sigma = chart1.Series["series_sigma"].Points[index];

                chart1.Series["series_avg"].Points.AddXY(
                    FirstBoltNo + index,
                    avg);
                point_avg = chart1.Series["series_avg"].Points[index];
            }
            else
            {
                point_sigma = chart1.Series["series_sigma"].Points[index];
                point_sigma.YValues[0] = upper;
                point_sigma.YValues[1] = lower;
                point_sigma.XValue = FirstBoltNo + index;

                point_avg = chart1.Series["series_avg"].Points[index];
                point_avg.YValues[0] = avg;
                point_avg.XValue = FirstBoltNo + index;
            }
            point_avg.AxisLabel = (point_avg.XValue * MmOfBolt).ToString("F0") + "mm";

            //设定空数据
            if (double.IsNaN(avg))
            {
                point_sigma.IsEmpty = true;
                point_avg.IsEmpty = true;

                System.Drawing.Color c = System.Drawing.Color.Transparent;
                point_sigma.MarkerColor = c;
                point_sigma.BorderColor = c;
                point_sigma.Color = c;

                point_avg.MarkerColor = c;
                point_avg.BorderColor = c;
                point_avg.Color = c;
            }
            else
            {
                point_sigma.IsEmpty = false;
                point_avg.IsEmpty = false;

                double alarm;
                double target;
                double yrange;
                bool ispercent;

                GetActualTargetAlarm(out target, out alarm, out yrange, out ispercent);

                double threshold1 = alarm;
                double threshold2 = alarm * 2;


                System.Drawing.Color c;
                if (((upper) > (target + threshold2)) || ((upper) < (target - threshold2)))
                {
                    c = System.Drawing.Color.Red;
                }
                else if (((lower) > (target + threshold2)) || ((lower) < (target - threshold2)))
                {
                    c = System.Drawing.Color.Red;
                }
                else if (((upper) > (target + threshold1)) || ((upper) < (target - threshold1)))
                {
                    c = System.Drawing.Color.Orange;
                }
                else if (((lower) > (target + threshold1)) || ((lower) < (target - threshold1)))
                {
                    c = System.Drawing.Color.Orange;
                }
                else
                {
                    c = System.Drawing.Color.Green;
                }

                point_sigma.BorderColor = c;
                point_sigma.Color = c;

                point_avg.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240)))));
                point_avg.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105)))));


            }
        }

        void DataBindAll_all()
        {
            chart1.Series["series_avg"].Points.Clear();
            chart1.Series["series_sigma"].Points.Clear();
            if (DataSource != null)
            {
                for (int i = 0; i < DataSource.Count(); i++)
                {
                    UpdateOnePoint_all(i);
                }
            }
            CheckDataSourceEmpty();
            UpdateCalState_all();
        }

        /// <summary>
        /// 与 Multi,EmptyValue,DataFirst,DataLast 相关
        /// </summary>
        public void UpdateCalState_all()
        {
            int emptyvalue = EmptyValue;
            double multi = Multi;

            if (DataSource == null)
            {
                goto _err;
            }

            string title;
            var dats_max = from data in DataSource where data.Avg != emptyvalue select data.Avg + data.Sigma * 2;
            var dats_min = from data in DataSource where data.Avg != emptyvalue select data.Avg - data.Sigma * 2;
            List<int> dats = new List<int>();
            dats.AddRange(dats_max);
            dats.AddRange(dats_min);
            if (dats.Count() == 0)
            {
                goto _err;
            }
            else
            {
                //AutoTarget = (int)dats.Average();

                double avg = dats.Average() / multi;
                double max = dats.Max() / multi;
                double min = dats.Min() / multi;

                double sum = 0;
                foreach (int dat in dats)
                {
                    sum += Math.Pow(avg - (double)dat / multi, 2);
                }
                sum /= (dats.Count() - 1);
                double sigma = Math.Sqrt(sum);


                if (IsPercent)
                {
                    title = "Max:+" + ((max / avg * 100) - 100).ToString("N1") + "% " +
                        "Min:-" + (100 - (min / avg * 100)).ToString("N1") + "% " +
                        "Avg:" + avg.ToString("N1") + " " +
                        "2σ:" + (sigma / avg * 2 * 100).ToString("N1") + "%";
                }
                else
                {
                    title = "Max:" + max.ToString("N1") + " " +
                        "Min:" + min.ToString("N1") + " " +
                        "Avg:" + avg.ToString("N1") + " " +
                        "2σ:" + (sigma * 2).ToString("N1");
                }

            }
            goto _end;
        _err:
            //title = Properties.Resources.StrMax + ":" + "NULL " +
            //        Properties.Resources.StrMin+":"+"NULL "+
            //        Properties.Resources.StrAvg+":"+"NULL "+
            //        "3Sigma:"+"NULL ";
            title = "Max:null Min:null Avg:null 2σ:null";

        _end:



            CalState = title;
            UpdateDataCalRange();
        }

        

        /// <summary>
        /// DataSource 里面的数据都是 EmptyValue 组成, 当修改数据时，应该clear ,再添加
        /// </summary>
        private bool DataSourceIsEmpty = false;
        /// <summary>
        /// 当一个数据都没有时，需要添加空数据
        /// </summary>
        public void CheckDataSourceEmpty()
        {
            if ((DataSource == null) || (DataSource.Count() == 0))
            {
                chart1.Series["series_avg"].Points.Clear();
                chart1.Series["series_avg"].Points.AddXY(FirstBoltNo, EmptyValue);
                chart1.Series["series_avg"].Points[0].IsEmpty = true;
                DataSourceIsEmpty = true;
            }
            else
            {
                DataSourceIsEmpty = false;
            }
        }


        void dataSource_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            mRefresh.UpdateData = true;
        }

        public void Button_Click(object sender, RoutedEventArgs e)
        {
            ShowSettingDialogEvent?.Invoke(this, new EventArgs());
        }
        private void Button2_Click(object sender, RoutedEventArgs e)
        {
            TitleClickEvent?.Invoke(this, new EventArgs());
        }


        #region INotifyPropertyChanged 成员
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion


    }
    public struct GraphScan4Data
    {
        public int Avg;
        public int Sigma;
    }
}
