/**
 * @license Licensed under the Apache License, Version 2.0 (the "License"):
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 * @fileoverview Ardublockly JavaScript for the Blockly resources and bindings.
 */
'use strict';

/** Create a namespace for the application. */
var Ardublockly = Ardublockly || {};

/**
 * Blockly main workspace.
 * @type Blockly.WorkspaceSvg
 */
Ardublockly.workspace = null;

/**
 * Blockly workspace toolbox XML.
 * @type Element
 */
Ardublockly.xmlTree = null;

Ardublockly.injectBlockly = function (blocklyEl, toolboxXml, blocklyPath) {
    // Remove any trailing slashes in the blockly path
    if (blocklyPath.substr(-1) === '/') {
        blocklyPath = blocklyPath.slice(0, -1);
    }
    // Ardublockly.xmlTree = Blockly.Xml.textToDom(toolboxXml);

    // The Toolbox menu language is edited directly from the XML nodes.
    Ardublockly.updateToolboxLanguage(toolboxXml);
    Ardublockly.workspace = Blockly.inject(blocklyEl, {
        collapse: true,
        comments: true,
        css: true,
        disable: true,
        grid: false,
        maxBlocks: Infinity,
        media: blocklyPath + '/media/',
        rtl: false,
        scrollbars: true,
        sounds: true,
        toolbox: Ardublockly.xmlTree,
        trashcan: true,
        zoom: {
            controls: true,
            wheel: false,
            startScale: 1.0,
            maxScale: 2,
            minScale: 0.2,
            scaleSpeed: 1.2
        }
    });

};

/** Binds the event listeners relevant to Blockly. */
Ardublockly.bindBlocklyEventListeners = function () {
    blockpy.components.editor.blockly.addChangeListener(Ardublockly.renderContent);

    // Ensure the Blockly workspace resizes accordingly
    window.addEventListener('resize',
        function () { Blockly.asyncSvgResize(blockpy.components.editor.blockly); }, false);
};

/** @return {!string} Generated Arduino code from the Blockly workspace. */
Ardublockly.generateArduino = function () {
    return Blockly.Python.workspaceToCode(blockpy.components.editor.blockly);
};

/** @return {!string} Generated XML code from the Blockly workspace. */
Ardublockly.generateXml = function () {
    var xmlDom = Blockly.Xml.workspaceToDom(blockpy.components.editor.blockly);
    //add tag for different mode 
    var tag = CCB.mode ? "main" : "wifi"
    var xmlText = tag + "$" + Blockly.Xml.domToPrettyText(xmlDom);
    return xmlText;
};


Ardublockly.loadXmlBlockFile = function (xmlFile, cbSuccess, cbError) {
    var request = Ardublockly.ajaxRequest();
    var requestCb = function () {
        if (request.readyState == 4) {
            if (request.status == 200) {
                var result_xml = request.responseText;
                //if file has tag(main/wifi)
                if (request.responseText.indexOf('$') == 4) {
                    result_xml = request.responseText.substr(5);
                }
                var success = Ardublockly.replaceBlocksfromXml(result_xml);
                cbSuccess(success);
            } else {
                cbError();
            }
        }
    };
    try {
        request.open('GET', xmlFile, true);
        request.onreadystatechange = requestCb;
        request.send(null);
    } catch (e) {
        cbError();
    }
};


Ardublockly.replaceBlocksfromXml = function (blocksXml) {
    var xmlDom = null;
    try {
        xmlDom = Blockly.Xml.textToDom(blocksXml);
    } catch (e) {
        return false;
    }
    blockpy.components.editor.blockly.clear();
    var sucess = false;
    if (xmlDom) {
        sucess = Ardublockly.loadBlocksfromXmlDom(xmlDom);
    }
    return sucess;
};

/**
 * Parses the XML from its argument input to generate and add blocks to the
 * Blockly workspace.
 * @param {!string} blocksXmlDom String of XML DOM code for the blocks.
 * @return {!boolean} Indicates if the XML into blocks parse was successful.
 */
