'use strict';

goog.provide('Blockly.JavaScript.Timeouts');

goog.require('Blockly.JavaScript');

Blockly.CustomBlocks = Blockly.CustomBlocks || [];
Blockly.CustomBlocks.push('Timeouts');

Blockly.Timeouts = {
    HUE: 70,
    blocks: {}
};

/**
 * Ensure two identically-named procedures don't exist.
 * @param {string} name Proposed procedure name.
 * @param {!Blockly.Block} block Block to disambiguate.
 * @return {string} Non-colliding name.
 */
Blockly.Timeouts.findLegalName = function(name, block) {
    if (block.isInFlyout) {
        // Flyouts can have multiple procedures called 'do something'.
        return name;
    }
    while (!Blockly.Timeouts.isLegalName_(name, block.workspace, block)) {
        // Collision with another procedure.
        var r = name.match(/^(.*?)(\d+)$/);
        if (!r) {
            name += '2';
        } else {
            name = r[1] + (parseInt(r[2], 10) + 1);
        }
    }
    return name;
};

/**
 * Does this procedure have a legal name?  Illegal names include names of
 * procedures already defined.
 * @param {string} name The questionable name.
 * @param {!Blockly.Workspace} workspace The workspace to scan for collisions.
 * @param {Blockly.Block=} opt_exclude Optional block to exclude from
 *     comparisons (one doesn't want to collide with oneself).
 * @return {boolean} True if the name is legal.
 * @private
 */
Blockly.Timeouts.isLegalName_ = function(name, workspace, opt_exclude) {
    var blocks = workspace.getAllBlocks();
    // Iterate through every block and check the name.
    for (var i = 0; i < blocks.length; i++) {
        if (blocks[i] == opt_exclude) {
            continue;
        }
        if (blocks[i].isTimeout_ || blocks[i].isInterval_) {
            var blockName = blocks[i].getFieldValue('NAME');
            if (Blockly.Names.equals(blockName, name)) {
                return false;
            }
        }
    }
    return true;
};

/**
 * Rename a procedure.  Called by the editable field.
 * @param {string} name The proposed new name.
 * @return {string} The accepted name.
 * @this {!Blockly.Field}
 */
Blockly.Timeouts.rename = function (name) {
    // Strip leading and trailing whitespace.  Beyond this, all names are legal.
    name = name.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
    return Blockly.Timeouts.findLegalName(name, this.sourceBlock_);
};

// --- setTimeout -----------------------------------------------------------
Blockly.Timeouts.blocks['timeouts_settimeout'] =
    '<block type="timeouts_settimeout">'
    + '     <value name="NAME">'
    + '     </value>'
    + '     <value name="DELAY">'
    + '     </value>'
    + '     <value name="UNIT">'
    + '     </value>'
    + '     <value name="STATEMENT">'
    + '     </value>'
    + '</block>';

Blockly.Blocks['timeouts_settimeout'] = {
    init: function() {
        var nameField = new Blockly.FieldTextInput(
            Blockly.Timeouts.findLegalName('timeout', this),
            Blockly.Timeouts.rename);

        nameField.setSpellcheck(false);

        this.appendDummyInput()
            .appendField(Blockly.Words['timeouts_settimeout'][systemLang])
            .appendField(nameField, 'NAME')
            .appendField(Blockly.Words['timeouts_settimeout_in'][systemLang])
            .appendField(new Blockly.FieldTextInput(1000), "DELAY")
            .appendField(new Blockly.FieldDropdown([
                [Blockly.Words['timeouts_settimeout_ms'][systemLang], 'ms'],
                [Blockly.Words['timeouts_settimeout_sec'][systemLang], 'sec'],
                [Blockly.Words['timeouts_settimeout_min'][systemLang], 'min']
            ]), 'UNIT')
            .appendField(Blockly.Words['timeouts_settimeout_ms'][systemLang]);

        this.appendStatementInput("STATEMENT")
            .setCheck(null);

        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setInputsInline(false);
        this.setColour(Blockly.Timeouts.HUE);
        this.setTooltip(Blockly.Words['timeouts_settimeout_tooltip'][systemLang]);
        this.setHelpUrl(getHelp('timeouts_settimeout_help'));
    },
    isTimeout_: true,
    getVars: function () {
        return [this.getFieldValue('NAME')];
    }
};

Blockly.JavaScript['timeouts_settimeout'] = function(block) {
    var delay = block.getFieldValue('DELAY');
    var name  = block.getFieldValue('NAME');
    var unit  = block.getFieldValue('UNIT');
    if (unit === 'min') {
        delay *= 60000;
    } else if (unit === 'sec') {
        delay *= 1000;
    }
    var statements_name = Blockly.JavaScript.statementToCode(block, 'STATEMENT');
    return name + ' = setTimeout(function () {\n' + statements_name + '}, ' + delay + ');\n';
};

// --- clearTimeout -----------------------------------------------------------
Blockly.Timeouts.getAllTimeouts = function (workspace) {
    var blocks = workspace.getAllBlocks();
    var result = [];

    // Iterate through every block and check the name.
    for (var i = 0; i < blocks.length; i++) {
        if (blocks[i].isTimeout_) {
            result.push([blocks[i].getFieldValue('NAME'), blocks[i].getFieldValue('NAME')]);
        }
    }
    if (!result.length) result.push(['', '']);

    return result;
};

