using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms.DataVisualization.Charting;
using System.Drawing;

namespace FLY.ControlLibrary
{
    public class GraphRange_coslight : GraphRange
    {
        public GraphRange_coslight()
            : base()
        {
            this.chart1.SizeChanged += new EventHandler(chart1_SizeChanged);
        }

        /// <summary>
        /// 解决右边坐标显示问题
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void chart1_SizeChanged(object sender, EventArgs e)
        {
            ChartArea area = chart1.ChartAreas[0];
            Graphics g = chart1.CreateGraphics();
            SizeF size = g.MeasureString("目标值", area.AxisY.LabelStyle.Font);//获取字符串尺寸
            float pw = 100 * (chart1.Width - size.Width - 10) / chart1.Width;
            chart1.ChartAreas[0].Position.Width = (int)pw;

            chart1.ChartAreas[0].Position.Height = 100F;
            chart1.ChartAreas[0].Position.X = 0F;
            chart1.ChartAreas[0].Position.Y = 0F;

            g.Dispose();
        }


        /// <summary>
        /// 获取实际应用的目标值，公差
        /// </summary>
        /// <param name="target"></param>
        /// <param name="alarm"></param>
        /// <param name="yrange"></param>
        /// <param name="ctrlline"></param>
        /// <param name="ispercent"></param>
        void GetActualTargetAlarm(
            out double target,
            out double alarm,
            out double yrange,
            out double ctrlline,
            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;
            }

            ctrlline = CtrlLine / multi;
        }


