"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.CdmOperationIncludeAttributes = void 0;
const internal_1 = require("../../internal");
/**
 * Class to handle IncludeAttributes operations
 */
class CdmOperationIncludeAttributes extends internal_1.CdmOperationBase {
    constructor(ctx) {
        super(ctx);
        this.TAG = CdmOperationIncludeAttributes.name;
        this.objectType = internal_1.cdmObjectType.operationIncludeAttributesDef;
        this.type = internal_1.cdmOperationType.includeAttributes;
    }
    /**
     * @inheritdoc
     */
    copy(resOpt, host) {
        if (!resOpt) {
            resOpt = new internal_1.resolveOptions(this, this.ctx.corpus.defaultResolutionDirectives);
        }
        const copy = !host ? new CdmOperationIncludeAttributes(this.ctx) : host;
        copy.includeAttributes = this.includeAttributes ? this.includeAttributes.slice() : undefined;
        this.copyProj(resOpt, copy);
        return copy;
    }
    /**
     * @inheritdoc
     */
    getName() {
        return 'operationIncludeAttributes';
    }
    /**
     * @inheritdoc
     */
    getObjectType() {
        return internal_1.cdmObjectType.operationIncludeAttributesDef;
    }
    /**
     * @inheritdoc
     */
    validate() {
        const missingFields = [];
        if (!this.includeAttributes) {
            missingFields.push('includeAttributes');
        }
        if (missingFields.length > 0) {
            internal_1.Logger.error(this.ctx, this.TAG, this.validate.name, this.atCorpusPath, internal_1.cdmLogCode.ErrValdnIntegrityCheckFailure, this.atCorpusPath, 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 (postChildren && postChildren(this, path)) {
            return true;
        }
        return false;
    }
    /**
     * @inheritdoc
     * @internal
     */
    appendProjectionAttributeState(projCtx, projAttrStateSet, attrCtx) {
        // Create a new attribute context for the operation
        const attrCtxOpIncludeAttrsParam = {
            under: attrCtx,
            type: internal_1.cdmAttributeContextType.operationIncludeAttributes,
            name: `operation/index${this.index}/operationIncludeAttributes`
        };
        const attrCtxOpIncludeAttrs = internal_1.CdmAttributeContext.createChildUnder(projCtx.projectionDirective.resOpt, attrCtxOpIncludeAttrsParam);
        // Get the top-level attribute names for each of the included attributes
        // Since the include operation allows providing either current state resolved attribute names
        //   or the previous state resolved attribute names, we search for the name in the PAS tree
        //   and fetch the top level resolved attribute names.
        const topLevelIncludeAttributeNames = internal_1.ProjectionResolutionCommonUtil.getTopList(projCtx, this.includeAttributes);
        // Initialize a projection attribute context tree builder with the created attribute context for the operation
        const attrCtxTreeBuilder = new internal_1.ProjectionAttributeContextTreeBuilder(attrCtxOpIncludeAttrs);
        // Index that holds the current attribute name as the key and the attribute as value
        const topLevelIncludeAttribute = new Map();
        // List of attributes that were not included on the final attribute list
        const removedAttributes = [];
        // Iterate through all the PAS in the PASSet generated from the projection source's resolved attributes
        for (const currentPAS of projCtx.currentAttributeStateSet.states) {
            // Check if the current PAS's RA is in the list of attributes to include.
            if (topLevelIncludeAttributeNames.has(currentPAS.currentResolvedAttribute.resolvedName)) {
                topLevelIncludeAttribute.set(currentPAS.currentResolvedAttribute.resolvedName, currentPAS);
            }
            else {
                removedAttributes.push(currentPAS);
            }
        }
        for (const entry of topLevelIncludeAttributeNames) {
            // Get the attribute state
            const currentPAS = topLevelIncludeAttribute.get(entry[0]);
            // Get the attribute name the way it appears in the include list
            const includeAttributeName = entry[1];
            // Create the attribute context parameters and just store it in the builder for now
            // We will create the attribute contexts at the end
            attrCtxTreeBuilder.createAndStoreAttributeContextParameters(includeAttributeName, currentPAS, currentPAS.currentResolvedAttribute, internal_1.cdmAttributeContextType.attributeDefinition, currentPAS.currentResolvedAttribute.attCtx, // lineage is the included attribute
            undefined // don't know who will point here yet
            );
            // Create a projection attribute state for the included attribute by creating a copy of the current state
            // Copy() sets the current state as the previous state for the new one
            // We only create projection attribute states for attributes in the include list
            const newPAS = currentPAS.copy();
            projAttrStateSet.add(newPAS);
        }
        // Generate attribute context nodes for the attributes that were not included
        for (const currentPAS of removedAttributes) {
            // Create the attribute context parameters and just store it in the builder for now
            // We will create the attribute contexts at the end
            attrCtxTreeBuilder.createAndStoreAttributeContextParameters(undefined, currentPAS, currentPAS.currentResolvedAttribute, internal_1.cdmAttributeContextType.attributeExcluded, currentPAS.currentResolvedAttribute.attCtx, // lineage is the excluded attribute
            undefined // don't know who will point here, probably nobody, I mean, we got excluded
            );
        }
        // Create all the attribute contexts and construct the tree
        attrCtxTreeBuilder.constructAttributeContextTree(projCtx);
        return projAttrStateSet;
    }
}
exports.CdmOperationIncludeAttributes = CdmOperationIncludeAttributes;
//# sourceMappingURL=CdmOperationIncludeAttributes.js.map