/**
 * @license
 * Copyright 2020 Sébastien CANET
 * SPDX-License-Identifier: BSD-3-Clause
 */

/**
 * @fileoverview Helper functions for buttons visible in UI.
 * @author scanet@libreduc.cc (SebCanet)
 */

const FILE_EXTENSION = ".brlg"; // здесь задаем расширение наших файлов, еще оно фигурирует в package.json

// наши определения для окон уведомления, подтверждения, ввода
Code.showCustomNotice = function({ titleKey, title, messageKey, message, onClose }) {
    document.getElementById("customNoticeOverlay").style.display = "block";
    document.getElementById("customNoticeModal").style.display = "block";
  
    document.getElementById("customNoticeOk").textContent = MSG['ok'] || 'OK';
    document.getElementById("customNoticeTitle").textContent = title || MSG[titleKey] || 'Notice';

    const messageContainer = document.getElementById("customNoticeMessage");
    if (message) {  // если передан message (готовый HTML), то вставляем через innerHTML
        messageContainer.innerHTML = message;
    } else if (messageKey && MSG[messageKey]) { // по ключу
        messageContainer.textContent = MSG[messageKey];
    } else {
        messageContainer.textContent = '';
    }
  
    const close = () => {
      document.getElementById("customNoticeOverlay").style.display = "none";
      document.getElementById("customNoticeModal").style.display = "none";
      document.getElementById("closeCustomNotice").onclick = null;
      document.getElementById("customNoticeOk").onclick = null;

      if (typeof onClose === 'function') {
        onClose();
      }
    };
  
    document.getElementById("closeCustomNotice").onclick = close;
    document.getElementById("customNoticeOk").onclick = close;
};

Code.showCustomConfirm = function ({ title, titleKey, message, messageKey, okKey, cancelKey, callback }) {
    const overlay = document.getElementById("customConfirmOverlay");
    const modal = document.getElementById("customConfirmModal");

    overlay.classList.add("show");
    modal.classList.add("show");

    // Установка текста
    document.getElementById("customConfirmTitle").textContent = title || MSG[titleKey] || "Confirm";
    document.getElementById("customConfirmMessage").textContent = message || MSG[messageKey] || "Are you sure?";
    document.getElementById("customConfirmOk").textContent = MSG[okKey] || "OK";
    document.getElementById("customConfirmCancel").textContent = MSG[cancelKey] || "Cancel";

    const cleanup = () => {
        overlay.classList.remove("show");
        modal.classList.remove("show");
        okBtn.onclick = null;
        cancelBtn.onclick = null;
        closeBtn.onclick = null;
    };

    const okBtn = document.getElementById("customConfirmOk");
    const cancelBtn = document.getElementById("customConfirmCancel");
    const closeBtn = document.getElementById("closeCustomConfirm");

    okBtn.onclick = () => {
        cleanup();
        callback(true);
    };
    cancelBtn.onclick = closeBtn.onclick = () => {
        cleanup();
        callback(false);
    };
};

Code.showCustomPrompt = function ({ title, titleKey, placeholderKey, okKey, cancelKey, callback }) {
    // Показываем
    document.getElementById("customPromptOverlay").style.display = "block";
    document.getElementById("customPromptModal").style.display = "block";

    // Устанавливаем текст
    document.getElementById("customPromptTitle").textContent = title || MSG[titleKey] || 'Prompt';
    document.getElementById("customPromptInput").value = '';
    document.getElementById("customPromptInput").placeholder = MSG[placeholderKey] || '';

    document.getElementById("customPromptOk").textContent = MSG[okKey] || 'OK';
    document.getElementById("customPromptCancel").textContent = MSG[cancelKey] || 'Cancel';

    // Обработчики
    const closeModal = () => {
        document.getElementById("customPromptOverlay").style.display = "none";
        document.getElementById("customPromptModal").style.display = "none";
    };

    const okBtn = document.getElementById("customPromptOk");
    const cancelBtn = document.getElementById("customPromptCancel");
    const closeBtn = document.getElementById("closeCustomPrompt");

    okBtn.onclick = () => {
        const value = document.getElementById("customPromptInput").value;
        closeModal();
        if (callback) callback(value);
    };
    cancelBtn.onclick = closeBtn.onclick = closeModal;
};

/*
 * auto save and restore blocks
 */
function auto_save_and_restore_blocks() {
    // Store the blocks for the duration of the reload.
    // MSIE 11 does not support sessionStorage on file:// URLs.
    if (window.sessionStorage) {
        var xml = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace());
        var text = Blockly.Xml.domToText(xml);
        window.sessionStorage.loadOnceBlocks = text;
    }
}
;

var fullScreen_ = false;

