using System;
using System.Collections;
using System.Collections.Generic;

namespace Volpe.Cafe.Reporting
{
    /// <summary>
    /// Defines a range object that may be used to generate a sequence of values between a specific starting and ending
    /// points, with an option to generate an additional value at the end of the sequence.
    /// </summary>
    /// <remarks>
    /// The range object generates a sequence of nullable integers (<c>int?</c>) between the specified starting and
    /// ending points (inclusive). If the <see cref="Suffix"/> property is set to <c>true</c>, an additional value will
    /// be generated at the end of the sequence by using <c>null</c> to represent that value.<br/><br/>
    /// For example, given a range object that as initialized as:<br/>
    /// <code>
    ///     new Range(5, 10, true)
    /// </code>
    /// The following sequence will be generated:<br/>
    /// <code>
    ///     5, 6, 7, 8, 9, 10, null
    /// </code>
    /// </remarks>
    [Serializable]
    public class Range : IEnumerable<int?>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Range"/> class, using the specified <paramref name="start"/>
        /// and <paramref name="end"/> values (inclusive).
        /// </summary>
        /// <param name="start">The inclusive starting value of the range.</param>
        /// <param name="end">The inclusive ending value of the range.</param>
        /// <param name="suffix">Whether to generate an extra value at the end of the sequence.</param>
        public Range(int start, int end, bool suffix)
        {
            this.Start = start;
            this.End = end;
            this.Suffix = suffix;
        }

        /// <summary>Gets the inclusive starting value of the range.</summary>
        public int Start { get; }
        /// <summary>Gets the inclusive ending value of the range.</summary>
        public int End { get; }
        /// <summary>Gets whether to generate an extra value at the end of the sequence.</summary>
        public bool Suffix { get; }

        /// <summary>
        /// Returns an enumerator that iterates through a range values between the <see cref="Start"/> and
        /// <see cref="End"/> points, with an optional extra value for the <see cref="Suffix"/>.
        /// </summary>
        public IEnumerator<int?> GetEnumerator()
        {
            if (this.Start > this.End) {
                for (int i = this.Start; i >= this.End; i--) {
                    yield return i;
                }
            }
            else {
                for (int i = this.Start; i <= this.End; i++) {
                    yield return i;
                }
            }

            if (this.Suffix) {
                yield return null;
            }
        }

        //----- explicit interface implementation -----
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

    }
}
