using System;
using System.Collections.Generic;

using Volpe.Cafe.Generic;
using Volpe.Cafe.MarketData.BaselineInfo;

namespace Volpe.Cafe.MarketData.Design
{
    /// <summary>
    /// Defines an original equipment manufacturer (OEM), which produces vehicles, components, and component families.
    /// </summary>
    /// <seealso cref="BaselineManufacturer"/>
    /// <seealso cref="BaselineInfo.BaselineCreditBank"/>
    /// <seealso cref="BaselineInfo.CreditsAndAdjustments"/>
    /// <seealso cref="IIndustry"/>
    /// <seealso cref="IManufacturerInfo"/>
    /// <seealso cref="IManufacturerRevision"/>
    /// <seealso cref="IVehicle"/>
    /// <seealso cref="IPlatform"/>
    /// <seealso cref="IEngine"/>
    /// <seealso cref="ITransmission"/>
    /// <seealso cref="IPlatformFamily"/>
    /// <seealso cref="IEngineFamily"/>
    /// <seealso cref="ITransmissionFamily"/>
    public interface IManufacturer : IManufacturerInfo, IOEMQueryable
    {
        #region <<< Properties >>>

        /// <summary>
        /// Gets the unique runtime-assigned index for the manufacturer.
        /// </summary>
        int Index { get; }

        /// <summary>
        /// Gets a description of baseline engineering characteristics for the manufacturer.
        /// </summary>
        BaselineManufacturer BaselineInfo { get; }

        /// <summary>
        /// Gets the initial credit bank, containing the amounts of CAFE and CO-2 credits that are available to the
        /// manufacturer at the start of analysis.
        /// </summary>
        BaselineCreditBank BaselineCreditBank { get; }

        /// <summary>
        /// Gets the various credits and adjustments that the manufacturer may use toward compliance with either
        /// NHTSA's CAFE standards or EPA's CO-2 standards.
        /// </summary>
        CreditsAndAdjustments CreditsAndAdjustments { get; }

        /// <summary>
        /// Gets the CAFE credit bank for the manufacturer, which is updated during runtime.
        /// </summary>
        /// <remarks>
        /// <b>NOTE</b>:
        /// Currently, this value only keeps track of credit balances from the baseline credit bank.
        /// </remarks>
        AnnualValue<RCValue<double>> CAFEBank { get; }

        /// <summary>
        /// Gets the CO-2 credit bank for the manufacturer, which is updated during runtime.
        /// </summary>
        /// <remarks>
        /// <b>NOTE</b>:
        /// Currently, this value only keeps track of credit balances from the baseline credit bank.
        /// </remarks>
        AnnualValue<RCAltValue<double>> CO2Bank { get; }

        /// <summary>
        /// Gets the latest revision of the manufacturer's compliance attributes.
        /// </summary>
        IManufacturerRevision RevisionInfo { get; }

        /// <summary>
        /// Gets the model year representing the manufacturer's latest revision.
        /// </summary>
        /// <remarks>
        /// A value of 0 (zero) indicates that no new revisions for the manufacturer have been created yet.
        /// </remarks>
        int RevisionYear { get; }

        /// <summary>
        /// Gets a value indicating whether the manufacturer has any revisions.
        /// </summary>
        bool HasRevisions { get; }

        /// <summary>
        /// Gets an annual stream of <see cref="IManufacturerRevision"/> objects, containing revisions of
        /// manufacturer's compliance attributes.
        /// </summary>
        AnnualValue<IManufacturerRevision> Revisions { get; }

        /// <summary>
        /// Gets the minimum model year available for analysis.
        /// </summary>
        int MinYear { get; }

        /// <summary>
        /// Gets the maximum model year available for analysis.
        /// </summary>
        int MaxYear { get; }

        /// <summary>
        /// Gets whether this <see cref="IManufacturer"/> was initialized for analysis.
        /// </summary>
        bool IsInitializedForAnalysis { get; }

        /// <summary>
        /// Gets or sets the manufacturer-level compliance statistics, based on the manufacturer's latest revision.
        /// </summary>
        ComplianceStatistics ComplianceStats { get; }

        /// <summary>
        /// Gets the industry object to which the manufacturer belongs.
        /// </summary>
        IIndustry Industry { get; }

        /// <summary>
        /// Gets a list of vehicles produced by the manufacturer.
        /// </summary>
        IReadOnlyList<IVehicle> Vehicles { get; }

        /// <summary>
        /// Gets a list of platforms produced by the manufacturer.
        /// </summary>
        IReadOnlyList<IPlatform> Platforms { get; }
        /// <summary>
        /// Gets a list of engines produced by the manufacturer.
        /// </summary>
        IReadOnlyList<IEngine> Engines { get; }
        /// <summary>
        /// Gets a list of transmissions produced by the manufacturer.
        /// </summary>
        IReadOnlyList<ITransmission> Transmissions { get; }

        /// <summary>
        /// Gets a list of platform families produced by the manufacturer.
        /// </summary>
        IReadOnlyList<IPlatformFamily> PlatformFamilies { get; }
        /// <summary>
        /// Gets a list of engine families produced by the manufacturer.
        /// </summary>
        IReadOnlyList<IEngineFamily> EngineFamilies { get; }
        /// <summary>
        /// Gets a list of transmission families produced by the manufacturer.
        /// </summary>
        IReadOnlyList<ITransmissionFamily> TransmissionFamilies { get; }

        /// <summary>
        /// Gets an object that can be used for storing additional data to associate with the manufacturer.
        /// </summary>
        Dictionary<string, object> Tag { get; }

        #endregion

        #region <<< Methods >>>

        /// <summary>
        /// Links this manufacturer to the specified <paramref name="industry"/>, then initializes the required
        /// references (such as vehicles, engines, etc.).
        /// </summary>
        void LinkToIndustry(IIndustry industry);

        /// <summary>
        /// Initializes this manufacturer for analysis, including all of the vehicles, vehicle components, and
        /// component families produced by the manufacturer.
        /// </summary>
        /// <param name="minYear">The minimum model year available for analysis.</param>
        /// <param name="maxYear">The maximum model year available for analysis.</param>
        void InitializeForAnalysis(int minYear, int maxYear);

        /// <summary>
        /// Advances the revision year for the manufacturer by one, and creates a new manufacturer revision for that
        /// year.
        /// </summary>
        /// <returns>A manufacturer revision for the new revision year.</returns>
        /// <remarks>
        /// This method must be called by the compliance model at the start of each new model year. That is, a
        /// manufacturer revision must be created for a given model year, before analysis of that year can begin.
        /// </remarks>
        /// <exception cref="InvalidOperationException">
        ///     The manufacturer must be initialized for analysis before manufacturer revisions may be created.
        ///     -or-
        ///     A manufacturer revision may not be created for a model year beyond the last analysis year.
        /// </exception>
        IManufacturerRevision CreateRevision();

        /// <summary>
        /// Obtains a manufacturer revision for the specified model year.
        /// </summary>
        /// <param name="year">
        ///     The model year for which to obtain a manufacturer revision, or null to return the manufacturer's latest
        ///     revision.
        /// </param>
        /// <returns>
        ///     A manufacturer revision for the specified model year, or null, if the manufacturer does not have any
        ///     revisions.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///     The specified year is out-of-bounds of the minimum and maximum range of model years available for
        ///     analysis.
        /// </exception>
        IManufacturerRevision GetRevision(int? year = null);

        #endregion
    }
}
