/* lib/browser/content/terminal - A library to process command terminal output in the browser. */ import browser from "../utilities/browser.js";
import modal from "../utilities/modal.js";
import network from "../utilities/network.js";
import util from "../utilities/util.js";
// cspell:words agenttype, arrowdown, arrowup, pagedown, pageup
/**
 * Interaction methods for the command terminal in the browser.
 * ```typescript
 * interface module_browserTerminal {
 *     content: () => [HTMLElement, HTMLElement];
 *     events: {
 *         close: (event:MouseEvent) => void;
 *         command: (event:KeyboardEvent) => void;
 *         keyInput: (event:KeyboardEvent) => void;
 *         keyOutput: (event:KeyboardEvent) => void;
 *         receive: (socketData:socketData) => void;
 *     };
 *     tools: {
 *         controlKeys: (event:KeyboardEvent, list:HTMLElement) => void;
 *         populate: (box:modal, logs:string[], restore:boolean) => void;
 *         send: (box:modal, command:string, autoComplete:boolean) => void;
 *     };
 * }
 * ``` */ const terminal = {
    content: function browser_content_terminal_content() {
        const footer = document.createElement("div"), cwd = document.createElement("p"), logs = document.createElement("ol"), label = document.createElement("label"), span = document.createElement("span"), textArea = document.createElement("textarea"), scroll = {
            position: -1,
            entries: []
        };
        logs.setAttribute("data-scroll", JSON.stringify(scroll));
        logs.setAttribute("class", "terminal-list");
        logs.onkeyup = terminal.events.keyOutput;
        cwd.setAttribute("class", "terminal-cwd");
        footer.setAttribute("class", "footer");
        label.setAttribute("class", "terminal");
        textArea.setAttribute("wrap", "hard");
        textArea.setAttribute("spellcheck", "false");
        textArea.onkeydown = terminal.events.command;
        textArea.onkeyup = terminal.events.keyInput;
        textArea.onmouseup = modal.events.footerResize;
        textArea.onblur = modal.events.textSave;
        span.appendText("Terminal command input");
        label.appendChild(span);
        label.appendChild(textArea);
        footer.appendChild(cwd);
        footer.appendChild(label);
        return [
            logs,
            footer
        ];
    },
    events: {
        close: function browser_content_terminal_close(event) {
            const box = event.target.getAncestor("box", "class");
            terminal.tools.send(box, "close-modal", false);
            modal.events.close(event);
        },
        command: function browser_content_terminal_command(event) {
            const key = event.key.toLowerCase(), target = event.target, box = target.getAncestor("box", "class"), id = box.getAttribute("id"), list = box.getElementsByClassName("terminal-list")[0], clearTarget = function browser_content_terminal_command() {
                browser.ui.modals[id].text_value = "";
                browser.ui.modals[id].historyIndex = browser.ui.modals[id].history.length;
                target.value = "";
                network.configuration();
            }, tab = box.dataset.tab === "true" ? true : false;
            if (key === "tab") {
                if (event.shiftKey === true) {
                    return;
                }
                if (tab === true) {
                    box.setAttribute("data-tab", "false");
                    return;
                }
                event.preventDefault();
                target.focus();
                terminal.tools.send(box, target.value.replace(/^\s+/, "").replace(/\s+$/, ""), true);
                modal.events.textTimer(event);
                box.setAttribute("data-tab", "true");
                return;
            }
            box.setAttribute("data-tab", "false");
            if (key === "c" && event.ctrlKey === true) {
                terminal.tools.send(box, "close-modal", false);
                terminal.tools.populate(box, [
                    ""
                ], false);
                clearTarget();
                return;
            }
            if (key === "enter" && event.shiftKey === false) {
                const value = target.value, history = browser.ui.modals[id].history;
                event.preventDefault();
                if (value === "clear") {
                    const scroll = {
                        position: -1,
                        entries: []
                    };
                    list.appendText("", true);
                    list.setAttribute("data-scroll", JSON.stringify(scroll));
                } else if (value === "") {
                    terminal.tools.populate(box, [
                        ""
                    ], false);
                } else {
                    terminal.tools.send(box, value, false);
                }
                if (history[history.length - 1] !== value && value !== "") {
                    history.push(value);
                }
                clearTarget();
            }
        },
        keyInput: function browser_content_terminal_keyInput(event) {
            const key = event.key.toLowerCase(), target = event.target, box = target.getAncestor("box", "class"), list = box.getElementsByClassName("terminal-list")[0], id = box.getAttribute("id"), history = browser.ui.modals[id].history;
            let index = isNaN(browser.ui.modals[id].historyIndex) ? browser.ui.modals[id].history.length : browser.ui.modals[id].historyIndex;
            event.preventDefault();
            if (key === "arrowup") {
                if (index > 0) {
                    index = index - 1;
                    target.value = history[index];
                    browser.ui.modals[id].historyIndex = index;
                    network.configuration();
                }
                return;
            }
            if (key === "arrowdown") {
                if (index < history.length) {
                    index = index + 1;
                    if (index === history.length) {
                        target.value = browser.ui.modals[id].text_value;
                    } else {
                        target.value = history[index];
                    }
                    browser.ui.modals[id].historyIndex = index;
                    network.configuration();
                }
                return;
            }
            if (key === "end" || key === "home" || key === "pagedown" || key === "pageup") {
                terminal.tools.controlKeys(event, list);
                return;
            }
            modal.events.textTimer(event);
        },
        keyOutput: function browser_content_terminal_keyOutput(event) {
            const list = event.target;
            terminal.tools.controlKeys(event, list);
        },
        receive: function browser_content_terminal_receive(socketData) {
            const data = socketData.data, write = function browser_content_terminal_receive_update(box) {
                if (box !== null) {
                    const cwd = box.getElementsByClassName("terminal-cwd")[0];
                    terminal.tools.populate(box, data.logs, false);
                    if (browser.ui.modals[data.id] !== null && browser.ui.modals[data.id].text_placeholder !== data.directory) {
                        browser.ui.modals[data.id].text_placeholder = data.directory;
                    }
                    cwd.appendText(data.directory, true);
                    network.configuration();
                }
            };
            if (data.id === "all") {
                const terminals = document.getModalsByModalType("terminal"), each = function browser_content_terminal_each(box) {
                    if (box.dataset.agent === data.agentSource.agent && box.dataset !== undefined && box.dataset.agenttype === data.agentSource.agentType) {
                        write(box);
                    }
                };
                terminals.forEach(each);
            } else if (data.autoComplete > -1) {
                const box = document.getElementById(data.id);
                if (box !== null) {
                    const textArea = box.getElementsByTagName("textarea")[0];
                    textArea.value = data.instruction;
                    textArea.selectionStart = data.autoComplete;
                    textArea.selectionEnd = data.autoComplete;
                }
            } else {
                const box = document.getElementById(data.id);
                write(box);
            }
        }
    },
    tools: {
        controlKeys: function browser_content_terminal_controlKeys(event, list) {
            const key = event.key.toLowerCase();
            if (key === "end") {
                const parent = list.parentNode;
                parent.scrollTo(parent.scrollLeft, parent.scrollHeight);
                return;
            }
            if (key === "home") {
                const parent = list.parentNode;
                parent.scrollTo(parent.scrollLeft, 0);
                return;
            }
            if (key === "pagedown" && event.shiftKey === true) {
                const items = list.getElementsByTagName("li"), parent = list.parentNode, scroll = JSON.parse(list.dataset.scroll), scrollPosition = scroll.position + 1, position = scroll.entries[scrollPosition] === undefined || items[scroll.entries[scrollPosition]] === undefined ? parent.scrollHeight : items[scroll.entries[scrollPosition]].offsetTop;
                parent.scrollTo(parent.scrollLeft, position);
                scroll.position = scrollPosition < scroll.entries.length ? scroll.position = scrollPosition : scroll.entries.length;
                list.setAttribute("data-scroll", JSON.stringify(scroll));
                return;
            }
            if (key === "pagedown") {
                const parent = list.parentNode;
                parent.scrollTo(parent.scrollLeft, parent.clientHeight + parent.scrollTop);
                return;
            }
            if (key === "pageup" && event.shiftKey === true) {
                const items = list.getElementsByTagName("li"), parent = list.parentNode, scroll = JSON.parse(list.dataset.scroll), scrollPosition = scroll.position - 1, position = scroll.entries[scrollPosition] === undefined || items[scroll.entries[scrollPosition]] === undefined ? 0 : items[scroll.entries[scrollPosition]].offsetTop;
                parent.scrollTo(parent.scrollLeft, position);
                scroll.position = scrollPosition < 0 ? -1 : scrollPosition;
                list.setAttribute("data-scroll", JSON.stringify(scroll));
                return;
            }
            if (key === "pageup") {
                const parent = list.parentNode, height = parent.clientHeight, top = parent.scrollTop, vertical = height > top ? 0 : top - height;
                parent.scrollTo(parent.scrollLeft, vertical);
                return;
            }
        },
        populate: function browser_content_terminal_populate(box, logs, restore) {
            const element = box.getElementsByClassName("terminal-list")[0], id = box.getAttribute("id"), items = element.getElementsByTagName("li").length, each = function browser_content_terminalPopulate_each(logItem) {
                let count = 0;
                const li = document.createElement("li"), names = {
                    "1": "bold",
                    "3": "italic",
                    "4": "underline",
                    "22": "no-bold",
                    "23": "no-italic",
                    "24": "no-underline",
                    "30": "black",
                    "31": "red",
                    "32": "green",
                    "33": "yellow",
                    "34": "blue",
                    "35": "purple",
                    "36": "cyan",
                    "37": "white",
                    "39": "no-color"
                }, ansi = /(\u001b\[\d{1,2}(;\d{1,2})*m)+/, list = function browser_content_terminalPopulate_list(result) {
                    let formatList = result.replace(/^\u001b\[/, "").replace(/m\u001b\[/g, "|").replace(/m$/, "").replace(/;/g, "|").split("|"), index = formatList.indexOf("0"), endString = "";
                    if (result === "\u001b[0m") {
                        return "\u001b[0m";
                    }
                    if (index > -1) {
                        if (index === 0) {
                            endString = end();
                            do {
                                formatList.splice(0, 1);
                                index = formatList.indexOf("0");
                            }while (index === 0)
                        }
                        if (index > 0) {
                            formatList = formatList.slice(0, index);
                        }
                    }
                    formatList.forEach(function browser_Content_terminalPopulate_list_each(value, index, list) {
                        list[index] = names[value];
                    });
                    count = count + 1;
                    return `${endString}<span class="${formatList.join(" ")}">`;
                }, end = function browser_content_terminalPopulate_end() {
                    if (count > 0) {
                        let output = "";
                        do {
                            count = count - 1;
                            output = output + "</span>";
                        }while (count > 0)
                        return output;
                    }
                    return "";
                };
                if (restore === false) {
                    browser.ui.modals[id].string_store.push(logItem);
                }
                logItem = util.sanitizeHTML(logItem);
                do {
                    logItem = logItem.replace(ansi, list).replace(/\u001b\[0m/g, end);
                }while (ansi.test(logItem) === true)
                if (count > 0) {
                    logItem = logItem + "</span>";
                }
                // eslint-disable-next-line
                li.innerHTML = logItem;
                element.appendChild(li);
            }, oldScroll = JSON.parse(element.dataset.scroll), scroll = {
                position: oldScroll.entries.length,
                entries: oldScroll.entries
            }, parent = element.parentNode, scrollBottom = parent !== null && (parent.scrollTop === 0 || parent.scrollTop + parent.clientHeight === parent.scrollHeight);
            scroll.entries.push(logs.length + items);
            logs.forEach(each);
            element.setAttribute("data-scroll", JSON.stringify(scroll));
            if (scrollBottom === true) {
                parent.scrollTo(0, parent.scrollHeight);
            }
        },
        send: function browser_content_terminal_send(box, command, autoComplete) {
            // send close signal on modal close
            // capture c + ctrl - without alt or shift
            const agentType = box.dataset.agenttype, payload = {
                agentRequest: agentType === "device" ? {
                    agent: browser.identity.hashDevice,
                    agentType: "device",
                    share: box.getAttribute("id")
                } : {
                    agent: browser.identity.hashUser,
                    agentType: "user"
                },
                agentSource: {
                    agent: box.dataset.agent,
                    agentType: agentType
                },
                autoComplete: autoComplete === true ? box.getElementsByTagName("textarea")[0].selectionStart : -1,
                directory: box.getElementsByClassName("terminal-cwd")[0].innerHTML,
                id: box.getAttribute("id"),
                instruction: command,
                logs: [],
                target: "agentSource"
            };
            network.send(payload, "terminal");
        }
    }
};
export default terminal;
