/* lib/browser/utilities/modal - A collection of utilities for generating and manipulating modals/windows in the browser. */ import agent_management from "../content/agent_management.js";
import browser from "./browser.js";
import common from "../../common/common.js";
import file_browser from "../content/file_browser.js";
import media from "../content/media.js";
import modal_configuration from "./modal_configurations.js";
import network from "./network.js";
import webSocket from "./webSocket.js";
// cspell:words agenttype
/**
 * Provides generic modal specific interactions such as resize, move, generic modal buttons, and so forth.
 * ```typescript
 * interface module_modal {
 *     content: (options:config_modal) => modal; // Creates a new modal.
 *     events: {
 *         close         : (event:MouseEvent) => void;                               // Closes a modal by removing it from the DOM, removing it from state, and killing any associated media.
 *         closeEnduring : (event:MouseEvent) => void;                               // Modal types that are enduring are hidden, not destroyed, when closed.
 *         confirm       : (event:MouseEvent) => void;                               // Handling for an optional confirmation button.
 *         footerResize  : (event:MouseEvent) => void;                               // If a resizable textarea element is present in the modal outside the body this ensures the body is the correct size.
 *         importSettings: (event:MouseEvent) => void;                               // Handler for import/export modals that modify saved settings from an imported JSON string then reloads the page.
 *         maximize      : (event:MouseEvent, callback?:() => void, target?:HTMLElement) => void; // Maximizes a modal to fill the view port.
 *         minimize      : (event:MouseEvent, callback?:() => void, target?:HTMLElement) => void; // Minimizes a modal to the tray at the bottom of the page.
 *         move          : (event:MouseEvent|TouchEvent) => void;                    // Allows dragging a modal around the screen.
 *         resize        : (event:MouseEvent|TouchEvent, boxElement?:modal) => void; // Resizes a modal respective to the event target, which could be any of 4 corners or 4 sides.
 *         textSave      : (event:Event) => void;                                    // Handler to push the text content of a text-pad modal into settings so that it is saved.
 *         textTimer     : (event:KeyboardEvent) => void;                            // A timing event so that contents of a text-pad modal are automatically save after a brief duration of focus blur.
 *         zTop          : (event:KeyboardEvent|MouseEvent, elementInput?:HTMLElement) => void; // Processes visual overlapping or depth of modals.
 *     };
 *     tools: {
 *         dynamicWidth : (box:modal, width:number, buttonCount:number) => [number, number]; // uniformly calculates widths for modal headings and status bars.
 *         forceMinimize: (id:string) => void;                                               // Modals that do not have a minimize button still need to conform to minimize from other interactions.
 *         textModal    : (title:string, value:string, type:modalType) => HTMLElement;       // Defines the content of a textarea modal in a uniform way.
 *     };
 * }
 * ``` */ const modal = {
    /* Modal creation factory */ content: function browser_utilities_modal_content(options) {
        let buttonCount = 0, section = document.createElement("h2"), input, extra, widths = null;
        const id = options.type === "configuration" ? "configuration-modal" : options.id || `${options.type}-${Math.random().toString() + String(browser.ui.zIndex + 1)}`, textType = options.type === "export" || options.type === "file-edit" || options.type === "text-pad", titleButton = document.createElement("button"), box = document.createElement("article"), body = textType === true ? options.content : document.createElement("div"), border = document.createElement("div"), modalCount = Object.keys(browser.ui.modals).length, button = function browser_utilities_modal_content_fileNavigateButtons(config) {
            const el = document.createElement("button");
            el.setAttribute("type", "button");
            el.appendText(config.text);
            if (config.spanText !== null) {
                const span = document.createElement("span");
                span.appendText(config.spanText);
                el.appendChild(span);
            }
            el.setAttribute("class", config.class);
            el.setAttribute("title", config.title);
            el.onclick = config.event;
            config.parent.appendChild(el);
        }, socket = options.socket === true ? webSocket.start(null, browser.identity.hashDevice, options.type) : null;
        // Uniqueness constraints
        if (browser.ui.modalTypes.indexOf(options.type) > -1) {
            if (options.single === true) {
                const keys = Object.keys(browser.ui.modals), length = keys.length;
                let a = 0;
                do {
                    if (browser.ui.modals[keys[a]].type === options.type && document.getElementById(keys[a]) !== null) {
                        return document.getElementById(keys[a]);
                    }
                    a = a + 1;
                }while (a < length)
            }
        } else {
            browser.ui.modalTypes.push(options.type);
        }
        // Default values
        browser.ui.zIndex = browser.ui.zIndex + 1;
        if (options.zIndex === undefined) {
            options.zIndex = browser.ui.zIndex;
        }
        if (options.left === undefined || options.left < 10) {
            options.left = 10 + modalCount * 10 - modalCount;
        }
        if (options.top === undefined || options.top < 10) {
            options.top = 10 + modalCount * 10 - modalCount;
        }
        if (options.width === undefined) {
            options.width = 565;
        }
        if (options.height === undefined) {
            options.height = 400;
        }
        if (options.status === undefined) {
            options.status = "normal";
        }
        if (options.agent === undefined) {
            options.agent = browser.identity.hashDevice;
        }
        if (options.agentType === undefined) {
            options.agentType = "device";
        }
        options.id = id;
        // Title bar functionality
        {
            const span = document.createElement("span"), text = [];
            if (options.type === "shares") {
                if (options.agentType === "") {
                    text.push("All Shares");
                    span.appendText("⌘");
                } else {
                    if (options.agentType === "device") {
                        span.appendText("🖳");
                    } else {
                        span.appendText("👤");
                    }
                    if (options.agent === "") {
                        text.push(`All ${common.capitalize(options.agentType)} Shares`);
                    } else if (browser.agents[options.agentType][options.agent].name === undefined) {
                        text.push("Shares");
                    } else {
                        text.push(`${common.capitalize(options.agentType)} ${browser.agents[options.agentType][options.agent].name} Shares`);
                    }
                }
            } else {
                text.push(modal_configuration.titles[options.type].text);
                if (options.title_supplement !== "" && options.title_supplement !== null && options.title_supplement !== undefined) {
                    text.push(options.title_supplement);
                }
                if (options.agentIdentity === true) {
                    text.push(`- ${common.capitalize(options.agentType)}, ${browser.agents[options.agentType][options.agent].name}`);
                }
                span.appendText(modal_configuration.titles[options.type].icon);
            }
            titleButton.setAttribute("class", options.type);
            titleButton.appendChild(span);
            titleButton.appendText(` ${text.join(" ")}`);
        }
        titleButton.onmousedown = modal.events.move;
        titleButton.ontouchstart = modal.events.move;
        titleButton.setAttribute("type", "button");
        titleButton.onblur = function browser_utilities_modal_content_blur() {
            titleButton.onclick = null;
        };
        section.appendChild(titleButton);
        section.setAttribute("class", "heading");
        border.appendChild(section);
        // Box universal definitions
        browser.ui.modals[id] = options;
        box.socket = socket;
        box.setAttribute("id", id);
        box.onmousedown = modal.events.zTop;
        box.setAttribute("class", "box");
        box.setAttribute("data-agent", options.agent);
        box.setAttribute("data-agenttype", options.agentType);
        box.style.zIndex = browser.ui.zIndex.toString();
        box.style.left = `${options.left / 10}em`;
        box.style.top = `${options.top / 10}em`;
        body.style.height = `${options.height / 10}em`;
        body.style.width = `${options.width / 10}em`;
        if (options.scroll === false || textType === true) {
            body.style.overflow = "hidden";
        }
        // Top input controls
        section = document.createElement("p");
        section.setAttribute("class", "buttons");
        if (Array.isArray(options.inputs) === true) {
            // Universal input controls
            if (options.inputs.indexOf("maximize") > -1 || options.inputs.indexOf("minimize") > -1) {
                if (options.inputs.indexOf("minimize") > -1) {
                    button({
                        class: "minimize",
                        event: modal.events.minimize,
                        parent: section,
                        spanText: "Minimize",
                        text: "↙ ",
                        title: "Minimize"
                    });
                    buttonCount = buttonCount + 1;
                }
                if (options.inputs.indexOf("maximize") > -1) {
                    button({
                        class: "maximize",
                        event: modal.events.maximize,
                        parent: section,
                        spanText: "Maximize",
                        text: "⇱ ",
                        title: "Maximize"
                    });
                    buttonCount = buttonCount + 1;
                }
            }
            // Apply a text input control
            if (options.inputs.indexOf("text") > -1) {
                const label = document.createElement("label"), span = document.createElement("span");
                span.appendText("Text of file system address.");
                label.appendChild(span);
                extra = document.createElement("p");
                input = document.createElement("input");
                input.type = "text";
                input.spellcheck = false;
                if (options.text_event !== undefined) {
                    input.onkeyup = options.text_event;
                    input.onclick = function browser_utilities_modal_content_inputFocus(event) {
                        const element = event.target;
                        element.focus();
                        return false;
                    };
                }
                if (options.text_placeholder !== undefined) {
                    input.placeholder = options.text_placeholder;
                }
                if (options.text_value !== undefined) {
                    input.value = options.text_value;
                }
                if (options.type === "file-navigate") {
                    const searchLabel = document.createElement("label"), search = document.createElement("input"), span = document.createElement("span");
                    extra.style.paddingLeft = "15em";
                    button({
                        class: "backDirectory",
                        event: file_browser.events.back,
                        parent: extra,
                        spanText: "Previous address",
                        text: "◀ ",
                        title: "Back to previous address"
                    });
                    button({
                        class: "reloadDirectory",
                        event: file_browser.events.text,
                        parent: extra,
                        spanText: "Reload",
                        text: "↺ ",
                        title: "Reload directory"
                    });
                    button({
                        class: "parentDirectory",
                        event: file_browser.events.parent,
                        parent: extra,
                        spanText: "Parent directory",
                        text: "▲ ",
                        title: "Move to parent directory"
                    });
                    search.type = "text";
                    search.placeholder = "⌕ Search";
                    search.onblur = file_browser.events.search;
                    search.onclick = file_browser.events.searchFocus;
                    search.onfocus = file_browser.events.searchFocus;
                    search.onkeyup = file_browser.events.search;
                    search.value = options.search[1];
                    span.appendText("Search for file system artifacts from this location. Searches starting with ! are negation searches and regular expressions are supported if the search starts and ends with a forward slash.");
                    searchLabel.appendChild(span);
                    searchLabel.setAttribute("class", "fileSearch");
                    searchLabel.appendChild(search);
                    extra.setAttribute("class", "header");
                    label.setAttribute("class", "fileAddress");
                    label.appendChild(input);
                    extra.appendChild(label);
                    extra.appendChild(searchLabel);
                } else {
                    extra.setAttribute("class", "header");
                    label.appendChild(input);
                    extra.appendChild(label);
                }
                border.appendChild(extra);
            }
            // Apply history to those types that record a history state
            if (options.type === "file-navigate" || options.type === "terminal") {
                if (options.history === undefined) {
                    if (options.text_value === undefined) {
                        browser.ui.modals[id].history = [];
                    } else {
                        browser.ui.modals[id].history = [
                            options.text_value
                        ];
                    }
                } else {
                    browser.ui.modals[id].history = options.history;
                }
            }
        }
        button({
            class: "close",
            event: typeof options.closeHandler === "function" ? options.closeHandler : modal.events.close,
            parent: section,
            spanText: "Close",
            text: "✖ ",
            title: "Close"
        });
        buttonCount = buttonCount + 1;
        border.appendChild(section);
        // Adjust titleButton width to compensate for the presence of universal input controls
        widths = modal.tools.dynamicWidth(box, options.width, buttonCount);
        titleButton.style.width = `${widths[0]}em`;
        // Append body content after top areas and before bottom areas
        if (options.content !== null && options.content !== undefined) {
            if (textType === true) {
                body.setAttribute("class", "body text-pad");
            } else {
                body.setAttribute("class", "body");
                body.appendChild(options.content);
            }
        }
        border.appendChild(body);
        // Status bar
        if (options.footer !== null && options.footer !== undefined) {
            options.footer.style.width = `${widths[1]}em`;
            border.appendChild(options.footer);
        }
        // Confirmation and text posting
        if (Array.isArray(options.inputs) === true && (options.inputs.indexOf("cancel") > -1 || options.inputs.indexOf("confirm") > -1 || options.inputs.indexOf("save") > -1)) {
            section = document.createElement("footer");
            section.setAttribute("class", "footer");
            extra = document.createElement("p");
            extra.setAttribute("class", "footer-buttons");
            if (options.inputs.indexOf("save") > -1) {
                button({
                    class: "save",
                    event: file_browser.events.saveFile,
                    parent: extra,
                    spanText: null,
                    text: "🖫 Save File",
                    title: "Save"
                });
            }
            if (options.inputs.indexOf("confirm") > -1) {
                button({
                    class: "confirm",
                    event: modal.events.confirm,
                    parent: extra,
                    spanText: null,
                    text: "✓ Confirm",
                    title: "Confirm"
                });
            }
            if (options.inputs.indexOf("cancel") > -1) {
                button({
                    class: "cancel",
                    event: options.type === "invite-ask" ? agent_management.events.inviteDecline : modal.events.close,
                    parent: extra,
                    spanText: null,
                    text: "🗙 Cancel",
                    title: "Cancel"
                });
            }
            section.appendChild(extra);
            extra = document.createElement("span");
            extra.setAttribute("class", "clear");
            section.appendChild(extra);
            border.appendChild(section);
        }
        // Append modal
        if (options.status === "hidden") {
            box.style.display = "none";
        }
        box.appendChild(border);
        browser.content.appendChild(box);
        // Modal resize buttons in border
        if (options.resize !== false) {
            const borderButton = function browser_utilities_modal_content_borderButton(className, text) {
                const span = document.createElement("span"), buttonElement = document.createElement("button");
                span.appendText(text);
                buttonElement.setAttribute("class", className);
                buttonElement.setAttribute("type", "button");
                buttonElement.setAttribute("aria-hidden", "true");
                buttonElement.onmousedown = modal.events.resize;
                buttonElement.appendChild(span);
                border.appendChild(buttonElement);
            };
            border.setAttribute("class", "border");
            borderButton("corner-tl", "resize both width and height");
            borderButton("corner-tr", "resize both width and height");
            borderButton("corner-bl", "resize both width and height");
            borderButton("corner-br", "resize both width and height");
            borderButton("side-t", "resize box height");
            borderButton("side-r", "resize box width");
            borderButton("side-b", "resize box height");
            borderButton("side-l", "resize box width");
        }
        // Apply universal controls from saved state
        if (options.status === "maximized" && options.inputs.indexOf("maximize") > -1) {
            const maximize = box.getElementsByClassName("maximize")[0];
            browser.ui.modals[options.id].status = "normal";
            modal.events.maximize(null, options.callback, maximize);
        } else if (options.status === "minimized" && options.inputs.indexOf("minimize") > -1) {
            const minimize = box.getElementsByClassName("minimize")[0];
            browser.ui.modals[options.id].status = "normal";
            modal.events.minimize(null, options.callback, minimize);
        } else if (options.status === "minimized") {
            browser.ui.modals[options.id].status = "normal";
            modal.tools.forceMinimize(options.id);
            if (options.callback !== undefined) {
                options.callback();
            }
        } else {
            if (options.status === "hidden") {
                browser.ui.modals[options.id].status = "hidden";
                box.style.display = "none";
            }
            if (browser.loading === false) {
                network.configuration();
            }
            if (options.callback !== undefined) {
                options.callback();
            }
        }
        if (options.footer !== undefined && options.footer !== null && options.footer.getElementsByTagName("textarea").length > 0) {
            modal.events.resize(null, box);
        }
        // return modal
        return box;
    },
    events: {
        /* Removes a modal from the DOM for garbage collection */ close: function browser_utilities_modal_close(event) {
            const element = event.target, keys = Object.keys(browser.ui.modals), keyLength = keys.length, box = element.getAncestor("box", "class"), id = box.getAttribute("id"), type = browser.ui.modals[id] === undefined ? null : browser.ui.modals[id].type;
            let a = 0, count = 0;
            // box is off the DOM, so don't worry about it
            if (box.parentNode === null || type === null) {
                return;
            }
            // modal type specific instructions
            if (type === "invite-ask") {
                const inviteBody = box.getElementsByClassName("agentInvitation")[0], invitation = JSON.parse(inviteBody.dataset.invitation);
                if (invitation.status === "invited") {
                    invitation.action = "invite-answer";
                    invitation.status = "ignored";
                    network.send(invitation, "invite");
                }
            } else if (type === "media") {
                media.tools.kill(browser.ui.modals[id]);
            }
            if (box.socket !== null && box.socket !== undefined) {
                box.socket.close();
            }
            // remove the box
            box.onclick = null;
            box.parentNode.removeChild(box);
            // remove from modal type list if the last of respective modal types open
            do {
                if (browser.ui.modals[keys[a]].type === type) {
                    count = count + 1;
                    if (count > 1) {
                        break;
                    }
                }
                a = a + 1;
            }while (a < keyLength)
            if (count === 1) {
                browser.ui.modalTypes.splice(browser.ui.modalTypes.indexOf(type), 1);
            }
            // remove from state and send to storage
            delete browser.ui.modals[id];
            network.configuration();
        },
        /* Modal types that are enduring are hidden, not destroyed, when closed */ closeEnduring: function browser_utilities_modal_closeEnduring(event) {
            let box = event.target;
            box = box.getAncestor("box", "class");
            if (box.getAttribute("class") === "box") {
                box.style.display = "none";
                // this must remain separated from modal identity as more than one thing users it
                browser.ui.modals[box.getAttribute("id")].status = "hidden";
            }
            network.configuration();
        },
        /* Event handler for the modal's "Confirm" button */ confirm: function browser_utilities_modal_confirm(event) {
            const element = event.target, box = element.getAncestor("box", "class"), id = box.getAttribute("id"), options = browser.ui.modals[id];
            if (options.type === "export") {
                modal.events.importSettings(event);
            } else if (options.type === "invite-ask") {
                agent_management.tools.inviteAccept(box);
            } else if (options.type === "agent-management") {
                const section = box.getElementsByClassName("section")[0], inputs = section.getElementsByTagName("input");
                let a = inputs.length;
                do {
                    a = a - 1;
                    if (inputs[a].value === "invite") {
                        break;
                    }
                }while (a > 0)
                agent_management.events.confirm(event);
                if (inputs[a].value === "invite" && inputs[a].checked === true) {
                    return;
                }
            }
            modal.events.close(event);
        },
        /* If a resizable textarea element is present in the modal outside the body this ensures the body is the correct size. */ footerResize: function browser_utilities_modal_footerResize(event) {
            const element = event.target, box = element.getAncestor("box", "class"), body = box.getElementsByClassName("body")[0], bottom = box.getElementsByClassName("side-b")[0], top = box.getElementsByClassName("side-t")[0], width = (box.clientWidth - 19) / 10, title = box.getElementsByTagName("h2")[0];
            body.style.width = `${width}em`;
            bottom.style.width = `${width}em`;
            top.style.width = `${width}em`;
            title.style.width = `${(box.clientWidth - 17) / 10}em`;
            element.style.width = "100%";
        },
        /* Modifies saved settings from an imported JSON string then reloads the page */ importSettings: function browser_utilities_modal_importSettings(event) {
            const element = event.target, box = element.getAncestor("box", "class"), button = document.getElementsByClassName("cancel")[0], textArea = box.getElementsByTagName("textarea")[0];
            button.click();
            network.send(textArea.value, "import");
        },
        /* The given modal consumes the entire view port of the content area */ maximize: function browser_utilities_modal_maximize(event, callback, target) {
            const element = event === null ? target : event.target, contentArea = document.getElementById("content-area"), box = element.getAncestor("box", "class"), id = box.getAttribute("id"), body = box.getElementsByClassName("body")[0], title = box.getElementsByTagName("h2")[0], titleButton = title === undefined ? undefined : title.getElementsByTagName("button")[0], status = box.getElementsByClassName("status-bar")[0], footer = box.getElementsByClassName("footer")[0], footerButtons = footer === undefined ? undefined : footer.getElementsByClassName("footer-buttons")[0], footerOffset = footerButtons === undefined ? 0 : footerButtons.clientWidth, message = footer === undefined ? undefined : footer.getElementsByClassName("message")[0];
            if (box === document.documentElement) {
                return;
            }
            if (browser.ui.modals[id].status === "maximized") {
                titleButton.style.cursor = "move";
                titleButton.onmousedown = modal.events.move;
                browser.ui.modals[id].status = "normal";
                box.style.top = `${browser.ui.modals[id].top / 10}em`;
                box.style.left = `${browser.ui.modals[id].left / 10}em`;
                body.style.width = `${browser.ui.modals[id].width / 10}em`;
                body.style.height = `${browser.ui.modals[id].height / 10}em`;
                if (status !== undefined) {
                    status.style.width = `${(browser.ui.modals[id].width - 20) / 10}em`;
                }
            } else {
                browser.ui.modals[id].status = "maximized";
                titleButton.style.cursor = "default";
                titleButton.onmousedown = null;
                box.style.top = "0em";
                box.style.left = "0em";
                body.style.width = `${(contentArea.clientWidth - 20) / 10}em`;
                body.style.height = function browser_utilities_modal_maximize_maxHeight() {
                    let height = contentArea.clientHeight;
                    const header = box.getElementsByClassName("header")[0];
                    height = height - title.clientHeight - 27;
                    if (footer !== undefined) {
                        height = height - footer.clientHeight;
                    }
                    if (header !== undefined) {
                        height = height - header.clientHeight;
                    }
                    if (status !== undefined) {
                        height = height - status.clientHeight;
                        status.style.width = `${(contentArea.clientWidth - 40) / 10}em`;
                    }
                    if (message !== undefined) {
                        message.style.width = `${(contentArea.clientWidth - footerOffset - 60) / 15}em`;
                    }
                    return `${height / 10}em`;
                }();
            }
            if (browser.loading === false) {
                network.configuration();
            }
            if (callback !== undefined) {
                callback();
            }
        },
        /* Visually minimize a modal to the tray at the bottom of the content area */ minimize: function browser_utilities_modal_minimize(event, callback, target) {
            const element = event === null ? target : event.target, border = element.getAncestor("border", "class"), box = border.parentNode, id = box.getAttribute("id"), title = border.getElementsByTagName("h2")[0], titleButton = title.getElementsByTagName("button")[0], children = border.childNodes, statusBar = box.getElementsByClassName("status-bar")[0];
            let buttons, borders, child, a = 1;
            if (border === document.documentElement || event !== null && event.target.lowName() === "textarea") {
                return;
            }
            if (browser.ui.modals[id].status === "minimized") {
                const li = box.parentNode, body = border.getElementsByClassName("body")[0];
                do {
                    child = children[a];
                    child.style.removeProperty("display");
                    a = a + 1;
                }while (a < children.length)
                document.getElementById("tray").getElementsByTagName("ul")[0].removeChild(li);
                li.removeChild(box);
                box.style.zIndex = browser.ui.modals[id].zIndex.toString();
                titleButton.style.cursor = "move";
                browser.content.appendChild(box);
                browser.ui.modals[id].status = "normal";
                box.style.top = `${browser.ui.modals[id].top / 10}em`;
                box.style.left = `${browser.ui.modals[id].left / 10}em`;
                body.style.width = `${browser.ui.modals[id].width / 10}em`;
                body.style.height = `${browser.ui.modals[id].height / 10}em`;
                if (statusBar !== undefined) {
                    statusBar.style.width = `${(browser.ui.modals[id].width - 20) / 10}em`;
                }
                buttons = box.getElementsByClassName("buttons")[0];
                borders = border.getElementsByClassName("corner-tl").length > 0 ? 15 : 0;
                titleButton.style.width = `${(browser.ui.modals[id].width - buttons.clientWidth - borders) / 18}em`;
                titleButton.lastChild.textContent = titleButton.lastChild.textContent.replace(" - Minimized", "");
                titleButton.onclick = null;
            } else {
                const li = document.createElement("li");
                do {
                    child = children[a];
                    child.style.display = "none";
                    a = a + 1;
                }while (a < children.length)
                box.style.zIndex = "0";
                browser.content.removeChild(box);
                titleButton.style.width = "11.5em";
                titleButton.style.cursor = "pointer";
                titleButton.lastChild.textContent = `${titleButton.lastChild.textContent} - Minimized`;
                titleButton.onclick = browser_utilities_modal_minimize;
                title.style.width = "";
                li.appendChild(box);
                document.getElementById("tray").getElementsByTagName("ul")[0].appendChild(li);
                browser.ui.modals[id].status = "minimized";
            }
            if (browser.loading === false) {
                network.configuration();
            }
            if (callback !== undefined) {
                callback();
            }
        },
        /* Drag and drop interaction for modals */ move: function browser_utilities_modal_move(event) {
            const element = event.target, box = element.getAncestor("box", "class"), boxParent = box.parentNode, settings = browser.ui.modals[box.getAttribute("id")], border = box.getElementsByTagName("div")[0], minifyTest = boxParent.lowName() === "li", touch = event !== null && event.type === "touchstart", mouseEvent = event, touchEvent = event, mouseX = touch === true ? 0 : mouseEvent.clientX, mouseY = touch === true ? 0 : mouseEvent.clientY, touchX = touch === true ? touchEvent.touches[0].clientX : 0, touchY = touch === true ? touchEvent.touches[0].clientY : 0, drop = function browser_utilities_modal_move_drop(dropEvent) {
                const titleBar = document.getElementById("title-bar").clientWidth, boxWidth = box.clientWidth;
                boxLeft = box.offsetLeft;
                boxTop = box.offsetTop;
                if (touch === true) {
                    document.ontouchmove = null;
                    document.ontouchend = null;
                } else {
                    document.onmousemove = null;
                    document.onmouseup = null;
                }
                if (boxTop < 10) {
                    boxTop = 10;
                } else if (boxTop > max - 40) {
                    boxTop = max - 40;
                }
                if (boxLeft > titleBar - 60) {
                    boxLeft = titleBar - 60;
                } else if (boxLeft < boxWidth * -1 + 200) {
                    boxLeft = boxWidth * -1 + 200;
                }
                box.style.top = `${boxTop / 10}em`;
                box.style.left = `${boxLeft / 10}em`;
                border.style.opacity = "1";
                box.style.height = "auto";
                settings.top = boxTop;
                settings.left = boxLeft;
                network.configuration();
                dropEvent.preventDefault();
                return false;
            }, boxMove = function browser_utilities_modal_move_boxMove(moveEvent) {
                const touchEvent = touch === true ? moveEvent : null, mouseEvent = touch === true ? null : moveEvent, clientX = touch === true ? touchEvent.touches[0].clientX : mouseEvent.clientX, clientY = touch === true ? touchEvent.touches[0].clientY : mouseEvent.clientY, x = touch === true ? touchX : mouseX, y = touch === true ? touchY : mouseY;
                moveEvent.preventDefault();
                box.style.right = "auto";
                box.style.left = `${(boxLeft + (clientX - x)) / 10}em`;
                box.style.top = `${(boxTop + (clientY - y)) / 10}em`;
                return false;
            }, max = browser.content.clientHeight;
            let boxLeft = box.offsetLeft, boxTop = box.offsetTop;
            if (minifyTest === true) {
                if (touch === true) {
                    const button = box.getElementsByClassName("minimize")[0];
                    button.click();
                }
                return;
            }
            if (browser.ui.modals[box.getAttribute("id")].status === "maximized") {
                return;
            }
            element.focus();
            event.preventDefault();
            border.style.opacity = "0.5";
            box.style.height = "0.1em";
            if (touch === true) {
                document.ontouchmove = boxMove;
                document.ontouchstart = null;
                document.ontouchend = drop;
            } else {
                document.onmousemove = boxMove;
                document.onmousedown = null;
                document.onmouseup = drop;
            }
        },
        /* Allows resizing of modals in 1 of 8 directions */ resize: function browser_utilities_modal_resize(event, boxElement) {
            let clientWidth = 0, clientHeight = 0;
            const node = boxElement === null || boxElement === undefined ? event.target : boxElement.getElementsByClassName("side-r")[0], box = boxElement === null || boxElement === undefined ? node.getAncestor("box", "class") : boxElement, top = box.offsetTop, left = box.offsetLeft, body = box.getElementsByClassName("body")[0], heading = box.getElementsByTagName("h2")[0], headingButton = heading.getElementsByTagName("button")[0], touch = event !== null && event.type === "touchstart", boxStatus = browser.ui.modals[box.getAttribute("id")].status, footer = box.getElementsByClassName("footer")[0], footerButton = footer !== undefined && footer.getElementsByTagName("button").length > 0, status = box.getElementsByClassName("status-bar")[0], sideBottom = box.getElementsByClassName("side-b")[0], sideTop = box.getElementsByClassName("side-t")[0], mouseEvent = event, touchEvent = event, offX = event === null ? node.offsetLeft : touch === true ? touchEvent.touches[0].clientX : mouseEvent.clientX, offY = event === null ? node.offsetTop : touch === true ? touchEvent.touches[0].clientY : mouseEvent.clientY, mac = navigator.userAgent.indexOf("macintosh") > 0, direction = node.getAttribute("class").split("-")[1], offsetWidth = mac === true ? 20 : footerButton === false ? browser.scrollbar * -1 : 0, offsetHeight = mac === true ? 18 : footerButton === false ? browser.scrollbar * -1 : 0, drop = function browser_utilities_modal_resize_drop() {
                const settings = browser.ui.modals[box.getAttribute("id")];
                if (touch === true) {
                    document.ontouchmove = null;
                    document.ontouchstart = null;
                } else {
                    document.onmousemove = null;
                    document.onmouseup = null;
                }
                clientWidth = body.clientWidth;
                clientHeight = body.clientHeight;
                settings.width = clientWidth - offsetWidth;
                settings.height = clientHeight - offsetHeight;
                media.tools.kill(settings);
                if (settings.type === "media") {
                    body.appendChild(media.content(settings.text_value, settings.height, settings.width));
                }
                network.configuration();
            }, compute = function browser_utilities_modal_resize_compute(leftTest, topTest, values) {
                if (values[0] > -10) {
                    const minWidth = 55.7, computedWidth = leftTest === true ? left + (values[0] - offX) : (clientWidth + (values[0] - offsetWidth - offX)) / 10, bodyWidth = leftTest === true ? (clientWidth - offsetWidth + (left - computedWidth)) / 10 : 0, bodyLong = leftTest === true && bodyWidth > minWidth, principle = bodyLong === true ? bodyWidth : computedWidth, widths = modal.tools.dynamicWidth(box, null, null);
                    if (bodyLong === true) {
                        box.style.left = `${computedWidth / 10}em`;
                    }
                    if (bodyLong === true || leftTest === false && computedWidth > minWidth) {
                        body.style.width = `${principle}em`;
                        if (footer !== undefined && footer !== null) {
                            footer.style.width = `${principle - 2 - (browser.scrollbar + 3) / 10}em`;
                        }
                        sideBottom.style.width = `${principle}em`;
                        sideTop.style.width = `${principle}em`;
                        heading.style.width = `${principle + 0.2}em`;
                    }
                    headingButton.style.width = `${widths[0]}em`;
                    if (status !== undefined) {
                        status.style.width = `${widths[1]}em`;
                    }
                }
                if (values[1] > -10) {
                    const computedHeight = topTest === true ? top + (values[1] - offY) : (clientHeight + (values[1] - offsetHeight - offY)) / 10, bodyHeight = topTest === true ? (clientHeight - offsetHeight + (top - computedHeight)) / 10 : 0;
                    if (topTest === true && (clientHeight - offsetHeight + (top - computedHeight)) / 10 > 10) {
                        box.style.top = `${computedHeight / 10}em`;
                        body.style.height = `${bodyHeight}em`;
                    } else if (topTest === false && computedHeight > 10) {
                        body.style.height = `${computedHeight}em`;
                    }
                }
            }, nullCheck = function browser_utilities_modal_resize_nullCheck(moveEvent, xCheck, yCheck) {
                const mouseMove = moveEvent, touchMove = moveEvent, x = moveEvent === null ? offX - 8 : xCheck === true ? touch === true ? touchMove.touches[0].clientX : mouseMove.clientX : -10, y = moveEvent === null ? offY - 8 : yCheck === true ? touch === true ? touchMove.touches[0].clientY : mouseMove.clientY : -10;
                return [
                    x,
                    y
                ];
            }, side = {
                b: function browser_utilities_modal_resize_sizeB(moveEvent) {
                    compute(false, false, nullCheck(moveEvent, false, true));
                },
                bl: function browser_utilities_modal_resize_sizeBL(moveEvent) {
                    compute(true, false, nullCheck(moveEvent, true, true));
                },
                br: function browser_utilities_modal_resize_sizeBR(moveEvent) {
                    compute(false, false, nullCheck(moveEvent, true, true));
                },
                l: function browser_utilities_modal_resize_sizeL(moveEvent) {
                    compute(true, false, nullCheck(moveEvent, true, false));
                },
                r: function browser_utilities_modal_resize_sizeR(moveEvent) {
                    compute(false, false, nullCheck(moveEvent, true, false));
                },
                t: function browser_utilities_modal_resize_sizeT(moveEvent) {
                    compute(false, true, nullCheck(moveEvent, false, true));
                },
                tl: function browser_utilities_modal_resize_sizeTL(moveEvent) {
                    compute(true, true, nullCheck(moveEvent, true, true));
                },
                tr: function browser_utilities_modal_resize_sizeTR(moveEvent) {
                    compute(false, true, nullCheck(moveEvent, true, true));
                }
            };
            if (boxStatus === "maximized" || boxStatus === "minimized") {
                return;
            }
            clientWidth = body.clientWidth;
            clientHeight = body.clientHeight;
            if (event === null) {
                side[direction](null);
            } else {
                if (touch === true) {
                    document.ontouchmove = side[direction];
                    document.ontouchstart = null;
                    document.ontouchend = drop;
                } else {
                    document.onmousemove = side[direction];
                    document.onmousedown = null;
                    document.onmouseup = drop;
                }
            }
        },
        /* Pushes the text content of a text-pad modal into settings so that it is saved */ textSave: function browser_utilities_modal_textSave(event) {
            const element = event.target, box = element.getAncestor("box", "class"), data = browser.ui.modals[box.getAttribute("id")];
            if (box.timer !== undefined) {
                window.clearTimeout(box.timer);
            }
            data.text_value = element.value;
            network.configuration();
        },
        /* An idle delay is a good time to save written notes */ textTimer: function browser_utilities_modal_textTimer(event) {
            const element = event.target, box = element.getAncestor("box", "class"), data = browser.ui.modals[box.getAttribute("id")];
            if (box.timer !== undefined) {
                window.clearTimeout(box.timer);
            }
            box.timer = window.setTimeout(function browser_utilities_modal_textTimer_delay() {
                window.clearTimeout(box.timer);
                if (data.text_value !== element.value) {
                    data.text_value = element.value;
                    network.configuration();
                }
            }, browser.ui.statusTime);
        },
        /* Manages z-index of modals and moves a modal to the top on interaction */ zTop: function browser_utilities_modal_zTop(event, elementInput) {
            const element = event !== null && elementInput === undefined ? event.target : elementInput, parent = element.parentNode, grandParent = parent.parentNode, box = element.getAncestor("box", "class");
            if ((parent.getAttribute("class") === "fileList" || grandParent.getAttribute("class") === "fileList") && event.shiftKey === true) {
                event.preventDefault();
            }
            browser.ui.zIndex = browser.ui.zIndex + 1;
            browser.ui.modals[box.getAttribute("id")].zIndex = browser.ui.zIndex;
            box.style.zIndex = browser.ui.zIndex.toString();
        }
    },
    tools: {
        /* A singles source of truth for computing the width of the heading button */ dynamicWidth: function browser_utilities_modal_headingButtonWidth(box, width, buttonCount) {
            const output = [
                0,
                0
            ];
            if (buttonCount === undefined || buttonCount === null) {
                buttonCount = box.getElementsByClassName("buttons")[0].getElementsByTagName("button").length;
            }
            if (width === undefined || width === null) {
                const body = box.getElementsByClassName("body")[0];
                width = Number(body.style.width.replace(/em;?/, "")) * 10;
            }
            output[0] = (width - 20 - buttonCount * 45) / 18;
            output[1] = width / 10 - 2;
            return output;
        },
        /* Modals that do not have a minimize button still need to conform to minimize from other interactions. */ forceMinimize: function browser_utilities_modal_forceMinimize(id) {
            const modalItem = document.getElementById(id).getElementsByClassName("body")[0], handler = modalItem.onclick;
            modalItem.onclick = modal.events.minimize;
            modalItem.click();
            modalItem.onclick = handler;
        },
        /* Defines text area modal bodies in a uniform way. */ textModal: function browser_utilities_modal_textModal(title, value, type) {
            const textArea = document.createElement("textarea"), span = document.createElement("span"), label = document.createElement("label");
            textArea.value = value;
            if (type !== "file-edit") {
                textArea.onblur = modal.events.textSave;
            }
            span.appendText(title);
            label.appendChild(span);
            label.appendChild(textArea);
            return label;
        }
    }
};
export default modal;