Blockly.Timeouts.blocks['timeouts_cleartimeout'] =
    '<block type="timeouts_cleartimeout">'
    + '     <value name="NAME">'
    + '     </value>'
    + '</block>';

Blockly.Blocks['timeouts_cleartimeout'] = {
    init: function() {
        this.appendDummyInput('NAME')
            .appendField(Blockly.Words['timeouts_cleartimeout'][systemLang])
            .appendField(new Blockly.FieldDropdown(function () {
                return Blockly.Timeouts.getAllTimeouts(scripts.blocklyWorkspace);
            }), 'NAME');

        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setInputsInline(true);
        this.setColour(Blockly.Timeouts.HUE);
        this.setTooltip(Blockly.Words['timeouts_cleartimeout_tooltip'][systemLang]);
        this.setHelpUrl(getHelp('timeouts_cleartimeout_help'));
    }
};

Blockly.JavaScript['timeouts_cleartimeout'] = function(block) {
    var name = block.getFieldValue('NAME');
    return '(function () {if (' + name + ') {clearTimeout(' + name + '); ' + name + ' = null;}})();\n';
};

// --- setInterval -----------------------------------------------------------
Blockly.Timeouts.blocks['timeouts_setinterval'] =
    '<block type="timeouts_setinterval">'
    + '     <value name="NAME">'
    + '     </value>'
    + '     <value name="INTERVAL">'
    + '     </value>'
    + '     <value name="UNIT">'
    + '     </value>'
    + '     <value name="STATEMENT">'
    + '     </value>'
    + '</block>';

Blockly.Blocks['timeouts_setinterval'] = {
    init: function() {
        var nameField = new Blockly.FieldTextInput(
            Blockly.Timeouts.findLegalName(Blockly.Words['timeouts_setinterval_name'][systemLang], this),
            Blockly.Timeouts.rename);

        nameField.setSpellcheck(false);

        this.appendDummyInput()
            .appendField(Blockly.Words['timeouts_setinterval'][systemLang])
            .appendField(nameField, 'NAME')
            .appendField(Blockly.Words['timeouts_setinterval_in'][systemLang])
            .appendField(new Blockly.FieldTextInput(1000), "INTERVAL")
            .appendField(new Blockly.FieldDropdown([
                [Blockly.Words['timeouts_settimeout_ms'][systemLang], 'ms'],
                [Blockly.Words['timeouts_settimeout_sec'][systemLang], 'sec'],
                [Blockly.Words['timeouts_settimeout_min'][systemLang], 'min']
            ]), 'UNIT')
            .appendField(Blockly.Words['timeouts_setinterval_ms'][systemLang]);

        this.appendStatementInput("STATEMENT")
            .setCheck(null);

        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setInputsInline(false);
        this.setColour(Blockly.Timeouts.HUE);
        this.setTooltip(Blockly.Words['timeouts_setinterval_tooltip'][systemLang]);
        this.setHelpUrl(getHelp('timeouts_setinterval_help'));
    },
    isInterval_: true,
    getVars: function () {
        return [this.getFieldValue('NAME')];
    }
};

Blockly.JavaScript['timeouts_setinterval'] = function(block) {
    var delay = block.getFieldValue('INTERVAL');
    var name  = block.getFieldValue('NAME');
    var unit  = block.getFieldValue('UNIT');
    if (unit === 'min') {
        delay *= 60000;
    } else if (unit === 'sec') {
        delay *= 1000;
    }

    var statements_name = Blockly.JavaScript.statementToCode(block, 'STATEMENT');
    return name + ' = setInterval(function () {\n' + statements_name + '}, ' + delay + ');\n';
};

// --- clearInterval -----------------------------------------------------------
Blockly.Timeouts.blocks['timeouts_clearinterval'] =
    '<block type="timeouts_clearinterval">'
    + '     <value name="NAME">'
    + '     </value>'
    + '</block>';

Blockly.Timeouts.getAllIntervals = function (workspace) {
    var blocks = workspace.getAllBlocks();
    var result = [];

    // Iterate through every block and check the name.
    for (var i = 0; i < blocks.length; i++) {
        if (blocks[i].isInterval_) {
            result.push([blocks[i].getFieldValue('NAME'), blocks[i].getFieldValue('NAME')]);
        }
    }

    if (!result.length) result.push(['', '']);

    return result;
};

Blockly.Blocks['timeouts_clearinterval'] = {
    init: function() {
        this.appendDummyInput("NAME")
            .appendField(Blockly.Words['timeouts_clearinterval'][systemLang])
            .appendField(new Blockly.FieldDropdown(function () {
                return Blockly.Timeouts.getAllIntervals(scripts.blocklyWorkspace);
            }), "NAME");

        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setInputsInline(true);
        this.setColour(Blockly.Timeouts.HUE);
        this.setTooltip(Blockly.Words['timeouts_clearinterval_tooltip'][systemLang]);
        this.setHelpUrl(getHelp('timeouts_clearinterval_help'));
    }
};

Blockly.JavaScript['timeouts_clearinterval'] = function(block) {
    var name = block.getFieldValue('NAME');
    return '(function () {if (' + name + ') {clearInterval(' + name + '); ' + name + ' = null;}})();\n';
};