import * as i0 from '@angular/core';
import { EventEmitter, forwardRef, ViewChild, Output, Input, Component, Directive } from '@angular/core';
import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
import * as i1 from '@c8y/ngx-components';
import { LoadingComponent } from '@c8y/ngx-components';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NgIf } from '@angular/common';

function initializeMonacoEnvironment() {
    if (typeof window.MonacoEnvironment === 'undefined') {
        window.MonacoEnvironment = {
            getWorkerUrl: function (moduleId, label) {
                const base = MONACO_WORKERS_BASE;
                switch (label) {
                    case 'json':
                        return `${base}json.worker.bundle.js`;
                    case 'css':
                        return `${base}css.worker.bundle.js`;
                    case 'html':
                        return `${base}html.worker.bundle.js`;
                    case 'typescript':
                    case 'javascript':
                        return `${base}ts.worker.bundle.js`;
                    default:
                        return `${base}editor.worker.bundle.js`;
                }
            }
        };
    }
}
async function loadMonacoEditor() {
    initializeMonacoEnvironment();
    const monaco = await import('monaco-editor');
    return monaco.default || monaco;
}
/**
 * Editor component for displaying and editing code
 *
 * Based on the monaco editor (the same editor as in VS Code)
 * Supports syntax highlighting for various languages (default: JSON)
 * and can be extended with additional features like JSON schema validation
 */
