/* ===================== AUTOGENERATED SOURCE IMPORT ===================== */

import Template from "/emcJS/util/html/template/HTMLTemplate.js";

const TPL = new Template(`
    <div id="focus_catcher_top" tabindex="0"></div>
    <emc-ctxmenulayer>
        <div id="modal" role="modal" aria-modal="true" aria-labelledby="title" aria-describedby="title">
            <div id="header">
                <div id="title-icon">❖</div>
                <div id="title">
                    <emc-i18n-label id="title-text"></emc-i18n-label>
                </div>
                <button id="close" aria-label="close">
                    <emc-symbol-close></emc-symbol-close>
                </button>
            </div>
            <div id="content">
                <div id="text"></div>
                <slot id="slot"></slot>
            </div>
            <div id="footer"></div>
        </div>
    </emc-ctxmenulayer>
    <div id="focus_catcher_bottom" tabindex="0"></div>
    
`);

import GlobalStyle from "/emcJS/util/html/template/CSSTemplate.js";

const STYLE = new GlobalStyle(`
    :host {
        position: fixed !important;
        box-sizing: border-box !important;
        align-items: flex-start !important;
        justify-content: center !important;
        top: 0 !important;
        left: 0 !important;
        right: 0 !important;
        bottom: 0 !important;
        width: 100% !important;
        height: 100% !important;
        cursor: default !important;
        overflow: hidden !important;
        background-color: rgba(0, 0, 0, 0.3);
        backdrop-filter: blur(2px);
        -webkit-backdrop-filter: blur(2px);
        z-index: var(--z-index-modal, 900600);
        pointer-events: all !important;
    }
    
    :host(.inactive) {
        background-color: transparent !important;
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
        z-index: calc(var(--z-index-modal, 900600) - 1);
    }
    
    :host,
    .button {
        display: flex;
    }
    
    #modal {
        display: flex;
        flex-direction: column;
        width: auto;
        height: auto;
        min-width: min(400px, calc(100dvw - 50px));
        max-width: min(1000px, calc(100dvw - 50px));
        min-height: min(200px, calc(100dvh - 50px));
        max-height: min(800px, calc(100dvh - 50px));
        margin-top: min(100px, calc(25px + max(0px, calc(55dvh - 480px))));
        color: var(--modal-text-color, #000000);
        background-color: var(--modal-back-color, #ffffff);
        background-image: var(--modal-back-image, none);
        border-style: solid;
        border-width: var(--modal-border-width, 2px);
        border-color: var(--modal-border-color, #cccccc);
        border-radius: 4px;
        font-size: 1rem;
        resize: both;
        pointer-events: all;
        box-shadow: #000000c4 11px 11px 20px 0px;
    }
    
    :host([streched]:not([streched="false"])) #modal {
        width: 100%;
    }
    
    @media (max-height: 1000px) {
        #modal {
            margin-top: 25px;
        }
    }
    
    :host(.inactive) #modal {
        pointer-events: none;
        filter: blur(2px);
    }
    
    #header {
        display: flex;
        color: var(--modal-header-text-color, #000000);
        background-color: var(--modal-header-back-color, #e4e4e4);
        background-image: var(--modal-header-back-image, none);
        border-bottom: solid var(--modal-border-width, 2px) var(--modal-border-color, #cccccc);
    }
    
    #footer {
        display: flex;
        align-items: center;
        justify-content: flex-end;
        min-height: 50px;
        padding: 5px;
        color: var(--modal-footer-text-color, #000000);
        background-color: var(--modal-footer-back-color, #e4e4e4);
        background-image: var(--modal-footer-back-image, none);
        border-top: solid var(--modal-border-width, 2px) var(--modal-border-color, #cccccc);
    }
    
    #footer:empty {
        display: none;
    }
    
    #close {
        display: flex;
        width: 40px;
        height: 40px;
        border: none;
        align-items: center;
        justify-content: center;
        color: var(--modal-close-text-color, #222222);
        background-color: var(--modal-close-back-color, #ffb9b9);
        background-image: var(--modal-close-back-image, none);
        cursor: pointer;
        user-select: none;
        appearance: none;
        font-size: 1.5em;
        line-height: 1em;
    }
    
    #close:hover {
        color: var(--modal-close-hover-text-color, #ffffff);
        background-color: var(--modal-close-hover-back-color, #ff0000);
        background-image: var(--modal-close-hover-back-image, none);
    }
    
    #close:focus {
        box-shadow: inset var(--modal-close-focus-color, #000000) 0 0px 3px 4px;
        outline: none;
    }
    
    #title {
        display: flex;
        align-items: center;
        flex: 1;
        height: 40px;
        padding: 0 10px;
        font-weight: bold;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 1em;
        line-height: 1em;
    }
    
    #title-icon {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        height: 40px;
        width: 40px;
        margin-left: 5px;
        color: var(--modal-icon-default-color, #000000);
        font-family: monospace;
        font-size: 2.8em;
        line-height: 1em;
        background-size: contain;
        background-repeat: no-repeat;
        background-position: center;
        user-select: none;
    }
    
    #title-icon.small {
        font-size: 1.9em;
    }
    
    #content {
        display: flex;
        flex-direction: column;
        flex: 1;
        overflow: auto;
        scroll-padding-top: 20px;
        scroll-padding-bottom: 20px;
    }
    
    #text {
        display: block;
        margin-bottom: 8px;
        line-height: 1.3em;
        word-wrap: break-word;
        white-space: pre-wrap;
        resize: none;
    }
    
    #text:empty {
        display: none;
    }
    
    a {
        color: var(--modal-link-text-color, #004472);
        text-decoration: none;
        border-radius: var(--button-border-radius, 4px);
    }
    
    a:hover {
        color: var(--modal-link-hover-text-color, #003597);
    }
    
    a:focus {
        box-shadow: 0 0 2px 3px var(--button-focus-color, #06b5ff);
        outline: none;
    }
    
    .text-icon {
        margin-right: 0.5em;
    }
    
`);

