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


namespace FLY.ControlLibrary
{
    /// <summary>
    /// GraphScan.xaml 的交互逻辑
    /// </summary>
    public partial class GraphScan : UserControl, INotifyPropertyChanged, IGraphBase2, IGraphBase
    {
        //设定数据统计范围
        #region IGraphBase
        #region 附加属性
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(GraphScan), 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(GraphScan), 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(GraphScan), 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(GraphScan), 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(GraphScan), 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(GraphScan), 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 ChartTypeProperty =
            DependencyProperty.Register("ChartType", typeof(System.Windows.Forms.DataVisualization.Charting.SeriesChartType), typeof(GraphScan), new PropertyMetadata(
                System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Column,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                    (d as GraphScan).NotifyPropertyChanged("ChartType");
                })));
        public System.Windows.Forms.DataVisualization.Charting.SeriesChartType ChartType
        {
            get
            {
                return (System.Windows.Forms.DataVisualization.Charting.SeriesChartType)GetValue(ChartTypeProperty);
            }
            set
            {
                SetValue(ChartTypeProperty, value);
            }
        }

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

                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {

                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                1000,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
            3.0,
            new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {

                (d as GraphScan).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(GraphScan), new PropertyMetadata(
                false,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                1000,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                0,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                0,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                49,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                0,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan).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(GraphScan), new PropertyMetadata(
                49,
                new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as GraphScan).NotifyPropertyChanged("DataLast");
                })));

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


        #endregion

        /// <summary>
        /// 数据源
        /// </summary>
        private ObservableCollection<int> _datasource;
        public virtual ObservableCollection<int> 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;




        #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(GraphScan graph)
            {
                timer = new System.Windows.Threading.DispatcherTimer();
                timer.Tick += new EventHandler(delegate(object sender, EventArgs e)
                {
                    if (UpdateData)
                    {
                        UpdateData = false;
                        graph.DataBindAll2();
                    }
                    if (UpdateY)
                    {
                        UpdateY = false;
                        graph.UpdateAxisY();
                    }
                    if (UpdateX)
                    {
                        UpdateX = false;
                        graph.UpdateXRange();
                    }
                    if (UpdateCalX)
                    {
                        UpdateCalX = false;
                        graph.UpdateDataCalRange();
                        graph.UpdateCalState();
                    }
                    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 GraphScan()
        {
            
            InitializeComponent();
            InitializeComponent2();
            //this.DataContext = this;
            grid_title.DataContext = this;
            //this.rectangle.DataContext = this;
            //this.run_title.DataContext = this;
            //this.run_title2.DataContext = this;
            //this.grid_left.DataContext = this;
            //this.grid_right.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 == "ChartType")
            {
                UpdateChartType();
            }
            else if (e.PropertyName == "IsReversed")
            {
                chart1.ChartAreas[0].AxisX.IsReversed = IsReversed;
            }
            else if ((e.PropertyName == "HasCtrlLine") || (e.PropertyName == "CtrlLine")) 
            {
                UpdateCtrlLine();
            }
            
        }
        public virtual void UpdateChartType()
        {
            Series series1 = chart1.Series[0];
            series1.ChartType = ChartType;

            if (ChartType == SeriesChartType.Line)
            { 
                series1.MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.Circle;
            }
            else
            {
                series1.MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.None;
            }
        }

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

            AutoTarget = Target;
        }
        protected virtual void Test() 
        {
            ObservableCollection<int> datasource = new ObservableCollection<int>();

            // Populate series data
            Random random = new Random();

            for (int i = 0; i < 40; i++)
            {
                datasource.Add(random.Next(3000) - 1500 + Target);
            }

            DataSource = datasource;
        }

        protected virtual void InitializeComponent2()
        {
            System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
            System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
            System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();

            // 
            // chart1
            // 
            
            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.Interval = 5;
            chartArea1.AxisX.IsLabelAutoFit = true;
            chartArea1.AxisX.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont;

            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)))));
            
            

            //this.chart1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(78)))), ((int)(((byte)(160)))), ((int)(((byte)(34)))));
            //chartArea1.BackColor = this.chart1.BackColor;
            //chartArea1.BackColor = System.Drawing.Color.Transparent;
            //chartArea1.BackColor = System.Drawing.Color.OldLace;
            //chartArea1.BackGradientStyle = System.Windows.Forms.DataVisualization.Charting.GradientStyle.TopBottom;
            //chartArea1.BackSecondaryColor = System.Drawing.Color.White;
            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.Name = "Default";
            

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

            //chartArea1.ShadowColor = System.Drawing.Color.Transparent;
            this.chart1.ChartAreas.Add(chartArea1);
            

            //legend1.BackColor = System.Drawing.Color.Transparent;
            //legend1.Enabled = false;
            //legend1.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold);
            //legend1.IsTextAutoFit = false;
            //legend1.Name = "Default";
            //this.chart1.Legends.Add(legend1);
            //this.chart1.Location = new System.Drawing.Point(16, 32);
            this.chart1.Name = "chart1";
            series1.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105)))));
            series1.BorderWidth = 2;

            series1.ChartArea = chartArea1.Name;
            //TODO
            series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Column;

            series1.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240)))));
            
            series1.MarkerSize = 6;
            //series1.MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.Circle;
            series1.Name = "Series 1";
            series1.ShadowColor = System.Drawing.Color.Black;
            series1.ShadowOffset = 2;
            series1.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32;
            series1.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
            

            this.chart1.Series.Add(series1);

            this.chart1.BackColor = System.Drawing.Color.Transparent;

            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["Default"].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["Default"].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.
            chart1.ChartAreas["Default"].AxisX.Minimum = firstBoltNo + first;
            chart1.ChartAreas["Default"].AxisX.Maximum = firstBoltNo + last;
        }

        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]);
                }
            }
        }


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

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

            int datafirst = DataFirst;
            int datalast = DataLast;

            if (datafirst > datalast)
            {
                int swap = datalast;
                datalast = datafirst;
                datafirst = swap;
            }

            if (datafirst < 0)
                datafirst = 0;

            if (datalast >= DataSource.Count())
                datalast = DataSource.Count() - 1;

            int datalen = datalast - datafirst + 1;


            if(datafirst>=DataSource.Count())
            {
                goto _err;
            }

            if ((datafirst + datalen)>DataSource.Count())
            {
                datalen = DataSource.Count() - datafirst;
            }
            
            List<int> datlist = DataSource.ToList().GetRange(datafirst,datalen);
            string title;
            var dats = from data in datlist where data!=emptyvalue select data;
            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();
            //chart1.ChartAreas["Default"].AxisX.Title = title;  
            //chart1.ChartAreas["Default"].AxisX.TitleFont = new System.Drawing.Font("Times New Roman", 12, System.Drawing.FontStyle.Bold);
            //chart1.ChartAreas["Default"].AxisX.TitleForeColor = System.Drawing.Color.Black;
        }



        protected virtual void UpdateOnePoint(int index)
        {
            double multi = Multi;
            int emptyvalue = EmptyValue;
            DataPoint point;
            double v;
            if (DataSource[index] == emptyvalue)
                v = double.NaN;
            else
                v = DataSource[index] / multi;

            if (index >= chart1.Series[0].Points.Count)
            {
                chart1.Series[0].Points.AddXY(
                FirstBoltNo + index, v);
                point = chart1.Series["Series 1"].Points[index];
            }
            else
            {
                point = chart1.Series["Series 1"].Points[index];

                point.YValues[0] = v;
                point.XValue = FirstBoltNo + index;
            }
            //设定空数据
            if (double.IsNaN(point.YValues[0]))
            {
                point.IsEmpty = true;

                System.Drawing.Color c = System.Drawing.Color.Transparent;
                point.MarkerColor = c;
                point.BorderColor = c;
                point.Color = c;
            }
            else
            {
                point.IsEmpty = false;

                System.Drawing.Color c;

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

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


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

                if (ChartType == SeriesChartType.Line)
                {
                    point.MarkerColor = c;
                    point.BorderColor = chart1.Series["Series 1"].BorderColor;
                    point.Color = chart1.Series["Series 1"].Color;
                }
                else
                {
                    point.MarkerColor = c;
                    point.BorderColor = c;
                    point.Color = c;
                }
            }
        }
        void DataBindAll2() 
        {
            double multi = Multi;
            int emptyvalue=EmptyValue;

            UpdateCalState();

            chart1.Series["Series 1"].Points.Clear();
            
            if (DataSource != null)
            {
                for (int i = 0; i < DataSource.Count(); i++)
                {
                    chart1.Series["Series 1"].Points.AddXY(
                        FirstBoltNo + i,
                        (double)DataSource.ElementAt(i) / multi);
                    UpdateOnePoint(i);
                }
            }
            CheckDataSourceEmpty();
        }
        /// <summary>
        /// DataSource 里面的数据都是 EmptyValue 组成, 当修改数据时,应该clear ,再添加
        /// </summary>
        private bool DataSourceIsEmpty = false;
        /// <summary>
        /// 当一个数据都没有时,需要添加空数据
        /// </summary>
        public void CheckDataSourceEmpty() 
        {
            if ((DataSource == null) || (DataSource.Count() == 0))
            {
                chart1.Series["Series 1"].Points.Clear();
                chart1.Series["Series 1"].Points.AddXY(FirstBoltNo, EmptyValue);
                chart1.Series["Series 1"].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)
        {
            if (ShowSettingDialogEvent != null)
                ShowSettingDialogEvent(this, new EventArgs());
        }


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

        #endregion

    }
    class IsValidConverter : IValueConverter
    {

        #region IValueConverter 成员

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool isValid = (bool)value;
            if (isValid)
                return new SolidColorBrush(System.Windows.Media.Color.FromRgb(0x57, 0x9a, 0xab));
            else
                return new SolidColorBrush(System.Windows.Media.Color.FromRgb(237, 106, 0));

        }



        #endregion


        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    class LeftRightConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (values.Count() != 2)
                return null;
            if((!(values[0] is bool))||(!(values[1] is bool)))
                return null;
            bool leftright_isVisable = (bool)values[0];
            bool leftright_IsReversed = (bool)values[1];

            string flag = (string)parameter;

            if (!leftright_isVisable)
                return Visibility.Hidden;
            else
            {
                if (flag == "LIsL") 
                {
                    if (leftright_IsReversed)
                        return Visibility.Hidden;
                    else
                        return Visibility.Visible;
                }
                else if (flag == "LIsR")
                {
                    if (leftright_IsReversed)
                        return Visibility.Visible;
                    else
                        return Visibility.Hidden;
                }
                else if (flag == "RIsL")
                {
                    if (leftright_IsReversed)
                        return Visibility.Visible;
                    else
                        return Visibility.Hidden;
                }
                else if (flag == "RIsR")
                {
                    if (leftright_IsReversed)
                        return Visibility.Hidden;
                    else
                        return Visibility.Visible;
                }
            }
            return null;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}