using System;
using Volpe.Cafe.Generic;

namespace Volpe.Cafe.MarketData.Design
{
    /// <summary>
    /// Defines any product, produced by an original equipment manufacturer (OEM), that encapsulates a description of
    /// its engineering characteristics as well as provides an annual historic view of its revisions.
    /// </summary>
    /// <remarks>
    /// OEM products include vehicles, vehicle platforms, engines, and transmissions, and are capable of applying
    /// additional technology as well as reporting on their current technology applicability states and accumulated
    /// technology costs. Additionally, OEM products include component grouping entities, such as component families.
    /// </remarks>
    /// <seealso cref="IOEMProductInfo"/>
    /// <seealso cref="IOEMProductRevision"/>
    public interface IOEMProduct : IOEMProductInfo
    {
        /// <summary>
        /// Gets an array of technology indexes that are applicable to the <see cref="IOEMProduct"/>.
        /// </summary>
        /// <remarks>
        /// The technology list should include any technology for which <see cref="TechUtilization"/> is defined. For
        /// vehicles, this means all available technologies are included, while for components and component families,
        /// only the component-level technologies (e.g., engine-level) are considered.
        /// </remarks>
        int[] TechnologyList { get; }

        /// <summary>
        /// Gets a description of baseline engineering characteristics for the <see cref="IOEMProduct"/>.
        /// </summary>
        IOEMProductInfo BaselineInfo { get; }

        /// <summary>
        /// Gets the product information for the latest revision of the <see cref="IOEMProduct"/>, or the
        /// <see cref="IOEMProduct"/>'s baseline engineering characteristics (by means of <see cref="BaselineInfo"/>)
        /// if no new revisions have been created yet.
        /// </summary>
        IOEMProductRevision RevisionInfo { get; }

        /// <summary>
        /// Gets the model year representing the <see cref="IOEMProduct"/>'s latest revision.
        /// </summary>
        /// <remarks>
        /// A value of 0 (zero) indicates that no new revisions for the <see cref="IOEMProduct"/> have been created
        /// yet. In such a case, the product's <see cref="RevisionInfo"/> and engineering characteristics are derived
        /// from its <see cref="BaselineInfo"/>.
        /// </remarks>
        int RevisionYear { get; }

        /// <summary>
        /// Gets a value indicating whether the <see cref="IOEMProduct"/> has any revisions.
        /// </summary>
        bool HasRevisions { get; }

        /// <summary>
        /// Gets an annual stream of <see cref="IOEMProductRevision"/> objects, containing the revisions of the
        /// product's engineering characteristics and/or compliance attributes.
        /// </summary>
        IAnnualValue<IOEMProductRevision> 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="IOEMProduct"/> was initialized for analysis.
        /// </summary>
        bool IsInitializedForAnalysis { get; }

        /// <summary>
        /// Gets the <see cref="IIndustry"/> object to which the <see cref="IOEMProduct"/> belongs.
        /// </summary>
        IIndustry Industry { get; }

        /// <summary>
        /// Gets the manufacturer that produces the <see cref="IOEMProduct"/>.
        /// </summary>
        IManufacturer Manufacturer { get; }

        /// <summary>
        /// Gets the utilization of each applicable technology on the <see cref="IOEMProduct"/>.
        /// </summary>
        /// <remarks>
        /// <b>Provisional Implementation</b><br/>
        /// Currently, the length of the technology utilization array has to match the number of known technologies
        /// (i.e., <see cref="TechnologyIndexes.TechnologyCount"/>). Then, any technology applicable to the product
        /// will have a non-null value at a specific array index, while any technology that is not applicable will be
        /// null. For vehicles, technology utilization has to be defined for all elements of the array.<br/>
        /// <b>NOTE</b>: This behavior may change during a future refactoring.
        /// </remarks>
        TechnologyUtilization[] TechUtilization { get; }


        /// <summary>
        /// Links this <see cref="IOEMProduct"/> to the specified <paramref name="industry"/> object, then initializes
        /// the required references (such as manufacturer, vehicle, engine, etc.).
        /// </summary>
        /// <param name="industry">
        ///     The <see cref="IIndustry"/> object to link with this <see cref="IOEMProduct"/>.
        /// </param>
        /// <exception cref="InvalidOperationException">This object has already been linked to an industry.</exception>
        /// <exception cref="ArgumentNullException">The industry object may not be null.</exception>
        void LinkToIndustry(IIndustry industry);

        /// <summary>
        /// Initializes this <see cref="IOEMProduct"/> for analysis.
        /// </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 product by one, and creates a new product revision for that year.
        /// </summary>
        /// <returns>
        /// A <see cref="IOEMProductRevision"/> object containing revision information 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 product
        /// revision must be created for a given model year, before analysis of that year can begin.
        /// </remarks>
        /// <exception cref="InvalidOperationException">
        ///     The product must be initialized for analysis before product revisions may be created.
        ///     -or-
        ///     A product revision may not be created for a model year beyond the last analysis year.
        /// </exception>
        IOEMProductRevision CreateRevision();

        /// <summary>
        /// Obtains a product revision for the specified model year.
        /// </summary>
        /// <param name="year">
        ///     The model year for which to obtain a product revision; or, specify null to return the product's latest
        ///     revision.
        /// </param>
        /// <returns>
        /// A product revision for the specified model year, or null, if the product 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>
        IOEMProductRevision GetRevision(int? year = null);

        /// <summary>
        /// Determines whether the <see cref="IOEMProduct"/> is at redesign for the specified model year.
        /// </summary>
        /// <param name="year">
        ///     The model year for which to check the <see cref="IOEMProduct"/>'s redesign state.
        /// </param>
        /// <returns>
        /// <c>true</c>, if the <see cref="IOEMProduct"/> is at redesign for the specified model year;
        /// <c>false</c>, otherwise.
        /// </returns>
        bool IsAtRedesign(int year);

        /// <summary>
        /// Determines whether the <see cref="IOEMProduct"/> is at refresh for the specified model year.
        /// </summary>
        /// <param name="year">
        ///     The model year for which to check the <see cref="IOEMProduct"/>'s refresh state.
        /// </param>
        /// <returns>
        /// <c>true</c>, if the <see cref="IOEMProduct"/> is at refresh for the specified model year;
        /// <c>false</c>, otherwise.
        /// </returns>
        bool IsAtRefresh(int year);

    }
}
