"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.CdmTraitReference = void 0;
const internal_1 = require("../internal");
class CdmTraitReference extends internal_1.CdmTraitReferenceBase {
    constructor(ctx, trait, simpleReference, hasArguments) {
        super(ctx, trait, simpleReference);
        // let bodyCode = () =>
        {
            this.objectType = internal_1.cdmObjectType.traitRef;
            this.resolvedArguments = false;
            this.isFromProperty = false;
            this.arguments = new internal_1.CdmArgumentCollection(ctx, this);
        }
        // return p.measure(bodyCode);
    }
    getObjectType() {
        // let bodyCode = () =>
        {
            return internal_1.cdmObjectType.traitRef;
        }
        // return p.measure(bodyCode);
    }
    /**
     * @internal
     */
    copyRefObject(resOpt, refTo, simpleReference, host) {
        var _a;
        // let bodyCode = () =>
        {
            let copy;
            if (!host) {
                copy = new CdmTraitReference(this.ctx, refTo, simpleReference, this.arguments ? this.arguments.length > 0 : undefined);
            }
            else {
                copy = host.copyToHost(this.ctx, refTo, simpleReference);
                copy.arguments.clear();
            }
            if (!simpleReference) {
                for (const arg of this.arguments) {
                    copy.arguments.push(arg.copy(resOpt));
                }
                copy.resolvedArguments = this.resolvedArguments;
            }
            copy.verb = (_a = this.verb) === null || _a === void 0 ? void 0 : _a.copy(resOpt);
            return copy;
        }
        // return p.measure(bodyCode);
    }
    /**
     * @internal
     */
    visitRef(pathFrom, preChildren, postChildren) {
        // let bodyCode = () =>
        {
            let result = false;
            if (this.arguments && this.arguments.allItems && this.arguments.allItems.length > 0) {
                // custom enumeration of args to force a path onto these things that just might not have a name
                const lItem = this.arguments.allItems.length;
                for (let iItem = 0; iItem < lItem; iItem++) {
                    const element = this.arguments.allItems[iItem];
                    if (element) {
                        const argPath = `${pathFrom}/arguments/a${iItem}`;
                        if (element.visit(argPath, preChildren, postChildren)) {
                            result = true;
                            break;
                        }
                    }
                }
            }
            if (this.verb !== undefined) {
                this.verb.owner = this;
                if (this.verb.visit(pathFrom + '/verb/', preChildren, postChildren)) {
                    return true;
                }
            }
            return result;
        }
        // return p.measure(bodyCode);
    }
    fetchFinalArgumentValues(resOpt) {
        const finalArgs = new Map();
        // get resolved traits does all the work, just clean up the answers
        const rts = this.fetchResolvedTraits(resOpt);
        if (!rts || rts.size !== 1) {
            // well didn't get the traits. maybe imports are missing or maybe things are just not defined yet.
            // this function will try to fake up some answers then from the arguments that are set on this reference only
            if (this.arguments && this.arguments.length > 0) {
                let unNamedCount = 0;
                for (const arg of this.arguments) {
                    // if no arg name given, use the position in the list.
                    let argName = arg.name;
                    if (!argName) {
                        argName = unNamedCount.toString();
                    }
                    finalArgs.set(argName, arg.value);
                    unNamedCount++;
                }
                return finalArgs;
            }
            return undefined;
        }
        // there is only one resolved trait
        const rt = rts.first;
        if (rt && rt.parameterValues && rt.parameterValues.length > 0) {
            const l = rt.parameterValues.length;
            for (let i = 0; i < l; i++) {
                const p = rt.parameterValues.fetchParameterAtIndex(i);
                const v = rt.parameterValues.fetchValue(i);
                let name = p.name;
                if (!name) {
                    name = i.toString();
                }
                finalArgs.set(name, v);
            }
        }
        return finalArgs;
    }
    /**
     * @internal
     */
    constructResolvedAttributes(resOpt, under) {
        // let bodyCode = () =>
        {
            return undefined;
        }
        // return p.measure(bodyCode);
    }
    /**
     * @internal
     */
    getMinimumSemanticVersion() {
        if (this.verb !== undefined || this.appliedTraits !== undefined && this.appliedTraits.length > 0) {
            return internal_1.CdmObjectBase.semanticVersionStringToNumber(internal_1.CdmObjectBase.jsonSchemaSemanticVersionTraitsOnTraits);
        }
        return super.getMinimumSemanticVersion();
    }
    /**
     * @internal
     */
    fetchResolvedTraits(resOpt) {
        var _a;
        // let bodyCode = () =>
        {
            if (!resOpt) {
                resOpt = new internal_1.resolveOptions(this, this.ctx.corpus.defaultResolutionDirectives);
            }
            const kind = 'rtsb';
            const ctx = this.ctx;
            // get referenced trait
            const trait = this.fetchObjectDefinition(resOpt);
            let rtsTrait;
            if (!trait) {
                return ctx.corpus.createEmptyResolvedTraitSet(resOpt);
            }
            // see if one is already cached
            // cache by name unless there are parameter
            if (trait.thisIsKnownToHaveParameters === undefined) {
                // never been resolved, it will happen soon, so why not now?
                rtsTrait = trait.fetchResolvedTraits(resOpt);
            }
            let rtsResult = undefined;
            // store the previous reference symbol set, we will need to add it with
            // children found from the constructResolvedTraits call
            const currSymRefSet = (_a = resOpt.symbolRefSet) !== null && _a !== void 0 ? _a : new internal_1.SymbolSet();
            resOpt.symbolRefSet = new internal_1.SymbolSet();
            // get the set of resolutions, should just be this one trait
            if (!rtsTrait) {
                // store current doc ref set
                const newDocRefSet = resOpt.symbolRefSet;
                resOpt.symbolRefSet = new internal_1.SymbolSet();
                rtsTrait = trait.fetchResolvedTraits(resOpt);
                // bubble up symbol reference set from children
                if (newDocRefSet) {
                    newDocRefSet.merge(resOpt.symbolRefSet);
                }
                resOpt.symbolRefSet = newDocRefSet;
            }
            if (rtsTrait) {
                rtsResult = rtsTrait.deepCopy();
            }
            // now if there are argument for this application, set the values in the array
            if (this.arguments && rtsResult) {
                // if never tried to line up arguments with parameters, do that
                if (!this.resolvedArguments) {
                    this.resolvedArguments = true;
                    const params = trait.fetchAllParameters(resOpt);
                    let paramFound;
                    let argumentIndex = 0;
                    for (const argument of this.arguments) {
                        paramFound = params.resolveParameter(argumentIndex, argument.getName());
                        argument.resolvedParameter = paramFound;
                        argument.value = paramFound.constTypeCheck(resOpt, this.inDocument, argument.value);
                        argumentIndex++;
                    }
                }
                for (const argument of this.arguments) {
                    rtsResult.setParameterValueFromArgument(trait, argument);
                }
            }
            // if an explicit verb is set, remember this. don't resolve that verb trait, cuz that sounds nuts.
            if (this.verb !== undefined) {
                rtsResult.setExplicitVerb(trait, this.verb);
            }
            // if a collection of meta traits exist, save on the resolved but don't resolve these. again, nuts
            if (this.appliedTraits !== undefined && this.appliedTraits.length > 0) {
                rtsResult.setMetaTraits(trait, this.appliedTraits.allItems);
            }
            // register set of possible symbols
            ctx.corpus.registerDefinitionReferenceSymbols(this.fetchObjectDefinition(resOpt), kind, resOpt.symbolRefSet);
            // merge child document set with current
            currSymRefSet.merge(resOpt.symbolRefSet);
            resOpt.symbolRefSet = currSymRefSet;
            return rtsResult;
        }
        // return p.measure(bodyCode);
    }
    /**
     * @internal
     */
    constructResolvedTraits(rtsb, resOpt) {
        // traits don't have traits.
    }
}
exports.CdmTraitReference = CdmTraitReference;
//# sourceMappingURL=CdmTraitReference.js.map