const _windowPaddingX = 1 * 2 + 10 * 2;
const _windowPaddingY = 1 * 2 + 10 * 2 + 35;
let WINDOWS = {};
let MOUSE_MOVE_PROCESSING = {};
let globalIncrement = 1;
function escapeHTML(string) {
    return string.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll("\"", "&quot;");
}
function incrementZIndex(windowID, focus = false) {
    WINDOWS[windowID].element.style.zIndex = String(globalIncrement);
    WINDOWS[windowID].zIndex = globalIncrement;
    globalIncrement++;
    if (focus) {
        WINDOWS[windowID].element.focus();
    }
}
function edgeMoveEvent(x, y, pos, windowID) {
    let w = WINDOWS[windowID];
    if (w.fullscreen) {
        return;
    }
    if (pos == "top" || pos.startsWith("top-")) {
        w.height = Math.max(-(y - w.vars.mouseOffsetY - w.vars.startingPosY) + w.vars.startingHeight, w.minHeight);
        w.posY = Math.max(w.vars.startingHeight - w.height + w.vars.startingPosY, 0);
        if (w.posY < 0) {
            w.height -= w.posY;
            w.posY = 0;
        }
    }
    else if (pos == "bottom" || pos.startsWith("bottom-")) {
        w.height = Math.max(y - w.vars.mouseOffsetY - w.vars.startingPosY + w.vars.startingHeight, w.minHeight);
    }
    if (pos == "left" || pos.endsWith("-left")) {
        w.width = Math.max(-(x - w.vars.mouseOffsetX - w.vars.startingPosX) + w.vars.startingWidth, w.minWidth);
        w.posX = Math.max(w.vars.startingWidth - w.width + w.vars.startingPosX, 0);
        if (w.posX < 0) {
            w.width -= w.posX;
            w.posX = 0;
        }
    }
    else if (pos == "right" || pos.endsWith("-right")) {
        w.width = Math.max(x - w.vars.mouseOffsetX - w.vars.startingPosX + w.vars.startingWidth, w.minWidth);
    }
    if (w.posX + w.width + _windowPaddingX > innerWidth) {
        w.width = Math.max(innerWidth - w.posX - _windowPaddingX, w.minWidth);
    }
    if (w.posY + w.height + _windowPaddingY > innerHeight) {
        w.height = Math.max(innerHeight - w.posY - _windowPaddingY, w.minHeight);
    }
    w.element.style.left = `${w.posX}px`;
    w.element.style.top = `${w.posY}px`;
    w.element.style.width = `${w.width + _windowPaddingX - 2}px`;
    w.element.querySelector(".window").style.width = `${w.width}px`;
    w.element.querySelector(".window").style.height = `${w.height}px`;
}
function createWindow(config) {
    if (document.getElementById(config.id)) {
        incrementZIndex(config.id);
        return;
    }
    config.width = config.width || 600;
    config.height = config.height || 400;
    config.minWidth = config.minWidth || 200;
    config.minHeight = config.minHeight || 200;
    let realWidth = Math.max(config.minWidth, Math.min(config.width, innerWidth - _windowPaddingX - 20));
    let realHeight = Math.max(config.minHeight, Math.min(config.height, innerHeight - _windowPaddingY - 20));
    let posX = config.posX || Math.round((innerWidth / 2) - ((realWidth + _windowPaddingX) / 2));
    let posY = config.posY || Math.round((innerHeight / 2) - ((realHeight + _windowPaddingY) / 2));
    let wO = document.createElement("div");
    wO.classList.add("window-outer");
    let w = document.createElement("div");
    w.classList.add("window");
    w.style.width = `${realWidth}px`;
    w.style.height = `${realHeight}px`;
    w.innerHTML = config.content;
    let wH = document.createElement("div");
    wH.classList.add("window-header");
    wH.innerHTML = `
    <i class="window-header-button blank"></i>
    <i class="window-header-button blank"></i>
    <i class="window-header-button blank"></i>
    <strong class="window-header-title">${config.title}</strong>
    <i data-no-move class="window-header-button minimize"></i>
    <i data-no-move class="window-header-button fullscreen"></i>
    <i data-no-move class="window-header-button close"></i>
  `;
    let wC;
    let wI = null;
    if (config.typeable !== false) {
        wI = document.createElement("input");
        wI.classList.add("window-input");
        wI.id = `${config.id}__input`;
        function syncInputs() {
            setTimeout(function () {
                let text = wI.value;
                let cursor = wI.selectionStart;
                let el = wC.querySelector("[data-type-area]");
                if (!el) {
                    return;
                }
                if (cursor == text.length) {
                    el.innerHTML = `${escapeHTML(text)}<i class="cursor">&nbsp;</i>`;
                }
                else {
                    el.innerHTML = `${escapeHTML(text.slice(0, cursor))}<span class="cursor">${escapeHTML(text[cursor])}</span>${escapeHTML(text.slice(cursor + 1))}`;
                }
            }, 1);
        }
        function setCursor() {
            setTimeout(() => {
                wI.setSelectionRange(wI.value.length, wI.value.length);
                syncInputs();
            }, 0);
        }
        wI.oninput = (event) => {
            syncInputs();
            w.scrollTop = w.scrollHeight;
        };
        wI.onkeydown = (event) => {
            if (event.key == "Enter") {
                commandManager(config.id, wI.value.trim());
                w.scrollTop = w.scrollHeight;
                wI.value = "";
            }
            else {
                syncInputs();
            }
        };
        wI.onfocus = setCursor;
        wI.onclick = setCursor;
        wC = document.createElement("label");
        wC.htmlFor = `${config.id}__input`;
    }
    else {
        wC = document.createElement("div");
    }
    wC.classList.add("window-container");
    wC.tabIndex = 0;
    wC.style.left = `${posX}px`;
    wC.style.top = `${posY}px`;
    wC.id = config.id;
    wC.style.zIndex = String(globalIncrement);
    wC.style.width = `${realWidth + _windowPaddingX - 2}px`;
    let edges = document.createDocumentFragment();
    for (const pos of ["top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"]) {
        let el = document.createElement("div");
        el.classList.add("edge", pos);
        el.addEventListener("mousedown", function (e) {
            e.preventDefault();
            WINDOWS[config.id].vars.mouseOffsetX = e.clientX - WINDOWS[config.id].posX;
            WINDOWS[config.id].vars.mouseOffsetY = e.clientY - WINDOWS[config.id].posY;
            WINDOWS[config.id].vars.startingWidth = WINDOWS[config.id].width;
            WINDOWS[config.id].vars.startingHeight = WINDOWS[config.id].height;
            WINDOWS[config.id].vars.startingPosX = WINDOWS[config.id].posX;
            WINDOWS[config.id].vars.startingPosY = WINDOWS[config.id].posY;
            MOUSE_MOVE_PROCESSING[config.id] = {
                callback: (x, y) => { edgeMoveEvent(x, y, pos, config.id); },
                mouseUp: true
            };
        });
        edges.append(el);
    }
    wO.append(w);
    wC.append(wH, wO, edges);
    document.body.append(wC);
    if (config.typeable !== false) {
        wC.append(wI);
        wI.focus();
    }
    else {
        wC.focus();
    }
    WINDOWS[config.id] = {
        element: wC,
        height: realHeight,
        width: realWidth,
        minHeight: config.minHeight,
        minWidth: config.minWidth,
        posX: posX,
        posY: posY,
        fullscreen: false,
        zIndex: globalIncrement,
        vars: {}
    };
    function mouseMoveEvent(x, y) {
        WINDOWS[config.id].posX = Math.max(0, Math.min(innerWidth - WINDOWS[config.id].width - _windowPaddingX, x - WINDOWS[config.id].vars.mouseOffsetX));
        WINDOWS[config.id].posY = Math.max(0, Math.min(innerHeight - WINDOWS[config.id].height - _windowPaddingY, y - WINDOWS[config.id].vars.mouseOffsetY));
        wC.style.left = `${WINDOWS[config.id].posX}px`;
        wC.style.top = `${WINDOWS[config.id].posY}px`;
    }
    wC.addEventListener("focus", function () { incrementZIndex(config.id); });
    for (const link of wC.querySelectorAll("a")) {
        link.addEventListener("focus", function () { incrementZIndex(config.id); });
    }
    wH.addEventListener("mousedown", function (e) {
        if (e.target.dataset.noMove !== undefined) {
            return;
        }
        WINDOWS[config.id].vars.mouseOffsetX = e.clientX - WINDOWS[config.id].posX;
        WINDOWS[config.id].vars.mouseOffsetY = e.clientY - WINDOWS[config.id].posY;
        MOUSE_MOVE_PROCESSING[config.id] = {
            callback: mouseMoveEvent,
            mouseUp: true
        };
    });
    wH.querySelector(".close").addEventListener("click", function () {
        delete WINDOWS[config.id];
        delete windowInformation[config.id];
        delete MOUSE_MOVE_PROCESSING[config.id];
        wC.remove();
        if (typeof config.onDestroy === "function") {
            config.onDestroy();
        }
    });
    wH.querySelector(".fullscreen").addEventListener("click", function () {
        let window = WINDOWS[config.id];
        if (window.fullscreen) {
            window.posX = Math.max(0, Math.min(innerWidth - window.vars.oldWidth - _windowPaddingX, window.vars.oldPosX));
            window.posY = Math.max(0, Math.min(innerHeight - window.vars.oldHeight - _windowPaddingY, window.vars.oldPosY));
            window.width = Math.max(window.minWidth, Math.min(window.vars.oldWidth, innerWidth - _windowPaddingX));
            window.height = Math.max(window.minHeight, Math.min(window.vars.oldHeight, innerHeight - _windowPaddingY));
            window.fullscreen = false;
            delete window.vars.oldPosX;
            delete window.vars.oldPosY;
            delete window.vars.oldWidth;
            delete window.vars.oldHeight;
            wC.style.left = `${window.posX}px`;
            wC.style.top = `${window.posY}px`;
            wC.style.width = `${window.width + _windowPaddingX - 2}px`;
            w.style.width = `${window.width}px`;
            w.style.height = `${window.height}px`;
        }
        else {
            window.vars.oldPosX = window.posX;
            window.vars.oldPosY = window.posY;
            window.vars.oldWidth = window.width;
            window.vars.oldHeight = window.height;
            window.fullscreen = true;
            window.posX = 0;
            window.posY = 0;
            window.width = innerWidth;
            window.height = innerHeight;
            wC.style.left = "0px";
            wC.style.top = "0px";
            wC.style.width = `${window.width}px`;
            w.style.width = `${window.width - _windowPaddingX}px`;
            w.style.height = `${window.height - _windowPaddingY}px`;
        }
    });
    globalIncrement++;
}
function windowPreset(template, dontDisableTyping = false) {
    let el = document.querySelector(`#window-templates > [data-template-id="${template}"]`);
    if (!el) {
        return;
    }
    if (WINDOWS[template]) {
        incrementZIndex(template, true);
        return;
    }
    let config = {
        id: template,
        title: "~ - tSh",
        content: "<div><b class=\"green\">trinkey@website</b>:<b class=\"blue\">~</b>$&nbsp;<span data-type-area><i class=\"cursor\">&nbsp;</i></span></div>"
    };
    for (const field of el.querySelectorAll("[data-template-field]")) {
        config[field.dataset.templateField] = field.dataset.isNumber === "" ? +field.innerText : field.innerHTML;
    }
    createWindow(config);
    for (const command of el.querySelectorAll("li")) {
        WINDOWS[template].element.querySelector("[data-type-area]").innerHTML = command.innerHTML;
        commandManager(template, command.innerHTML);
    }
    if (!dontDisableTyping) {
        WINDOWS[template].element.querySelector("input").remove();
    }
}
function emptyWindow() {
    createWindow({
        id: `terminal-${Math.random()}`,
        title: "~ - tSh",
        content: "<div><b class=\"green\">trinkey@website</b>:<b class=\"blue\">~</b>$&nbsp;<span data-type-area><i class=\"cursor\">&nbsp;</i></span></div>"
    });
}
function copyButton() {
    navigator.clipboard.writeText("<a href=\"https://trinkey.com/\" target=\"_blank\"><img src=\"https://trinkey.com/img/88x31.png\" alt=\"trinkey's 88x31. image of her cat on the right with the word 'trinkey' taking up the rest of the button.\" title=\"trinkey's 88x31. image of her cat on the right with the word 'trinkey' taking up the rest of the button.\"></a>");
}
onmousemove = function (e) {
    e.preventDefault();
    for (const key of Object.keys(MOUSE_MOVE_PROCESSING)) {
        MOUSE_MOVE_PROCESSING[key].callback(e.clientX, e.clientY);
    }
};
onmouseup = function () {
    for (const key of Object.keys(MOUSE_MOVE_PROCESSING)) {
        if (MOUSE_MOVE_PROCESSING[key].mouseUp) {
            delete MOUSE_MOVE_PROCESSING[key];
        }
        ;
    }
};
onresize = function () {
    for (const window of Object.keys(WINDOWS)) {
        let w = WINDOWS[window];
        if (w.fullscreen) {
            w.width = innerWidth - _windowPaddingX + 2;
            w.height = innerHeight - _windowPaddingY + 2;
        }
        else {
            w.posX = Math.max(0, Math.min(innerWidth - w.width - _windowPaddingX, w.posX));
            w.posY = Math.max(0, Math.min(innerHeight - w.height - _windowPaddingY, w.posY));
            w.width = Math.max(w.minWidth, Math.min(w.width, innerWidth - _windowPaddingX));
            w.height = Math.max(w.minHeight, Math.min(w.height, innerHeight - _windowPaddingY));
        }
        w.element.style.left = `${w.posX}px`;
        w.element.style.top = `${w.posY}px`;
        w.element.style.width = `${w.width + _windowPaddingX - 2}px`;
        w.element.querySelector(".window").style.width = `${w.width}px`;
        w.element.querySelector(".window").style.height = `${w.height}px`;
    }
};