/**
 * Full screen, thanks to HTML5 API
 * @argument {type} _element 
 */
function fullScreen(_element) {
    var elementClicked = _element || document.documentElement;
    // HTML5
    if (document.fullscreenEnabled) {
        if (!document.fullscreenElement) {
            elementClicked.requestFullscreen();
            document.addEventListener('fullscreenchange', exitFullScreen, false);
        } else {
            exitFullScreen();
            document.exitFullscreen();
            document.removeEventListener('fullscreenchange', exitFullScreen, false);
        }
    } else
    // Chrome, Safari and Opera
    if (document.webkitFullscreenEnabled) {
        if (!document.webkitFullscreenElement) {
            elementClicked.webkitRequestFullscreen();
            document.addEventListener('webkitfullscreenchange', exitFullScreen, false);
        } else {
            exitFullScreen();
            document.webkitExitFullscreen();
            document.removeEventListener('webkitfullscreenchange', exitFullScreen, false);
        }
    } else
    // IE/Edge
    if (document.msFullscreenEnabled) {
        if (!document.msFullscreenElement) {
            elementClicked.msRequestFullscreen();
            document.addEventListener('MSFullscreenChange', exitFullScreen, false);
        } else {
            exitFullScreen();
            document.msExitFullscreen();
            document.removeEventListener('MSFullscreenChange', exitFullScreen, false);
        }
    }
}
;

function exitFullScreen() {
    if (fullScreen_ === false) {
        fullScreenButton.className = 'iconButtonsClicked';
        fullScreen_ = true;
    } else {
        fullScreenButton.className = 'iconButtons';
        fullScreen_ = false;
    }
}
;

/**
 * Copy code from div code_peek in clipboard system
 */
Code.copyToClipboard = function () {
    if (document.selection) { // IE
        var range = document.body.createTextRange();
        range.moveToElementText(document.getElementsByClassName("ace_content")[0]);
        range.select();
        document.execCommand("copy");
    } else if (window.getSelection) {
        // var range = document.createRange();
        // range.selectNode(document.getElementsByClassName("ace_content")[0]);
        // window.getSelection().removeAllRanges();
        // window.getSelection().addRange(range);
    // }
    // document.execCommand("copy");
        navigator.clipboard.writeText(document.getElementsByClassName("ace_content")[0].innerText)
                .then(() => {console.log('Code copied!') })
                .catch((error) => { console.log('Copy failed! ${error}') });
    }
};

/**
 * modal controllers
 */
Code.boardsListModalShow = function () {
    document.getElementById('overlayForModals').style.display = "block";
    document.getElementById('boardListModal').classList.add('show');
    for (var i = 0; i < document.getElementById("boardDescriptionSelector").length; i++)
        document.getElementById("boardDescriptionSelector").options[i].style.backgroundColor = 'white';
    var boardValue = document.getElementById("boardMenu").value;
    if (boardValue !== 'none') {
        document.getElementById("boardDescriptionSelector").selectedIndex = boardValue;
        document.getElementById("boardDescriptionSelector").value = boardValue;
        document.getElementById("boardDescriptionSelector").options[document.getElementById("boardDescriptionSelector").selectedIndex].style.backgroundColor = '#d0ecf5';
    }
    Code.boardDescription();
};
Code.portsListModalShow = function () {
    document.getElementById('overlayForModals').style.display = "block";
    document.getElementById('portListModal').classList.add('show');
    const portValue = localStorage.getItem("comPort"); // Получаем сохранённый (уже encodeURIComponent) путь

    if (portValue && portValue !== 'none') {
        const serialMenu = document.getElementById("serialMenu");
        for (let i = 0; i < serialMenu.options.length; i++) {
            if (serialMenu.options[i].value === portValue) {
                serialMenu.selectedIndex = i;
                break;
            }
        }
    }
};
document.getElementById("closeModalBoards").onclick = function () {
    document.getElementById('overlayForModals').style.display = "none";
    document.getElementById('boardListModal').classList.remove('show');
};
document.getElementById("closeModalPorts").onclick = function () {
    document.getElementById('overlayForModals').style.display = "none";
    document.getElementById('portListModal').classList.remove('show');
};

/**
 * change information in the boards modal
 **/
function formatWithUnit(value, unitKey) {
    return value + " " + MSG[unitKey];
}

