#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

using System;
using Volpe.Cafe.MarketData;
using Volpe.Cafe.MarketData.Design;
using TechKey = Volpe.Cafe.TechKeys.TechKey128;

namespace Volpe.Cafe.TechAnalysis
{
    /// <summary>
    /// Defines a test vehicle affected by application of pending technologies in a specific model year.
    /// </summary>
    [Serializable]
    public class TestVehicle : IVehicleInfo
    {
        #region <<< Constructors >>>

        /// <summary>
        /// Initializes a new instance of the <see cref="TestVehicle"/> class for the specified model year, using the
        /// property values from the latest revision of the given vehicle model.
        /// <br/><br/>
        /// After initialization, the vehicle attributes of "this" instance as well as the attributes of the
        /// <see cref="PreviousState"/> instance will be the same and based on the current state of the specified
        /// vehicle.
        /// </summary>
        /// <param name="testYear">The model year associated with this test vehicle.</param>
        /// <param name="veh">The underlying vehicle affected by application of pending technologies.</param>
        public TestVehicle(int testYear, IVehicle veh)
        {
            this.RevisionYear = testYear;
            this.Vehicle = veh;
            this.Revision = veh.GetRevision(testYear);
            this.InitializeAttributes();

            // when initialized, prev-state is simply a copy of "this" state
            // NOTE: prev-state has to be a copy (rather than reference to revision) --
            //       this is b/c revision will get updated when tech is applied,
            //       but we still need prev-state info for incremental compliance calcs
            this.PreviousState = new TestVehicle {
                RevisionYear = this.RevisionYear,
                Vehicle = this.Vehicle,
                Revision = this.Revision,
                PreviousState = null
            };
            this.PreviousState.InitializeAttributes();
        }

        // Private constructor (for cloning).
        private TestVehicle() { }

        #endregion

        #region <<< Properties >>>

        /// <summary>
        /// Gets the underlying <see cref="IVehicle"/> associated with this <see cref="TestVehicle"/> instance.
        /// </summary>
        public IVehicle Vehicle { get; private set; }

        /// <summary>
        /// Gets the <see cref="IVehicleRevision"/> associated with this <see cref="TestVehicle"/> instance.
        /// </summary>
        public IVehicleRevision Revision { get; private set; }

        /// <summary>
        /// Gets the model year associated with this <see cref="TestVehicle"/> instance.
        /// </summary>
        public int RevisionYear { get; private set; }

        //----- general vehicle info -----
        public int Code => this.Revision.Code;
        public string ManufacturerName => this.Revision.ManufacturerName;

        public ModelYearKey RefreshYears => this.Revision.RefreshYears;
        public ModelYearKey RedesignYears => this.Revision.RedesignYears;

        public string Brand => this.Revision.Brand;
        public string Model => this.Revision.Model;
        public string Nameplate => this.Revision.Nameplate;

        public int PlatformCode => this.Revision.PlatformCode;
        public int EngineCode => this.Revision.EngineCode;
        public int TransmissionCode => this.Revision.TransmissionCode;

        //----- fuel-economy values -----
        /// <summary>
        /// Gets or sets the CAFE fuel economy rating of the vehicle for each fuel type.
        /// </summary>
        public FuelValue FuelEconomy { get; set; }
        /// <summary>
        /// Gets or sets the percent share that the vehicle operates on for each fuel type. That is, the amount of
        /// miles driven by the vehicle on each fuel type.
        /// </summary>
        public FuelValue FuelShare { get; set; }
        /// <summary>
        /// Gets the type(s) of fuel used by the vehicle.
        /// </summary>
        public FuelType FuelType => this.FuelShare.FuelType;

        //----- sales/msrp -----
        public double Sales { get; private set; }
        public double Msrp { get; private set; }

        //----- regulatory classification -----
        public RegulatoryClass RegClass => this.Revision.RegClass;
        public SafetyClass SafetyClass => this.Revision.SafetyClass;
        public VehicleClass VehicleClass => this.Revision.VehicleClass;

        public TechnologyClass TechnologyClass => this.Revision.TechnologyClass;
        public EngineTechnologyClass EngineTechnologyClass => this.Revision.EngineTechnologyClass;

        public bool IsZevCandidate => this.Revision.IsZevCandidate;
        public int? ZEVCandidate => this.Revision.ZEVCandidate;
        public int ZevApplicationYear => this.Revision.ZevApplicationYear;
        public int ZevReferenceVehicleCode => this.Revision.ZevReferenceVehicleCode;

        public bool CARBAgreement => this.Revision.CARBAgreement;

        //----- vehicle characteristics -----
        public Origin Origin => this.Revision.Origin;

        public VehicleStyle Style => this.Revision.Style;
        public VehicleFrame Structure => this.Revision.Structure;
        public DriveType Drive => this.Revision.Drive;

        /// <summary>Gets or sets the vehicle's footprint.</summary>
        public double Footprint { get; set; }

        /// <summary>Gets the "reference" curb weight of the vehicle (negating any mass reduction).</summary>
        public double CurbWeightMR0 => this.Revision.CurbWeightMR0;
        /// <summary>Gets or sets the vehicle's curb weight.</summary>
        public double CurbWeight { get; set; }
        /// <summary>Gets or sets the vehicle's Gross Vehicle Weight Rating (GVWR).</summary>
        public double GVWR { get; set; }
        /// <summary>Gets or sets the vehicle's Gross Combined Weight Rating (GCWR).</summary>
        public double GCWR { get; set; }

        public double FuelCapacity => this.Revision.FuelCapacity;

        //----- vehicle powertrain -----
        /// <summary>
        /// Gets or sets whether the vehicle uses a conventional or a hybrid/electric powertrain.
        /// </summary>
        public HEVType HevType { get; set; }

        //----- technology utilization -----
        /// <summary>
        /// Gets or sets the technology key, representing the technology configuration of the vehicle.
        /// </summary>
        public TechKey TechKey { get; set; }

        //----- cross-references vehicle's previous state -----        
        /// <summary>
        /// Gets the state of the test vehicle <b>before</b> application of pending technologies.
        /// </summary>
        public TestVehicle PreviousState { get; private set; }

        #endregion

        #region <<< Methods >>>

        private void InitializeAttributes()
        {
            var revision = this.Revision;

            this.FuelEconomy = revision.FuelEconomy;
            this.FuelShare   = revision.FuelShare;
            this.HevType     = revision.HevType;
            this.Sales       = revision.Sales;
            this.Msrp        = revision.Msrp;
            this.Footprint   = revision.Footprint;
            this.CurbWeight  = revision.CurbWeight;
            this.GVWR        = revision.GVWR;
            this.GCWR        = revision.GCWR;
            this.TechKey     = revision.TechKey;
        }

        #endregion
    }
}
