#region << Using Directives >>
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

using Volpe.Cafe.EspressoUI.Charts;
using Volpe.Cafe.MarketData.Design;
using Volpe.Cafe.Model;
using Volpe.Cafe.ModelSettings;
#endregion

namespace Volpe.Cafe.EspressoUI.ModelCharts
{
    [Serializable]
    class ManufacturerSummaryChart : ModelChart
    {

        #region /*** Nested Types ***/

        class CustomDataSeriesStatistics : DataSeriesStatistics
        {
            //----- ctors -----
            public CustomDataSeriesStatistics(Chart chart) : base(chart)
            {
                List<DataSeries> dataSeries = chart.DataSeries;

                // override min/max values
                bool hasData = false;
                double y1Min = double.MaxValue, y1Max = double.MinValue;
                double y2Min = double.MaxValue, y2Max = double.MinValue;
                //
                for (int i = 0; i < dataSeries.Count; i++)
                {
                    DataSeries series = dataSeries[i];
                    if (series.Values != null)
                    {
                        hasData = true;
                        this.GetMinMax(series.Values, ref y1Min, ref y1Max, 0, 2);
                        this.GetMinMax(series.Values, ref y2Min, ref y2Max, 3, 6);
                    }
                    
                }
                //
                if (hasData)
                {
                    this.HasPrimaryValues   = true;
                    this.HasSecondaryValues = true;
                    this.MinPrimaryValue    = y1Min;
                    this.MaxPrimaryValue    = y1Max;
                    this.MinSecondaryValue  = y2Min;
                    this.MaxSecondaryValue  = y2Max;
                }
            }

            //----- methods -----
            void GetMinMax(double[] arr, ref double min, ref double max, int sIdx, int eIdx)
            {
                for (int i = sIdx; i <= eIdx; i++)
                {
                    double d = arr[i];
                    min = Math.Min(min, d);
                    max = Math.Max(max, d);
                }
            }
        }
        class CustomSeriesInfo : SeriesInfo
        {
            //----- ctors -----
            internal CustomSeriesInfo(Chart parent) : base(parent) { }

            //----- methods -----
            protected override PointF TranslatePoint(int index, double x, double y, bool isSecondary)
            {
                //
                // treat index 0-2 (Standard, CAFE/CO2 Rating, Shortfall) as primary axis
                // treat index 3-6 (Fines, Costs, Fuel Savings, CO-2 Savings) as secondary axis
                //
                isSecondary = (index >= 3);
                return base.TranslatePoint(index, x, y, isSecondary);
            }
        }

        #endregion

        #region /*** Ctors ***/

        /// <summary>
        /// Initializes a new instance of the <see cref="ManufacturerSummaryChart"/> class.
        /// </summary>
        public ManufacturerSummaryChart() : base()
        {
            this.InitializeComponent();
            this.InitializeOther();
        }

        #endregion

        #region /*** Methods ***/

        //----- overriden DataSeriesStatistics from base class with custom object -----
        /// <summary>
        /// Returns aggregate statistics for all data-series contained within this chart.
        /// </summary>
        /// <returns>Aggregate statistics for all data-series within this chart.</returns>
        protected override DataSeriesStatistics GetDataSeriesStatistics()
        {
            return new CustomDataSeriesStatistics(this);
        }

