using System;
using System.IO;
using Volpe.Cafe.IO.DSV;
using DsvThrowHelper = Volpe.Cafe.IO.DSV.ThrowHelper;

namespace Volpe.Cafe.Logging
{
    /// <summary>
    /// Provides support for logging compliance findings to a text file.
    /// </summary>
    [Serializable]
    public class ComplianceWriter : LogFileWriter
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ComplianceWriter"/> class for the specified file, using the
        /// default encoding and buffer size. If the file exists, it can be either overwritten or appended to. If the
        /// file does not exist, this constructor creates a new file. When a new file is created, a headers line will
        /// be written to the file.
        /// </summary>
        /// <param name="path">The complete file path to write to.</param>
        /// <param name="append">
        ///     Specifies whether data is to be appended to the file. If the file exists and append is <c>false</c>,
        ///     the file is overwritten. If the file exists and append is <c>true</c>, the data is appended to the
        ///     file. Otherwise, a new file is created.
        /// </param>
        /// <inheritdoc cref="StreamWriter(string, bool)" path="/exception"/>
        /// <remarks>
        /// If a new file is created, a headers line will be written to the compliance log file. The abridged headers
        /// is as follows: <b>"LN\tCF\tScen\tYear\t...\tNew FE1-Imprv\tNew FE2-Imprv\tNew Battery Cost"</b>. The
        /// complete headers line may by obtained via the <see cref="DsvWriter.GetHeaders"/> method.
        /// </remarks>
        public ComplianceWriter(string path, bool append)
            : base(path, CanAppend(path, append) ? null : GetHeaders())
        {
            if (!CanAppend(path, append)) {
                this.LineCount = 1;
            }
        }

        /// <summary>
        /// Gets the total number of lines written to the text stream thus far.
        /// </summary>
        public int LineCount { get; protected set; }

        /// <summary>
        /// Writes the specified array of values, followed by a line terminator, to the log file. The
        /// <paramref name="values"/> array must not include the value for the line counter (the "LN" column), which
        /// will be automatically added by this method.
        /// </summary>
        /// <inheritdoc cref="DsvWriter.WriteValues(object[])" path="/param"/>
        /// <inheritdoc cref="DsvWriter.WriteValues(object[])" path="/exception"/>
        public override void WriteValues(params object[] values)
        {
            DsvThrowHelper.ThrowIfDisposed(this);
            DsvThrowHelper.ThrowIfValuesNotValid(values, this.Headers.Length - 1);

            this.Stream.Write(++this.LineCount);
            this.Stream.Write(this.Delimiter);
            this.WriteValuesInternal(values);
        }

        /// <inheritdoc/>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            this.LineCount = 0;
        }

        private static bool CanAppend(string path, bool append)
        {
            return append && File.Exists(path);
        }

        private static new string[] GetHeaders()
        {
            string[] headers = {
                //----- basic info -----
                "LN", "CF", "Scen", "Year", "Mfr", "Applied", "Eff-CAFE", "Eff-CO2",
                "CAFE Compliance", "CO2 Compliance", "Binding Program",

                //----- compliance "totals" -----
                "Total Affected Sales", "Total Tech Costs", "Total Tax Credits",
                "Total Battery Tax Credits", "Total Fuel Savings",
                // CAFE-realted cols
                "Delta CAFE Credits", "Delta CAFE Credits (k.Gal)",
                "Delta CAFE Credit Value", "Delta CAFE Credit Value Bound", "Delta CAFE Fines",
                // CO2-realted cols
                "Delta CO2 Credits", "Delta CO2 Credit Value", "Delta CO2 Credit Value Bound",

                //----- compliance values -----
                "Reg-Class",
                // CAFE-realted cols
                "Standard", "CAFE", "Credits", "Credits (k.Gal)", "Credit Value", "Fines", "New Standard",
                "New CAFE", "New Credits", "New Credits (k.Gal)", "New Credit Value", "New Fines",
                // CO2-realted cols
                "CO2 Standard", "CO2 Rating", "CO2 Credits", "CO2 Credit Value",
                "New CO2 Standard", "New CO2 Rating", "New CO2 Credits", "New CO2 Credit Value",

                //----- vehicle-level results -----
                "Eval.Year", "Techs",
                // veh info
                "Sales", "Veh", "Plt", "Eng", "Trn", "Tech-Class", "Eng Tech-Class", "CW (MR0)", "GW (MR0)",
                // veh FE/CO2 changes
                "FE", "CO2", "Share", "New FE", "New CO2", "New Share", "Delta FE", "Delta CO2",
                // tech impacts
                "Cost", "Battery Cost", "FE1-Adj", "FE2-Adj", "Delta CW", "Delta GVWR", "Delta GCWR",
                // tech keys
                "TechKey", "New TechKey",
                // tech effects for "ref" and "new" tech-keys
                "Ref FE1-Imprv", "Ref FE2-Imprv", "Ref Battery Cost",
                "New FE1-Imprv", "New FE2-Imprv", "New Battery Cost"
            };

            return headers;
        }

    }
}