Code.boardDescription = function () {
    var boardValue = document.getElementById("boardDescriptionSelector").value || 'none';
    const data = profile[boardValue][0];

    // Всегда обновляем картинку
    document.getElementById("board_mini_picture").setAttribute("src", data['picture']);

    const values = {
        "boardModal_connect_span":      boardValue === 'none' ? "..." : data['usb'],
        "boardModal_voltage_span":      boardValue === 'none' ? "..." : formatWithUnit(data['voltage'], 'unit_volt'),
        "boardModal_voltage_norm_span": boardValue === 'none' ? "..." : formatWithUnit(data['normal_voltage'], 'unit_volt'),
        "boardModal_voltage_max_span":  boardValue === 'none' ? "..." : formatWithUnit(data['max_voltage'], 'unit_volt'),
        "boardModal_cpu_span":          boardValue === 'none' ? "..." : data['cpu'],
        "boardModal_speed_span":        boardValue === 'none' ? "..." : formatWithUnit(data['cpu_speed_mhz'], 'unit_megahertz'),
        "boardModal_inout_span":        boardValue === 'none' ? "..." : data['digital_pins_qty'],
        "boardModal_analog_span":       boardValue === 'none' ? "..." : data['analog_pins_qty'],
        "boardModal_pwm_span":          boardValue === 'none' ? "..." : data['pwm_pins_qty'],
        "boardModal_flash_span":        boardValue === 'none' ? "..." : formatWithUnit(data['flash_size_mb'], 'unit_megabyte'),
        "boardModal_sram_span":         boardValue === 'none' ? "..." : formatWithUnit(data['ram_size_kb'], 'unit_kilobyte'),
        "boardModal_eeprom_span":       boardValue === 'none' ? "..." : formatWithUnit(data['eeprom_size_kb'], 'unit_kilobyte')
    };

    for (let id in values) {
        document.getElementById(id).textContent = values[id];
    }
};

/**
 * Undo/redo functions
 */
Code.Undo = function () {
    Blockly.getMainWorkspace().undo(0);
};
Code.Redo = function () {
    Blockly.getMainWorkspace().undo(1);
};

/**
 * Luanch blockFatcory with language argument
 */
Code.BlockFactory = function () {
    var lang = Code.getStringParamFromUrl('lang', '');
    if (!lang) {
        lang = "ru";
    }
    parent.open('tools/blockFactory/blockFactory.html?lang=' + lang);
};

/**
 * Creates an INO file containing the Arduino code from the Blockly workspace and
 * prompts the users to save it into their local file system.
 */
Code.newProject = function () {
    var count = Code.workspace.getAllBlocks().length;
    if (count > 0) {
        Code.showCustomConfirm({
            titleKey: "confirm_title",
            messageKey: null, // мы передадим текст вручную
            okKey: "ok",
            cancelKey: "cancel",
            callback: function (confirmed) {
                if (confirmed) {
                    Code.workspace.clear();
                }
            }
        });
        // Подставим динамический текст вместо messageKey
        const message = Blockly.Msg['DELETE_ALL_BLOCKS'].replace('%1', count);
        document.getElementById("customConfirmMessage").textContent = message;
    }
};

/**
 * Creates an INO file containing the Arduino code from the Blockly workspace and
 * prompts the users to save it into their local file system.
 */
Code.saveCodeFile = function () {
    const dataToSave = Blockly.Arduino.workspaceToCode(Code.workspace);
    const blob = new Blob([dataToSave], {
        type: 'text/plain;charset=utf-8'
    });
    // сразу вызываем окно сохранения из ОС
    const fakeDownloadLink = document.createElement("a");
    fakeDownloadLink.download =  `file.ino`; // дефолтное имя
    fakeDownloadLink.href = window.URL.createObjectURL(blob);
    fakeDownloadLink.onclick = function (event) {
        document.body.removeChild(event.target);
    };
    fakeDownloadLink.style.display = "none";
    document.body.appendChild(fakeDownloadLink);
    fakeDownloadLink.click();
};

/**
 * Creates an XML file containing the blocks from the Blockly workspace and
 * prompts the users to save it into their local file system.
 */
Code.saveXmlBlocklyFile = function () {
    var xmlData = Blockly.Xml.workspaceToDom(Code.workspace);
    var dataToSave = Blockly.Xml.domToPrettyText(xmlData);
    var blob = new Blob([dataToSave], {
        type: 'text/xml;charset=utf-8'
    });
    // сразу вызываем окно сохранения из ОС
    var fakeDownloadLink = document.createElement("a");
    fakeDownloadLink.download = 'file' + FILE_EXTENSION; // дефолтное имя
    fakeDownloadLink.href = window.URL.createObjectURL(blob);
    fakeDownloadLink.onclick = function destroyClickedElement(event) {
        document.body.removeChild(event.target);
    };
    fakeDownloadLink.style.display = "none";
    document.body.appendChild(fakeDownloadLink);
    fakeDownloadLink.click();
};

/**
 * Load blocks from local file.
 */