Ardublockly.loadBlocksfromXmlDom = function (blocksXmlDom) {
    // try {
    //     Blockly.Xml.domToWorkspace(blocksXmlDom, blockpy.components.editor.blockly);
    // } catch (e) {
    //     return false;
    // }
    // return true;
    Blockly.Xml.domToWorkspace(blocksXmlDom, blockpy.components.editor.blockly);
    return !Blockly.Xml.getLoadingXmlErr();
};

/**
 * Save blocks into session storage. Note that MSIE 11 does not support
 * sessionStorage on file:// URLs.
 */
Ardublockly.saveSessionStorageBlocks = function () {
    if (window.sessionStorage) {
        var xml = Blockly.Xml.workspaceToDom(blockpy.components.editor.blockly);
        var text = Blockly.Xml.domToText(xml);
        window.sessionStorage.loadOnceBlocks = text;
    }
};

/** Load blocks saved on session storage and deletes them from storage. */
Ardublockly.loadSessionStorageBlocks = function () {
    try {
        var loadOnce = window.sessionStorage.loadOnceBlocks;
    } catch (e) {
        // Firefox sometimes throws a SecurityError when accessing sessionStorage.
        // Restarting Firefox fixes this, so it looks like a bug.
        var loadOnce = null;
    }
    if (loadOnce) {
        delete window.sessionStorage.loadOnceBlocks;
        var xml = Blockly.Xml.textToDom(loadOnce);
        Blockly.Xml.domToWorkspace(xml, blockpy.components.editor.blockly);
    }
};


/**
 * Save blocks into local storage. Note that MSIE 11 does not support
 * LocalStorage on file:// URLs.
 */
Ardublockly.saveLocalStorageBlocks = function () {
    if (window.sessionStorage) {
        var xml = Blockly.Xml.workspaceToDom(blockpy.components.editor.blockly);
        var text = Blockly.Xml.domToText(xml);
        window.localStorage.loadOnceBlocks = text;
    }
};
/** Load blocks saved on loacl storage and deletes them from storage. */
Ardublockly.loadLocalStorageBlocks = function () {
    try {
        var loadOnce = window.localStorage.loadOnceBlocks;
    } catch (e) {
        // Firefox sometimes throws a SecurityError when accessing sessionStorage.
        // Restarting Firefox fixes this, so it looks like a bug.
        var loadOnce = null;
    }
    if (loadOnce) {
        delete window.localStorage.loadOnceBlocks;
        var xml = Blockly.Xml.textToDom(loadOnce);
        Blockly.Xml.domToWorkspace(xml, blockpy.components.editor.blockly);
    }
};

/** Discard all blocks from the workspace. */
Ardublockly.discardAllBlocks = function () {
    var blockCount = blockpy.components.editor.blockly.getAllBlocks().length;
    var is_delete = false;
    if (blockCount == 1) {
        blockpy.components.editor.blockly.clear();
        Ardublockly.renderContent();
    } else if (blockCount > 1) {
        Ardublockly.alertMessage(
            Ardublockly.getLocalStr('discardBlocksTitle'),
            Ardublockly.getLocalStr('discardBlocksBody').replace('%1', blockCount),
            true,
            function () {
                blockpy.components.editor.blockly.clear();
                Ardublockly.renderContent();
            });
    }
};

/** @return {!boolean} Indicates if the Blockly workspace has blocks. */
Ardublockly.isWorkspaceEmpty = function () {
    return blockpy.components.editor.blockly.getAllBlocks().length ? false : true;
};

/**
 * Changes the Arduino board profile if different from the currently set one.
 * @param {string} newBoard Name of the new profile to set.
 */
Ardublockly.changeBlocklyArduinoBoard = function (newBoard) {
    if (Blockly.Python.Boards.selected !== Blockly.Python.Boards[newBoard]) {
        Blockly.Python.Boards.changeBoard(blockpy.components.editor.blockly, newBoard);
    }
};

