using System;
using Volpe.Cafe.MarketData.Design;

namespace Volpe.Cafe.Reporting
{
    /// <summary>
    /// Provides data filters for reporting based on the mix of simulated vehicles.
    /// </summary>
    [Serializable]
    public class DataFilters
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="DataFilters"/> class, based on the mix of vehicles in the
        /// specified industry data.
        /// </summary>
        /// <param name="baseData">The final industry data for the baseline scenario.</param>
        /// <param name="scenData">
        ///     The final industry data for the action alternative scenario. Specify <c>null</c> to generate data
        ///     filters for the baseline scenario only.
        /// </param>
        /// <exception cref="ArgumentNullException">baseData is null.</exception>
        public DataFilters(IIndustry baseData, IIndustry scenData)
        {
            if (baseData == null) {
                throw new ArgumentNullException(nameof(baseData));
            }

            this.ReportRC = new bool[RegClasses.ReportingList.Length];
            this.ReportFT = new bool[FuelTypes.ReportingList.Length];

            this.ScanData(baseData, scenData);
        }

        /// <summary>
        /// Gets the regulatory classes from the <see cref="RegClasses.ReportingList"/> to include in modeling reports.
        /// </summary>
        /// <remarks>
        /// NOTE: The indexes in this array map directly to the ordering of regulatory classes in the
        /// <see cref="RegClasses.ReportingList"/> and <see cref="RegClasses.ReportingNames"/>.
        /// </remarks>
        public bool[] ReportRC { get; private set; }

        /// <summary>
        /// Gets the fuel types from the <see cref="FuelTypes.ReportingList"/> to include in modeling reports.
        /// </summary>
        /// <remarks>
        /// NOTE: The indexes in this array map directly to the ordering of fuel types in the
        /// <see cref="FuelTypes.ReportingList"/> and <see cref="FuelTypes.ReportingNames"/>.
        /// </remarks>
        public bool[] ReportFT { get; private set; }

        private void ScanData(IIndustry baseData, IIndustry scenData)
        {
            int minYear = baseData.MinYear;
            int maxYear = baseData.MaxYear;

            for (int year = minYear; year <= maxYear; year++) {
                this.ScanHelper(baseData, year);
                if (scenData != null && scenData != baseData) {
                    this.ScanHelper(scenData, year);
                }
            }

            // update reg-class totals --
            //  - All PC (index 2) -- show if DC and/or IC exist
            //  - LD Total (index 4) -- show if mix of PC -AND- LT
            //  - TOTAL (index 6) -- show if mix of LD (PC and/or LT) -AND- HDPUV
            this.ReportRC[2] |= (this.ReportRC[0] || this.ReportRC[1]);
            this.ReportRC[4] |= (this.ReportRC[2] && this.ReportRC[3]);
            this.ReportRC[6] |= ((this.ReportRC[2] || this.ReportRC[3]) && this.ReportRC[5]);

            // prefer "TOTAL" over "LD Total" if there are PC+LT mix but no HDPUV vehs
            if (this.ReportRC[4] && !this.ReportRC[6]) {
                this.ReportRC[4] = false;
                this.ReportRC[6] = true;
            }
        }

        private void ScanHelper(IIndustry data, int year)
        {
            // reg-classes: DC, IC, [PC], LT, [LD Total], HDPUV, [TOTAL]
            var rcMix = data.CalcRegClassMix(year);
            this.ReportRC[0] |= rcMix[RegulatoryClass.DomesticCar];
            this.ReportRC[1] |= rcMix[RegulatoryClass.ImportedCar];
            this.ReportRC[3] |= rcMix[RegulatoryClass.LightTruck];
            this.ReportRC[5] |= rcMix[RegulatoryClass.HDPUV];

            // fuel-types: Gas, E85, Dsl, Elec, H2, CNG, [TOTAL]
            var ftMix = data.CalcFuelTypeMix(year);
            this.ReportFT[0] |= ftMix[FuelType.Gasoline];
            this.ReportFT[1] |= ftMix[FuelType.Ethanol85];
            this.ReportFT[2] |= ftMix[FuelType.Diesel];
            this.ReportFT[3] |= ftMix[FuelType.Electricity];
            this.ReportFT[4] |= ftMix[FuelType.Hydrogen];
            this.ReportFT[5] |= ftMix[FuelType.CNG];
            this.ReportFT[6] |= ftMix.IsMultiFuel;
        }

    }
}
