/*
 * Copyright (C) 2015 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1 
 * (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-1.1>.
 * 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.
 */
 
/* global Blockly */

if (typeof Mythos === "undefined") {
// Hook up the rename function to notify the java editor when changes occur
    if (typeof window === "undefined") {
        window = {};
    }
    if (Blockly.Procedures && Blockly.Procedures.rename) {
        Blockly.Procedures.rename_old = Blockly.Procedures.rename;
        Blockly.Procedures.rename = function (name) {
            Mythos.editor.setFunctionName(name);
            return Blockly.Procedures.rename_old.call(this, name);
        };
    }
    Mythos = {
        setScriptXml: function (xml) {
            var ws = Mythos.workspace;
            ws.clear();
            var dom = new DOMParser().parseFromString(xml, 'text/xml').documentElement;
            Blockly.Xml.domToWorkspace(dom, ws);
            // Re-register custom variables after ws.clear() wiped them.
            // Must happen after domToWorkspace so we don't duplicate variables
            // that Blockly already auto-created from <field name="VAR"> elements.
            Mythos.addCustomVariables();
            var topBlocks = ws.getTopBlocks(false);
            while (topBlocks.length > 1) {
                topBlocks[topBlocks.length - 1].dispose();
                topBlocks = ws.getTopBlocks(false);
            }
        },
        getScriptXml: function () {
            return Blockly.Xml.workspaceToDom(Mythos.workspace).innerHTML;
        },
        helpUrl: 'https://docs.google.com/document/d/1VXbiY4G533-cokjQevZFhwvqMMCL--17ziMAoFoeJ5M/edit#heading=h.yv9dmneqjr2b',
        initCustomDefinitions: function () {
//            Mythos.editor.log("Add user defined types");
            Mythos.addUserDefinedTypes();
//            Mythos.editor.log("Add custom variables");
            Mythos.addCustomVariables();
//            Mythos.editor.log("Add global functions");
            Mythos.addFunctionsFromGlobalScope();
//            Mythos.editor.log("Add local functions");
            Mythos.addFunctionsFromLocalScope();
//            Mythos.editor.log("Reinitalizing toolbox");
            Mythos.workspace.updateToolbox(document.getElementById('toolbox'));
//            Mythos.editor.log("Done");
        },
        each: function (list, func) {
            if (list && list instanceof Array) {
                for (var i = 0; i < list.length; i++) {
                    func(list[i]);
                }
            } else if (list) {
                for (var i = 0; i < list.size(); i++) {
                    func(list.get(i));
                }
            }
        },
        addUserDefinedTypes: function () {
            var toolbarCategory = document.getElementById("customTypes");
            Mythos.each(Mythos.editor.getUserTypes(), function (userType) {
                var typeNode = document.createElement("block");
                typeNode.setAttribute("type", "userType_" + userType.getName());
                toolbarCategory.appendChild(typeNode);
                var getNode = document.createElement("block");
                getNode.setAttribute("type", "get_" + userType.getName());
                toolbarCategory.appendChild(getNode);
                var setNode = document.createElement("block");
                setNode.setAttribute("type", "set_" + userType.getName());
                toolbarCategory.appendChild(setNode);
                Mythos.buildCustomTypeBlocks(userType);
            });
        },
        buildCustomTypeBlocks: function (userType) {
            Blockly.Blocks['userType_' + userType.getName()] = {
                init: function () {
                    try {
                        var typeConstructor = this;
                        typeConstructor.setPreviousStatement(false);
                        typeConstructor.setNextStatement(false);
                        typeConstructor.setOutput(true, null);
                        typeConstructor.setColour(200);
                        typeConstructor.setTooltip(userType.getComment());
                        typeConstructor.appendDummyInput()
                                .appendField("Create " + userType.getName());
                        Mythos.each(userType.getAttribute(), function (attribute) {
                            typeConstructor.appendValueInput(attribute.getName())
                                    .setAlign(Blockly.ALIGN_RIGHT)
                                    .setCheck(attribute.getType())
                                    .appendField(attribute.getName());
                        });
                    } catch (error) {
                        Mythos.editor.log(error);
                    }
                }
            };
            Blockly.Blocks['set_' + userType.getName()] = {
                init: function () {
                    try {
                        var typeSetter = this;
                        typeSetter.setColour(200);
                        typeSetter.setPreviousStatement(true);
                        typeSetter.setNextStatement(true);
                        typeSetter.setOutput(false);
                        typeSetter.setTooltip(userType.getComment());
                        typeSetter.appendValueInput()
                                .setAlign(Blockly.ALIGN_LEFT)
                                .appendField("Set")
                                .appendField(new Blockly.FieldVariable(userType.getName()), "VAR")
                                .appendField(".")
                                .appendField(Mythos.getAttributeDropdown(userType), "ATTR")
                                .appendField("to");
                    } catch (error) {
                        Mythos.editor.log(error);
                    }
                }
            };
            Blockly.Blocks['get_' + userType.getName()] = {
                init: function () {
                    try {
                        var typeGetter = this;
                        typeGetter.setColour(200);
                        typeGetter.setPreviousStatement(false);
                        typeGetter.setNextStatement(false);
                        typeGetter.setOutput(true, null);
                        typeGetter.setTooltip(userType.getComment());
                        typeGetter.appendDummyInput()
                                .setAlign(Blockly.ALIGN_LEFT)
                                .appendField("Get")
                                .appendField(new Blockly.FieldVariable(userType.getName()), "VAR")
                                .appendField(".")
                                .appendField(Mythos.getAttributeDropdown(userType), "ATTR");
                    } catch (error) {
                        Mythos.editor.log(error);
                    }
                }
            };
        },
        getVariableDropdown: function (userType) {
            var variables = Mythos.editor.getVariablesByType(userType.getName());
            var options = [];
            Mythos.each(variables, function (variable) {
                options.push([variable.getName(), variable.getName()]);
            });
            return new Blockly.FieldDropdown(options);
        },
        getAttributeDropdown: function (userType) {
            var options = [];
            Mythos.each(userType.getAttribute(), function (attribute) {
                options.push([attribute.getName(), attribute.getName()]);
            });
            return new Blockly.FieldDropdown(options);
        },
        addFunctionsFromScope: function (target, prefix, functions) {
            Mythos.each(functions, function (func) {
                var scriptNode = document.createElement("block");
                scriptNode.setAttribute("type", prefix + "_" + func.getName());
                target.appendChild(scriptNode);
                scriptNode = document.createElement("block");
                scriptNode.setAttribute("type", prefix + "ignore_" + func.getName());
                target.appendChild(scriptNode);
                Blockly.Blocks[prefix + 'ignore_' + func.getName()] = {
                    init: function () {
                        this.setPreviousStatement(true);
                        this.setNextStatement(true);
                        this.setColour(250);
                        this.appendDummyInput()
                                .appendField(prefix + " " + func.getName());
                        var functionBlock = this;
                        Mythos.each(Mythos.editor.getParametersForScript(func), function (argName) {
                            functionBlock.appendValueInput(argName)
                                    .setAlign(Blockly.ALIGN_RIGHT)
                                    .setCheck(null)
                                    .appendField(argName);
                        });
                    }
                };
                Blockly.Blocks[prefix + '_' + func.getName()] = {
                    init: function () {
                        this.setColour(250);
                        this.setPreviousStatement(false);
                        this.setNextStatement(false);
                        this.setOutput(true, null);
                        this.appendDummyInput()
                                .appendField(prefix + " " + func.getName());
                        var functionBlock = this;
                        Mythos.each(Mythos.editor.getParametersForScript(func), function (argName) {
                            functionBlock.appendValueInput(argName)
                                    .setAlign(Blockly.ALIGN_RIGHT)
                                    .setCheck(null)
                                    .appendField(argName);
                        });
                    }
                };
            });
        },
        addFunctionsFromGlobalScope: function () {
            var toolbarCategory = document.getElementById("globalFunctions");
            Mythos.addFunctionsFromScope(toolbarCategory, "Global", Mythos.editor.getGlobalFunctions());
        },
        addFunctionsFromLocalScope: function () {
            var toolbarCategory = document.getElementById("localFunctions");
            Mythos.addFunctionsFromScope(toolbarCategory, "Local", Mythos.editor.getLocalFunctions());
        },
        addCustomVariables: function () {
            // Register global and local variables from the Java model into the workspace
            // variable map so they appear in variables_get/variables_set dropdowns.
            // Uses type '' (empty string) which is what the standard variable blocks expect.
            // createVariable() is idempotent: returns the existing var if already present.
            Mythos.each(Mythos.editor.getGlobalVariables(), function (variable) {
                var name = variable.getName();
                if (name) {
                    Mythos.workspace.createVariable(name, '');
                }
            });
            Mythos.each(Mythos.editor.getLocalVariables(), function (variable) {
                var name = variable.getName();
                if (name) {
                    Mythos.workspace.createVariable(name, '');
                }
            });
        },
        initBlocks: function () {
            Blockly.Blocks['flow_for'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(180);
                    this.appendDummyInput()
                            .appendField("For");
                    this.appendStatementInput("PRE")
                            .setAlign(Blockly.ALIGN_RIGHT)
                            .appendField("Init");
                    this.appendValueInput("CONDITION")
                            .setCheck("Boolean")
                            .appendField("condition");
                    this.appendStatementInput("AFTERTHOUGHT")
                            .setAlign(Blockly.ALIGN_RIGHT)
                            .appendField("after");
                    this.appendStatementInput("BODY")
                            .setAlign(Blockly.ALIGN_RIGHT)
                            .appendField("loop body");
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.setTooltip('');
                }
            };
            Blockly.Blocks['flow_repeat'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(180);
                    this.appendDummyInput()
                            .appendField("Repeat");
                    this.appendStatementInput("BODY")
                            .setAlign(Blockly.ALIGN_RIGHT)
                            .appendField("loop body");
                    this.appendValueInput("CONDITION")
                            .setCheck("Boolean")
                            .appendField("until");
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.setTooltip('');
                }
            };
            Blockly.Blocks['flow_break'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(180);
                    this.appendDummyInput()
                            .appendField("Break");
                    this.setTooltip('Break out of current loop');
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                }
            };
            Blockly.Blocks['flow_continue'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(180);
                    this.appendDummyInput()
                            .appendField("Continue");
                    this.setTooltip('Restart at top of current loop');
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                }
            };
            Blockly.Blocks['logic_cointoss'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(210);
                    this.appendDummyInput()
                            .appendField("Coin toss");
                }
            };
            Blockly.Blocks['events_set_map'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(false);
                    this.appendDummyInput()
                            .appendField("Set map to")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField('x')
                            .appendField(new Blockly.FieldTextInput("0"), "X")
                            .appendField('y')
                            .appendField(new Blockly.FieldTextInput("0"), "Y")
                            .appendField('facing')
                            .appendField(new Blockly.FieldTextInput("0"), "FACING")
                            .appendField('(0-15)');
                    this.setOutput(false);
                    this.setTooltip('Switch to a different map (by name) and set position on it');
                }
            };
            Blockly.Blocks['events_teleport'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Teleport to")
                            .appendField('x')
                            .appendField(new Blockly.FieldTextInput("0"), "X")
                            .appendField('y')
                            .appendField(new Blockly.FieldTextInput("0"), "Y")
                            .appendField('facing')
                            .appendField(new Blockly.FieldTextInput("0"), "FACING")
                            .appendField('(0-15)');
                    this.setOutput(false);
                    this.setTooltip('Teleport the player to a given location and direction on this map.');
                }
            };
            Blockly.Blocks['events_move_backward'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Move backward");
                    this.setOutput(false);
                    this.setTooltip('Moves the player one step backward.');
                }
            };
            Blockly.Blocks['events_set_sky'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Set sky color to")
                            .appendField(new Blockly.FieldTextInput("0"), "COLOR")
                            .appendField('(0-17)');
                    this.setOutput(false);
                    this.setTooltip('Set color of the sky');
                }
            };
            Blockly.Blocks['events_set_ground'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Set ground color to")
                            .appendField(new Blockly.FieldTextInput("0"), "COLOR")
                            .appendField('(0-17)');
                    this.setOutput(false);
                    this.setTooltip('Set color of the ground');
                }
            };
            Blockly.Blocks['events_add_encounter_zone'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Add encounter zone for enemy code")
                            .appendField(new Blockly.FieldTextInput(""), "CODE")
                            .appendField('at X=')
                            .appendField(new Blockly.FieldTextInput("0"), "X")
                            .appendField('Y=')
                            .appendField(new Blockly.FieldTextInput("0"), "Y")
                            .appendField('with max dist')
                            .appendField(new Blockly.FieldTextInput("0"), "MAXDIST")
                            .appendField('(0=inf), and chance')
                            .appendField(new Blockly.FieldTextInput("0.0"), "CHANCE")
                            .appendField('%');
                    this.setOutput(false);
                    this.setTooltip('Add an encounter zone');
                }
            };
            Blockly.Blocks['events_add_encounter_zone'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Add encounter zone for enemy code")
                            .appendField(new Blockly.FieldTextInput(""), "CODE")
                            .appendField('at X=')
                            .appendField(new Blockly.FieldTextInput("0"), "X")
                            .appendField('Y=')
                            .appendField(new Blockly.FieldTextInput("0"), "Y")
                            .appendField('with max dist')
                            .appendField(new Blockly.FieldTextInput("0"), "MAXDIST")
                            .appendField('(0=inf), and chance')
                            .appendField(new Blockly.FieldTextInput("0.0"), "CHANCE")
                            .appendField('%');
                    this.setOutput(false);
                    this.setTooltip('Add an encounter zone');
                }
            };
            Blockly.Blocks['events_start_encounter'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Start encounter with enemy code")
                            .appendField(new Blockly.FieldTextInput(""), "CODE");
                    this.setOutput(false);
                    this.setTooltip('Start an encounter');
                }
            };
            Blockly.Blocks['events_clr_encounter_zones'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Clear encounter zones");
                    this.setOutput(false);
                    this.setTooltip('Clear all encounter zones (for no encounters, or to add new zones)');
                }
            };
            Blockly.Blocks['text_window'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .setAlign(Blockly.ALIGN_RIGHT)
                            .appendField("Window")
                            .appendField('left')
                            .appendField(new Blockly.FieldTextInput("0"), "left")
                            .appendField('right')
                            .appendField(new Blockly.FieldTextInput("39"), "right");
                    this.appendDummyInput()
                            .setAlign(Blockly.ALIGN_RIGHT)
                            .appendField('top')
                            .appendField(new Blockly.FieldTextInput("0"), "top")
                            .appendField('bottom')
                            .appendField(new Blockly.FieldTextInput("23"), "bottom");
                    this.setOutput(false);
                    this.setTooltip('Define text window boundaries');
                }
            };
            Blockly.Blocks['text_moveto'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Move to")
                            .appendField('x')
                            .appendField(new Blockly.FieldTextInput("0"), "x")
                            .appendField('y')
                            .appendField(new Blockly.FieldTextInput("0"), "y");
                    this.setOutput(false);
                    this.setTooltip('Move text cursor to specified position');
                }
            };
            Blockly.Blocks['text_println'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendValueInput("VALUE")
                            .appendField("Println");
                    this.setOutput(false);
                    this.setTooltip('Print text and advance to next line');
                }
            };
            Blockly.Blocks['text_print'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendValueInput("VALUE")
                            .appendField("Print");
                    this.setOutput(false);
                    this.setTooltip('Print text and leave cursor at end of last printed character');
                }
            };
            Blockly.Blocks['text_printnum'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendValueInput("VALUE")
                            .appendField("Print number");
                    this.setOutput(false);
                    this.setTooltip('Print a number and leave cursor at end of last printed character');
                }
            };
            Blockly.Blocks['text_storybook'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendValueInput("INTRO")
                            .appendField("Storybook: intro");
                    this.appendValueInput("SHORT")
                            .appendField("short text");
                    this.appendValueInput("LONG")
                            .appendField("long text");
                    this.setOutput(false);
                    this.setTooltip('Show story text (floppy ver = intro+short, else intro+long)');
                }
            };
            Blockly.Blocks['text_getanykey'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Get any key");
                    this.setOutput(false);
                    this.setTooltip('Get a key from the keyboard (and discard it)');
                }
            };
            Blockly.Blocks['text_getanykey'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Get any key");
                    this.setOutput(false);
                    this.setTooltip('Get a key from the keyboard (and discard it)');
                }
            };
            Blockly.Blocks['text_promptanykey'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Prompt for key")
                            .appendField(new Blockly.FieldDropdown([["with", "1"], ["without", "0"]]), "CLEAR")
                            .appendField("clear");
                    this.setOutput(false);
                    this.setTooltip('Prompt "(press any key)", wait for key, optionally clear window after');
                }
            };
            Blockly.Blocks['text_clear_window'] = {
                init: function () {
                    this.setHelpUrl('https://docs.google.com/document/d/1VXbiY4G533-cokjQevZFhwvqMMCL--17ziMAoFoeJ5M');
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Clear Window");
                    this.setOutput(false);
                    this.setTooltip('Clears text window and moves cursor to the top');
                }
            };
            Blockly.Blocks['text_scroll'] = {
                init: function () {
                    this.setHelpUrl('https://docs.google.com/document/d/1VXbiY4G533-cokjQevZFhwvqMMCL--17ziMAoFoeJ5M');
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Scroll");
                    this.setOutput(false);
                    this.setTooltip('Scrolls text window up one line');
                }
            };
            Blockly.Blocks['text'] = {
                init: function () {
                    this.setHelpUrl(Blockly.Msg.TEXT_TEXT_HELPURL);
                    this.setColour(160);
                    this.appendDummyInput()
                            .appendField(this.newQuote_(true))
                            .appendField(new Blockly.FieldTextArea('', this.checkSpelling), 'TEXT')
                            .appendField(this.newQuote_(false));
                    this.setOutput(true, 'String');
                    this.setTooltip(Blockly.Msg.TEXT_TEXT_TOOLTIP);
                },
                newQuote_: function (open) {
                    var file;
                    if (open === this.RTL) {
                        file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAqUlEQVQI1z3KvUpCcRiA8ef9E4JNHhI0aFEacm1o0BsI0Slx8wa8gLauoDnoBhq7DcfWhggONDmJJgqCPA7neJ7p934EOOKOnM8Q7PDElo/4x4lFb2DmuUjcUzS3URnGib9qaPNbuXvBO3sGPHJDRG6fGVdMSeWDP2q99FQdFrz26Gu5Tq7dFMzUvbXy8KXeAj57cOklgA+u1B5AoslLtGIHQMaCVnwDnADZIFIrXsoXrgAAAABJRU5ErkJggg==';
                    } else {
                        file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAn0lEQVQI1z3OMa5BURSF4f/cQhAKjUQhuQmFNwGJEUi0RKN5rU7FHKhpjEH3TEMtkdBSCY1EIv8r7nFX9e29V7EBAOvu7RPjwmWGH/VuF8CyN9/OAdvqIXYLvtRaNjx9mMTDyo+NjAN1HNcl9ZQ5oQMM3dgDUqDo1l8DzvwmtZN7mnD+PkmLa+4mhrxVA9fRowBWmVBhFy5gYEjKMfz9AylsaRRgGzvZAAAAAElFTkSuQmCC';
                    }
                    return new Blockly.FieldImage(file, 12, 12, '"');
                },
                checkSpelling: function(value) {                    
                    if (this.sourceBlock_) {
                        if (value !== this.lastSpellCheck_) {
                            this.sourceBlock_.setCommentText(Mythos.editor.checkSpelling(value));
                        }
                        this.lastSpellCheck_ = value;
                    }
                    return value;
                }
            };
            Blockly.Blocks['text_getstring'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.appendDummyInput()
                            .appendField("Get String");
                    this.setOutput(true, "String");
                    this.setTooltip('');
                }
            };
            Blockly.Blocks['text_getnumber'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(210);
                    this.appendDummyInput()
                            .appendField("Get Number");
                    this.setOutput(true, "Number");
                    this.setTooltip('');
                }
            };
            Blockly.Blocks['text_getcharacter'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.appendDummyInput()
                            .appendField("Get Character");
                    this.setOutput(true, "Number");
                    this.setTooltip('');
                }
            };
            Blockly.Blocks['text_getboolean'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(210);
                    this.appendDummyInput()
                            .appendField("Get Yes or No");
                    this.setOutput(true, "Boolean");
                    this.setTooltip('');
                }
            };
            Blockly.Blocks['interaction_give_item'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Give item")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("to party");
                    this.setOutput(false);
                    this.setTooltip('Give an item to the party');
                }
            };
            Blockly.Blocks['interaction_take_item'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Take item")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("from party");
                    this.setOutput(false);
                    this.setTooltip('Take an item away from the party (if possible)');
                }
            };
            Blockly.Blocks['interaction_has_item'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(210);
                    this.appendDummyInput()
                            .appendField("party has item")
                            .appendField(new Blockly.FieldTextInput(""), "NAME");
                    this.setOutput(true, "Boolean");
                    this.setTooltip('Check if party has a given item');
                }
            };
            Blockly.Blocks['interaction_buy_from_store'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Buy items from store")
                    this.appendValueInput('CODE')
                        .appendField('code')
                        .setAlign(Blockly.ALIGN_RIGHT)
                        .setCheck('String');
                    this.appendValueInput('PROFIT')
                        .appendField('store profit %')
                        .setAlign(Blockly.ALIGN_RIGHT)
                        .setCheck('Number');
                    this.setOutput(false);
                    this.setTooltip('Offer item(s) with the specified store code for sale to player');
                }
            };
            Blockly.Blocks['interaction_sell_to_store'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                        .appendField("Sell items to store");
                    this.appendValueInput('PROFIT')
                        .appendField('store profit %')
                        .setAlign(Blockly.ALIGN_RIGHT)
                        .setCheck('Number');
                    this.setOutput(false);
                    this.setTooltip('Have player select item(s) to sell (except items that are equipped or have no store code)');
                }
            };
            Blockly.Blocks['interaction_add_player'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Add player")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("to party");
                    this.setOutput(false);
                    this.setTooltip('Add a player to the party');
                }
            };
            Blockly.Blocks['interaction_remove_player'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Remove player")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("from party");
                    this.setOutput(false);
                    this.setTooltip('Remove a player from the party (if possible)');
                }
            };
            Blockly.Blocks['interaction_has_player'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(210);
                    this.appendDummyInput()
                            .appendField("party has player")
                            .appendField(new Blockly.FieldTextInput(""), "NAME");
                    this.setOutput(true, "Boolean");
                    this.setTooltip('Check if party has a given player');
                }
            };
            Blockly.Blocks['interaction_bench_player'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Send a player to the bench");
                    this.setOutput(false);
                    this.setTooltip('Send a player to the bench (selected by user)');
                }
            };
            Blockly.Blocks['interaction_unbench_player'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Retrieve a benched player");
                    this.setOutput(false);
                    this.setTooltip('Retrieve a benched player (selected by user)');
                }
            };
            Blockly.Blocks['interaction_get_stat'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(230);
                    this.appendDummyInput()
                            .appendField("player's")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("stat");
                    this.setOutput(true, "Number");
                    this.setTooltip('Get best player stat in context');
                }
            };
            Blockly.Blocks['interaction_increase_stat'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Increase player's")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("stat by")
                            .appendField(new Blockly.FieldTextInput("0"), "AMOUNT");
                    this.setOutput(false);
                    this.setTooltip('Increase stat of player');
                }
            };
            Blockly.Blocks['interaction_increase_stat_expr'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendValueInput("EXPR")
                            .appendField("Increase player's")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("stat by");
                    this.setOutput(false);
                    this.setTooltip('Increase stat of player by variable amount');
                }
            };
            Blockly.Blocks['interaction_decrease_stat'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Decrease player's")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("stat by")
                            .appendField(new Blockly.FieldTextInput("0"), "AMOUNT");
                    this.setOutput(false);
                    this.setTooltip('Decrease stat of player');
                }
            };
            Blockly.Blocks['interaction_decrease_stat_expr'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendValueInput("EXPR")
                            .appendField("Decrease player's")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("stat by");
                    this.setOutput(false);
                    this.setTooltip('Decrease stat of player by variable amount');
                }
            };
            Blockly.Blocks['interaction_increase_party_stats'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Increase entire party's")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("stats by")
                            .appendField(new Blockly.FieldTextInput("0"), "AMOUNT");
                    this.setOutput(false);
                    this.setTooltip('Increase stat of every party member');
                }
            };
            Blockly.Blocks['interaction_decrease_party_stats'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Decrease entire party's")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("stats by")
                            .appendField(new Blockly.FieldTextInput("0"), "AMOUNT");
                    this.setOutput(false);
                    this.setTooltip('Decrease stat of every party member');
                }
            };
            Blockly.Blocks['interaction_get_flag'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(210);
                    this.appendDummyInput()
                            .appendField("game's")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("flag is set");
                    this.setOutput(true, "Boolean");
                    this.setTooltip('Get game flag');
                }
            };
            Blockly.Blocks['interaction_set_flag'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Set game's")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("flag");
                    this.setOutput(false);
                    this.setTooltip('Set a game flag');
                }
            };
            Blockly.Blocks['interaction_clr_flag'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Clear game's")
                            .appendField(new Blockly.FieldTextInput(""), "NAME")
                            .appendField("flag");
                    this.setOutput(false);
                    this.setTooltip('Clear a game flag');
                }
            };
            Blockly.Blocks['interaction_pause'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Pause for")
                            .appendField(new Blockly.FieldTextInput("0.5"), "NUM")
                            .appendField("second(s)");
                    this.setOutput(false);
                    this.setTooltip('Pause for a specified time');
                }
            };
            Blockly.Blocks['graphics_set_portrait'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Display portrait ")
                            .appendField(new Blockly.FieldTextInput(""), "NAME");
                    this.setOutput(false);
                    this.setTooltip('Display the given portait image (by name)');
                }
            };
            Blockly.Blocks['sound_play_emu_track'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Play track")
                            .appendField(new Blockly.FieldTextInput("1"), "NUM")
                            .appendField("in emulator")
                            .appendField(new Blockly.FieldDropdown([["once", "0"], ["repeating", "1"]]), "REPEAT");
                    this.setOutput(false);
                    this.setTooltip('Play track in emulator');
                }
            };
            Blockly.Blocks['sound_play_emu_sfx'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Play special effect")
                            .appendField(new Blockly.FieldTextInput("1"), "NUM")
                            .appendField("in emulator");
                    this.setOutput(false);
                    this.setTooltip('Play special effect in emulator');
                }
            };
            Blockly.Blocks['sound_stop_emu_playback'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Stop playback in emulator");
                    this.setOutput(false);
                    this.setTooltip('Stop playback in emulator');
                }
            };
            Blockly.Blocks['sound_generate_sfx'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                        .appendField("Generate sound effect: Name =")
                        .appendField(new Blockly.FieldTextInput(""), "NAME");
                    this.appendDummyInput()
                        .appendField("Up: A:dly=")
                        .appendField(new Blockly.FieldTextInput("0"), "A")
                        .appendField("  B:velo=")
                        .appendField(new Blockly.FieldTextInput("0"), "B")
                        .appendField("  C:noise=")
                        .appendField(new Blockly.FieldTextInput("0"), "C");
                    this.appendDummyInput()
                        .appendField("Dn: D:dly=")
                        .appendField(new Blockly.FieldTextInput("0"), "D")
                        .appendField("  E:velo=")
                        .appendField(new Blockly.FieldTextInput("0"), "E")
                        .appendField("  F:noise=")
                        .appendField(new Blockly.FieldTextInput("0"), "F");
                    this.appendDummyInput()
                        .appendField("Dur: G=")
                        .appendField(new Blockly.FieldTextInput("0"), "G");
                    this.setOutput(false);
                    this.setTooltip('Generate sound effect on internal speaker');
                }
            };
            Blockly.Blocks['graphics_set_avatar'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Set avatar to tile ")
                            .appendField(new Blockly.FieldTextInput(""), "NAME");
                    this.setOutput(false);
                    this.setTooltip('Use the given tile as the avatar image (by name)');
                }
            };
            Blockly.Blocks['graphics_swap_tile'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Copy tile from X/Y")
                            .appendField(new Blockly.FieldTextInput(""), "FROM_X")
                            .appendField(new Blockly.FieldTextInput(""), "FROM_Y")
                            .appendField("to X/Y")
                            .appendField(new Blockly.FieldTextInput(""), "TO_X")
                            .appendField(new Blockly.FieldTextInput(""), "TO_Y");
                    this.setOutput(false);
                    this.setTooltip('Copy a map tile from one spot to another (overwriting the latter)');
                }
            };
            Blockly.Blocks['graphics_clr_portrait'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Clear portrait");
                    this.setOutput(false);
                    this.setTooltip('Stop displaying a portrait, return to map display');
                }
            };
            Blockly.Blocks['graphics_set_fullscreen'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Display full screen image ")
                            .appendField(new Blockly.FieldTextInput(""), "NAME");
                    this.setOutput(false);
                    this.setTooltip('Display the given full screen image (by name)');
                }
            };
            Blockly.Blocks['graphics_clr_fullscreen'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Clear full screen image");
                    this.setOutput(false);
                    this.setTooltip('Stop displaying a full screen image, return to map display');
                }
            };
            Blockly.Blocks['graphics_intimate_mode'] = {
                init: function () {
                    this.setHelpUrl(Mythos.helpUrl);
                    this.setColour(54);
                    this.setPreviousStatement(true);
                    this.setNextStatement(true);
                    this.appendDummyInput()
                            .appendField("Intimate mode")
                            .appendField(new Blockly.FieldDropdown([["begin", "1"], ["end", "0"]]), "FLAG");
                    this.setOutput(false);
                    this.setTooltip('Begin or end intimate mode');
                }
            };
        }
    };
}
;
//------
// FieldTextArea: rewritten as ES6 class for Blockly v12+ (no Closure Library)
class MythosFieldTextArea extends Blockly.FieldTextInput {
    constructor(text, opt_changeHandler) {
        super(text, opt_changeHandler);
        this.changeHandler_ = opt_changeHandler;
    }