/** Update the toolbox categories language. */
Ardublockly.updateToolboxLanguage = function (data) {
    var categories = ['catLogic', 'catLoops', 'catMath', 'catText',
        'catVariables', 'catDefine', 'catFunctions', 'catInputOutput',
        'catTime', 'catAudio', 'catMotors', 'catComms', 'catFASTLED', 'catTouch', 'catHCI',
        'catENV', 'catMOTOR', 'catROBOT', 'catLists', 'catMOTION', 'catMainWifi',
        'catCloudData', 'catWifiClient', 'catWifiWebServices', 'catWifiComms', 'catNetwork', 'catEasyMode', 'catBlynk', "ExtendedFunction"
    ];
    Ardublockly.xmlTree = Blockly.Xml.textToDom(data)
    var categoryNodes = Ardublockly.xmlTree.getElementsByTagName('category');
    for (var i = 0, cat; cat = categoryNodes[i]; i++) {
        var catId = cat.getAttribute('id');
        var catText = Ardublockly.getLocalStr(catId);
        if (catText) {
            cat.setAttribute('name', catText);
        }
    }
};

/**
 * Adds a category to the current toolbox.
 * @param {!string} categoryTitle Toolbox category title.
 * @param {!Element} categoryDom Toolbox category to add add the end of tree.
 */
Ardublockly.addToolboxCategory = function (categoryTitle, categoryDom) {
    categoryDom.id = 'cat' + categoryTitle.replace(/\s+/g, '');
    categoryDom.setAttribute('name', categoryTitle);
    Ardublockly.xmlTree.appendChild(document.createElement('sep'));
    Ardublockly.xmlTree.appendChild(categoryDom);
    blockpy.components.editor.blockly.updateToolbox(Ardublockly.xmlTree);
};

/**
 * Removes a category to the current toolbox.
 * @param {!String} categoryTitle Toolbox category name to remove from tree.
 */
Ardublockly.removeToolboxCategory = function (categoryTitle) {
    var categoryId = 'cat' + categoryTitle.replace(/\s+/g, '');
    var categoryNodes = Ardublockly.xmlTree.getElementsByTagName('category');
    for (var i = 0; i < categoryNodes.length; i++) {
        if (categoryNodes[i].getAttribute('id') === categoryId) {
            var previousNode = categoryNodes[i].previousElementSibling;
            Ardublockly.xmlTree.removeChild(categoryNodes[i]);
            if (previousNode && previousNode.nodeName == 'sep') {
                Ardublockly.xmlTree.removeChild(previousNode);
            }
        }
    }
    blockpy.components.editor.blockly.updateToolbox(Ardublockly.xmlTree);
};

/** Closes the toolbox block container sub-menu. */
Ardublockly.blocklyCloseToolbox = function () {
    blockpy.components.editor.blockly.toolbox_.flyout_.hide();
};

/** @return {!integer} The width of the blockly workspace toolbox. */
Ardublockly.blocklyToolboxWidth = function () {
    return blockpy.components.editor.blockly.toolbox_.width;
};

/** @return {!boolean} Indicates if a block is currently being dragged. */
Ardublockly.blocklyIsDragging = function () {
    return (Blockly.dragMode_ != 0) ? true : false;
};


Ardublockly.blocklyCut = function () {
    if (Blockly.selected) {
        Blockly.copy_(Blockly.selected);
        Blockly.selected.dispose(true, true);
    }
};


Ardublockly.blocklyCopy = function () {
    if (Blockly.selected) {
        Blockly.copy_(Blockly.selected);
    }
};


Ardublockly.blocklyPaste = function () {
    if (Blockly.clipboardXml_) {
        Blockly.hideChaff();
        Blockly.clipboardSource_.paste(Blockly.clipboardXml_);
    }
};


