/* --------------------------------------------------------------------------------------------
 * Copyright (c) 2024 TypeFox and others.
 * Licensed under the MIT License. See LICENSE in the package root for license information.
 * ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import { MonacoEditorLanguageClientWrapper } from 'monaco-editor-wrapper';
import React from 'react';
export class MonacoEditorReactComp extends React.Component {
    wrapper = new MonacoEditorLanguageClientWrapper();
    containerElement;
    _subscription = null;
    isRestarting;
    started;
    constructor(props) {
        super(props);
        const { userConfig } = this.props;
        this.wrapper.getLogger().updateConfig(userConfig.loggerConfig);
    }
    async componentDidMount() {
        this.wrapper.getLogger().debug('Called: componentDidMount');
        if (!this.isRestarting) {
            await this.handleReinit();
        }
    }
    async componentDidUpdate(prevProps) {
        this.wrapper.getLogger().debug('Called: componentDidUpdate');
        const { userConfig } = this.props;
        const { wrapper } = this;
        const mustReInit = this.isReInitRequired(prevProps);
        if (mustReInit) {
            await this.handleReinit();
        }
        else {
            // the function now ensure a model update is only required if something else than the code changed
            this.wrapper.updateModel(userConfig.wrapperConfig.editorAppConfig);
            const config = userConfig.wrapperConfig.editorAppConfig;
            const prevConfig = prevProps.userConfig.wrapperConfig.editorAppConfig;
            if (prevConfig.$type === 'classic' && config.$type === 'classic') {
                if (prevConfig.editorOptions !== config.editorOptions) {
                    wrapper.getMonacoEditorApp().updateMonacoEditorOptions(config.editorOptions ?? {});
                }
            }
        }
    }
    componentWillUnmount() {
        this.wrapper.getLogger().debug('Called: componentWillUnmount');
        this.destroyMonaco();
    }
    assignRef = (component) => {
        this.wrapper.getLogger().debug('Called: assignRef');
        this.containerElement = component;
    };
    render() {
        this.wrapper.getLogger().debug('Called: render');
        return (React.createElement("div", { ref: this.assignRef, style: this.props.style, className: this.props.className }));
    }
    async handleReinit() {
        // block everything unti until (re)-start is complete
        this.isRestarting = new Promise((resolve) => {
            this.started = resolve;
        });
        await this.destroyMonaco();
        await this.initMonaco();
        await this.startMonaco();
    }
    isReInitRequired(prevProps) {
        const { className, userConfig } = this.props;
        let mustReInit = false;
        if (prevProps.className !== className && this.containerElement) {
            this.containerElement.className = className ?? '';
            mustReInit = true;
        }
        return mustReInit || this.wrapper.isReInitRequired(userConfig, prevProps.userConfig);
    }
    async destroyMonaco() {
        if (this.wrapper.isInitDone()) {
            if (this.isRestarting) {
                await this.isRestarting;
            }
            try {
                await this.wrapper.dispose();
            }
            catch {
                // The language client may throw an error during disposal.
                // This should not prevent us from continue working.
            }
        }
        if (this._subscription) {
            this._subscription.dispose();
        }
    }
    async initMonaco() {
        const { userConfig } = this.props;
        await this.wrapper.init(userConfig);
    }
    async startMonaco() {
        const { className, onLoad, onError, } = this.props;
        if (this.containerElement) {
            this.containerElement.className = className ?? '';
            // exceptions are forwarded to onError callback or the exception is thrown
            try {
                await this.wrapper.start(this.containerElement);
                // once awaiting start is done onLoad is called if available
                onLoad?.(this.wrapper);
                this.handleOnTextChanged();
            }
            catch (e) {
                if (onError) {
                    onError(e);
                }
                else {
                    throw e;
                }
            }
            finally {
                this.started();
                this.isRestarting = undefined;
            }
        }
    }
    handleOnTextChanged() {
        const { userConfig, onTextChanged } = this.props;
        if (!onTextChanged)
            return;
        const model = this.wrapper.getModel();
        if (model) {
            const verifyModelContent = () => {
                const modelText = model.getValue();
                onTextChanged(modelText, modelText !== userConfig.wrapperConfig.editorAppConfig.code);
            };
            this._subscription = model.onDidChangeContent(() => {
                verifyModelContent();
            });
            // do it initially
            verifyModelContent();
        }
    }
    getEditorWrapper() {
        return this.wrapper;
    }
    /**
     * Executes a custom VSCode/LSP command by name with args, and returns the result
     * @param cmd Command to execute
     * @param args Arguments to pass along with this command
     * @returns The result of executing this command in the language server
     */
    executeCommand(cmd, ...args) {
        return vscode.commands.executeCommand(cmd, ...args);
    }
}
//# sourceMappingURL=index.js.map