using System;

namespace Volpe.Cafe.Generic
{
    /// <summary>
    /// Defines an object that stores modeling data as a continuous stream of annual values.
    /// </summary>
    /// <typeparam name="T">The type of elements in the stream of annual values.</typeparam>
    public interface IAnnualValue<out T>
    {
        /// <summary>Gets a value associated with the specified year.</summary>
        /// <exception cref="ArgumentOutOfRangeException">
        ///     The specified year is out-of-bounds of the <see cref="MinYear"/> and <see cref="MaxYear"/> range.
        ///     This exception is only thrown when the <see cref="OutOfBoundsMode"/> is defined to throw exceptions
        ///     for out-of-bounds values.
        /// </exception>
        T this[int year] { get; }

        /// <summary>Gets the lowest year for which annual values are defined.</summary>
        int MinYear { get; }
        /// <summary>Gets the highest year for which annual values are defined.</summary>
        int MaxYear { get; }

        /// <summary>Gets the value for the lowest year for which annual values are defined.</summary>
        T MinValue { get; }
        /// <summary>Gets the value for the highest year for which annual values are defined.</summary>
        T MaxValue { get; }

        /// <summary>
        /// Gets the way this <see cref="IAnnualValue{T}"/> handles requested years that are not explicitly defined by
        /// this instance. That is, this option defines what the return value will be for years that are out-of-bounds
        /// of the <see cref="MinYear"/> and <see cref="MaxYear"/> range.
        /// <br/><br/>
        /// The following options are available for handling out-of-bounds years:
        /// <br/><br/>
        ///     <b>0</b>: returns the default value (0, false, or null) based on the underlying type;<br/>
        ///     <b>1</b>: returns the first value if year is less than <see cref="MinYear"/>, or the last value if year
        ///               is greater than <see cref="MaxYear"/>;<br/>
        ///     <b>2</b>: returns the default value (0, false, or null) based on the underlying type if year is less
        ///               than <see cref="MinYear"/>, or the last value if year is greater than <see cref="MaxYear"/>;
        ///               <br/>
        ///     <b>-1 <i>(or any other value)</i></b>: throws an <see cref="ArgumentOutOfRangeException"/>.
        /// </summary>
        int OutOfBoundsMode { get; }

        /// <summary>
        /// Determines whether this instance has a value defined for the specified year.
        /// </summary>
        /// <param name="year">The year to test.</param>
        /// <returns>true, if this instance has a value defined for the specified year; false, otherwise.</returns>
        bool HasValue(int year);

        /// <summary>
        /// Converts all elements in the current <see cref="IAnnualValue{T}"/> instance to another type, and returns a
        /// new <see cref="IAnnualValue{TOutput}"/> object containing the converted elements.
        /// </summary>
        /// <param name="converter">
        ///     A <see cref="Converter{T, TOutput}"/> delegate that converts each element from one type to another
        ///     type.
        /// </param>
        /// <param name="newOutOfBoundsMode">
        ///     An <see cref="OutOfBoundsMode"/> to use in the new <see cref="IAnnualValue{T}"/> object, or null, to
        ///     use the <see cref="OutOfBoundsMode"/> from the current instance.
        /// </param>
        /// <typeparam name="TOutput">
        ///     The target type of the converted elements in the new stream of annual values.
        /// </typeparam>
        /// <returns>
        /// An <see cref="AnnualValue{TOutput}"/> object of the target type containing the converted elements from the
        /// current instance.
        /// </returns>
        /// <exception cref="ArgumentNullException">converter is null.</exception>
        IAnnualValue<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter, int? newOutOfBoundsMode = null);

    }
}