/* ======================================================================= */

import CustomElement from "../element/CustomElement.js";
import UniqueEntriesStack from "../../data/stack/UniqueEntriesStack.js";
import {isColorString} from "../../util/helper/CheckType.js";
import {getFocusableElements} from "../../util/helper/html/ElementFocusHelper.js";
import "../i18n/I18nLabel.js";
import "../symbols/CloseSymbol.js";

const SIZE_REGEXP = /^[0-9]+(?:\.[0-9]+)?(?:em|px|%)$/;

const modalStorage = new Map();

const visibleModals = new UniqueEntriesStack();

export default class Modal extends CustomElement {

    #modalEl;

    #titleIconEl;

    #titleTextEl;

    #closeEl;

    #textEl;

    #footerEl;

    #focusTopEl;

    #focusBottomEl;

    #assocName = "";

    constructor(caption) {
        super();
        this.shadowRoot.append(TPL.generate());
        STYLE.apply(this.shadowRoot);
        /* --- */
        this.#modalEl = this.shadowRoot.getElementById("modal");
        this.#titleIconEl = this.shadowRoot.getElementById("title-icon");
        this.#titleTextEl = this.shadowRoot.getElementById("title-text");
        this.#closeEl = this.shadowRoot.getElementById("close");
        this.#textEl = this.shadowRoot.getElementById("text");
        this.#footerEl = this.shadowRoot.getElementById("footer");
        this.caption = caption;
        /* --- */
        this.#modalEl.addEventListener("keydown", (event) => {
            if (event.key == "Escape") {
                this.close();
                event.stopPropagation();
            }
        });
        this.#closeEl.addEventListener("click", () => this.close());
        /* --- */
        this.#focusTopEl = this.shadowRoot.getElementById("focus_catcher_top");
        this.#focusTopEl.addEventListener("focus", () => {
            this.focusLast();
        });
        this.#focusBottomEl = this.shadowRoot.getElementById("focus_catcher_bottom");
        this.#focusBottomEl.addEventListener("focus", () => {
            this.focusFirst();
        });
    }

    get assocName() {
        return this.#assocName;
    }

    disconnectedCallback() {
        this.classList.remove("inactive");
    }

    set caption(value) {
        this.setStringAttribute("caption", value);
    }

    get caption() {
        return this.getStringAttribute("caption");
    }

    set streched(value) {
        this.setBooleanAttribute("streched", value);
    }

    get streched() {
        return this.getBooleanAttribute("streched");
    }

    static get observedAttributes() {
        return ["caption"];
    }

    attributeChangedCallback(name, oldValue, newValue) {
        switch (name) {
            case "caption": {
                if (oldValue != newValue) {
                    this.#titleTextEl.i18nValue = newValue;
                }
            } break;
        }
    }

    setFontIcon(content, opts = {}) {
        const {
            color, size, circle = false
        } = opts;
        if (typeof content === "string" && content !== "") {
            this.#titleIconEl.innerText = content;
            if (SIZE_REGEXP.test(size)) {
                this.#titleIconEl.style.fontSize = size;
            }
            if (isColorString(color)) {
                this.#titleIconEl.style.color = color;
            } else {
                this.#titleIconEl.style.color = "";
            }
            if (circle) {
                if (isColorString(circle)) {
                    this.#titleIconEl.style.backgroundImage = `radial-gradient(transparent 45%, ${circle}, transparent 55%)`;
                } else {
                    this.#titleIconEl.style.backgroundImage = "radial-gradient(transparent 45%, black, transparent 55%)";
                }
                this.#titleIconEl.classList.add("small");
            } else {
                this.#titleIconEl.style.backgroundImage = "";
                this.#titleIconEl.classList.remove("small");
            }
            return true;
        } else {
            this.#titleIconEl.innerText = "❖";
            this.#titleIconEl.style.backgroundImage = "";
            this.#titleIconEl.style.color = "";
            this.#titleIconEl.classList.remove("small");
            return false;
        }
    }

    setImageIcon(content) {
        this.#titleIconEl.classList.remove("small");
        if (typeof content === "string" && content !== "") {
            this.#titleIconEl.innerText = "";
            this.#titleIconEl.style.backgroundImage = content;
            this.#titleIconEl.style.color = "";
            return true;
        } else {
            this.#titleIconEl.innerText = "❖";
            this.#titleIconEl.style.backgroundImage = "";
            this.#titleIconEl.style.color = "";
            return false;
        }
    }

    setHTMLIcon(content) {
        this.#titleIconEl.classList.remove("small");
        if (content instanceof HTMLElement) {
            this.#titleIconEl.innerText = "";
            this.#titleIconEl.append(content);
            return true;
        } else {
            this.#titleIconEl.innerText = "❖";
            this.#titleIconEl.style.backgroundImage = "";
            this.#titleIconEl.style.color = "";
            return false;
        }
    }

    setIcon(config) {
        switch (config.method) {
            case "font": {
                return this.setFontIcon(config.content, config.style);
            }
            case "image": {
                return this.setImageIcon(config.content);
            }
            case "html": {
                return this.setHTMLIcon(config.content);
            }
            default: {
                this.#titleIconEl.innerText = "❖";
                this.#titleIconEl.style.backgroundImage = "";
                this.#titleIconEl.style.color = "";
                return false;
            }
        }
    }

    show() {
        document.body.append(this);
        const oldModal = visibleModals.peek();
        if (oldModal != null) {
            oldModal.classList.add("inactive");
        }
        this.classList.remove("inactive");
        visibleModals.push(this);
        this.initialFocus();
    }

    remove() {
        super.remove();
        if (visibleModals.peek() === this) {
            visibleModals.pop();
            const lastModal = visibleModals.peek();
            if (lastModal != null) {
                lastModal.classList.remove("inactive");
            }
        } else {
            visibleModals.delete(this);
        }
    }

    close() {
        this.remove();
        this.dispatchEvent(new Event("close"));
    }

    #getTextFocusable() {
        return getFocusableElements(this.#textEl);
    }

    #getContentFocusable() {
        return getFocusableElements(this);
    }

    #getFooterFocusable() {
        return getFocusableElements(this.#footerEl);
    }

    initialFocus() {
        const textEls = this.#getTextFocusable();
        if (textEls.length) {
            textEls[0].focus();
        } else {
            const contentEls = this.#getContentFocusable();
            if (contentEls.length) {
                contentEls[0].focus();
            } else  {
                const footerEls = this.#getFooterFocusable();
                if (footerEls.length) {
                    footerEls[0].focus();
                } else {
                    this.#closeEl.focus();
                }
            }
        }
    }

    focusFirst() {
        this.#closeEl.focus();
    }

    focusLast() {
        const footerEls = this.#getFooterFocusable();
        if (footerEls.length) {
            footerEls.at(-1).focus();
        } else {
            const contentEls = this.#getContentFocusable();
            if (contentEls.length) {
                contentEls.at(-1).focus();
            } else  {
                const textEls = this.#getTextFocusable();
                if (textEls.length) {
                    textEls.at(-1).focus();
                } else {
                    this.#closeEl.focus();
                }
            }
        }
    }

    static getModalByName(name) {
        if (typeof name !== "string" || name === "") {
            return new this();
        }
        if (modalStorage.has(this)) {
            const modalsForType = modalStorage.get(this);
            if (modalsForType.has(name)) {
                return modalsForType.get(name);
            }
            const modal = new this();
            modal.#assocName = name;
            modalsForType.set(name, modal);
            return modal;
        }
        const modalsForType = new Map();
        const modal = new this();
        modal.#assocName = name;
        modalsForType.set(name, modal);
        modalStorage.set(this, modalsForType);
        return modal;
    }

    static closeAll() {
        while (visibleModals.size > 0) {
            visibleModals.pop().close();
        }
    }

}

customElements.define("emc-modal", Modal);
