/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { guaranteeNonNullable, IllegalStateError, isNonNullable, } from '@finos/legend-shared';
import { Package } from '../graph/metamodel/pure/packageableElements/domain/Package.js';
import { BasicModel } from '../graph/BasicModel.js';
import { GAV_DELIMITER } from '@finos/legend-storage';
import { LegendSDLC } from './GraphDataOrigin.js';
export const DEPENDENCY_ROOT_PACKAGE_PREFIX = '@dependency__';
export const generateDependencyRootPackageName = (dependencyKey) => `${DEPENDENCY_ROOT_PACKAGE_PREFIX}${dependencyKey}`;
export const extractDependencyGACoordinateFromRootPackageName = (packageName) => {
    const idx = packageName.indexOf(DEPENDENCY_ROOT_PACKAGE_PREFIX);
    if (idx !== 0) {
        return undefined;
    }
    return packageName.substring(DEPENDENCY_ROOT_PACKAGE_PREFIX.length);
};
export class DependencyModel extends BasicModel {
    constructor(extensionElementClasses, root, origin) {
        super(root.name, extensionElementClasses, origin);
        this.root = root;
    }
}
const buildDependencyElementGetter = (dependencyManager, elementGetter) => (path) => {
    for (const dependencyGraph of dependencyManager.dependencyGraphs) {
        const element = elementGetter(dependencyGraph, path);
        if (element) {
            return element;
        }
    }
    return undefined;
};
export class DependencyManager {
    graphPlugins;
    _origin;
    roots = [];
    projectDependencyModelsIndex = new Map();
    constructor(graphPlugins) {
        this.graphPlugins = graphPlugins;
    }
    /**
     * Here we create and index a graph for each dependency
     */
    initialize(dependencyEntitiesIndex) {
        Array.from(dependencyEntitiesIndex.entries()).forEach(([dependencyKey, entitiesWithOrigin]) => {
            const pkg = new Package(generateDependencyRootPackageName(dependencyKey));
            this.roots.push(pkg);
            // NOTE: all dependency models will share the dependency manager root package.
            this.projectDependencyModelsIndex.set(dependencyKey, new DependencyModel(this.graphPlugins, pkg, new LegendSDLC(entitiesWithOrigin.groupId, entitiesWithOrigin.artifactId, entitiesWithOrigin.versionId)));
        });
    }
    get numberOfDependencies() {
        return this.projectDependencyModelsIndex.size;
    }
    get hasDependencies() {
        return Boolean(this.projectDependencyModelsIndex.size);
    }
    get dependencyGraphs() {
        return Array.from(this.projectDependencyModelsIndex.values());
    }
    get allOwnElements() {
        return this.dependencyGraphs.flatMap((dep) => dep.allOwnElements);
    }
    get origin() {
        return this._origin;
    }
    setOrigin(val) {
        if (this._origin) {
            throw new IllegalStateError(`Graph origin has already been set`);
        }
        else {
            this._origin = val;
        }
    }
    getOwnNullableSectionIndex = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableSectionIndex(path));
    getOwnNullableProfile = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableProfile(path));
    getOwnNullableType = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableType(path));
    getOwnNullableClass = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableClass(path));
    getOwnNullableEnumeration = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableEnumeration(path));
    getOwnNullableMeasure = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableMeasure(path));
    getOwnNullableAssociation = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableAssociation(path));
    getOwnNullableFunction = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableFunction(path));
    getOwnNullableFunctionActivator = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableFunctionActivator(path));
    getOwnNullableStore = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableStore(path));
    getOwnNullableDataProduct = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableDataProduct(path));
    getOwnNullableIngestDefinition = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableIngestDefinition(path));
    getOwnNullableMapping = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableMapping(path));
    getOwnNullableConnection = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableConnection(path));
    getOwnNullableRuntime = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableRuntime(path));
    getOwnNullableService = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableService(path));
    getOwnNullableGenerationSpecification = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableGenerationSpecification(path));
    getOwnNullableFileGeneration = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableFileGeneration(path));
    getOwnNullableDataElement = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableDataElement(path));
    getOwnExecutionEnvironment = buildDependencyElementGetter(this, (dep, path) => dep.getOwnNullableExecutionEnviornment(path));
    getOwnNullableExtensionElement(path, extensionElementClass) {
        for (const dependencyGraph of this.dependencyGraphs) {
            const element = dependencyGraph
                .getExtensionForElementClass(extensionElementClass)
                .getElement(path);
            if (element) {
                return element;
            }
        }
        return undefined;
    }
    get sectionIndices() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownSectionIndices);
    }
    get profiles() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownProfiles);
    }
    get enumerations() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownEnumerations);
    }
    get measures() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownMeasures);
    }
    get classes() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownClasses);
    }
    get types() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownTypes);
    }
    get associations() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownAssociations);
    }
    get functions() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownFunctions);
    }
    get functionActivators() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownFunctionActivators);
    }
    get stores() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownStores);
    }
    get databases() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownDatabases);
    }
    get mappings() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownMappings);
    }
    get services() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownServices);
    }
    get runtimes() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownRuntimes);
    }
    get connections() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownConnections);
    }
    get dataElements() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownDataElements);
    }
    get generationSpecifications() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownGenerationSpecifications);
    }
    get fileGenerations() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownFileGenerations);
    }
    get testables() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownTestables);
    }
    get executionEnvironments() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownExecutionEnvironments);
    }
    get ingests() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownIngests);
    }
    get dataProducts() {
        return this.dependencyGraphs.flatMap((dep) => dep.ownDataProducts);
    }
    getExtensionElements(extensionElementClass) {
        return this.dependencyGraphs.flatMap((dep) => dep.getExtensionElements(extensionElementClass));
    }
    getModel(projectId) {
        return guaranteeNonNullable(this.projectDependencyModelsIndex.get(projectId), `Can't find dependency model with project ID '${projectId}'`);
    }
    getNullableElement(path, includePackage) {
        const model = this.dependencyGraphs.find((dep) => Boolean(dep.getOwnNullableElement(path, includePackage)));
        return model?.getOwnNullableElement(path, includePackage);
    }
    getPackages(path) {
        return this.dependencyGraphs
            .map((dep) => dep.getNullablePackage(path))
            .filter(isNonNullable);
    }
    getElementOrigin(element) {
        const model = this.dependencyGraphs.find((dep) => Boolean(dep.getOwnNullableElement(element.path)));
        return model?.origin instanceof LegendSDLC
            ? `${model.origin.groupId}${GAV_DELIMITER}${model.origin.artifactId}`
            : undefined;
    }
}
//# sourceMappingURL=DependencyManager.js.map