Ardublockly.blocklyDelete = function () {
    if (Blockly.selected && Blockly.selected.isDeletable()) {
        Blockly.hideChaff();
        Blockly.selected.dispose(true, true);
    }
};

/** @return {XMLHttpRequest} An XML HTTP Request multi-browser compatible. */
Ardublockly.ajaxRequest = function () {
    var request;
    try {
        // Firefox, Chrome, IE7+, Opera, Safari
        request = new XMLHttpRequest();
    } catch (e) {
        try {
            // IE6 and earlier
            request = new ActiveXObject('Msxml2.XMLHTTP');
        } catch (e) {
            try {
                request = new ActiveXObject('Microsoft.XMLHTTP');
            } catch (e) {
                throw 'Your browser does not support AJAX';
                request = null;
            }
        }
    }
    return request;
};



/**
 * get a workspace snapshot on blocks
 * handle with blocks imgs with onload function twice
 * in order to convert img into base64 format data for download
 * @param {String} name name of pic to store as 
 */
Ardublockly.workspace_capture = async function (name) {
    let _header = window.location.protocol + "//"
    let _href = window.location.origin + "/";
    let ws = blockpy.components.editor.blockly.svgBlockCanvas_.cloneNode(true);
    ws.removeAttribute("width");
    ws.removeAttribute("height");
    ws.removeAttribute("transform");
    let styleElem = document.createElementNS("http://www.w3.org/2000/svg", "style");
    styleElem.textContent = Blockly.Css.CONTENT.join('');
    ws.insertBefore(styleElem, ws.firstChild);
    let bbox = blockpy.components.editor.blockly.svgBlockCanvas_.getBBox();
    let canvas = document.createElement("canvas");
    // canvas.width = Math.ceil(bbox.width + 120);
    // canvas.height = Math.ceil(bbox.height + 50);
    canvas.width = Math.ceil(Math.abs(bbox.x) + bbox.width + 120);
    canvas.height = Math.ceil(Math.abs(bbox.y) + bbox.height + 50);
    canvas.appendChild(ws);
    let ctx = canvas.getContext("2d");
    let xml = new XMLSerializer().serializeToString(ws);
    let test = /xlink:href="[a-zA-z]+:\/\/[^\s]*"/g;
    let test1 = /xlink:href="[^\s]*"/g;
    let arr = xml.match(test1)
    if (arr != null) {
        let loadImage = function () {
            return new Promise((resolve) => {
                let length = arr.length;
                let count = 0;
                for (let i = 0; i < length; i++) {
                    let dataURL;
                    let canvas_inline = document.createElement("canvas");
                    let ctx1 = canvas_inline.getContext("2d");
                    let image_item = new Image();
                    image_item.setAttribute("src", _header + arr[i].replace("xlink:href=\"", _href).replace("\"", ""));
                    image_item.onload = function () {
                        //convert image to base64
                        canvas_inline.width = image_item.width;
                        canvas_inline.height = image_item.height;
                        ctx1.drawImage(image_item, 0, 0);
                        dataURL = canvas_inline.toDataURL("image/png", 1);
                        xml = xml.replace(arr[i], "xlink:href=\"" + dataURL + "\"");
                        count++;
                    }
                }
                let timer = setInterval(() => {
                    if (count == length) {
                        return resolve(true);
                        clearInterval(timer);
                    }
                });
            });
        }
        await loadImage();
    }
    xml = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  width="' + canvas.width + '" height="' + canvas.height + '" viewBox="' + bbox.x + ' ' + bbox.y + ' ' + canvas.width + ' ' + canvas.height + '"><rect width="100%" height="100%" fill="white"></rect>' + xml + '</svg>';
    var img = new Image();
    img.setAttribute("src", 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(xml))));
    img.onload = function () {
        ctx.drawImage(img, 5, 5);
        var canvasdata = canvas.toDataURL("image/png", 1);
        var a = document.createElement("a");
        a.download = name + ".png";
        a.href = canvasdata;
        document.body.appendChild(a);
        a.click();
    }
}