/* the server URL */
//var robotServer = "10.42.0.1";
var robotServer = "iot.koodur.com";
/* enable disable remote control */
var remoteControl = false;
/* the sumorobot state */
var sumostart = false;
/* the sumorobot object */
var sumorobot = null;
/* Blockly workspace */
var workspace = null;
/* last hightlighted block id */
var highlighted = "";
/* disable enable hotkeys */
var hotkeys = true;
/* the sumorobot code */
var sumocode = "";
/* block highlight WebSocket */
var block_highlight = null;

var Sumorobot = function(wsUri) {
    /* assign the WebSocket URI */
    this.wsUri = wsUri;
    /* start connecting to the WebSocket */
    this.connect();
    /* to ping the robot */
    this.watchdogTimer = null;
};

Sumorobot.prototype.connect = function() {
    /* to have access to this object */
    var self = this;
    this.websocket = new WebSocket(this.wsUri);
    /* when the WebSocket gets connected */
    this.websocket.onopen = function(evt) {
        console.log("INFO websocket connected");
        /* setup a timer to ping the robot */
        self.watchdogTimer = setInterval(function() {
            /* send a ping to the robot */
            //console.log("ping the robot")
            self.send("ping");
        }, 2000);
    };
    /* when the WebSocket closes */
    this.websocket.onclose = function(evt) {
        console.log("INFO websocket disconnected");
        /* clear the pinging */
        clearInterval(self.watchdogTimer);
        /* Try to recnnect to the sumorobot */
        self.connect();
    };
    /* when there is a message from the WebSocket */
    this.websocket.onmessage = function(evt) {
        /* when scope is received */
        var data = evt.data.replace(/'/g, '"').toLowerCase();
        console.log(data);
        var battery = JSON.parse(data)["battery_voltage"];
        battery = Math.round((((battery - 3.0) * 100) / (4.2 - 3.0)));
        $("#battery").html(battery + "%");
        //$("#bar").html("Battery");
        $("#bar").addClass("connected");
    };
    /* when there is an WebSocket error */
    this.websocket.onerror = function(err) {
        console.log("ERROR websocket error: " + err);
    };
};

Sumorobot.prototype.send = function(msg) {
    /* Ready state constants: CONNECTING 0, OPEN 1, CLOSING 2, CLOSED 3 */
    /* https://developer.mozilla.org/en-US/docs/Web/API/WebSocket */
    if (this.websocket.readyState == 1) {
        this.websocket.send(msg);
    }
};

window.onload = function() {
    /* function to update the control panel */
    function updateControlPanel() {
        /* hide all buttons and text fields */
        $(".robot-id, .robot-nr, .btn-robot-nr").hide();
        /* show the first button and text field */
        $(".robot-id:eq(0), .robot-nr:eq(0), .btn-robot-nr:eq(0)").show();

        /* adjust the buttons and text fields to be in the middle */
        $(".input-group, .btn-group-robot").css("width", "20%");
        $(".input-group, .btn-group-robot").css("margin-left", "40%");

        /* hide the robot add button */
        $(".btn-robot-add").hide();

        /* populate robots IDs and buttons */
        for (var i = 0; i < 5; i++) {
            var id = getLocalStorageItem("sumorobot.robotID" + i);
            if (id) {
                $(".robot-id:eq(" + i + ")").val(id);
                $(".robot-id:eq(" + i + "), .robot-nr:eq(" + i + "), .btn-robot-nr:eq(" + i + ")").show();
                $(".input-group, .btn-group-robot").css("width", 20 + (i * 20) + "%");
                $(".input-group, .btn-group-robot").css("margin-left", 40 - (i * 10) + "%");
            } else {
                /* when no robots yet added */
                if (i != 0) {
                    /* show the robot add button */
                    $(".btn-robot-add").show();
                    $(".btn-group-robot").css("width", 20 + (i * 20) + "%");
                    $(".input-group, .btn-group-robot").css("margin-left", 40 - (i * 10) + "%");
                    /* add click listener to the robot add button */
                    $(".btn-robot-add").click(function() {
                        $(".robot-id:eq(" + i + "), .robot-nr:eq(" + i + "), .btn-robot-nr:eq(" + i + ")").show();
                        $(".input-group, .btn-group-robot").css("width", 20 + (i * 20) + "%");
                        $(".input-group, .btn-group-robot").css("margin-left", 40 - (i * 10) + "%");
                        $(this).hide();
                    });
                }
                break;
            }
        }
    }

    /* load the control panel */
    updateControlPanel();

    /* remove previous and next statement from if block */
    Blockly.Blocks.controls_if.init = function() {
        this.setHelpUrl(Blockly.Msg.CONTROLS_IF_HELPURL);
        this.setColour(Blockly.Blocks.logic.HUE);
        this.appendValueInput("IF0").setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_IF);
        this.appendStatementInput("DO0").appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);
        this.setPreviousStatement(0);
        this.setNextStatement(0);
        this.setMutator(new Blockly.Mutator(["controls_if_elseif","controls_if_else"]));
        var a = this;
        this.setTooltip(function() {
            if (a.elseifCount_ || a.elseCount_) {
                if(!a.elseifCount_ && a.elseCount_) return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;
                if(a.elseifCount_ && !a.elseCount_) return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;
                if(a.elseifCount_ && a.elseCount_) return Blockly.Msg.CONTROLS_IF_TOOLTIP_4
            } else return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;
            return "";
        });
        this.elseCount_=this.elseifCount_ = 0;
    };
    /* magnify the tool icon on the if block */
    Blockly.Icon.prototype.renderIcon = function(cursorX) {
        if (this.collapseHidden && this.block_.isCollapsed()) {
            this.iconGroup_.setAttribute('display', 'none');
            return cursorX;
        }
        this.iconGroup_.setAttribute('display', 'block');

        var SIZE = 1.7;
        var TOP_MARGIN = 2;
        var LEFT_MARGIN = 5;
        var width = this.SIZE;
        if (this.block_.RTL) {
            cursorX -= width;
        }
        this.iconGroup_.setAttribute('transform',
            'translate(' + LEFT_MARGIN + ',' + TOP_MARGIN + ') scale(' + SIZE + ')');
        this.computeIconLocation();
        if (this.block_.RTL) {
            cursorX -= Blockly.BlockSvg.SEP_SPACE_X;
        } else {
            cursorX += width + Blockly.BlockSvg.SEP_SPACE_X;
        }
        return cursorX;
    };

    /* change to python code */
    Blockly.Sumorobot['controls_if'] = function(block) {
        // If/elseif/else condition.
        var n = 0;
        var argument = Blockly.Sumorobot.valueToCode(block, 'IF' + n,
            Blockly.Sumorobot.ORDER_NONE) || 'False';
        var branch = Blockly.Sumorobot.statementToCode(block, 'DO' + n);
        var code = 'if ' + argument + ':\n' + branch;
        if (branch === '') {
            code += '  pass\n';
        }
        for (n = 1; n <= block.elseifCount_; n++) {
            argument = Blockly.Sumorobot.valueToCode(block, 'IF' + n,
                Blockly.Sumorobot.ORDER_NONE) || 'False';
            branch = Blockly.Sumorobot.statementToCode(block, 'DO' + n);
            code += 'elif ' + argument + ':\n' + branch;
            if (branch === '') {
                code += '  pass\n';
            }
        }
        if (block.elseCount_) {
            branch = Blockly.Sumorobot.statementToCode(block, 'ELSE');
            code += 'else:\n' + branch;
            if (branch === '') {
                code += '  pass';
            }
        }
        return code + '\n';
    };

    Blockly.Sumorobot['sumorobot_delay'] = function(block) {
        var code = 'sumorobot.sleep(' + parseFloat(block.getFieldValue('DELAY')) + ', "' + block.id + '")\n';
        return code;
    };

    Blockly.Sumorobot['sumorobot_move'] = function(block) {
        var code = 'sumorobot.move(' + block.getFieldValue('MOVE') + ', "' + block.id + '")\n';
        return code;
    };

    Blockly.Sumorobot['sumorobot_enemy'] = function(block) {
        var code = 'sumorobot.is_enemy("' + block.id + '")';
        return [code, Blockly.Sumorobot.ORDER_ATOMIC];
    };

    Blockly.Sumorobot['sumorobot_line'] = function(block) {
        var code = 'sumorobot.is_line(' + block.getFieldValue('LINE') + ', "' + block.id + '")';
        return [code, Blockly.Sumorobot.ORDER_ATOMIC];
    };

    /* change the if block to be more cheerful */
    Blockly.Blocks.logic.HUE = '#44CC00';
    var blocklyArea = document.getElementById('blocklyArea');
    var blocklyDiv = document.getElementById('blocklyDiv');
    workspace = Blockly.inject(blocklyDiv, {
        scrollbars: false,
        media: 'media/',
        trashcan: true,
        sounds: true,
        zoom: {
            wheel: true,
            controls: true,
            startScale: 1.2
        },
        toolbox: document.getElementById('toolbox')
    });

    /* on blockly resize */
    var onresize = function(e) {
        // Compute the absolute coordinates and dimensions of blocklyArea.
        var element = blocklyArea;
        var x = 0;
        var y = 0;
        do {
            x += element.offsetLeft;
            y += element.offsetTop;
            element = element.offsetParent;
        } while (element);
        /* position blocklyDiv over blocklyArea */
        blocklyDiv.style.left = x + 'px';
        blocklyDiv.style.top = y + 'px';
        blocklyDiv.style.width = blocklyArea.offsetWidth + 'px';
        blocklyDiv.style.height = blocklyArea.offsetHeight + 'px';
    };
    window.addEventListener('resize', onresize, false);
    onresize();
    Blockly.svgResize(workspace);

    /* function to set local storage */
    function getLocalStorageItem(item) {
        /* when the local storage doesn't exist, return empty string */
        if (typeof(Storage) === "undefined") return "";
        /* otherwise return item from the local storage*/
        return localStorage.getItem(item);
    }

    /* function to set local storage */
    function setLocalStorageItem(item, value) {
        /* when local storage doesn't exist, return */
        if (typeof(Storage) === "undefined") return;
        /* otherwise set the item to the local storage */
        localStorage.setItem(item, value)
    }

    /* retrieve the blocks */
    var xml = Blockly.Xml.textToDom(getLocalStorageItem("sumorobot.currentProgram"));
    /* resume the blocks */
    Blockly.Xml.domToWorkspace(xml, workspace);

    /* on blockly code change */
    function onCodeChanged(event) {
        /* only process change and move commands */
        if (event.type != Blockly.Events.CHANGE && event.type != Blockly.Events.MOVE) return;
        /* generate code from the used blocks */
        sumocode = Blockly.Sumorobot.workspaceToCode(workspace);

        /* show the code to the user, filter out block IDs */
        document.getElementById("blocklyCode").value = sumocode.replace(/[,]?[ ]?"(.*?)"/g, "");

        /* save the code to the local storage */
        var xml = Blockly.Xml.workspaceToDom(workspace);
        localStorage.setItem("sumorobot.currentProgram", Blockly.Xml.domToText(xml));

        /* if the if condition block is used */
        if (sumocode.indexOf("if") != -1) {
            /* disable the if condition block */
            $("block[type=controls_if]").replaceWith("<block type='controls_if' disabled='true'></block>");
            workspace.updateToolbox(document.getElementById("toolbox"));
        } else {
            /* enable the if condition block */
            $("block[type=controls_if]").replaceWith("<block type='controls_if'></block>");
            workspace.updateToolbox(document.getElementById("toolbox"));
        }
    }

    /* add a change listener to Blockly */
    workspace.addChangeListener(onCodeChanged);

    /* key down event */
    $(document).keydown(function(e) {
        /* if the hotkeys are disabled or the focused element is a textarea or text input, don't use hotkeys */
        if (hotkeys == false || $(e.target).is("textarea") || $(e.target).is("[type=text]") || $(e.target).is("[class=blocklyHtmlInput]")) return;
        /* select the hotkey */
        switch(e.which) {
            case 32: // space bar
                sumostart = !sumostart;
                if (sumostart) {
                    $(".btn-start").addClass("hover");
                    $(".btn-start").click();
                } else {
                    $(".btn-stop").addClass("hover");
                    $(".btn-stop").click();
                }
                break;
            case 37: // left
                if (remoteControl) sumorobot.send("left");
                break;
            case 38: // up
                if (remoteControl) sumorobot.send("forward");
                break;
            case 39: // right
                if (remoteControl) sumorobot.send("right");
                break;
            case 40: // down
                if (remoteControl) sumorobot.send("backward");
                break;
            case 49: // 1
                $(".btn-robot-nr:eq(0)").click();
                break;
            case 50: // 2
                $(".btn-robot-nr:eq(1)").click();
                break;
            case 51: // 3
                $(".btn-robot-nr:eq(2)").click();
                break;
            case 52: // 4
                $(".btn-robot-nr:eq(3)").click();
                break;
            case 53: // 5
                $(".btn-robot-nr:eq(4)").click();
                break;
            case 67: // c
                updateControlPanel();
                $("#panel").toggle();
                break;
            case 76: // l
                $("#stream").toggle();
            case 82: // r
                $("#remote-control").click();
                break;
            case 83: // s
                $(".btn-stop").addClass("hover");
                $(".btn-stop").click();
                break;
            case 87: // w
                $(".btn-start").addClass("hover");
                $(".btn-start").click();
                break;
        }
    });

    /* key up event */
    $(document).keyup(function(e) {
        /* if the hotkeys are disabled or the focused element is a textarea or text input, don't use hotkeys */
        if (hotkeys == false || $(e.target).is("textarea") || $(e.target).is("[type=text]") || $(e.target).is("[class=blocklyHtmlInput]")) return;
        /* remove hover from buttons */
        $('.btn').removeClass('hover');
        /* if arrow keys */
        if (e.which == 37 || e.which == 38 || e.which == 39 || e.which == 40) {
            if (remoteControl) sumorobot.send("stop");
        }
    });

    /* start button listener */
    $(".btn-close").click(function() {
        $("#stream").hide();
    });

    /* start button listener */
    $(".btn-start").click(function() {
        sumostart = true;
        sumorobot.send("start:" + sumocode.replace(/sumorobot./g, ""));
    });

    /* stop button listener */
    $(".btn-stop").click(function() {
        sumostart = false;
        sumorobot.send("stop");
        workspace.highlightBlock(highlighted, false);
    });

    /* remote control checkbox listener */
    $("#remote-control").click(function() {
        remoteControl = $("#remote-control").is(":checked");
    });

    /* robot number button listener */
    $(".btn-robot-nr").click(function() {
        /* extract and validate the selected robot ID */
        var index = $(".btn-robot-nr").index($(this));
        var robotID = $(".robot-id:eq(" + index + ")").val();
        if (robotID.trim() === "") {
            $(".robot-nr:eq(" + index + "), .robot-id:eq(" + index + ")").addClass("has-error");
            return;
        } else {
            $(".robot-nr:eq(" + index + "), .robot-id:eq(" + index + ")").removeClass("has-error");
        }
        /* highlight the selected robot button */
        $(".btn-robot-nr").removeClass("btn-selected");
        $(this).addClass("btn-selected");
        /* update robot IDs in local storage */
        setLocalStorageItem("sumorobot.robotID" + index, robotID);
        /* connect to the selected robots WebSocket */
        sumorobot = new Sumorobot("ws://" + robotServer + ":80/p2p/browser/" + robotID + "/");
        /* connect to the other block highlight WebSocket */
        block_highlight = new WebSocket("ws://" + robotServer + ":80/p2p/browser/" + robotID + "-highlight/");
        /* when there is a message from the WebSocket */
        block_highlight.onmessage = function(evt) {
            /* when scope is received */
            if (evt.data.length == 20 && sumostart) {
                workspace.highlightBlock(evt.data);
                highlighted = evt.data;
            }
        };
        /* hide the configuration panel */
        $("#panel").hide();
    });

    $("#stream").prepend('<iframe width="100%" height="91%" allowfullscreen="true" src="https://mixer.com/embed/player/14551694"></iframe>');

    /* try to close if block bubble canvas */
    /*$(document).click(function(e) {
        var target = e.target;
        if (!$(target).is('.blocklyBubbleCanvas') && !$(target).parents().is('.blocklyBubbleCanvas')) {
            if (!$(target).is('.blocklyIconGroup') && !$(target).parents().is('.blocklyIconGroup'))
                $('.blocklyBubbleCanvas').empty();
        }
    });*/
}