        /// <summary>
        /// 画虚线 与 右坐标
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void Chart1_PrePaint(object sender, System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs e)
        {
            if (e.ChartElement is ChartArea)
            {
                ChartArea area = (ChartArea)e.ChartElement;
                if (Double.IsNaN(area.AxisY.Minimum))
                    return;

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

                //画目标值
                System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Green, 2);
                DrawYGridTick(e.ChartGraphics, pen, target);
                //画规格线
                if (alarm < yrange)
                {
                    pen.Color = System.Drawing.Color.Red;
                    DrawYGridTick(e.ChartGraphics, pen, target + alarm);
                    DrawYGridTick(e.ChartGraphics, pen, target - alarm);
                }
                //画控制线
                if (HasCtrlLine)
                {
                    if (ctrlline < yrange)
                    {
                        pen.Color = System.Drawing.Color.Orange;
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom;
                        pen.DashPattern = new float[] { 5, 5 };
                        DrawYGridTick(e.ChartGraphics, pen, target + ctrlline);

                        if (Type == GraphRangeType.All)
                        {
                            pen.Color = System.Drawing.Color.Orange;
                            DrawYGridTick(e.ChartGraphics, pen, target - ctrlline);
                        }
                        else 
                        {
                            pen.Color = System.Drawing.Color.Blue;
                            DrawYGridTick(e.ChartGraphics, pen, target - ctrlline);
                        }
                    }
                }

                //写字
                //if (y > area.AxisY.Maximum || y < area.AxisY.Minimum)
                //    return;

                ChartGraphics cg = e.ChartGraphics;
                Graphics graph = cg.Graphics;
                RectangleF rectangele_target = new RectangleF();
                RectangleF rectangele_alarm_min = new RectangleF();
                RectangleF rectangele_alarm_max = new RectangleF();
                RectangleF rectangele_ctrlline_min = new RectangleF();
                RectangleF rectangele_ctrlline_max = new RectangleF();

                rectangele_target.Size = graph.MeasureString("目标值", area.AxisY.LabelStyle.Font);//获取字符串尺寸

                double XMax = cg.GetPositionFromAxis(area.Name, AxisName.X, area.AxisX.Maximum);
                cg.GetAbsolutePoint(
                    new System.Drawing.PointF()
                    {
                        X = (float)(XMax),
                        Y = 0
                    });



                // Convert relative coordinates to absolute coordinates.
                rectangele_target.Location = cg.GetAbsolutePoint(new System.Drawing.PointF() { X = (float)(XMax), Y = (float)cg.GetPositionFromAxis(area.Name, AxisName.Y, target) });

                rectangele_target.X += 2;
                rectangele_target.Y -= rectangele_target.Height / 2;//移到中间

                graph.DrawString(
                    "目标值",
                    area.AxisY.LabelStyle.Font,
                    new System.Drawing.SolidBrush(System.Drawing.Color.Green), rectangele_target);


                //画控制线
                if (HasCtrlLine)
                {
                    if ((ctrlline < yrange) && (ctrlline < alarm))
                    {

                        rectangele_ctrlline_min.Size = graph.MeasureString("控制线", area.AxisY.LabelStyle.Font);//获取字符串尺寸

                        // Convert relative coordinates to absolute coordinates.
                        rectangele_ctrlline_min.Location =
                            cg.GetAbsolutePoint(
                            new System.Drawing.PointF()
                            {
                                X = (float)(XMax),
                                Y = (float)cg.GetPositionFromAxis(area.Name, AxisName.Y, target - ctrlline)
                            });

                        rectangele_ctrlline_min.X += 2;
                        rectangele_ctrlline_min.Y -= rectangele_ctrlline_min.Height / 2;//移到中间

                        if (rectangele_ctrlline_min.Top < rectangele_target.Bottom)
                        {
                            rectangele_ctrlline_min.Y = rectangele_target.Bottom;
                        }
                        if (Type == GraphRangeType.All)
                        {
                            graph.DrawString(
                                "控制线",
                                area.AxisY.LabelStyle.Font,
                                new System.Drawing.SolidBrush(System.Drawing.Color.Orange), rectangele_ctrlline_min);
                        }
                        else 
                        {
                            graph.DrawString(
                            "控制线",
                            area.AxisY.LabelStyle.Font,
                            new System.Drawing.SolidBrush(System.Drawing.Color.Blue), rectangele_ctrlline_min);
                        
                        }


                        rectangele_ctrlline_max.Size = graph.MeasureString("控制线", area.AxisY.LabelStyle.Font);//获取字符串尺寸

                        // Convert relative coordinates to absolute coordinates.
                        rectangele_ctrlline_max.Location =
                            cg.GetAbsolutePoint(
                            new System.Drawing.PointF()
                            {
                                X = (float)(XMax),
                                Y = (float)cg.GetPositionFromAxis(area.Name, AxisName.Y, target + ctrlline)
                            });

                        rectangele_ctrlline_max.X += 2;
                        rectangele_ctrlline_max.Y -= rectangele_ctrlline_max.Height / 2;//移到中间

                        if (rectangele_ctrlline_max.Bottom > rectangele_target.Top)
                        {
                            rectangele_ctrlline_max.Y = rectangele_target.Top - rectangele_ctrlline_max.Height;
                        }

                        graph.DrawString(
                            "控制线",
                            area.AxisY.LabelStyle.Font,
                            new System.Drawing.SolidBrush(System.Drawing.Color.Orange), rectangele_ctrlline_max);
                    }
                }


                //规格线
                if (alarm < yrange)
                {
                    rectangele_alarm_min.Size = graph.MeasureString("规格线", area.AxisY.LabelStyle.Font);//获取字符串尺寸

                    // Convert relative coordinates to absolute coordinates.
                    rectangele_alarm_min.Location =
                        cg.GetAbsolutePoint(
                        new System.Drawing.PointF()
                        {
                            X = (float)(XMax),
                            Y = (float)cg.GetPositionFromAxis(area.Name, AxisName.Y, target - alarm)
                        });

                    rectangele_alarm_min.X += 2;
                    rectangele_alarm_min.Y -= rectangele_alarm_min.Height / 2;//移到中间

                    if (HasCtrlLine && (ctrlline < alarm))
                    {
                        if (rectangele_alarm_min.Top < rectangele_ctrlline_min.Bottom)
                        {
                            rectangele_alarm_min.Y = rectangele_ctrlline_min.Bottom;
                        }
                    }
                    else
                    {
                        if (rectangele_alarm_min.Top < rectangele_target.Bottom)
                        {
                            rectangele_alarm_min.Y = rectangele_target.Bottom;
                        }
                    }

                    graph.DrawString(
                        "规格线",
                        area.AxisY.LabelStyle.Font,
                        new System.Drawing.SolidBrush(System.Drawing.Color.Red), rectangele_alarm_min);


                    rectangele_alarm_max.Size = graph.MeasureString("规格线", area.AxisY.LabelStyle.Font);//获取字符串尺寸

                    // Convert relative coordinates to absolute coordinates.
                    rectangele_alarm_max.Location =
                        cg.GetAbsolutePoint(
                        new System.Drawing.PointF()
                        {
                            X = (float)(XMax),
                            Y = (float)cg.GetPositionFromAxis(area.Name, AxisName.Y, target + alarm)
                        });

                    rectangele_alarm_max.X += 2;
                    rectangele_alarm_max.Y -= rectangele_alarm_max.Height / 2;//移到中间

                    if (HasCtrlLine && (ctrlline < alarm))
                    {
                        if (rectangele_alarm_max.Bottom > rectangele_ctrlline_max.Top)
                        {
                            rectangele_alarm_max.Y = rectangele_ctrlline_max.Top - rectangele_alarm_max.Height;
                        }
                    }
                    else
                    {
                        if (rectangele_alarm_max.Bottom > rectangele_target.Top)
                        {
                            rectangele_alarm_max.Y = rectangele_target.Top - rectangele_alarm_max.Height;
                        }
                    }
                    graph.DrawString(
                        "规格线",
                        area.AxisY.LabelStyle.Font,
                        new System.Drawing.SolidBrush(System.Drawing.Color.Red), rectangele_alarm_max);

                }
            }
        }

        void DrawYGridTick(ChartGraphics cg, System.Drawing.Pen pen, double y)
        {
            ChartArea area = chart1.ChartAreas[0];

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

            // Take Graphics object from chart
            Graphics graph = cg.Graphics;

            // Convert X and Y values to screen position
            double py = cg.GetPositionFromAxis(area.Name, AxisName.Y, y);

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

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

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

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

        }


        #region 2sigma
        protected override void UpdateAxisY_2sigma()
        {
            double multi = Multi;
            double alarm;
            double yrange;

            if (IsPercent)
            {
                alarm = 100.0 * Alarm / Target;
                yrange = alarm * YRangePercent;
            }
            else
            {
                alarm = Alarm / multi;
                yrange = alarm * YRangePercent;
            }
            if ((alarm < 0.1) || (yrange < 0.3))
            {
                alarm = 0.1;
                yrange = 0.3;
            }
            Axis axisY = chart1.ChartAreas["chartArea1"].AxisY;

            //TODO
            axisY.Crossing = 0;

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

            axisY.CustomLabels.Clear();

            //上下限
            SetCustomLabel_2sigma(axisY, alarm, GridTickTypes.All, System.Drawing.Color.Red, IsPercent, null);
            SetCustomLabel_2sigma(axisY, -alarm, GridTickTypes.All, System.Drawing.Color.Red, IsPercent, null);

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

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

        }
        protected override void UpdateOnePoint_2sigma(int index)
        {
            double multi = Multi;
            int emptyvalue = EmptyValue;
            DataPoint point;

            double sigma2 = 2 * DataSource[index].Sigma / multi;
            double avg = DataSource[index].Avg / multi;

            if (IsPercent)
            {
                if (avg <= 0)
                {
                    //异常
                    sigma2 = 0;
                }
                else
                {
                    sigma2 = sigma2 / avg * 100;
                }
            }
            if (index >= chart1.Series["series_sigma"].Points.Count)
            {
                chart1.Series["series_sigma"].Points.AddXY(index, sigma2, -sigma2);
                point = chart1.Series["series_sigma"].Points[index];
            }
            else
            {
                point = chart1.Series["series_sigma"].Points[index];
                point.YValues[0] = sigma2;
                point.YValues[1] = -sigma2;
                point.XValue = index;
            }

            //设定空数据
            if (DataSource[index].Avg == emptyvalue)
            {
                point.IsEmpty = true;
            }
            else
            {
                point.IsEmpty = false;
                double threshold05;
                double threshold1;
                double threshold2;

                if (IsPercent)
                {
                    threshold1 = 100.0 * Alarm / Target;
                    threshold05 = 100.0 * CtrlLine / Target;
                    threshold2 = threshold1 * YRangePercent;
                }
                else
                {
                    threshold1 = Alarm / multi;
                    threshold05 = CtrlLine / Target;
                    threshold2 = threshold1 * YRangePercent;
                }

                System.Drawing.Color c;
                if (sigma2 > threshold2)
                    c = System.Drawing.Color.Violet;
                else if (sigma2 > threshold1)
                    c = System.Drawing.Color.Red;
                else if (sigma2 > threshold05)
                    c = System.Drawing.Color.Orange;
                else
                    c = System.Drawing.Color.Green;

                point.BorderColor = c;
                point.Color = c;
            }
        }
        #endregion

        #region all
        protected override void UpdateOnePoint_all(int index)
        {
            double multi = Multi;
            int emptyvalue = EmptyValue;
            DataPoint point_sigma;
            DataPoint point_avg;

            double sigma2 = 2 * DataSource[index].Sigma / multi;
            double avg = DataSource[index].Avg / multi;


            if (index >= chart1.Series["series_sigma"].Points.Count)
            {
                chart1.Series["series_sigma"].Points.AddXY(index, avg + sigma2, avg - sigma2);
                point_sigma = chart1.Series["series_sigma"].Points[index];

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

                point_avg = chart1.Series["series_avg"].Points[index];
                point_avg.YValues[0] = avg;
                point_avg.XValue = index;
            }

            //设定空数据
            if (DataSource[index].Avg == emptyvalue)
            {
                point_sigma.IsEmpty = true;
                point_avg.IsEmpty = true;
            }
            else
            {
                point_sigma.IsEmpty = false;

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

                double threshold05 = ctrlline;
                double threshold1 = alarm;
                double threshold2 = yrange;
                

                System.Drawing.Color c;



                if (((avg + sigma2) > (target + threshold2)) || ((avg + sigma2) < (target - threshold2)))
                {
                    c = System.Drawing.Color.Violet;
                }
                else if (((avg - sigma2) > (target + threshold2)) || ((avg - sigma2) < (target - threshold2)))
                {
                    c = System.Drawing.Color.Violet;
                }
                else if (((avg + sigma2) > (target + threshold1)) || ((avg + sigma2) < (target - threshold1)))
                {
                    c = System.Drawing.Color.Red;
                }
                else if (((avg - sigma2) > (target + threshold1)) || ((avg - sigma2) < (target - threshold1)))
                {
                    c = System.Drawing.Color.Red;
                }
                else
                {
                    if (((avg + sigma2) > (target + threshold05)) || ((avg + sigma2) < (target - threshold05)))
                    {
                        c = System.Drawing.Color.Orange;
                    }
                    else if (((avg - sigma2) > (target + threshold05)) || ((avg - sigma2) < (target - threshold05)))
                    {
                        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)))));


            }
        }

        #endregion

        #region avg
        protected override void UpdateAxisY_avg()
        {
            double alarm;
            double yrange;
            double target;
            double ctrlline;
            bool ispercent;
            GetActualTargetAlarm(out target, out alarm, out yrange, out ctrlline, out ispercent);

            Axis axisY = chart1.ChartAreas["chartArea1"].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.Red, ispercent, null);
            SetCustomLabel(axisY, target - alarm, GridTickTypes.All, System.Drawing.Color.Red, ispercent, null);

            //显示范围数值
            SetCustomLabel(axisY, axisY.Minimum, GridTickTypes.All, System.Drawing.Color.DarkViolet, ispercent, null);
            SetCustomLabel(axisY, axisY.Maximum, GridTickTypes.All, System.Drawing.Color.DarkViolet, ispercent, null);

            //显示范围数值
            if (yrange != 2 * alarm)
            {
                SetCustomLabel(axisY, target + alarm * 2, GridTickTypes.TickMark, System.Drawing.Color.Black, ispercent, null);
                SetCustomLabel(axisY, target - alarm * 2, 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);
            }
        }
        protected override void UpdateOnePoint_avg(int index)
        {
            double multi = Multi;
            int emptyvalue = EmptyValue;
            DataPoint point_avg;

            double avg = DataSource[index].Avg / multi;




            if (index >= chart1.Series["series_avg"].Points.Count)
            {
                chart1.Series["series_avg"].Points.AddXY(index, avg);
                point_avg = chart1.Series["series_avg"].Points[index];
            }
            else
            {
                point_avg = chart1.Series["series_avg"].Points[index];
                point_avg.YValues[0] = avg;
                point_avg.XValue = index;
            }

            //设定空数据
            if (DataSource[index].Avg == emptyvalue)
            {
                point_avg.IsEmpty = true;
            }
            else
            {
                point_avg.IsEmpty = false;

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

                double data = avg;

                System.Drawing.Color c;
                if (data > (target + yrange))
                {
                    c = System.Drawing.Color.Violet;
                }
                else if (data > (target + alarm))
                {
                    c = System.Drawing.Color.Red;
                }
                else if (data >= (target - alarm))
                {
                    if (HasCtrlLine)
                    {
                        if (data > (target + ctrlline))
                        {
                            c = System.Drawing.Color.Orange;
                        }
                        else if (data >= (target - ctrlline))
                        {
                            c = System.Drawing.Color.Green;
                        }
                        else
                        {
                            c = System.Drawing.Color.FromArgb(0x00, 0x8B, 0xE5);
                        }
                    }
                    else
                    {
                        c = System.Drawing.Color.Green;
                    }
                }
                else if (data >= (target - yrange))
                {
                    c = System.Drawing.Color.Red;
                }
                else
                {
                    c = System.Drawing.Color.Violet;
                }



                point_avg.BorderColor = c;
                point_avg.Color = c;
            }
        }
        #endregion
    }
}
