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

using System;
using System.Collections.Generic;

using Volpe.Cafe.Initializers;
using Volpe.Cafe.MarketData.Design;
using Volpe.Cafe.MarketData.Parsers;
using Volpe.Cafe.TechAnalysis;

using TechKey = Volpe.Cafe.TechKeys.TechKey128;

namespace Volpe.Cafe.MarketData.BaselineInfo
{
    /// <summary>
    /// Provides a description of baseline engineering characteristics for a vehicle component.
    /// </summary>
    /// <seealso cref="IOEMComponent"/>
    [Serializable]
    public abstract class BaselineComponent : IOEMComponentInfo
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="BaselineComponent"/> class.
        /// </summary>
        public BaselineComponent(Dictionary<string, object> values)
        {
            bool HasOptionalProperty(string propertyName)
            {
                return values.TryGetValue(propertyName, out object s)
                    && s != null
                    && s.ToString().Trim().Length != 0;
            }

            bool autoGenFamilyName = false;
            bool autoGenComponentName = false;

            if (!HasOptionalProperty("FamilyName")) {
                autoGenFamilyName = true;
                values["FamilyName"] = string.Empty;
            }
            if (!HasOptionalProperty("ComponentName")) {
                autoGenComponentName = true;
                values["ComponentName"] = string.Empty;
            }

            DataObjectInitializer.SetPropertyValues(this, values);

            // set missing properties --
            // must do this after DOI.SetPropertyValues is run, b/c auto-gen
            // functions rely on object's other properties and methods
            if (autoGenFamilyName) {
                this.FamilyName = this.AutoGenerateFamilyName();
            }
            if (autoGenComponentName) {
                this.ComponentName = this.AutoGenerateComponentName();
            }

            // baseline tech-key must be assigned from used-techs
            this.TechKey = KeyInitializer.CalcBaselineTechKey(this);
        }

        /// <summary>
        /// Gets the unique code assigned to the component.
        /// </summary>
        public int Code { get; private set; }
        /// <summary>
        /// Gets the name of the manufacturer that produces the component.
        /// </summary>
        public string ManufacturerName { get; private set; }

        public string ComponentName { get; private set; }
        public string FamilyName { get; private set; }

        /// <summary>
        /// Gets the code of this component's leader vehicle that informed the <see cref="RefreshYears"/> and/or
        /// <see cref="RedesignYears"/> for the component. If both the refresh and the redesign years were not assigned
        /// by a leader vehicle, this value will be -1.
        /// </summary>
        public int LeaderCode { get; private set; }

        /// <summary>
        /// Gets the list of model years representing when the component is refreshed.
        /// </summary>
        public ModelYearKey RefreshYears { get; private set; }
        /// <summary>
        /// Gets the list of model years representing when the component is redesigned.
        /// </summary>
        public ModelYearKey RedesignYears { get; private set; }

        /// <summary>
        /// Gets the technologies initially in use on the component.
        /// </summary>
        public TechKey UsedTechnologies { get; private set; }
        /// <summary>
        /// Gets the technologies available for application on the component.
        /// </summary>
        public TechKey AvailableTechnologies { get; private set; }

        /// <summary>
        /// Gets the technology key, representing the baseline technology configuration associated with the component.
        /// </summary>
        /// <remarks>
        /// <b>NOTE</b>:
        /// The baseline technology key is a derived value, which is not parsed from the input data and must not be
        /// assigned by the input parser. Instead, this value will be computed and assigned by the constructor based on
        /// the value of the <see cref="UsedTechnologies"/> property.
        /// <br/><br/>
        /// The <see cref="TechKey"/> may not necessarily be the same as <see cref="UsedTechnologies"/>. While
        /// <see cref="UsedTechnologies"/> identifies the technologies selected as used on a component by the user, the
        /// <see cref="TechKey"/> represents the same technology configuration, but with the possible conflicts,
        /// redundancies, and dependencies resolved.
        /// </remarks>
        public TechKey TechKey { get; }

    }
}
