"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.CdmOperationReplaceAsForeignKey = void 0;
const internal_1 = require("../../internal");
/**
 * Class to handle ReplaceAsForeignKey operations
 */
class CdmOperationReplaceAsForeignKey extends internal_1.CdmOperationBase {
    constructor(ctx) {
        super(ctx);
        this.TAG = CdmOperationReplaceAsForeignKey.name;
        this.objectType = internal_1.cdmObjectType.operationReplaceAsForeignKeyDef;
        this.type = internal_1.cdmOperationType.replaceAsForeignKey;
    }
    /**
     * @inheritdoc
     */
    copy(resOpt, host) {
        if (!resOpt) {
            resOpt = new internal_1.resolveOptions(this, this.ctx.corpus.defaultResolutionDirectives);
        }
        const copy = !host ? new CdmOperationReplaceAsForeignKey(this.ctx) : host;
        copy.replaceWith = this.replaceWith ? this.replaceWith.copy(resOpt) : undefined;
        copy.reference = this.reference;
        this.copyProj(resOpt, copy);
        return copy;
    }
    /**
     * @inheritdoc
     */
    getName() {
        return 'operationReplaceAsForeignKey';
    }
    /**
     * @inheritdoc
     */
    getObjectType() {
        return internal_1.cdmObjectType.operationReplaceAsForeignKeyDef;
    }
    /**
     * @inheritdoc
     */
    validate() {
        const missingFields = [];
        if (!this.reference) {
            missingFields.push('reference');
        }
        if (!this.replaceWith) {
            missingFields.push('replaceWith');
        }
        if (missingFields.length > 0) {
            internal_1.Logger.error(this.ctx, this.TAG, this.validate.name, this.atCorpusPath, internal_1.cdmLogCode.ErrValdnIntegrityCheckFailure, missingFields.map((s) => `'${s}'`).join(', '));
            return false;
        }
        return true;
    }
    /**
     * @inheritdoc
     */
    visit(pathFrom, preChildren, postChildren) {
        const path = this.fetchDeclaredPath(pathFrom);
        if (preChildren && preChildren(this, path)) {
            return false;
        }
        if (this.replaceWith) {
            if (this.replaceWith.visit(pathFrom + 'foreignKeyAttribute/', preChildren, postChildren)) {
                return true;
            }
        }
        if (postChildren && postChildren(this, path)) {
            return true;
        }
        return false;
    }
    /**
     * @inheritdoc
     * @internal
     */
    appendProjectionAttributeState(projCtx, projOutputSet, attrCtx) {
        // Create new attribute context for the operation
        const attrCtxOpFKParam = {
            under: attrCtx,
            type: internal_1.cdmAttributeContextType.operationReplaceAsForeignKey,
            name: `operation/index${this.index}/operationReplaceAsForeignKey`
        };
        const attrCtxOpFK = internal_1.CdmAttributeContext.createChildUnder(projCtx.projectionDirective.resOpt, attrCtxOpFKParam);
        // Create new attribute context for the AddedAttributeIdentity
        const attrCtxFKParam = {
            under: attrCtxOpFK,
            type: internal_1.cdmAttributeContextType.addedAttributeIdentity,
            name: '_foreignKey'
        };
        const attrCtxFK = internal_1.CdmAttributeContext.createChildUnder(projCtx.projectionDirective.resOpt, attrCtxFKParam);
        // get the added attribute and applied trait
        const subFK = this.replaceWith;
        const addTrait = ['is.linkedEntity.identifier'];
        // Create new resolved attribute, set the new attribute as target, and apply "is.linkedEntity.identifier" trait
        const resAttrNewFK = internal_1.CdmOperationBase.createNewResolvedAttribute(projCtx, attrCtxFK, subFK, undefined, addTrait);
        const outputFromOpPasSet = CdmOperationReplaceAsForeignKey.createNewProjectionAttributeStateSet(projCtx, projOutputSet, resAttrNewFK, this.reference);
        return outputFromOpPasSet;
    }
    static createNewProjectionAttributeStateSet(projCtx, projOutputSet, newResAttrFK, refAttrName) {
        const pasList = internal_1.ProjectionResolutionCommonUtil.getLeafList(projCtx, refAttrName);
        const sourceEntity = projCtx.projectionDirective.originalSourceAttributeName;
        if (!sourceEntity) {
            internal_1.Logger.warning(projOutputSet.ctx, CdmOperationReplaceAsForeignKey.name, this.createNewProjectionAttributeStateSet.name, null, internal_1.cdmLogCode.WarnProjFKWithoutSourceEntity, refAttrName);
        }
        if (pasList) {
            // update the new foreign key resolved attribute with trait param with reference details
            const reqdTrait = newResAttrFK.resolvedTraits.find(projCtx.projectionDirective.resOpt, 'is.linkedEntity.identifier');
            if (reqdTrait && sourceEntity) {
                const traitParamEntRef = internal_1.ProjectionResolutionCommonUtil.createForeignKeyLinkedEntityIdentifierTraitParameter(projCtx.projectionDirective, projOutputSet.ctx.corpus, pasList);
                reqdTrait.parameterValues.setParameterValue(projCtx.projectionDirective.resOpt, 'entityReferences', traitParamEntRef);
            }
            // Create new output projection attribute state set for FK and add prevPas as previous state set
            const newProjAttrStateFK = new internal_1.ProjectionAttributeState(projOutputSet.ctx);
            newProjAttrStateFK.currentResolvedAttribute = newResAttrFK;
            newProjAttrStateFK.previousStateList = pasList;
            projOutputSet.add(newProjAttrStateFK);
        }
        else {
            // Log error & return projOutputSet without any change
            internal_1.Logger.error(projOutputSet.ctx, CdmOperationReplaceAsForeignKey.name, this.createNewProjectionAttributeStateSet.name, null, internal_1.cdmLogCode.ErrProjRefAttrStateFailure, refAttrName);
        }
        return projOutputSet;
    }
}
exports.CdmOperationReplaceAsForeignKey = CdmOperationReplaceAsForeignKey;
//# sourceMappingURL=CdmOperationReplaceAsForeignKey.js.map