"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.CdmParameterDefinition = void 0;
const internal_1 = require("../internal");
class CdmParameterDefinition extends internal_1.cdmObjectSimple {
    constructor(ctx, name) {
        super(ctx);
        this.TAG = CdmParameterDefinition.name;
        // let bodyCode = () =>
        {
            this.name = name;
            this.objectType = internal_1.cdmObjectType.parameterDef;
        }
        // return p.measure(bodyCode);
    }
    static get objectType() {
        return internal_1.cdmObjectType.parameterDef;
    }
    getObjectType() {
        // let bodyCode = () =>
        {
            return internal_1.cdmObjectType.parameterDef;
        }
        // return p.measure(bodyCode);
    }
    copy(resOpt, host) {
        // let bodyCode = () =>
        {
            if (!resOpt) {
                resOpt = new internal_1.resolveOptions(this, this.ctx.corpus.defaultResolutionDirectives);
            }
            let copy;
            if (!host) {
                copy = new CdmParameterDefinition(this.ctx, this.name);
            }
            else {
                copy = host;
                copy.ctx = this.ctx;
                copy.name = this.name;
            }
            let defVal;
            if (this.defaultValue) {
                if (typeof (this.defaultValue) === 'object' && 'copy' in this.defaultValue
                    && typeof (this.defaultValue.copy) === 'function') {
                    defVal = this.defaultValue.copy(resOpt);
                }
                else if (typeof (this.defaultValue) === 'object') {
                    defVal = Object.assign({}, this.defaultValue);
                }
                else {
                    defVal = this.defaultValue;
                }
            }
            copy.explanation = this.explanation;
            copy.defaultValue = defVal;
            copy.required = this.required;
            copy.dataTypeRef = this.dataTypeRef ? this.dataTypeRef.copy(resOpt) : undefined;
            return copy;
        }
        // return p.measure(bodyCode);
    }
    validate() {
        // let bodyCode = () =>
        {
            if (!this.name) {
                let missingFields = ['name'];
                internal_1.Logger.error(this.ctx, this.TAG, this.validate.name, this.atCorpusPath, internal_1.cdmLogCode.ErrValdnIntegrityCheckFailure, missingFields.map((s) => `'${s}'`).join(', '), this.atCorpusPath);
                return false;
            }
            return true;
        }
        // return p.measure(bodyCode);
    }
    getExplanation() {
        // let bodyCode = () =>
        {
            return this.explanation;
        }
        // return p.measure(bodyCode);
    }
    getName() {
        // let bodyCode = () =>
        {
            return this.name;
        }
        // return p.measure(bodyCode);
    }
    isDerivedFrom(baseDef, resOpt) {
        return false;
    }
    getDefaultValue() {
        // let bodyCode = () =>
        {
            return this.defaultValue;
        }
        // return p.measure(bodyCode);
    }
    getRequired() {
        // let bodyCode = () =>
        {
            return this.required;
        }
        // return p.measure(bodyCode);
    }
    /**
     * @internal
     */
    constTypeCheck(resOpt, wrtDoc, argumentValue) {
        // let bodyCode = () =>
        {
            const ctx = this.ctx;
            let replacement = argumentValue;
            // if parameter type is entity, then the value should be an entity or ref to one
            // same is true of 'dataType' dataType
            if (!this.dataTypeRef) {
                return replacement;
            }
            const dt = this.dataTypeRef.fetchObjectDefinition(resOpt);
            if (!dt) {
                internal_1.Logger.error(this.ctx, this.TAG, this.constTypeCheck.name, this.atCorpusPath, internal_1.cdmLogCode.ErrUnrecognizedDataType, this.name);
                return undefined;
            }
            // compare with passed in value or default for parameter
            let pValue = argumentValue;
            if (!pValue) {
                pValue = this.getDefaultValue();
                replacement = pValue;
            }
            if (pValue) {
                if (dt.isDerivedFrom('cdmObject', resOpt)) {
                    const expectedTypes = [];
                    let expected;
                    if (dt.isDerivedFrom('entity', resOpt)) {
                        expectedTypes.push(internal_1.cdmObjectType.constantEntityDef);
                        expectedTypes.push(internal_1.cdmObjectType.entityRef);
                        expectedTypes.push(internal_1.cdmObjectType.entityDef);
                        expectedTypes.push(internal_1.cdmObjectType.projectionDef);
                        expected = 'entity';
                    }
                    else if (dt.isDerivedFrom('attribute', resOpt)) {
                        expectedTypes.push(internal_1.cdmObjectType.attributeRef);
                        expectedTypes.push(internal_1.cdmObjectType.typeAttributeDef);
                        expectedTypes.push(internal_1.cdmObjectType.entityAttributeDef);
                        expected = 'attribute';
                    }
                    else if (dt.isDerivedFrom('dataType', resOpt)) {
                        expectedTypes.push(internal_1.cdmObjectType.dataTypeRef);
                        expectedTypes.push(internal_1.cdmObjectType.dataTypeDef);
                        expected = 'dataType';
                    }
                    else if (dt.isDerivedFrom('purpose', resOpt)) {
                        expectedTypes.push(internal_1.cdmObjectType.purposeRef);
                        expectedTypes.push(internal_1.cdmObjectType.purposeDef);
                        expected = 'purpose';
                    }
                    else if (dt.isDerivedFrom('trait', resOpt)) {
                        expectedTypes.push(internal_1.cdmObjectType.traitRef);
                        expectedTypes.push(internal_1.cdmObjectType.traitDef);
                        expected = 'trait';
                    }
                    else if (dt.isDerivedFrom('traitGroup', resOpt)) {
                        expectedTypes.push(internal_1.cdmObjectType.traitGroupRef);
                        expectedTypes.push(internal_1.cdmObjectType.traitGroupDef);
                        expected = 'traitGroup';
                    }
                    else if (dt.isDerivedFrom('attributeGroup', resOpt)) {
                        expectedTypes.push(internal_1.cdmObjectType.attributeGroupRef);
                        expectedTypes.push(internal_1.cdmObjectType.attributeGroupDef);
                        expected = 'attributeGroup';
                    }
                    if (expectedTypes.length === 0) {
                        internal_1.Logger.error(this.ctx, this.TAG, this.constTypeCheck.name, wrtDoc.atCorpusPath, internal_1.cdmLogCode.ErrUnexpectedDataType, this.getName());
                    }
                    // if a string constant, resolve to an object ref.
                    let foundType = internal_1.cdmObjectType.error;
                    if (typeof pValue === 'object' && 'objectType' in pValue) {
                        foundType = pValue.objectType;
                    }
                    let foundDesc = ctx.relativePath;
                    if (!(pValue instanceof internal_1.CdmObjectBase)) {
                        // pValue is a string or object
                        pValue = pValue;
                        if (pValue === 'this.attribute' && expected === 'attribute') {
                            // will get sorted out later when resolving traits
                            foundType = internal_1.cdmObjectType.attributeRef;
                        }
                        else {
                            foundDesc = pValue;
                            const seekResAtt = internal_1.CdmObjectReferenceBase.offsetAttributePromise(pValue);
                            if (seekResAtt >= 0) {
                                // get an object there that will get resolved later after resolved attributes
                                replacement = new internal_1.CdmAttributeReference(this.ctx, pValue, true);
                                replacement.inDocument = wrtDoc;
                                foundType = internal_1.cdmObjectType.attributeRef;
                            }
                            else {
                                const lu = ctx.corpus.resolveSymbolReference(resOpt, wrtDoc, pValue, internal_1.cdmObjectType.error, true);
                                if (lu) {
                                    if (expected === 'attribute') {
                                        replacement = new internal_1.CdmAttributeReference(this.ctx, pValue, true);
                                        replacement.inDocument = wrtDoc;
                                        foundType = internal_1.cdmObjectType.attributeRef;
                                    }
                                    else {
                                        replacement = lu;
                                        if (typeof replacement === 'object' && 'objectType' in replacement) {
                                            foundType = replacement.objectType;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (expectedTypes.indexOf(foundType) === -1) {
                        internal_1.Logger.error(this.ctx, this.TAG, this.constTypeCheck.name, wrtDoc.atCorpusPath, internal_1.cdmLogCode.ErrResolutionFailure, this.getName(), foundDesc, expected);
                    }
                    else {
                        internal_1.Logger.info(ctx, this.TAG, this.constTypeCheck.name, wrtDoc.atCorpusPath, `resolved '${foundDesc}'`);
                    }
                }
            }
            return replacement;
        }
        // return p.measure(bodyCode);
    }
    visit(pathFrom, preChildren, postChildren) {
        // let bodyCode = () =>
        {
            const path = this.fetchDeclaredPath(pathFrom);
            if (preChildren && preChildren(this, path)) {
                return false;
            }
            if (typeof (this.defaultValue) === 'object' && 'visit' in this.defaultValue
                && typeof (this.defaultValue.visit) === 'function') {
                if ((this.defaultValue).visit(`${path}/defaultValue/`, preChildren, postChildren)) {
                    return true;
                }
            }
            if (this.dataTypeRef) {
                if (this.dataTypeRef.visit(`${path}/dataType/`, preChildren, postChildren)) {
                    return true;
                }
            }
            if (postChildren && postChildren(this, path)) {
                return true;
            }
            return false;
        }
        // return p.measure(bodyCode);
    }
    /**
     * Given an initial path, returns this object's declared path
     * @internal
     */
    fetchDeclaredPath(pathFrom) {
        var _a;
        return (_a = pathFrom + this.getName()) !== null && _a !== void 0 ? _a : '';
    }
}
exports.CdmParameterDefinition = CdmParameterDefinition;
//# sourceMappingURL=CdmParameterDefinition.js.map