    clone() {
        return new MythosFieldTextArea(this.getText(), this.changeHandler_);
    }

    showEditor_(e) {
        var isMobile = /Mobi|Android|iPad/i.test(navigator.userAgent);
        if (isMobile) {
            var newValue = window.prompt(Blockly.Msg['CHANGE_VALUE_TITLE'] || 'Change value', this.getValue());
            if (newValue !== null) {
                this.setValue(newValue);
            }
            return;
        }

        var sourceBlock = this.getSourceBlock();
        var rtl = sourceBlock ? sourceBlock.RTL : false;
        var workspace = sourceBlock ? sourceBlock.workspace : null;
        // Pass workspace (arg 4) and false for takeFocus (arg 5) so Blockly's
        // focus manager doesn't steal focus away from the textarea we create.
        Blockly.WidgetDiv.show(this, rtl, () => {}, workspace, false);
        var div = Blockly.WidgetDiv.getDiv ? Blockly.WidgetDiv.getDiv() : Blockly.WidgetDiv.DIV;
        if (!div) {
            super.showEditor_(e);
            return;
        }

        var htmlInput = document.createElement('textarea');
        htmlInput.className = 'blocklyHtmlInput';
        htmlInput.setAttribute('spellcheck', false);
        htmlInput.setAttribute('cols', 80);
        htmlInput.setAttribute('rows', 7);
        div.style.fontSize = '11pt';
        div.style.width = '400px';
        div.style.background = 'transparent';
        htmlInput.style.width = '100%';
        htmlInput.style.boxSizing = 'border-box';
        htmlInput.style.fontSize = '11pt';
        htmlInput.style.backgroundColor = 'white';
        htmlInput.style.border = '2px solid #ccc';
        htmlInput.style.borderRadius = '4px';
        htmlInput.style.padding = '4px';
        htmlInput.style.boxShadow = '0 2px 6px rgba(0,0,0,0.3)';
        htmlInput.style.resize = 'vertical';
        div.appendChild(htmlInput);

        // Position the WidgetDiv near the field being edited.
        // getScaledBBox() returns absolute page coordinates of the field.
        // We position directly rather than using positionWithAnchor, to avoid
        // positionWithAnchor clamping div.style.height to a fixed estimate.
        try {
            var bbox = this.getScaledBBox();
            var viewportWidth = document.documentElement.clientWidth;
            var WIDGET_WIDTH = 400;
            // Place below the field; flip above if not enough room below.
            var left = rtl ? Math.max(0, bbox.right - WIDGET_WIDTH) : bbox.left;
            // Clamp to viewport so the widget doesn't overflow right edge.
            left = Math.min(left, viewportWidth - WIDGET_WIDTH);
            left = Math.max(0, left);
            div.style.left = left + 'px';
            div.style.top = bbox.bottom + 'px';
        } catch (ex) {
            // Leave positioning to browser defaults if bbox APIs are unavailable.
        }

        htmlInput.value = htmlInput.defaultValue = this.getValue();
        htmlInput.oldValue_ = null;
        htmlInput.focus();
        var len = htmlInput.value.length;
        htmlInput.setSelectionRange(len, len);

        htmlInput.addEventListener('keydown', (e) => {
            if (e.keyCode === 27) { // Esc
                this.setValue(htmlInput.defaultValue);
                Blockly.WidgetDiv.hide();
            }
        });
        htmlInput.addEventListener('input', () => {
            var text = htmlInput.value;
            if (text !== htmlInput.oldValue_) {
                htmlInput.oldValue_ = text;
                this.setValue(text);
            }
        });
    }
}
Blockly.FieldTextArea = MythosFieldTextArea;