using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Web.UI.DataVisualization.Charting;
using System.Collections;

/// <summary>
///DrawPareto 的摘要说明
/// </summary>
public class DrawPareto
{
	public DrawPareto()
	{
		//
		//TODO: 在此处添加构造函数逻辑
		//
	}


    /// <summary>
    /// Number of class intervals the data range is devided in.
    /// This property only has affect when "SegmentIntervalWidth" is 
    /// set to double.NaN.
    /// </summary>
    public int SegmentIntervalNumber = 20;

    /// <summary>
    /// Histogram class interval width. Setting this value to "double.NaN"
    /// will result in automatic width calculation based on the data range
    /// and number of required interval specified in "SegmentIntervalNumber".
    /// </summary>
    public double SegmentIntervalWidth = double.NaN;

    /// <summary>
    /// Indicates that percent frequency should be shown on the right axis
    /// </summary>
    public bool ShowPercentOnSecondaryYAxis = true;


    public void CreatePareto(
    Chart chartControl,
    string dataSeriesName,
    string histogramSeriesName)
    {
        // Validate input
        if (chartControl == null)
        {
            throw (new ArgumentNullException("chartControl"));
        }
        if (chartControl.Series.IndexOf(dataSeriesName) < 0)
        {
            throw (new ArgumentException("Series with name'" + dataSeriesName + "' was not found.", "dataSeriesName"));
        }

        // Make data series invisible
        chartControl.Series[dataSeriesName].Enabled = false;

        // Check if histogram series exsists
        Series histogramSeries = null;
        if (chartControl.Series.IndexOf(histogramSeriesName) < 0)
        {
            // Add new series
            histogramSeries = chartControl.Series.Add(histogramSeriesName);

            // Set new series chart type and other attributes
            histogramSeries.ChartType = SeriesChartType.Column;
            histogramSeries.BorderColor = Color.Black;
            histogramSeries.BorderWidth = 1;
            histogramSeries.BorderDashStyle = ChartDashStyle.Solid;
        }
        else
        {
            histogramSeries = chartControl.Series[histogramSeriesName];
            histogramSeries.Points.Clear();
        }

        // Get data series minimum and maximum values
        double minValue = double.MaxValue;
        double maxValue = double.MinValue;
        int pointCount = 0;
        foreach (DataPoint dataPoint in chartControl.Series[dataSeriesName].Points)
        {
            // Process only non-empty data points
            if (!dataPoint.IsEmpty)
            {
                if (dataPoint.YValues[0] > maxValue)
                {
                    maxValue = dataPoint.YValues[0];
                }
                if (dataPoint.YValues[0] < minValue)
                {
                    minValue = dataPoint.YValues[0];
                }
                ++pointCount;
            }
        }

        // Calculate interval width if it's not set
        if (double.IsNaN(this.SegmentIntervalWidth))
        {
            this.SegmentIntervalWidth = (maxValue - minValue) / SegmentIntervalNumber;
            this.SegmentIntervalWidth = RoundInterval(this.SegmentIntervalWidth);
        }

        // Round minimum and maximum values
        minValue = Math.Floor(minValue / this.SegmentIntervalWidth) * this.SegmentIntervalWidth;
        maxValue = Math.Ceiling(maxValue / this.SegmentIntervalWidth) * this.SegmentIntervalWidth;

        // Create histogram series points
        double currentPosition = minValue;
        for (currentPosition = minValue; currentPosition <= maxValue; currentPosition += this.SegmentIntervalWidth)
        {
            // Count all points from data series that are in current interval
            int count = 0;
            foreach (DataPoint dataPoint in chartControl.Series[dataSeriesName].Points)
            {
                if (!dataPoint.IsEmpty)
                {
                    double endPosition = currentPosition + this.SegmentIntervalWidth;
                    if (dataPoint.YValues[0] >= currentPosition &&
                        dataPoint.YValues[0] < endPosition)
                    {
                        ++count;
                    }

                    // Last segment includes point values on both segment boundaries
                    else if (endPosition >= maxValue)
                    {
                        if (dataPoint.YValues[0] >= currentPosition &&
                            dataPoint.YValues[0] <= endPosition)
                        {
                            ++count;
                        }
                    }
                }
            }


            // Add data point into the histogram series
            //histogramSeries.Points.AddXY("", count);
            histogramSeries.Points.AddY( count);

        }

        histogramSeries.Sort(PointSortOrder.Descending);

        // Adjust series attributes
        histogramSeries["PointWidth"] = "1";

        // Adjust chart area
        ChartArea chartArea = chartControl.ChartAreas[histogramSeries.ChartArea];
        chartArea.AxisY.Title = "频数";
        //chartArea.AxisX.Minimum = minValue;
        //chartArea.AxisX.Maximum = maxValue;

        // Set axis interval based on the histogram class interval
        // and do not allow more than 10 labels on the axis.
        double axisInterval = this.SegmentIntervalWidth;
        while ((maxValue - minValue) / axisInterval > 10.0)
        {
            axisInterval *= 2.0;
        }
        chartArea.AxisX.Interval = axisInterval;

        // Set chart area secondary Y axis
        chartArea.AxisY2.Enabled = AxisEnabled.Auto;
        if (this.ShowPercentOnSecondaryYAxis)
        {
            chartArea.RecalculateAxesScale();

            chartArea.AxisY2.Enabled = AxisEnabled.True;
            chartArea.AxisY2.LabelStyle.Format = "P0";
            chartArea.AxisY2.MajorGrid.Enabled = false;
            chartArea.AxisY2.Title = "Percent of Total";

            chartArea.AxisY2.Minimum = 0;
            chartArea.AxisY2.Maximum = chartArea.AxisY.Maximum / (pointCount / 100.0);
            double minStep = (chartArea.AxisY2.Maximum > 20.0) ? 5.0 : 1.0;
            chartArea.AxisY2.Interval = Math.Ceiling((chartArea.AxisY2.Maximum / 5.0 / minStep)) * minStep;

        }
    }

