"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
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.CdmManifestDefinition = void 0;
const timeUtils = require("../Utilities/timeUtils");
const internal_1 = require("../internal");
const cdmObjectTypeGuards_1 = require("../Utilities/cdmObjectTypeGuards");
const Logger_1 = require("../Utilities/Logging/Logger");
const using_statement_1 = require("using-statement");
class CdmManifestDefinition extends internal_1.CdmDocumentDefinition {
    constructor(ctx, name) {
        super(ctx, `${name}.manifest.cdm.json`);
        this._TAG = CdmManifestDefinition.name;
        this.objectType = internal_1.cdmObjectType.manifestDef;
        this.manifestName = name;
        this.subManifests = new internal_1.CdmCollection(this.ctx, this, internal_1.cdmObjectType.manifestDeclarationDef);
        this.entities = new internal_1.CdmEntityCollection(this.ctx, this);
        this.relationships = new internal_1.CdmCollection(this.ctx, this, internal_1.cdmObjectType.e2eRelationshipDef);
        this.exhibitsTraits = new internal_1.CdmTraitCollection(this.ctx, this);
    }
    static get objectType() {
        return internal_1.cdmObjectType.manifestDef;
    }
    getExplanation() {
        return this.explanation;
    }
    setExplanation(explanation) {
        this.explanation = explanation;
        return this.explanation;
    }
    isDerivedFrom(base, resOpt) {
        return false;
    }
    /**
     * @internal
     */
    getObjectPath() {
        return this.atCorpusPath;
    }
    visit(pathFrom, preChildren, postChildren) {
        if (preChildren && preChildren(this, pathFrom)) {
            return false;
        }
        if (this.imports) {
            if (this.imports.visitArray(pathFrom, preChildren, postChildren)) {
                return true;
            }
        }
        if (this.definitions) {
            if (this.definitions.visitArray(pathFrom, preChildren, postChildren)) {
                return true;
            }
        }
        if (this.entities) {
            if (this.entities.visitArray(pathFrom, preChildren, postChildren)) {
                return true;
            }
        }
        if (this.relationships) {
            if (this.relationships.visitArray(`${pathFrom}/relationships/`, preChildren, postChildren)) {
                return true;
            }
        }
        if (this.subManifests) {
            if (this.subManifests.visitArray(`${pathFrom}/subManifests/`, preChildren, postChildren)) {
                return true;
            }
        }
        if (postChildren && postChildren(this, pathFrom)) {
            return true;
        }
        return false;
    }
    copy(resOpt, host) {
        // since we need to call the base copy which will only return a document when there is no host, make a fake host here
        const tempHost = host instanceof CdmManifestDefinition ? host : new CdmManifestDefinition(this.ctx, this.manifestName);
        const copy = super.copy(resOpt, tempHost);
        copy.manifestName = this.manifestName;
        copy.explanation = this.explanation;
        copy.lastFileStatusCheckTime = this.lastFileStatusCheckTime;
        copy.lastFileModifiedTime = this.lastFileModifiedTime;
        copy.lastChildFileModifiedTime = this.lastChildFileModifiedTime;
        copy.entities.clear();
        for (const ent of this.entities) {
            copy.entities.push(ent.copy(resOpt));
        }
        copy.relationships.clear();
        for (const rel of this.relationships) {
            copy.relationships.push(rel.copy(resOpt));
        }
        copy.subManifests.clear();
        for (const man of this.subManifests) {
            copy.subManifests.push(man.copy(resOpt));
        }
        copy.exhibitsTraits.clear();
        for (const et of this.exhibitsTraits) {
            copy.exhibitsTraits.push(et.copy(resOpt));
        }
        return copy;
    }
    /**
     * creates a resolved copy of the manifest.
     * newEntityDocumentNameFormat specifies a pattern to use when creating documents for resolved entites
     * the default is "{f}resolved/{n}.cdm.json" to avoid a document name conflict with documents in the same
     * folder as the manifest. every instance of the string {n} is replaced with the entity name from the source manifest
     * every instance of the string {f} is replaced with the folder path from the source manifest to the source entity
     * (if there is one that is possible as a relative location, else nothing)
     */
    createResolvedManifestAsync(newManifestName, newEntityDocumentNameFormat, directives) {
        return __awaiter(this, void 0, void 0, function* () {
            return yield using_statement_1.using(Logger_1.enterScope(CdmManifestDefinition.name, this.ctx, this.createResolvedManifestAsync.name), (_) => __awaiter(this, void 0, void 0, function* () {
                if (!this.entities) {
                    return undefined;
                }
                if (!this.owner) {
                    internal_1.Logger.error(this.ctx, this._TAG, this.createResolvedManifestAsync.name, this.atCorpusPath, internal_1.cdmLogCode.ErrResolveManifestFailed, this.manifestName);
                    return undefined;
                }
                if (newEntityDocumentNameFormat == undefined) {
                    newEntityDocumentNameFormat = '{f}resolved/{n}.cdm.json';
                }
                else if (newEntityDocumentNameFormat === '') { // for back compat
                    newEntityDocumentNameFormat = '{n}.cdm.json';
                }
                else if (newEntityDocumentNameFormat.search('{n}') === -1) { // for back compat
                    newEntityDocumentNameFormat = `${newEntityDocumentNameFormat}/{n}.cdm.json`;
                }
                const sourceManifestPath = this.ctx.corpus.storage.createAbsoluteCorpusPath(this.atCorpusPath, this);
                const sourceManifestFolderPath = this.ctx.corpus.storage.createAbsoluteCorpusPath(this.owner.atCorpusPath, this);
                const resolvedManifestPathSplit = newManifestName.lastIndexOf('/') + 1;
                let resolvedManifestFolder;
                if (resolvedManifestPathSplit > 0) {
                    const resolvedManifestPath = newManifestName.substring(0, resolvedManifestPathSplit);
                    const newFolderPath = this.ctx.corpus.storage.createAbsoluteCorpusPath(resolvedManifestPath, this);
                    resolvedManifestFolder = yield this.ctx.corpus.fetchObjectAsync(newFolderPath);
                    if (!resolvedManifestFolder) {
                        internal_1.Logger.error(this.ctx, this._TAG, this.createResolvedManifestAsync.name, this.atCorpusPath, internal_1.cdmLogCode.ErrResolveFolderNotFound, newFolderPath);
                        return undefined;
                    }
                    newManifestName = newManifestName.substr(resolvedManifestPathSplit, newManifestName.length - resolvedManifestPathSplit);
                }
                else {
                    resolvedManifestFolder = this.owner;
                }
                if (resolvedManifestFolder.documents.item(newManifestName) !== undefined) {
                    internal_1.Logger.error(this.ctx, this._TAG, this.createResolvedManifestAsync.name, this.atCorpusPath, internal_1.cdmLogCode.ErrResolveManifestExists, newManifestName, resolvedManifestFolder.atCorpusPath);
                    return undefined;
                }
                internal_1.Logger.debug(this.ctx, this._TAG, this.createResolvedManifestAsync.name, this.atCorpusPath, `resolving manifest ${this.manifestName}`);
                // Using the references present in the resolved entities, get an entity
                // create an imports doc with all the necessary resolved entity references and then resolve it
                // sometimes they might send the docname, that makes sense a bit, don't include the suffix in the name
                if (newManifestName.toLowerCase().endsWith('.manifest.cdm.json')) {
                    newManifestName = newManifestName.substring(0, newManifestName.length - '.manifest.cdm.json'.length);
                }
                const resolvedManifest = new CdmManifestDefinition(this.ctx, newManifestName);
                // bring over any imports in this document or other bobbles
                resolvedManifest.schema = this.schema;
                resolvedManifest.explanation = this.explanation;
                resolvedManifest.documentVersion = this.documentVersion;
                for (const imp of this.imports) {
                    resolvedManifest.imports.push(imp.copy());
                }
                // add the new document to the folder
                if (resolvedManifestFolder.documents.push(resolvedManifest) === undefined) {
                    // when would this happen?
                    return undefined;
                }
                for (const entity of this.entities) {
                    const entityPath = yield this.getEntityPathFromDeclaration(entity, this);
                    const entDef = yield this.ctx.corpus.fetchObjectAsync(entityPath);
                    if (entDef === undefined) {
                        internal_1.Logger.error(this.ctx, this._TAG, this.createResolvedManifestAsync.name, this.atCorpusPath, internal_1.cdmLogCode.ErrResolveEntityFailure, entityPath);
                        return undefined;
                    }
                    if (!entDef.inDocument.owner) {
                        internal_1.Logger.error(this.ctx, this._TAG, this.createResolvedManifestAsync.name, this.atCorpusPath, internal_1.cdmLogCode.ErrDocIsNotFolder, entDef.entityName);
                        return undefined;
                    }
                    // get the path from this manifest to the source entity. This will be the {f} replacement value
                    const sourceEntityFullPath = this.ctx.corpus.storage.createAbsoluteCorpusPath(entDef.inDocument.owner.atCorpusPath, this);
                    let f = '';
                    if (sourceEntityFullPath.startsWith(sourceManifestFolderPath)) {
                        f = sourceEntityFullPath.substr(sourceManifestFolderPath.length, sourceEntityFullPath.length - sourceManifestFolderPath.length);
                    }
                    let newDocumentFullPath = newEntityDocumentNameFormat.replace('{n}', entDef.entityName);
                    newDocumentFullPath = newDocumentFullPath.replace('{f}', f);
                    newDocumentFullPath = this.ctx.corpus.storage.createAbsoluteCorpusPath(newDocumentFullPath, this);
                    const newDocumentPathSplit = newDocumentFullPath.lastIndexOf('/') + 1;
                    const newDocumentPath = newDocumentFullPath.slice(0, newDocumentPathSplit);
                    const newDocumentName = newDocumentFullPath.substr(newDocumentPathSplit);
                    // make sure the new folder exists
                    const folder = yield this.ctx.corpus.fetchObjectAsync(newDocumentPath);
                    if (folder === undefined) {
                        internal_1.Logger.error(this.ctx, this._TAG, this.createResolvedManifestAsync.name, this.atCorpusPath, internal_1.cdmLogCode.ErrResolveFolderNotFound, newDocumentPath);
                        return undefined;
                    }
                    // Next create the resolved entity
                    const withDirectives = directives !== undefined ? directives :
                        this.ctx.corpus.defaultResolutionDirectives;
                    const resOpt = new internal_1.resolveOptions(entDef.inDocument, withDirectives === null || withDirectives === void 0 ? void 0 : withDirectives.copy());
                    internal_1.Logger.debug(this.ctx, this._TAG, this.createResolvedManifestAsync.name, this.atCorpusPath, `resolving entity ${sourceEntityFullPath} to document ${newDocumentFullPath}`);
                    const resolvedEntity = yield entDef.createResolvedEntityAsync(entDef.entityName, resOpt, folder, newDocumentName);
                    if (resolvedEntity === undefined) {
                        // Fail all resolution, if any one entity resolution fails
                        return undefined;
                    }
                    const result = entity.copy(resOpt);
                    if (result.objectType === internal_1.cdmObjectType.localEntityDeclarationDef) {
                        result.entityPath =
                            this.ctx.corpus.storage.createRelativeCorpusPath(resolvedEntity.atCorpusPath, resolvedManifest)
                                || result.atCorpusPath;
                    }
                    resolvedManifest.entities.push(result);
                }
                internal_1.Logger.debug(this.ctx, this._TAG, this.createResolvedManifestAsync.name, this.atCorpusPath, `calculating relationships`);
                // calculate the entity graph for this manifest and any submanifests
                yield this.ctx.corpus.calculateEntityGraphAsync(resolvedManifest);
                // stick results into the relationships list for the manifest
                // only put in relationships that are between the entities that are used in the manifest
                yield resolvedManifest.populateManifestRelationshipsAsync(internal_1.cdmRelationshipDiscoveryStyle.exclusive);
                // needed until Matt's changes with collections where I can propigate
                resolvedManifest.isDirty = true;
                return resolvedManifest;
            }));
        });
    }
    populateManifestRelationshipsAsync(option = internal_1.cdmRelationshipDiscoveryStyle.all) {
        return __awaiter(this, void 0, void 0, function* () {
            return yield using_statement_1.using(Logger_1.enterScope(CdmManifestDefinition.name, this.ctx, this.populateManifestRelationshipsAsync.name), (_) => __awaiter(this, void 0, void 0, function* () {
                this.relationships.clear();
                const relCache = new Set();
                if (this.entities !== undefined) {
                    // Indexes on this manifest before calling `AddElevatedTraitsAndRelationships`
                    // and calls `RefreshAsync` after adding all imports and traits to relationships
                    const outResOpt = new internal_1.resolveOptions(this);
                    this.indexIfNeeded(outResOpt, true);
                    for (const entDec of this.entities) {
                        const entPath = yield this.getEntityPathFromDeclaration(entDec, this);
                        const currEntity = yield this.ctx.corpus.fetchObjectAsync(entPath);
                        if (!currEntity) {
                            continue;
                        }
                        // handle the outgoing relationships
                        const outgoingRels = this.ctx.corpus.fetchOutgoingRelationships(currEntity);
                        if (outgoingRels) {
                            for (const rel of outgoingRels) {
                                const cacheKey = rel.createCacheKey();
                                if (!relCache.has(cacheKey) && this.isRelAllowed(rel, option)) {
                                    yield this.addElevatedTraitsAndRelationships(rel);
                                    relCache.add(cacheKey);
                                }
                            }
                        }
                        const incomingRels = (this.ctx.corpus).fetchIncomingRelationships(currEntity);
                        if (incomingRels) {
                            for (const inRel of incomingRels) {
                                // get entity object for current toEntity
                                let currentInBase = yield this.ctx.corpus.fetchObjectAsync(inRel.toEntity, this);
                                if (!currentInBase) {
                                    continue;
                                }
                                // create graph of inheritance for to currentInBase
                                // graph represented by an array where entity at i extends entity at i+1
                                const toInheritanceGraph = [];
                                while (currentInBase) {
                                    const resOpt = new internal_1.resolveOptions(currentInBase.inDocument);
                                    currentInBase = currentInBase.extendsEntity ? currentInBase.extendsEntity.fetchObjectDefinition(resOpt) : undefined;
                                    if (currentInBase) {
                                        toInheritanceGraph.push(currentInBase);
                                    }
                                }
                                // add current incoming relationship
                                const cacheKey = inRel.createCacheKey();
                                if (!relCache.has(cacheKey) && this.isRelAllowed(inRel, option)) {
                                    yield this.addElevatedTraitsAndRelationships(inRel);
                                    relCache.add(cacheKey);
                                }
                                // if A points at B, A's base classes must point at B as well
                                for (const baseEntity of toInheritanceGraph) {
                                    const incomingRelsForBase = this.ctx.corpus.fetchIncomingRelationships(baseEntity);
                                    if (incomingRelsForBase) {
                                        for (const inRelBase of incomingRelsForBase) {
                                            const newRel = new internal_1.CdmE2ERelationship(this.ctx, '');
                                            newRel.fromEntity = inRelBase.fromEntity;
                                            newRel.fromEntityAttribute = inRelBase.fromEntityAttribute;
                                            newRel.toEntity = inRel.toEntity;
                                            newRel.toEntityAttribute = inRel.toEntityAttribute;
                                            const baseRelCacheKey = newRel.createCacheKey();
                                            if (!relCache.has(baseRelCacheKey) && this.isRelAllowed(newRel, option)) {
                                                yield this.addElevatedTraitsAndRelationships(newRel);
                                                relCache.add(baseRelCacheKey);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // Calls RefreshAsync on this manifest to resolve purpose traits in relationships
                    // after adding all imports and traits by calling `AddElevatedTraitsAndRelationships`
                    this.refreshAsync(outResOpt);
                }
                if (this.subManifests !== undefined) {
                    for (const subManifestDef of this.subManifests) {
                        const corpusPath = this.ctx.corpus.storage.createAbsoluteCorpusPath(subManifestDef.definition, this);
                        const subManifest = yield this.ctx.corpus.fetchObjectAsync(corpusPath);
                        yield subManifest.populateManifestRelationshipsAsync(option);
                    }
                }
            }));
        });
    }
    /**
     * @inheritdoc
     */
    fileStatusCheckAsync(partitionCheckType = internal_1.partitionFileStatusCheckType.Full, incrementalType = internal_1.cdmIncrementalPartitionType.None) {
        return __awaiter(this, void 0, void 0, function* () {
            return yield using_statement_1.using(Logger_1.enterScope(CdmManifestDefinition.name, this.ctx, this.fileStatusCheckAsync.name), (_) => __awaiter(this, void 0, void 0, function* () {
                let adapter = this.ctx.corpus.storage.fetchAdapter(this.inDocument.namespace);
                let cacheContext = (adapter != null) ? adapter.createFileQueryCacheContext() : null;
                try {
                    const modifiedTime = yield (this.ctx.corpus).getLastModifiedTimeFromObjectAsync(this);
                    this.lastFileStatusCheckTime = new Date();
                    if (!this.lastFileModifiedTime) {
                        this.lastFileModifiedTime = this._fileSystemModifiedTime;
                    }
                    // reload the manifest if it has been updated in the file system
                    if (modifiedTime && this._fileSystemModifiedTime && modifiedTime.getTime() !== this._fileSystemModifiedTime.getTime()) {
                        yield this.reload();
                        this.lastFileModifiedTime = timeUtils.maxTime(modifiedTime, this.lastFileModifiedTime);
                        this._fileSystemModifiedTime = this.lastFileModifiedTime;
                    }
                    for (const entity of this.entities) {
                        if (cdmObjectTypeGuards_1.isReferencedEntityDeclarationDefinition(entity)) {
                            yield entity.fileStatusCheckAsync();
                        }
                        else if (cdmObjectTypeGuards_1.isLocalEntityDeclarationDefinition(entity)) {
                            yield entity.fileStatusCheckAsync(partitionCheckType, incrementalType);
                        }
                    }
                    for (const subManifest of this.subManifests) {
                        yield subManifest.fileStatusCheckAsync();
                    }
                }
                finally {
                    if (cacheContext != null) {
                        cacheContext.dispose();
                    }
                }
            }));
        });
    }
    /**
     * @inheritdoc
     */
    reportMostRecentTimeAsync(childTime) {
        return __awaiter(this, void 0, void 0, function* () {
            if (childTime) {
                this.lastChildFileModifiedTime = timeUtils.maxTime(childTime, this.lastChildFileModifiedTime);
            }
        });
    }
    /**
     * @internal
     * Helper that fixes a path from local to absolute, gets the object from that path
     * then looks at the document where the object is found.
     * If dirty, the document is saved with the original name.
     */
    saveDirtyLink(relative, options) {
        return __awaiter(this, void 0, void 0, function* () {
            // get the document object from the import
            const docPath = this.ctx.corpus.storage.createAbsoluteCorpusPath(relative, this);
            if (!docPath) {
                internal_1.Logger.error(this.ctx, this._TAG, this.saveDirtyLink.name, this.atCorpusPath, internal_1.cdmLogCode.ErrValdnInvalidCorpusPath, relative);
                return false;
            }
            const objAt = yield this.ctx.corpus.fetchObjectAsync(docPath);
            if (!objAt) {
                internal_1.Logger.error(this.ctx, this._TAG, this.saveDirtyLink.name, this.atCorpusPath, internal_1.cdmLogCode.ErrPersistObjectNotFound, docPath);
                return false;
            }
            const docImp = objAt.inDocument;
            if (docImp !== undefined) {
                if (docImp.isDirty) {
                    // save it with the same name
                    if ((yield docImp.saveAsAsync(docImp.name, true, options)) === false) {
                        internal_1.Logger.error(this.ctx, this._TAG, this.saveDirtyLink.name, docImp.atCorpusPath, internal_1.cdmLogCode.ErrDocEntityDocSavingFailure, docImp.name);
                    }
                }
            }
            return true;
        });
    }
    /**
     * @internal
     * Helper that fixes a path from local to absolute.Gets the object from that path.
     * Created from saveDirtyLink in order to be able to save docs in parallel.
     * Represents the part of saveDirtyLink that could not be parallelized.
     */
    fetchDocumentDefinition(relativePath) {
        return __awaiter(this, void 0, void 0, function* () {
            // get the document object from the import
            const docPath = this.ctx.corpus.storage.createAbsoluteCorpusPath(relativePath, this);
            if (!docPath) {
                internal_1.Logger.error(this.ctx, this._TAG, this.fetchDocumentDefinition.name, this.atCorpusPath, internal_1.cdmLogCode.ErrValdnInvalidCorpusPath, relativePath);
                return undefined;
            }
            const resOpt = new internal_1.resolveOptions();
            resOpt.importsLoadStrategy = internal_1.importsLoadStrategy.load;
            const objAt = yield this.ctx.corpus.fetchObjectAsync(relativePath, this, resOpt);
            if (!objAt) {
                internal_1.Logger.error(this.ctx, this._TAG, this.fetchDocumentDefinition.name, this.atCorpusPath, internal_1.cdmLogCode.ErrPersistObjectNotFound, docPath);
                return undefined;
            }
            return objAt.inDocument;
        });
    }
    /**
     * @internal
     * Saves CdmDocumentDefinition if dirty.
     * Was created from SaveDirtyLink in order to be able to save docs in parallel.
     * Represents the part of SaveDirtyLink that could be parallelized.
     */
    saveDocumentIfDirty(docImp, options) {
        return __awaiter(this, void 0, void 0, function* () {
            // get the document object from the import
            if (docImp !== undefined && docImp.isDirty) {
                // save it with the same name
                if ((yield docImp.saveAsAsync(docImp.name, true, options)) === false) {
                    internal_1.Logger.error(this.ctx, this._TAG, this.saveDocumentIfDirty.name, docImp.atCorpusPath, internal_1.cdmLogCode.ErrDocEntityDocSavingFailure, docImp.name);
                    return false;
                }
            }
            return true;
        });
    }
    /**
     * @internal
     */
    saveLinkedDocuments(options) {
        return __awaiter(this, void 0, void 0, function* () {
            let links = new Set();
            if (!options) {
                options = new internal_1.copyOptions();
            }
            if (this.imports !== undefined) {
                for (const imp of this.imports) {
                    links.add(imp.corpusPath);
                }
            }
            if (this.entities !== undefined) {
                // only the local entity declarations please
                for (const def of this.entities) {
                    if (cdmObjectTypeGuards_1.isLocalEntityDeclarationDefinition(def)) {
                        const defImp = def;
                        links.add(defImp.entityPath);
                        // also, partitions can have their own schemas
                        if (defImp.dataPartitions !== undefined) {
                            for (const part of defImp.dataPartitions) {
                                if (part.specializedSchema !== undefined) {
                                    links.add(part.specializedSchema);
                                }
                            }
                        }
                        // so can patterns
                        if (defImp.dataPartitionPatterns !== undefined) {
                            for (const part of defImp.dataPartitionPatterns) {
                                if (part.specializedSchema !== undefined) {
                                    links.add(part.specializedSchema);
                                }
                            }
                        }
                    }
                }
            }
            const docs = [];
            for (var link of links) {
                const doc = yield this.fetchDocumentDefinition(link);
                if (!doc) {
                    return false;
                }
                docs.push(doc);
            }
            yield Promise.all(docs.map((doc) => __awaiter(this, void 0, void 0, function* () {
                if (doc) {
                    if (!(yield this.saveDocumentIfDirty(doc, options))) {
                        return false;
                    }
                }
            })));
            if (this.subManifests !== undefined) {
                for (const subDeclaration of this.subManifests) {
                    const subManifest = yield this.fetchDocumentDefinition(subDeclaration.definition);
                    if (!subManifest || !(yield this.saveDocumentIfDirty(subManifest, options))) {
                        return false;
                    }
                }
            }
            return true;
        });
    }
    /**
     * @internal
     */
    getEntityPathFromDeclaration(entityDec, obj) {
        return __awaiter(this, void 0, void 0, function* () {
            // keep following referenceEntityDeclaration paths until a LocalentityDeclaration is hit
            while (cdmObjectTypeGuards_1.isReferencedEntityDeclarationDefinition(entityDec)) {
                const currCorpusPath = this.ctx.corpus.storage.createAbsoluteCorpusPath(entityDec.entityPath, obj);
                entityDec = yield this.ctx.corpus.fetchObjectAsync(currCorpusPath);
                if (!entityDec) {
                    return undefined;
                }
                obj = entityDec.inDocument;
            }
            return entityDec ?
                this.ctx.corpus.storage.createAbsoluteCorpusPath(entityDec.entityPath, obj)
                : undefined;
        });
    }
    /**
     * Query the manifest for a set of entities that match an input query
     * querySpec = a JSON object (or a string that can be parsed into one) of the form
     * {"entityName":"", "attributes":[{see QueryOnTraits for CdmEntityDefinition for details}]}
     * returns null for 0 results or an array of json objects, each matching the shape of the input query,
     * with entity and attribute names filled in
     */
    queryOnTraitsAsync(querySpec) {
        return __awaiter(this, void 0, void 0, function* () {
            return undefined;
        });
    }
    localizeRelToManifest(rel) {
        const relCopy = this.ctx.corpus.MakeObject(internal_1.cdmObjectType.e2eRelationshipDef, rel.name);
        relCopy.toEntity = this.ctx.corpus.storage.createRelativeCorpusPath(rel.toEntity, this);
        relCopy.fromEntity = this.ctx.corpus.storage.createRelativeCorpusPath(rel.fromEntity, this);
        relCopy.toEntityAttribute = rel.toEntityAttribute;
        relCopy.fromEntityAttribute = rel.fromEntityAttribute;
        relCopy.exhibitsTraits.concat(rel.exhibitsTraits.allItems);
        return relCopy;
    }
    isRelAllowed(rel, option) {
        if (option === internal_1.cdmRelationshipDiscoveryStyle.none) {
            return false;
        }
        else if (option === internal_1.cdmRelationshipDiscoveryStyle.exclusive) {
            // only true if from and to entities are both found in the entities list of this manifest
            const absoluteFromEntString = this.ctx.corpus.storage.createAbsoluteCorpusPath(rel.fromEntity, this);
            const fromEntInManifest = this.entities.allItems.filter((x) => {
                return this.ctx.corpus.storage.createAbsoluteCorpusPath(x.entityPath, this) === absoluteFromEntString;
            }).length > 0;
            const absoluteToEntString = this.ctx.corpus.storage.createAbsoluteCorpusPath(rel.toEntity, this);
            const toEntInManifest = this.entities.allItems.filter((x) => {
                return this.ctx.corpus.storage.createAbsoluteCorpusPath(x.entityPath, this) === absoluteToEntString;
            }).length > 0;
            return fromEntInManifest && toEntInManifest;
        }
        else {
            return true;
        }
    }
    /**
     * Adds imports for elevated purpose traits for relationships, then adds the relationships to the manifest.
     * The last import has the highest priority, so we insert the imports for traits to the beginning of the list.
     */
    addElevatedTraitsAndRelationships(rel) {
        return __awaiter(this, void 0, void 0, function* () {
            const resOpt = new internal_1.resolveOptions(this);
            for (const traitRef of rel.exhibitsTraits) {
                const traitDef = this.ctx.corpus.resolveSymbolReference(resOpt, this, traitRef.fetchObjectDefinitionName(), internal_1.cdmObjectType.traitDef, true);
                if (traitDef === undefined) {
                    const absPath = rel.getElevatedTraitCorpusPath().get(traitRef);
                    const relativePath = this.ctx.corpus.storage.createRelativeCorpusPath(absPath, this);
                    // Adds the import to this manifest file
                    this.imports.insert(0, new internal_1.CdmImport(this.ctx, relativePath, undefined));
                    // Fetches the actual file of the import and indexes it
                    var importDocument = yield this.ctx.corpus.fetchObjectAsync(absPath);
                    yield importDocument.indexIfNeeded(resOpt);
                    // Resolves the imports in the manifests
                    yield this.ctx.corpus.resolveImportsAsync(this, new Set(this.atCorpusPath), resOpt);
                    // Calls `GetImportPriorities` to prioritize all imports properly after a new import added (which requires `ImportPriorities` set to null)
                    this.importPriorities = undefined;
                    this.getImportPriorities();
                    // As adding a new import above set the manifest needsIndexing to true, we want to avoid over indexing for each import insertion
                    // so we handle the indexing for the new import above seperately in this case, no indexing needed at this point
                    this.needsIndexing = false;
                }
            }
            this.relationships.push(this.localizeRelToManifest(rel));
        });
    }
}
exports.CdmManifestDefinition = CdmManifestDefinition;
//# sourceMappingURL=CdmManifestDefinition.js.map