/**
 * 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 { action, observable, computed, makeObservable, flowResult, flow, } from 'mobx';
import { IllegalStateError, guaranteeType, UnsupportedOperationError, guaranteeNonNullable, } from '@finos/legend-shared';
import { decorateRuntimeWithNewMapping } from './editor-state/element-editor-state/RuntimeEditorState.js';
import { DEFAULT_GENERATION_SPECIFICATION_NAME, } from './editor-state/GraphGenerationState.js';
import { ModelStore, ELEMENT_PATH_DELIMITER, Package, Class, Association, Enumeration, ConcreteFunctionDefinition, Profile, Mapping, FlatData, Service, PackageableConnection, PackageableRuntime, PureSingleExecution, EngineRuntime, JsonModelConnection, FileGenerationSpecification, GenerationSpecification, FlatDataConnection, Database, PackageableElementExplicitReference, RelationalDatabaseConnection, DatabaseType, DefaultH2AuthenticationStrategy, ModelGenerationSpecification, DataElement, stub_Database, Measure, Multiplicity, PrimitiveType, LocalH2DatasourceSpecification, SnowflakeDatasourceSpecification, SnowflakePublicAuthenticationStrategy, StoreConnections, ConnectionPointer, IdentifiedConnection, generateIdentifiedConnectionId, getMappingCompatibleRuntimes, RuntimePointer, GenericTypeExplicitReference, GenericType, DataProduct, LakehouseRuntime, AccessPointGroup, ModelAccessPointGroup, stub_Mapping, InternalDataProductType, } from '@finos/legend-graph';
import { packageableConnection_setConnectionValue, runtime_addMapping, } from '../graph-modifier/DSL_Mapping_GraphModifierHelper.js';
import { fileGeneration_setScopeElements, fileGeneration_setType, generationSpecification_addGenerationElement, } from '../graph-modifier/DSL_Generation_GraphModifierHelper.js';
import { service_initNewService, service_setExecution, } from '../graph-modifier/DSL_Service_GraphModifierHelper.js';
import { dataElement_setEmbeddedData } from '../graph-modifier/DSL_Data_GraphModifierHelper.js';
import { PACKAGEABLE_ELEMENT_TYPE } from './utils/ModelClassifierUtils.js';
import { buildElementOption, } from '@finos/legend-lego/graph-editor';
import { EmbeddedDataType } from './editor-state/ExternalFormatState.js';
import { createEmbeddedData } from './editor-state/element-editor-state/data/EmbeddedDataState.js';
import { dataProduct_addAccessPointGroup, dataProduct_setTitle, dataProduct_setType, } from '../graph-modifier/DSL_DataProduct_GraphModifierHelper.js';
export const CUSTOM_LABEL = '(custom)';
export const resolvePackageAndElementName = (_package, isPackageRoot, name) => {
    const index = name.lastIndexOf(ELEMENT_PATH_DELIMITER);
    const elementName = index === -1 ? name : name.substring(index + 2, name.length);
    const additionalPackageName = index === -1 ? '' : name.substring(0, index);
    const selectedPackageName = isPackageRoot ? '' : _package.path;
    const packagePath = !selectedPackageName && !additionalPackageName
        ? ''
        : selectedPackageName
            ? `${selectedPackageName}${additionalPackageName
                ? `${ELEMENT_PATH_DELIMITER}${additionalPackageName}`
                : ''}`
            : additionalPackageName;
    return [packagePath, elementName];
};
export const handlePostCreateAction = async (element, editorStore) => {
    // post creation handling
    if (element instanceof FileGenerationSpecification ||
        element instanceof ModelGenerationSpecification) {
        const generationElement = element;
        const generationSpecifications = editorStore.graphManagerState.graph.ownGenerationSpecifications;
        let generationSpec;
        if (generationSpecifications.length) {
            // TODO? handle case when more than one generation specification
            generationSpec = generationSpecifications[0];
        }
        else {
            generationSpec = new GenerationSpecification(DEFAULT_GENERATION_SPECIFICATION_NAME);
            await flowResult(editorStore.graphEditorMode.addElement(generationSpec, guaranteeNonNullable(generationElement.package).path, false));
        }
        generationSpecification_addGenerationElement(generationSpec, generationElement);
    }
    const extraElementEditorPostCreateActions = editorStore.pluginManager
        .getApplicationPlugins()
        .flatMap((plugin) => plugin.getExtraElementEditorPostCreateActions?.() ?? []);
    for (const postCreateAction of extraElementEditorPostCreateActions) {
        postCreateAction(editorStore, element);
    }
};
export class NewElementDriver {
    editorStore;
    constructor(editorStore) {
        this.editorStore = editorStore;
    }
}
export var NewRuntimeType;
(function (NewRuntimeType) {
    NewRuntimeType["LEGACY"] = "LEGACY";
    NewRuntimeType["LAKEHOUSE"] = "LAKEHOUSE";
})(NewRuntimeType || (NewRuntimeType = {}));
export class NewPackageableRuntimeDriver extends NewElementDriver {
    mapping;
    type = NewRuntimeType.LEGACY;
    constructor(editorStore) {
        super(editorStore);
        makeObservable(this, {
            mapping: observable,
            setMapping: action,
            isValid: computed,
            type: observable,
            setType: action,
        });
        const firstMapping = this.editorStore.graphManagerState.graph.mappings[0];
        this.mapping = firstMapping;
        if (!firstMapping) {
            this.type = NewRuntimeType.LAKEHOUSE;
        }
    }
    setType(val) {
        this.type = val;
    }
    setMapping(mapping) {
        this.mapping = mapping;
    }
    get isValid() {
        if (this.type === NewRuntimeType.LEGACY) {
            return Boolean(this.mapping);
        }
        return true;
    }
    createElement(name) {
        const runtime = new PackageableRuntime(name);
        if (this.type === NewRuntimeType.LAKEHOUSE) {
            const lakehouseRuntime = new LakehouseRuntime();
            lakehouseRuntime.environment = '';
            lakehouseRuntime.warehouse = '';
            lakehouseRuntime.connectionPointer = undefined;
            runtime.runtimeValue = lakehouseRuntime;
            return runtime;
        }
        runtime.runtimeValue = new EngineRuntime();
        runtime_addMapping(runtime.runtimeValue, PackageableElementExplicitReference.create(guaranteeNonNullable(this.mapping)));
        return runtime;
    }
}
export class NewConnectionValueDriver {
    editorStore;
    constructor(editorStore) {
        this.editorStore = editorStore;
    }
}
export var CONNECTION_TYPE;
(function (CONNECTION_TYPE) {
    CONNECTION_TYPE["PURE_MODEL_CONNECTION"] = "MODEL_CONNECTION";
    CONNECTION_TYPE["FLAT_DATA_CONNECTION"] = "FLAT_DATA_CONNECTION";
    CONNECTION_TYPE["RELATIONAL_CONNECTION"] = "RELATIONAL_CONNECTION";
})(CONNECTION_TYPE || (CONNECTION_TYPE = {}));
export class NewPureModelConnectionDriver extends NewConnectionValueDriver {
    class;
    constructor(editorStore) {
        super(editorStore);
        makeObservable(this, {
            class: observable,
            setClass: action,
            isValid: computed,
        });
        const classes = this.editorStore.graphManagerState.graph.classes;
        if (classes.length) {
            this.class = classes[0];
        }
    }
    setClass(_class) {
        this.class = _class;
    }
    get isValid() {
        return Boolean(this.class);
    }
    getConnectionType() {
        return CONNECTION_TYPE.PURE_MODEL_CONNECTION;
    }
    createConnection(store) {
        return new JsonModelConnection(PackageableElementExplicitReference.create(store), PackageableElementExplicitReference.create(guaranteeNonNullable(this.class)));
    }
}
export class NewFlatDataConnectionDriver extends NewConnectionValueDriver {
    constructor(editorStore) {
        super(editorStore);
        makeObservable(this, {
            isValid: computed,
        });
    }
    get isValid() {
        return true;
    }
    getConnectionType() {
        return CONNECTION_TYPE.FLAT_DATA_CONNECTION;
    }
    createConnection(store) {
        return new FlatDataConnection(PackageableElementExplicitReference.create(store));
    }
}
export const DEFAULT_H2_SQL = '-- loads sample data for getting started. See https://github.com/pthom/northwind_psql for more info\n call loadNorthwindData()';
export class NewRelationalDatabaseConnectionDriver extends NewConnectionValueDriver {
    constructor(editorStore) {
        super(editorStore);
        makeObservable(this, {
            isValid: computed,
        });
    }
    get isValid() {
        return true;
    }
    getConnectionType() {
        return CONNECTION_TYPE.RELATIONAL_CONNECTION;
    }
    createConnection(store) {
        let selectedStore;
        if (store instanceof Database) {
            selectedStore = store;
        }
        else {
            const dbs = this.editorStore.graphManagerState.usableDatabases;
            selectedStore = dbs.length ? dbs[0] : stub_Database();
        }
        const spec = new LocalH2DatasourceSpecification();
        spec.testDataSetupSqls = [DEFAULT_H2_SQL];
        return new RelationalDatabaseConnection(PackageableElementExplicitReference.create(selectedStore), DatabaseType.H2, spec, new DefaultH2AuthenticationStrategy());
    }
}
export class NewPackageableConnectionDriver extends NewElementDriver {
    store;
    newConnectionValueDriver;
    constructor(editorStore) {
        super(editorStore);
        makeObservable(this, {
            store: observable,
            newConnectionValueDriver: observable,
            setStore: action,
            changeConnectionState: action,
            isValid: computed,
        });
        this.store = ModelStore.INSTANCE;
        this.newConnectionValueDriver =
            this.getNewConnectionValueDriverBasedOnStore(this.store);
    }
    geDriverConnectionType() {
        return this.newConnectionValueDriver?.getConnectionType() ?? '';
    }
    changeConnectionState(val) {
        switch (val) {
            case CONNECTION_TYPE.PURE_MODEL_CONNECTION:
                this.newConnectionValueDriver = new NewPureModelConnectionDriver(this.editorStore);
                return;
            case CONNECTION_TYPE.FLAT_DATA_CONNECTION:
                this.newConnectionValueDriver = new NewFlatDataConnectionDriver(this.editorStore);
                return;
            case CONNECTION_TYPE.RELATIONAL_CONNECTION:
                this.newConnectionValueDriver =
                    new NewRelationalDatabaseConnectionDriver(this.editorStore);
                return;
            default: {
                const extraNewConnectionDriverCreators = this.editorStore.pluginManager
                    .getApplicationPlugins()
                    .flatMap((plugin) => plugin.getExtraNewConnectionDriverCreators?.() ?? []);
                for (const creator of extraNewConnectionDriverCreators) {
                    const driver = creator(this.editorStore, val);
                    if (driver) {
                        this.newConnectionValueDriver = driver;
                        return;
                    }
                }
                this.editorStore.applicationStore.notificationService.notifyError(new UnsupportedOperationError(`Can't create new connection driver for type: no compatible creator available from plugins`, val));
            }
        }
    }
    getNewConnectionValueDriverBasedOnStore(store) {
        if (store instanceof ModelStore) {
            return new NewPureModelConnectionDriver(this.editorStore);
        }
        else if (store instanceof FlatData) {
            return new NewFlatDataConnectionDriver(this.editorStore);
        }
        else if (store instanceof Database) {
            return new NewRelationalDatabaseConnectionDriver(this.editorStore);
        }
        const extraNewConnectionDriverCreators = this.editorStore.pluginManager
            .getApplicationPlugins()
            .flatMap((plugin) => plugin.getExtraNewConnectionDriverCreators?.() ?? []);
        for (const creator of extraNewConnectionDriverCreators) {
            const driver = creator(this.editorStore, store);
            if (driver) {
                return driver;
            }
        }
        this.editorStore.applicationStore.notificationService.notifyError(new UnsupportedOperationError(`Can't create new connection driver for store: no compatible creator available from plugins`, store));
        return undefined;
    }
    setStore(store) {
        const newDriver = this.getNewConnectionValueDriverBasedOnStore(store);
        if (newDriver) {
            this.store = store;
            this.newConnectionValueDriver = newDriver;
        }
    }
    get isValid() {
        return this.newConnectionValueDriver?.isValid ?? true;
    }
    createElement(name) {
        const connection = new PackageableConnection(name);
        if (this.newConnectionValueDriver) {
            packageableConnection_setConnectionValue(connection, this.newConnectionValueDriver.createConnection(this.store), this.editorStore.changeDetectionState.observerContext); // default to model store
        }
        return connection;
    }
}
export class NewLakehouseDataProductDriver extends NewElementDriver {
    title;
    modeled = false;
    constructor(editorStore) {
        super(editorStore);
        this.title = '';
        makeObservable(this, {
            title: observable,
            modeled: observable,
            setModeled: action,
            setTitle: action,
            isValid: computed,
        });
    }
    get isValid() {
        return Boolean(this.title);
    }
    setTitle(val) {
        this.title = val;
    }
    setModeled(val) {
        this.modeled = val;
    }
    createElement(name) {
        const dataProduct = new DataProduct(name);
        dataProduct_setTitle(dataProduct, this.title);
        dataProduct_setType(dataProduct, new InternalDataProductType());
        if (!this.modeled) {
            const defaultGroup = new AccessPointGroup();
            defaultGroup.id = 'default';
            dataProduct_addAccessPointGroup(dataProduct, defaultGroup);
        }
        else {
            const defaultGroup = new ModelAccessPointGroup();
            defaultGroup.id = 'default';
            defaultGroup.mapping =
                PackageableElementExplicitReference.create(stub_Mapping());
            dataProduct_addAccessPointGroup(dataProduct, defaultGroup);
        }
        return dataProduct;
    }
}
export class NewServiceDriver extends NewElementDriver {
    mappingOption;
    runtimeOption;
    constructor(editorStore) {
        super(editorStore);
        makeObservable(this, {
            mappingOption: observable,
            runtimeOption: observable,
            setMappingOption: action,
            setRuntimeOption: action,
            runtimeOptions: computed,
            isValid: computed,
            createElement: action,
        });
        this.mappingOption =
            editorStore.graphManagerState.usableMappings.map(buildElementOption)[0];
        this.runtimeOption = guaranteeNonNullable(this.runtimeOptions[0]);
    }
    setMappingOption(val) {
        this.mappingOption = val;
    }
    setRuntimeOption(val) {
        this.runtimeOption = val;
    }
    get compatibleMappingRuntimes() {
        return this.mappingOption?.value
            ? getMappingCompatibleRuntimes(this.mappingOption.value, this.editorStore.graphManagerState.usableRuntimes)
            : [];
    }
    get runtimeOptions() {
        return [
            ...this.compatibleMappingRuntimes.map((runtime) => buildElementOption(runtime)),
            {
                label: CUSTOM_LABEL,
                value: undefined,
            },
        ];
    }
    get isValid() {
        return Boolean(this.mappingOption);
    }
    createElement(name) {
        const mappingOption = guaranteeNonNullable(this.mappingOption);
        const _mapping = mappingOption.value;
        const mapping = PackageableElementExplicitReference.create(_mapping);
        const service = new Service(name);
        let runtimeValue;
        if (this.runtimeOption.value) {
            runtimeValue = new RuntimePointer(PackageableElementExplicitReference.create(this.runtimeOption.value));
        }
        else {
            const engineRuntime = new EngineRuntime();
            runtime_addMapping(engineRuntime, mapping);
            decorateRuntimeWithNewMapping(engineRuntime, _mapping, this.editorStore);
            runtimeValue = engineRuntime;
        }
        service_setExecution(service, new PureSingleExecution(this.editorStore.graphManagerState.graphManager.createDefaultBasicRawLambda(), service, mapping, runtimeValue), this.editorStore.changeDetectionState.observerContext);
        service_initNewService(service);
        return service;
    }
}
export class NewFileGenerationDriver extends NewElementDriver {
    typeOption;
    constructor(editorStore) {
        super(editorStore);
        makeObservable(this, {
            typeOption: observable,
            setTypeOption: action,
        });
        this.typeOption = editorStore.graphState.graphGenerationState
            .globalFileGenerationState.fileGenerationConfigurationOptions.length
            ? editorStore.graphState.graphGenerationState.globalFileGenerationState
                .fileGenerationConfigurationOptions[0]
            : undefined;
    }
    setTypeOption(typeOption) {
        this.typeOption = typeOption;
    }
    get isValid() {
        return Boolean(this.typeOption);
    }
    createElement(name) {
        const fileGeneration = new FileGenerationSpecification(name);
        fileGeneration_setType(fileGeneration, guaranteeNonNullable(this.typeOption).value);
        // default to all packages
        fileGeneration_setScopeElements(fileGeneration, this.editorStore.graphManagerState.graph.root.children
            .filter((element) => element instanceof Package)
            .map((element) => PackageableElementExplicitReference.create(element)));
        return fileGeneration;
    }
}
// NOTE: Main reason for driver is to disallow if generation specification already exists
export class NewGenerationSpecificationDriver extends NewElementDriver {
    constructor(editorStore) {
        super(editorStore);
        makeObservable(this, {
            isValid: computed,
        });
    }
    get isValid() {
        // only one generation specification should exist
        return !this.editorStore.graphManagerState.graph.ownGenerationSpecifications
            .length;
    }
    createElement(name) {
        return new GenerationSpecification(name);
    }
}
export class NewDataElementDriver extends NewElementDriver {
    embeddedDataOption;
    constructor(editorStore) {
        super(editorStore);
        makeObservable(this, {
            embeddedDataOption: observable,
            setEmbeddedDataOption: action,
        });
        this.embeddedDataOption = {
            label: EmbeddedDataType.EXTERNAL_FORMAT_DATA,
            value: EmbeddedDataType.EXTERNAL_FORMAT_DATA,
        };
    }
    setEmbeddedDataOption(typeOption) {
        this.embeddedDataOption = typeOption;
    }
    createElement(name) {
        const embeddedDataOption = guaranteeNonNullable(this.embeddedDataOption);
        const dataElement = new DataElement(name);
        const data = createEmbeddedData(embeddedDataOption.value, this.editorStore);
        dataElement_setEmbeddedData(dataElement, data, this.editorStore.changeDetectionState.observerContext);
        return dataElement;
    }
    get isValid() {
        return Boolean(this.embeddedDataOption);
    }
}
export class NewElementState {
    editorStore;
    showModal = false;
    showType = false;
    type;
    _package;
    name = '';
    newElementDriver;
    constructor(editorStore) {
        makeObservable(this, {
            showModal: observable,
            showType: observable,
            type: observable,
            _package: observable,
            name: observable,
            newElementDriver: observable,
            selectedPackage: computed,
            isValid: computed,
            setShowModal: action,
            setName: action,
            setShowType: action,
            setNewElementDriver: action,
            setPackage: action,
            setElementType: action,
            openModal: action,
            closeModal: action,
            createElement: action,
            save: flow,
        });
        this.editorStore = editorStore;
        this.type = PACKAGEABLE_ELEMENT_TYPE.PACKAGE;
    }
    get selectedPackage() {
        return this._package
            ? this._package
            : this.editorStore.explorerTreeState.getSelectedNodePackage();
    }
    get isValid() {
        return this.newElementDriver?.isValid ?? true;
    }
    setShowModal(val) {
        this.showModal = val;
    }
    setName(name) {
        this.name = name;
    }
    setShowType(showType) {
        this.showType = showType;
    }
    setNewElementDriver(newElementDriver) {
        this.newElementDriver = newElementDriver;
    }
    setPackage(_package) {
        this._package = _package;
    }
    getNewElementDriver(clazz) {
        return guaranteeType(this.newElementDriver, clazz, `New element driver is not of the specified type (this is likely caused by calling this method at the wrong place)`);
    }
    setElementType(newType) {
        if (this.type !== newType) {
            let driver = undefined;
            switch (newType) {
                case PACKAGEABLE_ELEMENT_TYPE.RUNTIME:
                    driver = new NewPackageableRuntimeDriver(this.editorStore);
                    break;
                case PACKAGEABLE_ELEMENT_TYPE.CONNECTION:
                    driver = new NewPackageableConnectionDriver(this.editorStore);
                    break;
                case PACKAGEABLE_ELEMENT_TYPE.FILE_GENERATION:
                    driver = new NewFileGenerationDriver(this.editorStore);
                    break;
                case PACKAGEABLE_ELEMENT_TYPE.GENERATION_SPECIFICATION:
                    driver = new NewGenerationSpecificationDriver(this.editorStore);
                    break;
                case PACKAGEABLE_ELEMENT_TYPE.DATA:
                    driver = new NewDataElementDriver(this.editorStore);
                    break;
                case PACKAGEABLE_ELEMENT_TYPE.SERVICE:
                    driver = new NewServiceDriver(this.editorStore);
                    break;
                case PACKAGEABLE_ELEMENT_TYPE._DATA_PRODUCT:
                    driver = new NewLakehouseDataProductDriver(this.editorStore);
                    break;
                default: {
                    const extraNewElementDriverCreators = this.editorStore.pluginManager
                        .getApplicationPlugins()
                        .flatMap((plugin) => plugin.getExtraNewElementDriverCreators?.() ?? []);
                    for (const creator of extraNewElementDriverCreators) {
                        const _driver = creator(this.editorStore, newType);
                        if (_driver) {
                            driver = _driver;
                            break;
                        }
                    }
                    break;
                }
            }
            this.setNewElementDriver(driver);
            this.type = newType;
        }
    }
    openModal(type, _package) {
        this.setShowModal(true);
        this.setElementType(type ?? PACKAGEABLE_ELEMENT_TYPE.PACKAGE);
        this.setPackage(_package);
        this.setShowType(!type);
    }
    closeModal() {
        this.setShowModal(false);
        this.setElementType(PACKAGEABLE_ELEMENT_TYPE.PACKAGE);
        this.setPackage(undefined);
        this.setShowType(false);
        this.setName('');
    }
    *save() {
        if (this.name && this.isValid) {
            const [packagePath, elementName] = resolvePackageAndElementName(this.selectedPackage, this._package === this.editorStore.graphManagerState.graph.root, this.name);
            if (this.editorStore.graphManagerState.graph.getNullablePackage(packagePath) === this.editorStore.graphManagerState.graph.root &&
                this.type !== PACKAGEABLE_ELEMENT_TYPE.PACKAGE) {
                throw new IllegalStateError(`Can't create elements for type other than 'package' in root package`);
            }
            else {
                if (this.editorStore.applicationStore.config.options
                    .TEMPORARY__enableLocalConnectionBuilder &&
                    this.type === PACKAGEABLE_ELEMENT_TYPE.TEMPORARY__LOCAL_CONNECTION) {
                    // NOTE: this is temporary until we have proper support for local connection
                    // For now, we aim to fulfill the PoC for SnowflakeApp use case and will generate
                    // everything: mapping, store, connection, runtime, etc.
                    const store = new Database(`${this.name}_Database`);
                    const mapping = new Mapping(`${this.name}_Mapping`);
                    // connection
                    const connection = new PackageableConnection(`${this.name}_LocalConnection`);
                    const _suffix = `${packagePath.replaceAll(ELEMENT_PATH_DELIMITER, '-')}-${connection.name}`;
                    const datasourceSpecification = new SnowflakeDatasourceSpecification(`legend-local-snowflake-accountName-${_suffix}`, `legend-local-snowflake-region-${_suffix}`, `legend-local-snowflake-warehouseName-${_suffix}`, `legend-local-snowflake-databaseName-${_suffix}`);
                    datasourceSpecification.cloudType = `legend-local-snowflake-cloudType-${_suffix}`;
                    datasourceSpecification.role = `legend-local-snowflake-role-${_suffix}`;
                    const connectionValue = new RelationalDatabaseConnection(PackageableElementExplicitReference.create(store), DatabaseType.Snowflake, datasourceSpecification, new SnowflakePublicAuthenticationStrategy(`legend-local-snowflake-privateKeyVaultReference-${_suffix}`, `legend-local-snowflake-passphraseVaultReference-${_suffix}`, `legend-local-snowflake-publicuserName-${_suffix}`));
                    connectionValue.localMode = true;
                    connection.connectionValue = connectionValue;
                    // runtime
                    const runtime = new PackageableRuntime(`${this.name}_Runtime`);
                    const engineRuntime = new EngineRuntime();
                    engineRuntime.mappings = [
                        PackageableElementExplicitReference.create(mapping),
                    ];
                    const storeConnections = new StoreConnections(PackageableElementExplicitReference.create(store));
                    storeConnections.storeConnections = [
                        new IdentifiedConnection(generateIdentifiedConnectionId(engineRuntime), new ConnectionPointer(PackageableElementExplicitReference.create(connection))),
                    ];
                    engineRuntime.connections = [storeConnections];
                    runtime.runtimeValue = engineRuntime;
                    // add the elements
                    yield flowResult(this.editorStore.graphEditorMode.addElement(store, packagePath, false));
                    yield flowResult(this.editorStore.graphEditorMode.addElement(connection, packagePath, false));
                    yield flowResult(this.editorStore.graphEditorMode.addElement(mapping, packagePath, false));
                    yield flowResult(this.editorStore.graphEditorMode.addElement(runtime, packagePath, false));
                }
                else {
                    const element = this.createElement(elementName);
                    yield flowResult(this.editorStore.graphEditorMode.addElement(element, packagePath, true));
                    // post creation handling
                    yield handlePostCreateAction(element, this.editorStore);
                }
            }
        }
        this.closeModal();
    }
    createElement(name) {
        let element;
        switch (this.type) {
            case PACKAGEABLE_ELEMENT_TYPE.PACKAGE:
                element = new Package(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.CLASS:
                element = new Class(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.ASSOCIATION:
                element = new Association(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.ENUMERATION:
                element = new Enumeration(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.MEASURE:
                element = new Measure(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.PROFILE:
                element = new Profile(name);
                break;
            // default for function -> return type: String, return Multiplicity 1
            case PACKAGEABLE_ELEMENT_TYPE.FUNCTION: {
                const fn = new ConcreteFunctionDefinition(name, GenericTypeExplicitReference.create(new GenericType(PrimitiveType.STRING)), Multiplicity.ONE);
                // default to empty string
                fn.expressionSequence =
                    this.editorStore.graphManagerState.graphManager.createDefaultBasicRawLambda()
                        .body;
                element = fn;
                break;
            }
            case PACKAGEABLE_ELEMENT_TYPE.MAPPING:
                element = new Mapping(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.FLAT_DATA_STORE:
                element = new FlatData(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.DATABASE:
                element = new Database(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.SERVICE: {
                element =
                    this.getNewElementDriver(NewServiceDriver).createElement(name);
                break;
            }
            case PACKAGEABLE_ELEMENT_TYPE.CONNECTION:
                element = this.getNewElementDriver(NewPackageableConnectionDriver).createElement(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.RUNTIME:
                element = this.getNewElementDriver(NewPackageableRuntimeDriver).createElement(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.FILE_GENERATION:
                element = this.getNewElementDriver(NewFileGenerationDriver).createElement(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.DATA:
                element =
                    this.getNewElementDriver(NewDataElementDriver).createElement(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE.GENERATION_SPECIFICATION:
                element = new GenerationSpecification(name);
                break;
            case PACKAGEABLE_ELEMENT_TYPE._DATA_PRODUCT:
                element = this.getNewElementDriver(NewLakehouseDataProductDriver).createElement(name);
                break;
            default: {
                const extraNewElementFromStateCreators = this.editorStore.pluginManager
                    .getApplicationPlugins()
                    .flatMap((plugin) => plugin.getExtraNewElementFromStateCreators?.() ?? []);
                for (const creator of extraNewElementFromStateCreators) {
                    const _element = creator(this.type, name, this);
                    if (_element) {
                        element = _element;
                        break;
                    }
                }
                if (!element) {
                    throw new UnsupportedOperationError(`Can't create element of type '${this.type}': no compatible element creator available from plugins`);
                }
            }
        }
        return element;
    }
}
//# sourceMappingURL=NewElementState.js.map