"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.ResolvedTraitSet = void 0;
const internal_1 = require("../internal");
/**
     * @internal
     */
class ResolvedTraitSet {
    constructor(resOpt) {
        // let bodyCode = () =>
        {
            this.resOpt = resOpt;
            this.set = [];
            this.lookupByTrait = new Map();
            this.hasElevated = false;
        }
        // return p.measure(bodyCode);
    }
    get size() {
        // let bodyCode = () =>
        {
            if (this.set) {
                return this.set.length;
            }
            return 0;
        }
        // return p.measure(bodyCode);
    }
    get first() {
        // let bodyCode = () =>
        {
            if (this.set) {
                return this.set[0];
            }
            return undefined;
        }
        // return p.measure(bodyCode);
    }
    merge(toMerge, copyOnWrite) {
        // let bodyCode = () =>
        {
            let traitSetResult = this;
            const trait = toMerge.trait;
            let av;
            let wasSet;
            if (toMerge.parameterValues) {
                av = toMerge.parameterValues.values;
                wasSet = toMerge.parameterValues.wasSet;
            }
            if (!this.hasElevated) {
                this.hasElevated = trait.elevated;
            }
            if (traitSetResult.lookupByTrait.has(trait)) {
                let rtOld = traitSetResult.lookupByTrait.get(trait);
                let avOld;
                if (rtOld.parameterValues) {
                    avOld = rtOld.parameterValues.values;
                }
                if (av && avOld) {
                    // the new values take precedence
                    const l = av.length;
                    for (let i = 0; i < l; i++) {
                        if (av[i] !== avOld[i]) {
                            if (copyOnWrite) {
                                traitSetResult = traitSetResult.shallowCopyWithException(trait);
                                rtOld = traitSetResult.lookupByTrait.get(trait);
                                avOld = rtOld.parameterValues.values;
                                copyOnWrite = false;
                            }
                            avOld[i] = internal_1.ParameterValue.fetchReplacementValue(this.resOpt, avOld[i], av[i], wasSet[i]);
                        }
                    }
                }
            }
            else {
                if (copyOnWrite) {
                    traitSetResult = traitSetResult.shallowCopy();
                }
                toMerge = toMerge.copy();
                traitSetResult.set.push(toMerge);
                traitSetResult.lookupByTrait.set(trait, toMerge);
            }
            return traitSetResult;
        }
        // return p.measure(bodyCode);
    }
    mergeSet(toMerge, elevatedOnly = false) {
        // let bodyCode = () =>
        {
            let copyOnWrite = true;
            let traitSetResult = this;
            if (toMerge) {
                const l = toMerge.set.length;
                for (let i = 0; i < l; i++) {
                    const rt = toMerge.set[i];
                    if (!elevatedOnly || rt.trait.elevated) {
                        const traitSetMerge = traitSetResult.merge(rt, copyOnWrite);
                        if (traitSetMerge !== traitSetResult) {
                            traitSetResult = traitSetMerge;
                            copyOnWrite = false;
                        }
                    }
                }
            }
            return traitSetResult;
        }
        // return p.measure(bodyCode);
    }
    get(trait) {
        // let bodyCode = () =>
        {
            if (this.lookupByTrait.has(trait)) {
                return this.lookupByTrait.get(trait);
            }
            return undefined;
        }
        // return p.measure(bodyCode);
    }
    find(resOpt, traitName) {
        // let bodyCode = () =>
        {
            const l = this.set.length;
            for (let i = 0; i < l; i++) {
                const rt = this.set[i];
                if (rt.trait.isDerivedFrom(traitName, resOpt)) {
                    return rt;
                }
            }
            return undefined;
        }
        // return p.measure(bodyCode);
    }
    remove(resOpt, traitName) {
        const rt = this.find(resOpt, traitName);
        if (rt != null) {
            this.lookupByTrait.delete(rt.trait);
            const index = this.set.indexOf(rt);
            if (index > -1) {
                this.set.splice(index, 1);
            }
            return true;
        }
        return false;
    }
    deepCopy() {
        // let bodyCode = () =>
        {
            const copy = new ResolvedTraitSet(this.resOpt);
            const l = this.set.length;
            for (let i = 0; i < l; i++) {
                const rt = this.set[i].copy();
                copy.set.push(rt);
                copy.lookupByTrait.set(rt.trait, rt);
            }
            copy.hasElevated = this.hasElevated;
            return copy;
        }
        // return p.measure(bodyCode);
    }
    shallowCopyWithException(just) {
        // let bodyCode = () =>
        {
            const copy = new ResolvedTraitSet(this.resOpt);
            const l = this.set.length;
            for (let i = 0; i < l; i++) {
                let rt = this.set[i];
                if (rt.trait === just) {
                    rt = rt.copy();
                }
                copy.set.push(rt);
                copy.lookupByTrait.set(rt.trait, rt);
            }
            copy.hasElevated = this.hasElevated;
            return copy;
        }
        // return p.measure(bodyCode);
    }
    shallowCopy() {
        // let bodyCode = () =>
        {
            const copy = new ResolvedTraitSet(this.resOpt);
            if (this.set) {
                const l = this.set.length;
                for (let i = 0; i < l; i++) {
                    const rt = this.set[i];
                    copy.set.push(rt);
                    copy.lookupByTrait.set(rt.trait, rt);
                }
            }
            copy.hasElevated = this.hasElevated;
            return copy;
        }
        // return p.measure(bodyCode);
    }
    collectTraitNames() {
        // let bodyCode = () =>
        {
            const collection = new Set();
            if (this.set) {
                const l = this.set.length;
                for (let i = 0; i < l; i++) {
                    const rt = this.set[i];
                    rt.collectTraitNames(this.resOpt, collection);
                }
            }
            return collection;
        }
        // return p.measure(bodyCode);
    }
    setParameterValueFromArgument(trait, arg) {
        // let bodyCode = () =>
        {
            const resTrait = this.get(trait);
            if (resTrait && resTrait.parameterValues) {
                const av = resTrait.parameterValues.values;
                const newVal = arg.getValue();
                // get the value index from the parameter collection given the parameter that this argument is setting
                let paramDef = arg.getParameterDef();
                if (paramDef) {
                    resTrait.parameterValues.setParameterValue(this.resOpt, paramDef.getName(), newVal);
                }
                else {
                    // debug
                    paramDef = arg.getParameterDef();
                }
            }
        }
        // return p.measure(bodyCode);
    }
    setTraitParameterValue(resOpt, toTrait, paramName, value) {
        // let bodyCode = () =>
        {
            const altered = this.shallowCopyWithException(toTrait);
            const currTrait = altered.get(toTrait);
            if (currTrait) {
                currTrait.parameterValues
                    .setParameterValue(this.resOpt, paramName, value);
            }
            return altered;
        }
        // return p.measure(bodyCode);
    }
    replaceTraitParameterValue(resOpt, toTrait, paramName, valueWhen, valueNew) {
        // let bodyCode = () =>
        {
            let traitSetResult = this;
            const l = traitSetResult.set.length;
            for (let i = 0; i < l; i++) {
                let rt = traitSetResult.set[i];
                if (rt && rt.trait.isDerivedFrom(toTrait, this.resOpt)) {
                    if (rt.parameterValues) {
                        const pc = rt.parameterValues.pc;
                        let av = rt.parameterValues.values;
                        const idx = pc.fetchParameterIndex(paramName);
                        if (idx !== undefined && av[idx] === valueWhen) {
                            // copy the set and make a deep copy of the trait being set
                            traitSetResult = this.shallowCopyWithException(rt.trait);
                            // assume these are all still true for this copy
                            rt = traitSetResult.set[i];
                            av = rt.parameterValues.values;
                            av[idx] = internal_1.ParameterValue.fetchReplacementValue(this.resOpt, av[idx], valueNew, true);
                            break;
                        }
                    }
                }
            }
            return traitSetResult;
        }
        // return p.measure(bodyCode);
    }
    spew(resOpt, to, indent, nameSort) {
        // let bodyCode = () =>
        {
            const l = this.set.length;
            let list = this.set;
            if (nameSort) {
                list = list.sort((lhs, rhs) => lhs.traitName.localeCompare(rhs.traitName));
            }
            for (let i = 0; i < l; i++) {
                // comment this line to simplify spew results to stop at attribute names
                list[i].spew(resOpt, to, indent);
            }
        }
        // return p.measure(bodyCode);
    }
}
exports.ResolvedTraitSet = ResolvedTraitSet;
//# sourceMappingURL=ResolvedTraitSet.js.map