Vue.component("vv-monaco-editor", {
template: '<template>     <div ref="ref_monaco_editor" style="height: 100%; width: 100%;"></div>     <script type="text/javascript" src="monaco/min/vs/loader.min.js"></script> </template>',
props :{
    monaco: Function,
    options: Object,
    theme: Object,
    lang: Object,
    value: Object,
    state: Object,
    shareSuggestion: Boolean
},
data :function () {
    return {
        editor: undefined,
        text_changed_emit: false,
        options: {}
    };
},
watch :{
    theme: function (newVal, oldVal) {
        this.setTheme(newVal);
    },
    lang: function (newVal, oldVal) {
        this.setLang(newVal);
    },
    value: function (newVal, oldVal) {
        this.setText(newVal);
    }
},
methods :{
    setOptions(options) {
        if (!this.editor || !options)
            return;
        this.options = Object.assign(this.options || {}, options);
        let new_options = Object.assign(this.editor.getRawOptions() || {}, this.options);
        this.editor.updateOptions(new_options);
    },
    getAction(action_name) {
        if (!this.editor)
            return;
        return this.editor.getAction(action_name);
    },
    setText: function (text) {
        if (!this.editor)
            return;
        let newText = typeof text === 'string' ? text : '';
        if (this.editor.getValue() === newText)
            return;
        this.editor.setValue(newText);
    },
    setLang: function (lang) {
        if (!this.editor || lang === null || typeof lang !== 'string')
            return;
        let self = this;
        require(['vs/editor/editor.main'], function () {
            monaco.editor.setModelLanguage(self.editor.getModel(), lang);
        });
    },
    setTheme: function (theme) {
        if (!this.editor || theme === null || typeof theme !== 'string')
            return;
        this.setOptions({ theme: theme });
    },
    toClipboard: function () {
        try {
            if (!this.editor)
                return;
            const textarea = document.createElement('textarea');
            textarea.value = this.editor.getValue();
            textarea.setAttribute('readonly', '');
            textarea.style.cssText = 'position:fixed;pointer-events:none;z-index:-9999;opacity:0;';
            document.body.appendChild(textarea);
            textarea.select();
            document.execCommand('copy');
            document.body.removeChild(textarea);
        } catch (error) {
            console.log('error copy to clipboard data from monaco editor:');
            console.warn(error);
        }
    }
},
mounted :function () {
    require.config({ paths: { 'vs': 'monaco/min/vs' } });
    let self = this;
    self.$refs.ref_monaco_editor.MonacoEnvironment = {
        getWorkerUrl: function (workerId, label) {
            return 'monaco/min/vs/base/worker/worker_loader_proxy.js';
        }
    };
    require(['vs/editor/editor.main'], function () {
        let options = {};
        try {
            options = typeof self.options === 'object' ? self.options : typeof self.options === 'string' ? JSON.parse(self.options) : {};
        } catch (error) {
            console.warn('IN VV-MONACO-EDITOR ERROR PARSE OPTIONS:');
            console.warn(options);
            console.error(error);
        }
        if (self.monaco) {
            self.monaco(monaco);
        }
        let build_options = {
            model: monaco.editor.createModel(undefined, options.language),
            automaticLayout: true
        };
        let ignore_prop = [
            'value',
            'language',
            'model',
            'theme'
        ];
        for (var prop in options) {
            if (ignore_prop.includes(prop))
                continue;
            build_options[prop] = options[prop];
        }
        self.editor = monaco.editor.create(self.$refs.ref_monaco_editor, build_options);
        self.setTheme(self.theme ? self.theme : options.theme);
        self.setLang(self.lang ? self.lang : options.language);
        if (self.state) {
            if (self.state.model) {
                self.editor.setModel(self.state.model);
            }
            if (self.shareSuggestion !== true && self.shareSuggestion !== 'true') {
                self.setText(self.state.text);
            }
            if (self.state.view) {
                self.editor.restoreViewState(self.state.view);
            }
            if (self.state.options) {
                self.setOptions(self.state.options);
            }
        } else {
            self.setText(self.value ? self.value : '');
        }
        self.editor.focus();
        self.text_changed_emit = true;
        self.editor.onDidChangeModelContent(e => {
            if (self.text_changed_emit === true) {
                self.$emit('input', self.editor.getValue());
            }
        });
        self.$emit('mounted');
    });
},
beforeDestroy :function () {
    if (this.editor) {
        this.text_changed_emit = false;
        let state = {
            model: this.editor.getModel(),
            view: this.editor.saveViewState(),
            text: this.editor.getValue(),
            options: this.options
        };
        this.$emit('state_changed', state);
        if (this.shareSuggestion !== true && this.shareSuggestion !== 'true') {
            this.setText('');
        }
        this.editor.dispose();
        this.editor = undefined;
    }
}
})