        //----- initialization -----
        void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // ManufacturerSummaryChart
            // 
            this.CategoryAxisDiscreteValues = new string[] {
        "Standard",
        "CAFE",
        "Shortfall",
        "Fines",
        "Costs",
        "Fuel Sav",
        "CO2 Sav"};
            this.GridBorderStyle = System.Windows.Forms.Border3DStyle.RaisedInner;
            this.GridOrientation = GridOrientation.SwappedAndFlipped;
            this.Name = "ManufacturerSummaryChart";
            this.PrimaryAxisLabel = "mpg";
            this.PrimaryAxisMaxValue = 30;
            this.PrimaryAxisMinValue = 0;
            this.PrimaryAxisNumberFormat = "0.0";
            this.SecondaryAxisLabel = "$ (m)";
            this.SecondaryAxisMaxValue = 300;
            this.SecondaryAxisMinValue = 0;
            this.SecondaryAxisNumberFormat = "0";
            this.ShowSecondaryAxis = true;
            this.Size = new Size(480, 320);
            this.Title = "Manufacturer Summary";
            this.ResumeLayout(false);

        }
        void InitializeOther()
        {
            this.Series = new CustomSeriesInfo(this);
            this.ChartStyle = ChartStyle.Bar;
            this.AddDataSeries("Values", AxisType.Primary, ChartStyle.Default);
            this.DataSeries[0].AlternateValueColors = true;
        }

        //----- chart refreshing -----
        public override void RefreshChartData(IModelingProgress progress)
        {
            try
            {
                if (!this.IsInitialized || progress == null || progress.ModelYear == null || progress.Manufacturer == null) { return; }
                this.RefreshComplianceProgram();
                this.RefreshChartDataInternal(progress.Scenario, progress.ModelYear, progress.Manufacturer);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        void RefreshComplianceProgram()
        {
            double primaryAxisMaxValue = this.PrimaryAxis.MaxValue;
            var program = this._settings.RuntimeSettings.ComplianceProgram;
            if (program.IsCO2())
            {
                this.CategoryAxisDiscreteValues = new string[] {
                    "CO2 Stnd", "CO2 Rating", "Shortfall",
                    "Fines", "Costs", "Fuel Sav", "CO2 Sav"};
                this.PrimaryAxis.Label = "g/mi";
                primaryAxisMaxValue = 300;
            }
            else
            {
                this.CategoryAxisDiscreteValues = new string[] {
                    "Standard", "CAFE", "Shortfall",
                    "Fines", "Costs", "Fuel Sav", "CO2 Sav"};
                this.PrimaryAxis.Label = "mpg";
                primaryAxisMaxValue = 30;
            }
            if (!this._compliance.Running)
            {
                this.PrimaryAxis.MaxValue = primaryAxisMaxValue;
            }
        }
        void RefreshChartDataInternal(Scenario scen, ModelYear year, IManufacturer mfr)
        {
            this._mfrFilter = mfr.Index;
            this._yearFilter = year.Year;

            this.Title = mfr.ProperName + ChartFilters.RegClassSuffix[this._rcFilter];
            this.DataSeries[0].Name = year.ToString();

            var program = this._settings.RuntimeSettings.ComplianceProgram;
            var metrics = (program.IsCO2() ? ComplianceMetrics.CO2Values : ComplianceMetrics.CAFEValues) |
                          ComplianceMetrics.ComplianceCosts | ComplianceMetrics.EffectsCosts;

            // get stats for the current year and mfr
            var statistics = ChartHelper.CalculateStatistics(mfr, this._rcFilter, this._yearFilter, metrics);

            // copy to array
            double[] values = new double[7];
            if (program.IsCO2())
            {
                values[0] = statistics.CO2Standard;
                values[1] = statistics.CO2Rating;
                values[2] = statistics.CO2Shortfall;
            }
            else
            {
                values[0] = statistics.Standard;
                values[1] = statistics.CAFE;
                values[2] = statistics.Shortfall;
            }
            values[3] = statistics.Fines;
            values[4] = statistics.Costs;
            values[5] = statistics.FuelSavings;
            values[6] = statistics.CO2Savings;

            double primaryMax = values.Take(3).Max();
            double scalar = (program.IsCO2()) ? 50D : 15D;
            this.PrimaryAxisMaxValue = Math.Ceiling(primaryMax / scalar) * scalar;
            this.SecondaryAxisMaxValue = double.NaN;

            this.UpdateDataSeriesValues(0, values);
        }

        #endregion

    }
}
