using Volpe.Cafe.MarketData.BaselineInfo;
using Volpe.Cafe.MarketData.Design;

using TechKey = Volpe.Cafe.TechKeys.TechKey128;
using TI = Volpe.Cafe.TechnologyIndexes;

namespace Volpe.Cafe.TechAnalysis
{
    /// <summary>
    /// Provides helper functions for calculating technology keys for various <see cref="IOEMProduct"/>s, based on
    /// their baseline information as well as for revisions created during modeling.
    /// </summary>
    public static class KeyInitializer
    {
        /// <summary>
        /// Calculates the technology key for a vehicle based on its baseline engineering characteristics.
        /// </summary>
        public static TechKey CalcBaselineTechKey(BaselineVehicle baselineInfo)
        {
            return CalcBaselineTechKey(baselineInfo.UsedTechnologiesFull);
        }
        /// <summary>
        /// Calculates the technology key for a component based on its baseline engineering characteristics.
        /// </summary>
        public static TechKey CalcBaselineTechKey(BaselineComponent baselineInfo)
        {
            return CalcBaselineTechKey(baselineInfo.UsedTechnologies);
        }
        /// <summary>
        /// Calculates and returns the technology key based on the specified state of initially used technologies on a
        /// vehicle or a component (as read from the market-data input file).
        /// </summary>
        public static TechKey CalcBaselineTechKey(TechKey usedTechnologies)
        {
            TechKey removeKey = BuildRemoveKey(usedTechnologies);
            return usedTechnologies & (~removeKey);
        }

        /// <summary>
        /// Calculates a "test" technology key for a product, adjusted based on a technology with the specified
        /// <paramref name="techIndex"/>.
        /// </summary>
        public static TechKey TestTechKey(IOEMProductInfo productInfo, int techIndex)
        {
            return TestTechKey(productInfo.TechKey, techIndex);
        }
        /// <summary>
        /// Calculates and returns a "test" technology key based on the specified <paramref name="currentTechKey"/>,
        /// adjusted based on a technology with the specified <paramref name="techIndex"/>.
        /// </summary>
        public static TechKey TestTechKey(TechKey currentTechKey, int techIndex)
        {
            return (currentTechKey & (~TI.GetTechSupersedes(techIndex))) | TechKey.Keys[techIndex];
        }

        /// <summary>
        /// Builds a "remove key" (i.e., all techs to exclude/remove from <b><i>techKey</i></b>).
        /// <br/><br/>
        /// Technologies are excluded either because they are superseded by one of the other technologies in
        /// <b><i>techKey</i></b>, or because they are not part of the simulation DB. Superseded technologies and
        /// non-simulated technologies must be removed from <b><i>techKey</i></b> to ensure that <b><i>techKey</i></b>
        /// matches the simulation DB structure and that the simulation DB lookups do not fail.
        /// </summary>
        private static TechKey BuildRemoveKey(TechKey techKey)
        {
            // build a "remove-key" (all techs to exclude from the tech-key)
            TechKey removeKey = TechKey.Empty;
            for (int i = 0; i < TI.TechnologyCount; i++) {
                if (techKey[i]) {
                    // remove technologies replaced (i.e., superseded) by this one
                    // we need to remove superseded techs to match the simulation DB structure
                    removeKey |= TI.GetTechSupersedes(i);
                }
            }
            return removeKey;
        }

    }
}