    /// <summary>
    /// Helper method which rounds specified axsi interval.
    /// </summary>
    /// <param name="interval">Calculated axis interval.</param>
    /// <returns>Rounded axis interval.</returns>
    public double RoundInterval(double interval)
    {
        // If the interval is zero return error
        if (interval == 0.0)
        {
            throw (new ArgumentOutOfRangeException("interval", "Interval can not be zero."));
        }

        // If the real interval is > 1.0
        double step = -1;
        double tempValue = interval;
        while (tempValue > 1.0)
        {
            step++;
            tempValue = tempValue / 10.0;
            if (step > 1000)
            {
                throw (new InvalidOperationException("Auto interval error due to invalid point values or axis minimum/maximum."));
            }
        }

        // If the real interval is < 1.0
        tempValue = interval;
        if (tempValue < 1.0)
        {
            step = 0;
        }

        while (tempValue < 1.0)
        {
            step--;
            tempValue = tempValue * 10.0;
            if (step < -1000)
            {
                throw (new InvalidOperationException("Auto interval error due to invalid point values or axis minimum/maximum."));
            }
        }

        double tempDiff = interval / Math.Pow(10.0, step);
        if (tempDiff < 3.0)
        {
            tempDiff = 2.0;
        }
        else if (tempDiff < 7.0)
        {
            tempDiff = 5.0;
        }
        else
        {
            tempDiff = 10.0;
        }

        // Make a correction of the real interval
        return tempDiff * Math.Pow(10.0, step);
    }

    public void MakeParetoChart(Chart chart, string srcSeriesName, string destSeriesName)
    {

        // get name of the ChartAre of the source series
        string strChartArea = chart.Series[srcSeriesName].ChartArea;

        // ensure the source series is a column chart type
        chart.Series[srcSeriesName].ChartType = SeriesChartType.Column;

        // sort the data in the series to be by values in descending order
        chart.DataManipulator.Sort(PointSortOrder.Descending, srcSeriesName);

        // find the total of all points in the source series
        double total = 0.0;
        foreach (DataPoint pt in chart.Series[srcSeriesName].Points)
            total += pt.YValues[0];

        // set the max value on the primary axis to total
        chart.ChartAreas[strChartArea].AxisY.Maximum = total;

        // create the destination series and add it to the chart
        Series destSeries = new Series(destSeriesName);
        chart.Series.Add(destSeries);

        // ensure the destination series is a Line or Spline chart type
        destSeries.ChartType = SeriesChartType.Line;

        destSeries.BorderWidth = 3;

        // assign the series to the same chart area as the column chart
        destSeries.ChartArea = chart.Series[srcSeriesName].ChartArea;

        // assign this series to use the secondary axis and set it maximum to be 100%
        destSeries.YAxisType = AxisType.Secondary;
        chart.ChartAreas[strChartArea].AxisY2.Maximum = 100;

        // locale specific percentage format with no decimals
        chart.ChartAreas[strChartArea].AxisY2.LabelStyle.Format = "0.#";

        // turn off the end point values of the primary X axis
        chart.ChartAreas[strChartArea].AxisX.LabelStyle.IsEndLabelVisible = false;

        // for each point in the source series find % of total and assign to series
        double percentage = 0.0;

        foreach (DataPoint pt in chart.Series[srcSeriesName].Points)
        {
            percentage += (pt.YValues[0] / total * 100.0);
            //Chart1.Series["Default"].Points.AddXY(pt.XValue,Math.Round(percentage, 2));
            destSeries.Points.Add(Math.Round(percentage, 2));
        }

    }


}