Code.loadXmlBlocklyFile = function () {
    // Create event listener function
    var parseInputXMLfile = function (e) {
        var files = e.target.files;
        var reader = new FileReader();
        reader.onloadend = function () {
            var success = Code.loadBlocksfromXml(reader.result);
            if (success) {
                Code.workspace.render();
            } else {
                Blockly.alert(MSG[badXml], callback);
            }
        };
        reader.readAsText(files[0]);
    };
    // Create once invisible browse button with event listener, and click it
    var selectFile = document.getElementById('select_file');
    if (selectFile === null) {
        var selectFileDom = document.createElement('INPUT');
        selectFileDom.type = 'file';
        selectFileDom.id = 'select_file';
        selectFileDom.accept = `${FILE_EXTENSION}, .xml`;
        selectFileDom.style.display = 'none';
        document.body.appendChild(selectFileDom);
        selectFile = document.getElementById('select_file');
        selectFile.addEventListener('change', parseInputXMLfile, false);
    }
    selectFile.click();
};

/**
 * Parses the XML from its input to generate and replace the blocks in the
 * Blockly workspace.
 * @param {!string} defaultXml String of XML code for the blocks.
 * @return {!boolean} Indicates if the XML into blocks parse was successful.
 */
Code.loadBlocksfromXml = function (defaultXml) {
    var count = Code.workspace.getAllBlocks().length;
    var xml = Blockly.Xml.textToDom(defaultXml);
    if (count > 0) {
        Blockly.confirm(MSG['loadXML_span'], function (confirm) {
            if (confirm)
                Code.workspace.clear();
                Blockly.Xml.domToWorkspace(xml, Code.workspace);
                return true;
        });
    } else {
        Blockly.Xml.domToWorkspace(xml, Code.workspace);
        return true;
    }
};

/**
 * Add or replace a parameter to the URL.
 *
 * @param {string} name The name of the parameter.
 * @param {string} value Value to set
 * @return {string} The url completed with parameter and value
 */
Code.addReplaceParamToUrl = function (url, param, value) {
    var re = new RegExp("([?&])" + param + "=.*?(&|$)", "i");
    var separator = url.indexOf('?') !== -1 ? "&" : "?";
    if (url.match(re)) {
        return url.replace(re, '$1' + param + "=" + value + '$2');
    } else {
        return url + separator + param + "=" + value;
    }
};

/**
 * Reset workspace and parameters
 */
Code.ResetWorkspace = function () {
    var count = Blockly.mainWorkspace.getAllBlocks(false).length;
    const message = MSG['resetQuestion_span'] + ' ' + Blockly.Msg['DELETE_ALL_BLOCKS_SMALL'].replace('%1', count);
    
    Code.showCustomConfirm({
        titleKey: "reset_confirm_title",
        messageKey: null,
        okKey: "ok",
        cancelKey: "cancel",
        callback: function (answer) {
            if (answer) {
                Blockly.Events.disable();
                Blockly.getMainWorkspace().clear();
                Blockly.getMainWorkspace().trashcan.contents_ = [];
                Blockly.getMainWorkspace().trashcan.setLidOpen('false');
                window.removeEventListener('unload', auto_save_and_restore_blocks, false);
                localStorage.clear();
                sessionStorage.clear();
                Code.renderContent();
                Blockly.Events.enable();
                if (window.location.hash) {
                    window.location.hash = '';
                }
                window.location = window.location.protocol + '//' + window.location.host + window.location.pathname;
            }
        }
    });
    document.getElementById("customConfirmMessage").textContent = message;
};

/**
 * Change font size in blocks in all workspace
 */
Code.changeRenderingConstant = function (value) {
    var type = document.getElementById('rendering-constant-selector').value;
    switch (type) {
        case 'fontSizeBlocks':
            var fontStyle = {
                'size': value
            };
            Blockly.getMainWorkspace().getTheme().setFontStyle(fontStyle);
            editor.setOptions({
                fontSize: value + "pt"
            });
        case 'fontSizePage':
        // fontSizePageModify('access', value);
        case 'fontSpacingPage':
        // document.body.style.fontSize = value + 'px';
    }
    // Refresh theme.
    Blockly.getMainWorkspace().setTheme(Blockly.getMainWorkspace().getTheme());
};

// вывод окна о программе
Code.showHelpNotice = function () {  
    const version = window.APP_VERSION || 'v?';
    const name = window.APP_NAME || '...';
    const repoUrl = window.REPO_URL || '#';

    // Заменяем {VERSION} на значение
    const helpHtml = (MSG['helpModalSpan_text'] || '')
        .replace('{VERSION}', version)
        .replace('{APP_NAME}', name)
        .replace('{REPO_URL}', repoUrl);

    Code.showCustomNotice({
    title: MSG['helpModalSpan_title'] || 'Help',
    message: helpHtml
  });
};