class EditorComponent {
    constructor(zone, themeSwitcher) {
        this.zone = zone;
        this.themeSwitcher = themeSwitcher;
        /**
         * Options to pass to the monaco editor instance
         * Allows to e.g. set a different language.
         */
        this.editorOptions = {};
        /**
         * Emits the editor instance once it is initialized
         * Can be used to e.g. access the monaco instance and add a JSON schema for validation
         */
        this.editorInit = new EventEmitter();
        this._readOnly = false;
        this._currentValue = '';
        this.themeChanges$ = this.themeSwitcher.currentlyAppliedTheme$.pipe(takeUntilDestroyed());
    }
    writeValue(obj) {
        if (typeof obj === 'string') {
            this._currentValue = obj;
        }
        else {
            this._currentValue = JSON.stringify(obj, null, 2);
        }
        if (this.editor) {
            this.editor.setValue(this._currentValue);
        }
    }
    registerOnChange(fn) {
        this._onChanges = fn;
        this.register();
    }
    registerOnTouched(fn) {
        this._onTouched = fn;
        this.register();
    }
    setDisabledState(isDisabled) {
        this._readOnly = isDisabled;
    }
    async ngAfterViewInit() {
        this.monaco = await loadMonacoEditor();
        this.editor = this.monaco.editor.create(this._editorContainer.nativeElement, Object.assign({
            value: this._currentValue || '',
            language: 'json',
            automaticLayout: true,
            readOnly: this._readOnly
        }, this.editorOptions));
        window.monacoEditor = this.editor;
        this.editorInit.emit(this.editor);
        this.register();
        if (this.theme) {
            this.setTheme(this.theme);
        }
        else {
            this.themeChanges$.subscribe(theme => {
                this.setTheme(theme);
            });
        }
    }
    ngOnChanges(changes) {
        if (changes.editorOptions && this.editor) {
            this.updateOptionsAndLanguage(changes);
        }
    }
    register() {
        if (!this.editor) {
            return;
        }
        if (this._onChanges) {
            const onChanges = this._onChanges;
            this.editor.onDidChangeModelContent(() => {
                this.zone.run(() => {
                    const value = this.editor.getValue();
                    this._currentValue = value;
                    onChanges(value);
                });
            });
            this._onChanges = undefined;
        }
        if (this._onTouched) {
            const onTouched = this._onTouched;
            this.editor.onDidChangeModelContent(() => {
                this.zone.run(() => {
                    onTouched();
                });
            });
            this._onTouched = undefined;
        }
    }
    ngOnDestroy() {
        this.editor?.getModel().dispose();
        this.editor?.dispose();
    }
    setTheme(theme) {
        const themeToSet = theme === 'dark' ? `vs-dark` : 'vs';
        this.monaco.editor.setTheme(themeToSet);
    }
    updateOptionsAndLanguage(changes) {
        this.editor.updateOptions(this.editorOptions);
        if (this.editorOptions.language !== changes.editorOptions.previousValue.language) {
            const model = this.editor.getModel();
            if (model) {
                this.monaco.editor.setModelLanguage(model, this.editorOptions.language);
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EditorComponent, deps: [{ token: i0.NgZone }, { token: i1.ThemeSwitcherService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: EditorComponent, isStandalone: true, selector: "c8y-editor", inputs: { editorOptions: "editorOptions", theme: "theme" }, outputs: { editorInit: "editorInit" }, providers: [
            {
                provide: NG_VALUE_ACCESSOR,
                useExisting: forwardRef(() => EditorComponent),
                multi: true
            }
        ], viewQueries: [{ propertyName: "_editorContainer", first: true, predicate: ["editorContainer"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<c8y-loading *ngIf=\"!monaco\"></c8y-loading>\n<div class=\"editor-container\" style=\"height: 100%\" #editorContainer></div>\n", dependencies: [{ kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: EditorComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-editor', standalone: true, imports: [LoadingComponent, NgIf], providers: [
                        {
                            provide: NG_VALUE_ACCESSOR,
                            useExisting: forwardRef(() => EditorComponent),
                            multi: true
                        }
                    ], template: "<c8y-loading *ngIf=\"!monaco\"></c8y-loading>\n<div class=\"editor-container\" style=\"height: 100%\" #editorContainer></div>\n" }]
        }], ctorParameters: () => [{ type: i0.NgZone }, { type: i1.ThemeSwitcherService }], propDecorators: { editorOptions: [{
                type: Input
            }], theme: [{
                type: Input
            }], editorInit: [{
                type: Output
            }], _editorContainer: [{
                type: ViewChild,
                args: ['editorContainer', { static: true }]
            }] } });

class MonacoEditorMarkerValidatorDirective {
    constructor(editorComponent, zone) {
        this.editorComponent = editorComponent;
        this.zone = zone;
    }
    ngOnDestroy() {
        this.editorInitSubscription?.unsubscribe();
    }
    validate(_control) {
        if (!this.editorComponent.monaco || !this.editorComponent.editor) {
            return null;
        }
        const uri = this.editorComponent.editor.getModel().uri;
        const markers = this.editorComponent.monaco.editor.getModelMarkers({ resource: uri });
        if (markers.length) {
            return markers;
        }
        return null;
    }
    registerOnValidatorChange(fn) {
        this.editorInitSubscription = this.editorComponent.editorInit.subscribe(editor => {
            editor.onDidChangeModelDecorations(() => {
                this.zone.run(() => {
                    fn();
                });
            });
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MonacoEditorMarkerValidatorDirective, deps: [{ token: EditorComponent }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: MonacoEditorMarkerValidatorDirective, isStandalone: true, selector: "c8y-editor [monacoEditorMarkerValidator]", providers: [
            {
                provide: NG_VALIDATORS,
                useExisting: forwardRef(() => MonacoEditorMarkerValidatorDirective),
                multi: true
            }
        ], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MonacoEditorMarkerValidatorDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: 'c8y-editor [monacoEditorMarkerValidator]',
                    standalone: true,
                    providers: [
                        {
                            provide: NG_VALIDATORS,
                            useExisting: forwardRef(() => MonacoEditorMarkerValidatorDirective),
                            multi: true
                        }
                    ]
                }]
        }], ctorParameters: () => [{ type: EditorComponent }, { type: i0.NgZone }] });

/**
 * Generated bundle index. Do not edit.
 */

export { EditorComponent, MonacoEditorMarkerValidatorDirective, initializeMonacoEnvironment, loadMonacoEditor };
//# sourceMappingURL=c8y-ngx-components-editor.mjs.map
