var editor = ace.edit("editor");
editor.setTheme("ace/theme/tomorrow_night");
editor.setShowPrintMargin(false);
editor.session.setMode("ace/mode/javascript");

// Append the theme <style> block
let style = document.createElement("style");
style.setAttribute('id', 'ace-custom-theme');
let head = document.getElementsByTagName('head')[0];
head.appendChild(style);

// Set up change event
editor.getSession().on('change', () => {
    window.parent.postMessage({
        'name': 'updateStatus',
        'data': 'dirty'
    }, '*');
});

let toolbar = {
    items: [
        {
            type: "button",
            file: "floppy.small.svg",
            tooltip: "Save",
            name: "save",
        }
    ]
};

var toolbarItems = {};
toolbar.items.forEach( (item) => {
    if (item.name) {
        toolbarItems[item.name] = item;
    }
});

// Handle OCCAM events
window.addEventListener('message', function(event) {
    if (event.data.name === 'updateConfiguration') {
        var configuration = event.data.data;

        // If it is the first configuration, then set the theme
        if (configuration.index == 1) {
            configuration = configuration.values;

            if (configuration.theme != "custom") {
                // Set the theme
                editor.setTheme('ace/theme/' + configuration.theme);

                // Void out custom theme
                style.textContent = "";
            }
            else {
                // Set the theme to one that is known to us
                editor.setTheme('ace/theme/cobalt');

                // Get the theme data
                let theme = configuration.custom_theme;

                let reform = function(background, opacity) {
                    let r = parseInt(background.substring(1, 3), 16);
                    let g = parseInt(background.substring(3, 5), 16);
                    let b = parseInt(background.substring(5, 7), 16);

                    return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + opacity + ')';
                };

                // Craft the css
                css = ""
                css += ".ace-cobalt .ace_gutter{background: " + theme.gutter.background + " !important; color: " + theme.gutter.text + " !important}";
                css += ".ace-cobalt .ace_print-margin{background: " + theme.print_margin.background + " !important; width: " + theme.print_margin.width + "px !important}";
                css += ".ace-cobalt{background: " + theme.editor.background + " !important; color: " + theme.editor.text + " !important}";
                css += ".ace-cobalt .ace_cursor{color: " + theme.editor.cursor + " !important}";
                css += ".ace-cobalt .ace_marker-layer .ace_selection{background: " + reform(theme.selection.background, theme.selection.opacity) + " !important}";
                css += ".ace-cobalt .ace_marker-layer .ace_step{background: " + reform(theme.step.background, theme.step.opacity) + " !important}";
                css += ".ace-cobalt .ace_marker-layer .ace_active-line{background: " + reform(theme.active_line.background, theme.active_line.opacity) + " !important}";
                css += ".ace-cobalt .ace_marker-layer .ace_bracket{background: " + reform(theme.bracket.background, theme.bracket.opacity) + " !important}";
                css += ".ace-cobalt .ace_gutter-active-line{background: " + theme.active_line.gutter.background + " !important}";
                css += ".ace-cobalt .ace_marker-layer .ace_selected-word{background: " + reform(theme.selected_word.background, theme.selected_word.opacity) + " !important}";
                css += ".ace-cobalt .ace_invisible{background: " + reform(theme.invisible.background, theme.invisible.opacity) + " !important}";
                css += ".ace-cobalt .ace_support{background: " + reform(theme.support.background, theme.support.opacity) + " !important; color: " + theme.support.text + " !important}";
                css += ".ace-cobalt .ace_string{background: " + reform(theme.string.background, theme.string.opacity) + " !important; color: " + theme.string.text + " !important}";
                css += ".ace-cobalt .ace_comment{background: " + reform(theme.comment.background, theme.comment.opacity) + " !important; color: " + theme.comment.text + " !important}";
                css += ".ace-cobalt .ace_invalid{background: " + reform(theme.invalid.background, theme.invalid.opacity) + " !important; color: " + theme.invalid.text + " !important}";
                css += ".ace-cobalt .ace_entity{background: " + reform(theme.entity.background, theme.entity.opacity) + " !important; color: " + theme.entity.text + " !important}";
                css += ".ace-cobalt .ace_xml_pe{background: " + reform(theme.xml_pe.background, theme.xml_pe.opacity) + " !important; color: " + theme.xml_pe.text + " !important}";
                css += ".ace-cobalt .ace_variable{background: " + reform(theme.variable.background, theme.variable.opacity) + " !important; color: " + theme.variable.text + " !important}";
                css += ".ace-cobalt .ace_keyword{background: " + reform(theme.keyword.background, theme.keyword.opacity) + " !important; color: " + theme.keyword.text + " !important}";
                css += ".ace-cobalt .ace_constant{background: " + reform(theme.constant.background, theme.constant.opacity) + " !important; color: " + theme.constant.text + " !important}";
                css += ".ace-cobalt .ace_meta{background: " + reform(theme.meta.background, theme.meta.opacity) + " !important; color: " + theme.meta.text + " !important}";
                css += ".ace-cobalt .ace_meta.ace_tag{background: " + reform(theme.tag.background, theme.tag.opacity) + " !important; color: " + theme.tag.text + " !important}";
                css += ".ace-cobalt .ace_string.ace_regexp{background: " + reform(theme.regexp.background, theme.regexp.opacity) + " !important; color: " + theme.regexp.text + " !important}";
                style.textContent = css;

                style.remove();
                head.appendChild(style);
            }

            if (configuration.fontSize) {
                editor.setOption('fontSize', configuration.fontSize + 'px');
            }
            else {
                editor.setOption('fontSize', '12px');
            }

            if (configuration.fontFamily) {
                editor.setOption('fontFamily', configuration.fontFamily);
            }
            else {
                editor.setOption('fontFamily', "'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace");
            }
        }
        else if (configuration.index == 2) {
            configuration = configuration.values;

            ['useSoftTabs', 'showInvisibles', 'showGutter',
             'showLineNumbers', 'showFoldWidgets', 'showPrintMargin',
             'highlightGutterLine', 'fixedWidthGutter', 'highlightActiveLine',
             'highlightSelectedWord', 'useElasticTabstops', 'indentedSoftWrap',
             'cursorStyle'].forEach( (key) => {
                editor.setOption(key, configuration[key]);
            });
        }
    }
    else if (event.data.name === 'updateStatus') {
        if (event.data.data == "ready") {
            // Maximize the widget
            window.parent.postMessage({
                'name': 'updateSize',
                'data': {
                    'height': "100%"
                }
            }, '*');

            // Say we are "loading"
            window.parent.postMessage({
                'name': 'updateStatus',
                'data': "loading"
            }, '*');

            // Initialize empty toolbar
            window.parent.postMessage({
                'name': 'updateToolbar',
                'data': { items: [] }
            }, '*');

            // Request input data
            window.parent.postMessage({
                'name': 'updateInput'
            }, '*');
        }
    }
    else if (event.data.name === 'updateToolbar') {
        if (event.data.data.name === 'save') {
            var data = editor.getValue();
            window.parent.postMessage({
                'name': 'updateFile',
                'file': inputInfo.file,
                'data': data
            }, '*');
        }
    }
    else if (event.data.name === 'updateInput') {
        var objectInfo = event.data.data;

        // Say we are "loading"
        window.parent.postMessage({
            'name': 'updateStatus',
            'data': "loading"
        }, '*');

        inputInfo = objectInfo;

        if (inputInfo) {
            // Get the filename to pull the data
            var filename = objectInfo.file;
            var url = objectInfo.url;

            var modelist = ace.require("ace/ext/modelist");
            var mode = modelist.getModeForPath(filename);
            // mode.name (small name), mode.caption (description name), mode.mode (module path)
            editor.session.setMode(mode.mode);

            if (inputInfo.link) {
                // Load toolbar when the editor is active
                window.parent.postMessage({
                    'name': 'updateToolbar',
                    'data': toolbar
                }, '*');
            }

            // Pull the data
            fetch(url, {
                credentials: 'include'
            }).then(function(response) {
                return response.text()
            }).then(function(text) {
                editor.setValue(text, -1); // -1 moves the cursor to the start (without this,
                // it will select the entire text)
                editor.getSession().setUndoManager(new ace.UndoManager());

                // Say we are "loaded"
                window.parent.postMessage({
                    'name': 'updateStatus',
                    'data': "loaded"
                }, '*');
            });
        }
        else {
            // No file to load

            // Create the toolbar anyway
            window.parent.postMessage({
                'name': 'updateToolbar',
                'data': toolbar
            }, '*');

            // Say we are "loaded"
            window.parent.postMessage({
                'name': 'updateStatus',
                'data': "loaded"
            }, '*');
        }
    }
});

// We are ready.

// Say we are "loading"
window.parent.postMessage({
    'name': 'updateStatus',
    'data': "loading"
}, '*');

// Initialize toolbar
window.parent.postMessage({
    'name': 'updateToolbar',
    'data': toolbar
}, '*');

// Request configuration data.
window.parent.postMessage({
    'name': 'updateConfiguration'
}, '*');

// Request input file (if any)
window.parent.postMessage({
    'name': 'updateInput'
}, '*');
