"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AttributeContextUtil = void 0;
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
const fs = require("fs");
const os_1 = require("os");
const internal_1 = require("../../../internal");
const testHelper_1 = require("../../testHelper");
/**
 * Multiple test classes in projections test the attribute context tree generated for various scenarios.
 * This utility class helps generate the actual attribute context generated by the scenario, so that it can be compared with expected attribute context tree.
 * This also handles the validation of the expected vs. actual attribute context.
 */
class AttributeContextUtil {
    constructor() {
        /**
         * This string is used to concatenate all the attribute contexts and traits of an entity into one string
         * so that we can compare it to the expected output txt file.
         */
        this.bldr = '';
        /**
         * Platform-specific line separator
         */
        this.endOfLine = os_1.EOL;
    }
    /**
     * Function to get the attribute context string tree from a resolved entity
     */
    getAttributeContextStrings(resolvedEntity) {
        // clear the string builder
        this.bldr = '';
        // get the corpus path for each attribute context in the tree
        this.getContentDeclaredPath(resolvedEntity.attributeContext);
        // get the traits for all the attributes of a resolved entity
        this.getTraits(resolvedEntity.attributes);
        return this.bldr;
    }
    getArgumentValuesAsString(args) {
        // clear the string builder
        this.bldr = '';
        this.getArgumentValues(args);
        return this.bldr;
    }
    /**
     * Get the corpus path for each attribute context in the tree and build a string collection that we can
     * compare with the expected attribute context corpus path collection.
     */
    getContentDeclaredPath(attribContext) {
        if (attribContext && attribContext.contents && attribContext.contents.length > 0) {
            for (let i = 0; i < attribContext.contents.length; i++) {
                let str = '';
                if ((attribContext.contents.allItems[i] instanceof internal_1.CdmAttributeReference)) {
                    const ar = attribContext.contents.allItems[i];
                    str = ar.atCorpusPath;
                    this.bldr += str;
                    this.bldr += this.endOfLine;
                }
                else {
                    const ac = attribContext.contents.allItems[i];
                    str = ac.atCorpusPath;
                    this.bldr += str;
                    this.bldr += this.endOfLine;
                    this.getContentDeclaredPath(ac);
                }
            }
        }
    }
    /**
     * Get the traits for all the attributes of a resolved entity
     */
    getTraits(attributes) {
        for (const attrib of attributes) {
            const attribCorpusPath = attrib.atCorpusPath;
            this.bldr += attribCorpusPath;
            this.bldr += this.endOfLine;
            if (attrib instanceof internal_1.CdmAttributeGroupReference) {
                const attGroupDef = attrib.explicitReference;
                this.bldr += attGroupDef.atCorpusPath;
                this.bldr += this.endOfLine;
                this.getTraitCollection(attGroupDef.exhibitsTraits);
                this.getTraits(attGroupDef.members);
            }
            else {
                this.getTraitCollection(attrib.appliedTraits);
            }
        }
    }
    getTraitCollection(traitCollection) {
        for (const trait of traitCollection) {
            const attribTraits = trait.namedReference;
            this.bldr += attribTraits;
            this.bldr += this.endOfLine;
            if (trait instanceof internal_1.CdmTraitReference) {
                for (const args of trait.arguments) {
                    this.getArgumentValues(args);
                }
            }
        }
    }
    getArgumentValues(args) {
        var _a, _b, _c, _d;
        const paramName = (_a = args.resolvedParameter) === null || _a === void 0 ? void 0 : _a.name;
        const paramDefaultValue = (_b = args.resolvedParameter) === null || _b === void 0 ? void 0 : _b.defaultValue;
        if (paramName || paramDefaultValue) {
            this.bldr += `  [Parameter (Name / DefaultValue): ${paramName ? paramName : ''} / ${paramDefaultValue ? paramDefaultValue : ''}]`;
            this.bldr += this.endOfLine;
        }
        if (typeof args.value === 'string') {
            const argsValue = args.value;
            if (argsValue) {
                this.bldr += `  [Argument Value: ${argsValue}]`;
                this.bldr += this.endOfLine;
            }
        }
        else if (((_c = args.value) === null || _c === void 0 ? void 0 : _c.simpleNamedReference) === true) {
            const argsValue = args.value.namedReference;
            if (argsValue) {
                this.bldr += `  [Argument Value: ${argsValue}]`;
                this.bldr += this.endOfLine;
            }
        }
        else if (((_d = args.value) === null || _d === void 0 ? void 0 : _d.explicitReference.objectType) === internal_1.cdmObjectType.constantEntityDef) {
            const constEnt = args.value.explicitReference;
            if (constEnt) {
                const refs = [];
                for (const val of constEnt.constantValues) {
                    this.bldr += `  [Argument Value: ${val.join(',')}]`;
                    this.bldr += this.endOfLine;
                }
            }
        }
    }
    /**
     * A function to validate if the attribute context tree & traits generated for a resolved entity is the same as the expected and
     * saved attribute context tree & traits for a test case
     */
    static validateAttributeContext(expectedOutputPath, entityName, resolvedEntity, updateExpectedOutput = false) {
        return __awaiter(this, void 0, void 0, function* () {
            if (resolvedEntity.attributeContext) {
                // Actual
                const actualStringFilePath = `${expectedOutputPath.replace('ExpectedOutput', testHelper_1.testHelper.getTestActualOutputFolderName())}/AttrCtx_${entityName}.txt`;
                // Save Actual AttrCtx_*.txt and Resolved_*.cdm.json
                const attrCtxUtil = new AttributeContextUtil();
                const actualText = attrCtxUtil.getAttributeContextStrings(resolvedEntity);
                fs.writeFileSync(actualStringFilePath, actualText);
                yield resolvedEntity.inDocument.saveAsAsync(`Resolved_${entityName}.cdm.json`, false);
                // Expected
                const expectedStringFilePath = `${expectedOutputPath}/AttrCtx_${entityName}.txt`;
                if (updateExpectedOutput) {
                    fs.writeFileSync(expectedStringFilePath, actualText);
                }
                const expectedText = fs.readFileSync(expectedStringFilePath).toString();
                // Test if Actual is Equal to Expected
                expect(actualText)
                    .toEqual(expectedText);
            }
        });
    }
}
exports.AttributeContextUtil = AttributeContextUtil;
//# sourceMappingURL=AttributeContextUtil.js.map