/**
 * 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 { Association, Class, ConcreteFunctionDefinition, Database, DataElement, Enumeration, FileGenerationSpecification, FlatData, GenerationSpecification, Mapping, Measure, PackageableConnection, PackageableRuntime, PrimitiveType, Profile, Service, INTERNAL__UnknownFunctionActivator, SnowflakeApp, SnowflakeM2MUdf, HostedService, DataProduct, IngestDefinition, MemSQLFunction, } from '@finos/legend-graph';
import { guaranteeType, isNonNullable, UnsupportedOperationError, } from '@finos/legend-shared';
import { makeObservable, action, observable } from 'mobx';
import { ClassEditorState } from './editor-state/element-editor-state/ClassEditorState.js';
import { DatabaseEditorState } from './editor-state/element-editor-state/DatabaseEditorState.js';
import { PackageableConnectionEditorState } from './editor-state/element-editor-state/connection/ConnectionEditorState.js';
import { PackageableDataEditorState } from './editor-state/element-editor-state/data/DataEditorState.js';
import { ElementEditorState } from './editor-state/element-editor-state/ElementEditorState.js';
import { FileGenerationEditorState } from './editor-state/element-editor-state/FileGenerationEditorState.js';
import { FunctionEditorState } from './editor-state/element-editor-state/FunctionEditorState.js';
import { MappingEditorState } from './editor-state/element-editor-state/mapping/MappingEditorState.js';
import { PackageableRuntimeEditorState } from './editor-state/element-editor-state/RuntimeEditorState.js';
import { ServiceEditorState } from './editor-state/element-editor-state/service/ServiceEditorState.js';
import { UMLEditorState } from './editor-state/element-editor-state/UMLEditorState.js';
import { EntityDiffViewerState } from './editor-state/entity-diff-editor-state/EntityDiffEditorState.js';
import { GenerationSpecificationEditorState } from './editor-state/GenerationSpecificationEditorState.js';
import { UnsupportedElementEditorState } from './editor-state/UnsupportedElementEditorState.js';
import { TabManagerState } from '@finos/legend-lego/application';
import { INTERNAL__UnknownFunctionActivatorEdtiorState } from './editor-state/element-editor-state/function-activator/INTERNAL__UnknownFunctionActivatorEditorState.js';
import { SnowflakeAppFunctionActivatorEdtiorState } from './editor-state/element-editor-state/function-activator/SnowflakeAppFunctionActivatorEditorState.js';
import { SnowflakeM2MUdfFunctionActivatorEdtiorState } from './editor-state/element-editor-state/function-activator/SnowflakeM2MUdfFunctionActivatorEditorState.js';
import { HostedServiceFunctionActivatorEditorState } from './editor-state/element-editor-state/function-activator/HostedServiceFunctionActivatorEditorState.js';
import { MemSQLFunctionActivatorEditorState } from './editor-state/element-editor-state/function-activator/MemSQLFunctionActivatorEditorState.js';
import { ArtifactGenerationViewerState } from './editor-state/ArtifactGenerationViewerState.js';
import { DataProductEditorState } from './editor-state/element-editor-state/dataProduct/DataProductEditorState.js';
import { IngestDefinitionEditorState } from './editor-state/element-editor-state/ingest/IngestDefinitionEditorState.js';
export class EditorTabManagerState extends TabManagerState {
    editorStore;
    cachedTabs;
    constructor(editorStore) {
        super();
        makeObservable(this, {
            refreshCurrentEntityDiffViewer: action,
            cachedTabs: observable,
            recoverTabs: action,
            clearTabCache: action,
            cacheAndClose: action,
        });
        this.editorStore = editorStore;
    }
    get dndType() {
        return 'editor.tab-manager.tab';
    }
    /**
     * Here we store the element paths of the
     * elements editors as element paths don't refer to the actual graph. We can find the element
     * from the new graph that is built by using element path and can reprocess the element editor states.
     * The other kind of editors we reprocess are file generation editors, we store them as is as they don't
     * hold any reference to the actual graph.
     */
    cacheAndClose(options) {
        const openedTabPaths = [];
        this.tabs.forEach((state) => {
            if (state instanceof ElementEditorState) {
                openedTabPaths.push(state.elementPath);
            }
        });
        // Only stores editor state for file generation editors as they don't hold any references to the
        // actual graph.
        const currentTabState = this.currentTab instanceof ElementEditorState ||
            (options?.cacheGeneration &&
                this.currentTab instanceof ArtifactGenerationViewerState)
            ? undefined
            : this.currentTab;
        const currentTabElementPath = this.currentTab instanceof ElementEditorState
            ? this.currentTab.elementPath
            : undefined;
        this.cachedTabs = {
            openedTabEditorPaths: openedTabPaths,
            currentTabState,
            currentTabElementPath,
        };
        this.closeAllTabs();
    }
    clearTabCache() {
        this.cachedTabs = undefined;
    }
    getCurrentEditorState(clazz) {
        return guaranteeType(this.currentTab, clazz, `Current editor state is not of the specified type (this is likely caused by calling this method at the wrong place)`);
    }
    createElementEditorState(element, config) {
        if (element instanceof PrimitiveType) {
            throw new UnsupportedOperationError(`Can't create element state for primitive type`);
        }
        else if (element instanceof Class) {
            return new ClassEditorState(this.editorStore, element);
        }
        else if (element instanceof Association ||
            element instanceof Enumeration ||
            element instanceof Profile) {
            return new UMLEditorState(this.editorStore, element);
        }
        else if (element instanceof ConcreteFunctionDefinition) {
            return new FunctionEditorState(this.editorStore, element);
        }
        else if (element instanceof Database) {
            return new DatabaseEditorState(this.editorStore, element);
        }
        else if (element instanceof Measure || element instanceof FlatData) {
            return new UnsupportedElementEditorState(this.editorStore, element);
        }
        else if (element instanceof PackageableRuntime) {
            return new PackageableRuntimeEditorState(this.editorStore, element);
        }
        else if (element instanceof PackageableConnection) {
            return new PackageableConnectionEditorState(this.editorStore, element);
        }
        else if (element instanceof Mapping) {
            return new MappingEditorState(this.editorStore, element);
        }
        else if (element instanceof IngestDefinition) {
            return new IngestDefinitionEditorState(this.editorStore, element, config);
        }
        else if (element instanceof Service) {
            return new ServiceEditorState(this.editorStore, element);
        }
        else if (element instanceof DataProduct) {
            return new DataProductEditorState(this.editorStore, element, config);
        }
        else if (element instanceof GenerationSpecification) {
            return new GenerationSpecificationEditorState(this.editorStore, element);
        }
        else if (element instanceof FileGenerationSpecification) {
            return new FileGenerationEditorState(this.editorStore, element);
        }
        else if (element instanceof DataElement) {
            return new PackageableDataEditorState(this.editorStore, element);
        }
        else if (element instanceof SnowflakeApp) {
            return new SnowflakeAppFunctionActivatorEdtiorState(this.editorStore, element);
        }
        else if (element instanceof SnowflakeM2MUdf) {
            return new SnowflakeM2MUdfFunctionActivatorEdtiorState(this.editorStore, element);
        }
        else if (element instanceof HostedService) {
            return new HostedServiceFunctionActivatorEditorState(this.editorStore, element);
        }
        else if (element instanceof MemSQLFunction) {
            return new MemSQLFunctionActivatorEditorState(this.editorStore, element);
        }
        else if (element instanceof INTERNAL__UnknownFunctionActivator) {
            return new INTERNAL__UnknownFunctionActivatorEdtiorState(this.editorStore, element);
        }
        const extraElementEditorStateCreators = this.editorStore.pluginManager
            .getApplicationPlugins()
            .flatMap((plugin) => plugin.getExtraElementEditorStateCreators?.() ?? []);
        for (const creator of extraElementEditorStateCreators) {
            const elementEditorState = creator(this.editorStore, element);
            if (elementEditorState) {
                return elementEditorState;
            }
        }
        return new UnsupportedElementEditorState(this.editorStore, element);
    }
    refreshCurrentEntityDiffViewer() {
        if (this.currentTab instanceof EntityDiffViewerState) {
            this.currentTab.refresh();
        }
    }
    /**
     * After we do graph processing, we want to recover the tabs
     *
     * NOTE: we have to flush old tab states to ensure, we have no reference
     * to the old graph to avoid memory leak. Here, we only recreate element
     * editor tabs, and keep special editors open. Some tabs will be closed.
     * But we **ABSOLUTELY** must never make this behavior customizable by extension
     * i.e. we should not allow extension control if a tab should be kept open, because
     * the plugin implementation could accidentally reference older graph and therefore
     * cause memory issues
     *
     * See https://github.com/finos/legend-studio/issues/1713
     */
    recoverTabs = () => {
        if (this.cachedTabs) {
            this.tabs = this.cachedTabs.openedTabEditorPaths
                .map((editorPath) => {
                const correspondingElement = this.editorStore.graphManagerState.graph.getNullableElement(editorPath);
                if (correspondingElement) {
                    return this.createElementEditorState(correspondingElement);
                }
                return undefined;
            })
                .filter(isNonNullable);
            this.setCurrentTab(this.findCurrentTab(this.cachedTabs.currentTabState, this.cachedTabs.currentTabElementPath));
            this.clearTabCache();
        }
    };
    findCurrentTab = (tab, tabElementPath) => {
        if (tab) {
            return tab;
        }
        else {
            return this.tabs.find((editorState) => editorState instanceof ElementEditorState &&
                editorState.elementPath === tabElementPath);
        }
    };
}
//# sourceMappingURL=EditorTabManagerState.js.map