/**
 * 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 { observable, action, makeObservable, flow } from 'mobx';
import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js';
import { FileSystem_Directory, GENERATION_FILE_ROOT_NAME, getFileSystemTreeData, buildFileSystemDirectory, } from '../utils/FileSystemTreeUtils.js';
import { assertErrorThrown, deepEqual, isEmpty, LogEvent, ActionState, } from '@finos/legend-shared';
import { ConfigurationProperty, GenerationPropertyItemType, PackageableElement, PackageableElementReference, PackageableElementExplicitReference, ELEMENT_PATH_DELIMITER, getNullableFileGenerationConfig, } from '@finos/legend-graph';
import { configurationProperty_setValue, configurationProperty_addConfigurationProperty, fileGeneration_addScopeElement, fileGeneration_deleteScopeElement, } from '../../graph-modifier/DSL_Generation_GraphModifierHelper.js';
import { FileSystemState } from './FileSystemState.js';
export class GeneratedFileStructureState {
    editorStore;
    fileSystemState;
    generatingAction = ActionState.create();
    rootDirectoryName;
    constructor(rootDirectory, editorStore) {
        this.rootDirectoryName = rootDirectory;
        this.fileSystemState = new FileSystemState(rootDirectory);
        this.editorStore = editorStore;
    }
    processGenerationResult(output) {
        this.fileSystemState.root = new FileSystem_Directory(this.rootDirectoryName);
        this.fileSystemState.filesIndex = new Map();
        const openedNodeIds = this.fileSystemState.directoryTreeData
            ? Array.from(this.fileSystemState.directoryTreeData.nodes.values())
                .filter((node) => node.isOpen)
                .map((node) => node.id)
            : [];
        const generationResultIndex = new Map();
        const rootFolder = this.rootFolder;
        output.forEach((entry) => {
            entry.cleanFileName(rootFolder);
            if (generationResultIndex.has(entry.fileName)) {
                this.editorStore.applicationStore.logService.warn(LogEvent.create(LEGEND_STUDIO_APP_EVENT.GENERATION_FAILURE), 'Found 2 generation outputs with same path');
            }
            generationResultIndex.set(entry.fileName, {
                value: entry,
                parentId: this.generationParentId,
            });
        });
        // take generation outputs and put them into the root directory
        buildFileSystemDirectory(this.fileSystemState.root, generationResultIndex, this.fileSystemState.filesIndex);
        this.fileSystemState.directoryTreeData = getFileSystemTreeData(this.fileSystemState.root);
        this.fileSystemState.reprocessNodeTree(Array.from(generationResultIndex.values()), this.fileSystemState.directoryTreeData, openedNodeIds);
    }
}
export class FileGenerationState extends GeneratedFileStructureState {
    fileGeneration;
    constructor(editorStore, fileGeneration) {
        super(GENERATION_FILE_ROOT_NAME, editorStore);
        makeObservable(this, {
            generatingAction: observable,
            fileSystemState: observable,
            resetGenerator: action,
            processGenerationResult: action,
            addScopeElement: action,
            deleteScopeElement: action,
            updateFileGenerationParameters: action,
            generate: flow,
        });
        this.fileGeneration = fileGeneration;
    }
    get rootFolder() {
        return (this.fileGeneration.generationOutputPath ??
            this.fileGeneration.path.split(ELEMENT_PATH_DELIMITER).join('_'));
    }
    get generationParentId() {
        return this.fileGeneration.path;
    }
    resetGenerator() {
        this.fileGeneration.configurationProperties = [];
    }
    updateFileGenerationParameters(fileGeneration, generationProperty, newValue) {
        if (generationProperty.type === GenerationPropertyItemType.MAP) {
            if (!newValue ||
                isEmpty(newValue) ||
                deepEqual(newValue, generationProperty.defaultValue)) {
                fileGeneration.configurationProperties =
                    fileGeneration.configurationProperties.filter((e) => e.name !== generationProperty.name);
            }
            else {
                const configProperty = getNullableFileGenerationConfig(fileGeneration, generationProperty.name);
                if (configProperty) {
                    configurationProperty_setValue(configProperty, {
                        ...newValue,
                    });
                }
                else {
                    const newItem = new ConfigurationProperty(generationProperty.name, newValue);
                    configurationProperty_addConfigurationProperty(fileGeneration.configurationProperties, newItem);
                }
            }
        }
        else {
            const configProperty = getNullableFileGenerationConfig(fileGeneration, generationProperty.name);
            let useDefaultValue = generationProperty.defaultValue === newValue;
            if (generationProperty.type === GenerationPropertyItemType.BOOLEAN) {
                useDefaultValue =
                    (generationProperty.defaultValue === 'true') ===
                        newValue;
            }
            const newConfigValue = useDefaultValue ? undefined : newValue;
            if (newConfigValue !== undefined) {
                if (configProperty) {
                    configurationProperty_setValue(configProperty, newConfigValue);
                }
                else {
                    const newItem = new ConfigurationProperty(generationProperty.name, newConfigValue);
                    configurationProperty_addConfigurationProperty(fileGeneration.configurationProperties, newItem);
                }
            }
            else {
                fileGeneration.configurationProperties =
                    fileGeneration.configurationProperties.filter((e) => e.name !== generationProperty.name);
            }
        }
    }
    *generate() {
        this.generatingAction.inProgress();
        try {
            // avoid wasting a network call when the scope is empty, we can short-circuit this
            if (!this.fileGeneration.scopeElements.length) {
                this.fileSystemState.selectedNode = undefined;
                this.processGenerationResult([]);
                return;
            }
            const mode = this.editorStore.graphState.graphGenerationState.globalFileGenerationState.getFileGenerationConfiguration(this.fileGeneration.type).generationMode;
            const result = (yield this.editorStore.graphManagerState.graphManager.generateFile(this.fileGeneration, mode, this.editorStore.graphManagerState.graph));
            this.processGenerationResult(result);
        }
        catch (error) {
            assertErrorThrown(error);
            this.fileSystemState.selectedNode = undefined;
            this.processGenerationResult([]);
            this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.GENERATION_FAILURE), error);
            this.editorStore.applicationStore.notificationService.notifyError(error);
        }
        finally {
            this.generatingAction.complete();
        }
    }
    getScopeElement(element) {
        return this.fileGeneration.scopeElements.find((el) => el instanceof PackageableElementReference
            ? el.value === element
            : element === el);
    }
    addScopeElement(element) {
        const el = this.getScopeElement(element);
        if (!el) {
            fileGeneration_addScopeElement(this.fileGeneration, element instanceof PackageableElement
                ? PackageableElementExplicitReference.create(element)
                : element);
        }
    }
    deleteScopeElement(element) {
        const el = this.getScopeElement(element);
        if (el) {
            fileGeneration_deleteScopeElement(this.fileGeneration, el);
        }
    }
}
//# sourceMappingURL=FileGenerationState.js.map