using System;
using Volpe.Cafe.Generic;

namespace Volpe.Cafe
{
    /// <summary>
    /// Represents an object that stores modeling data, as double precision numeric values, for each pollutant.
    /// <br/>
    /// This object supports and operates on all pollutants as defined by <see cref="Pollutants.List"/>.
    /// </summary>
    [Serializable]
    public class EmissionsValue : PollutantValue<double>, ICloneable
    {
        #region <<< Constructors >>>

        /// <summary>
        /// Initializes a new instance of the <see cref="EmissionsValue"/> class.
        /// </summary>
        public EmissionsValue() : base() { }

        /// <summary>
        /// Initializes a new instance of the <see cref="EmissionsValue"/> class using the specified initial value for
        /// all members.
        /// </summary>
        EmissionsValue(double initialValue) : base(() => initialValue) { }

        #endregion

        #region <<< Properties >>>

        /// <summary>Gets the <see cref="EmissionsValue"/> whose elements are all 0.</summary>
        public static EmissionsValue Zero => new EmissionsValue();
        /// <summary>Gets the <see cref="EmissionsValue"/> whose elements are all 1.</summary>
        public static EmissionsValue One => new EmissionsValue(1D);

        #endregion

        #region <<< Methods >>>

        #region < Overloaded Operators >

        /// <summary>Returns a new <see cref="EmissionsValue"/> that is the sum of the two specified values.</summary>
        public static EmissionsValue operator +(EmissionsValue value1, EmissionsValue value2)
        {
            EmissionsValue result = new EmissionsValue();
            for (int i = 0; i < result.Items.Length; i++)
            {
                result.Items[i] = value1.Items[i] + value2.Items[i];
            }
            return result;
        }
        /// <summary>Returns a new <see cref="EmissionsValue"/> that is the difference of the two specified values.</summary>
        public static EmissionsValue operator -(EmissionsValue value1, EmissionsValue value2)
        {
            EmissionsValue result = new EmissionsValue();
            for (int i = 0; i < result.Items.Length; i++)
            {
                result.Items[i] = value1.Items[i] - value2.Items[i];
            }
            return result;
        }
        /// <summary>Returns a new <see cref="EmissionsValue"/> that is the product of the two specified values.</summary>
        public static EmissionsValue operator *(EmissionsValue value1, EmissionsValue value2)
        {
            EmissionsValue result = new EmissionsValue();
            for (int i = 0; i < result.Items.Length; i++)
            {
                result.Items[i] = value1.Items[i] * value2.Items[i];
            }
            return result;
        }
        /// <summary>Returns a new <see cref="EmissionsValue"/> that is the first value divided by the second value.</summary>
        public static EmissionsValue operator /(EmissionsValue value1, EmissionsValue value2)
        {
            EmissionsValue result = new EmissionsValue();
            for (int i = 0; i < result.Items.Length; i++)
            {
                result.Items[i] = value1.Items[i] / value2.Items[i];
            }
            return result;
        }

        /// <summary>Returns a copy of the specified value.</summary>
        public static EmissionsValue operator +(EmissionsValue value) => value.Clone();
        /// <summary>Returns a negated copy of the specified value.</summary>
        public static EmissionsValue operator -(EmissionsValue value) => Zero - value;
        /// <summary>Returns a copy of the specified value, incremented by one.</summary>
        public static EmissionsValue operator ++(EmissionsValue value) => value + One;
        /// <summary>Returns a copy of the specified value, decremented by one.</summary>
        public static EmissionsValue operator --(EmissionsValue value) => value - One;

        #endregion

        #region < ICloneable Members >

        /// <summary>
        /// Creates a new object that is a copy of the current <see cref="EmissionsValue"/> instance.
        /// </summary>
        /// <returns>A new object that is a copy of this <see cref="EmissionsValue"/>.</returns>
        object ICloneable.Clone()
        {
            return this.Clone();
        }
        /// <summary>
        /// Creates a copy of the current <see cref="EmissionsValue"/> instance.
        /// </summary>
        /// <returns>A new object that is a copy of this <see cref="EmissionsValue"/>.</returns>
        public new EmissionsValue Clone()
        {
            EmissionsValue value = new EmissionsValue();
            this.CloneInternal(this, value, null);
            return value;
        }

        #endregion

        /// <summary>
        /// Returns the string representation of this <see cref="EmissionsValue"/> instance, using the specified format
        /// for all elements.
        /// </summary>
        /// <param name="format">A format string.</param>
        /// <returns>
        /// The string representation of the <see cref="EmissionsValue"/> instance, using the specified format.
        /// </returns>
        public string ToString(string format)
        {
            return GenericsHelper.CalcString(this.Items, Pollutants.Names, d => d.ToString(format));
        }
        /// <summary>
        /// Returns the string representation of this <see cref="EmissionsValue"/> instance, whose elements are rounded
        /// with the specified precision.
        /// </summary>
        /// <param name="digits">The number of fractional digits (precision) in the return value.</param>
        /// <returns>The string representation of the <see cref="EmissionsValue"/> instance.</returns>
        public string ToString(int digits)
        {
            return GenericsHelper.CalcString(this.Items, Pollutants.Names, d => Math.Round(d, digits).ToString());
        }

        #endregion
    }
}
