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

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

const TPL = new Template(`
    <div id="container">
        <div id="cover">
        </div>
        <ul id="content">
        </ul>
    </div>
    <emc-navbar-hamburger id="hamburger-button">
    </emc-navbar-hamburger>
`);

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

const STYLE = new GlobalStyle(`
    :host {
        display: flex;
        justify-content: center;
        top: 0;
        width: 100%;
        min-height: 2em;
        background-color: var(--navigation-back-color, #ffffff);
        background-image: var(--navigation-back-image, none);
        color: var(--navigation-text-color, #000000);
        flex-grow: 0;
        flex-shrink: 0;
        z-index: var(--z-index-navbar, 900500);
    }
    
    #container {
        display: block;
        margin: 0;
        width: 100%;
        z-index: 100;
    }
    
    #cover {
        position: fixed;
        display: none;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
    }
    
    #container.cover #cover,
    #container.open #cover {
        display: block;
    }
    
    #hamburger-button {
        position: relative;
        display: none;
        width: 3em;
        height: 3em;
        margin: 0;
        transition: transform 0.2s ease-in-out;
    }
    
    #container.open ~ #hamburger-button {
        transform: translateX(calc(100dvw - (3em + 10px)));
    }
    
    ul {
        position: relative;
        -webkit-padding-start: 0;
        -webkit-margin-before: 0;
        -webkit-margin-after: 0;
        -moz-padding-start: 0;
        -moz-margin-before: 0;
        -moz-margin-after: 0;
        list-style: none;
    }
    
    ul li {
        position: relative;
        min-width: 150px;
        padding: 0 5px;
        background-color: var(--navigation-back-color, #ffffff);
        background-image: var(--navigation-back-image, none);
    }
    
    ul > li {
        display: inline-block;
    }
    
    ul > li > ul {
        left: 0;
        width: 100px;
        z-index: 100;
        box-shadow: var(--navigation-shadow-color, #000000) 2px 4px 6px -2px;
    }
    
    ul#content {
        display: inline-flex;
        margin: 0;
    }
    
    ul li > emc-navbar-button {
        height: 2em;
        width: 100%;
    }
    
    @media (max-width: 500px) {
        :host {
            display: block;
            min-height: 3em;
            width: 100dvw;
        }
    
        #container {
            position: absolute;
            width: 100dvw;
            left: -100dvw;
            height: 100dvh;
            padding-right: calc(3em + 10px);
            transition: left 0.2s ease-in-out;
        }
    
        #container.open {
            left: 0;
        }
    
        #hamburger-button {
            display: inline-block;
            z-index: 99;
        }
    
        ul li {
            width: 100%;
        }
    
        ul#content {
            flex-direction: column;
            width: 100%;
            max-height: 100%;
            overflow-y: auto;
            box-shadow: var(--navigation-marker-color, #000000) 2px 4px 8px 2px;
        }
    
        ul#content > li > ul {
            display: none;
            width: 100%;
            padding: 0 0 0 20px;
        }
    
        ul#content > li.open > ul {
            display: table;
            box-shadow: none;
        }
    
        ul#content > li > ul:not(:last-child) {
            padding-bottom: 4px;
        }
    
        ul li > emc-navbar-button {
            height: 3em;
            --justify-content: flex-start;
        }
    }
    
    @media (min-width: 501px) {
        ul#content {
            flex-wrap: wrap;
            width: 100%;
        }
    
        ul#content > li > ul {
            position: absolute;
            display: table;
            top: 100%;
            transition: transform 0.2s ease-in-out;
            transform-origin: center top;
            transform: scaleY(0);
        }
    
        ul#content > li.open > ul {
            transform: scaleY(1);
        }
    
        ul#content > li > ul > li {
            display: inline-block;
            width: 100%;
        }
    }
    
`);

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

import CustomElement from "../element/CustomElement.js";
import {
    isFunction,
    isHttpUrl
} from "../../util/helper/CheckType.js";
import "./components/Button.js";
import "./components/HamburgerButton.js";

const MIXINS = new Map();

function closeAll(targetEl) {
    for (const el of targetEl.querySelectorAll(".open")) {
        el.classList.remove("open");
    }
    for (const el of targetEl.querySelectorAll("[expand=\"open\"]")) {
        el.expand = "closed";
        el.blur();
    }
}

function encodeWindowFeatures(input) {
    if (typeof input === "string") {
        return input;
    } else if (typeof input === "object" && !Array.isArray(input)) {
        return Object.entries(input).map((entry) => {
            const [key, value] = entry;
            return `${key}=${value}`;
        }).join(",");
    }
}

export default class NavBar extends CustomElement {

    #containerEl;

    #contentEl;

    #coverEl;

    #hamburgerEl;

    #navigationHandler = null;

    constructor() {
        super();
        this.shadowRoot.append(TPL.generate());
        STYLE.apply(this.shadowRoot);
        /* --- */

        // layout
        this.#containerEl = this.shadowRoot.getElementById("container");
        this.#contentEl = this.shadowRoot.getElementById("content");
        this.#hamburgerEl = this.shadowRoot.getElementById("hamburger-button");
        this.#coverEl = this.shadowRoot.getElementById("cover");
        this.#hamburgerEl.addEventListener("click", () => {
            if (this.#containerEl.classList.contains("open")) {
                this.#containerEl.classList.remove("open");
                this.#containerEl.classList.remove("cover");
                closeAll(this.#contentEl);
                this.#hamburgerEl.open = false;
            } else {
                this.#containerEl.classList.add("open");
                this.#hamburgerEl.open = true;
            }
        });
        this.#coverEl.addEventListener("click", () => {
            this.#containerEl.classList.remove("open");
            this.#containerEl.classList.remove("cover");
            closeAll(this.#contentEl);
            this.#hamburgerEl.open = false;
        });
    }

    set maxWidth(value) {
        this.setIntAttribute("maxwidth", value, 0);
    }

    get maxWidth() {
        return this.getIntAttribute("maxwidth");
    }

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

    attributeChangedCallback(name, oldValue, newValue) {
        if (name == "maxwidth") {
            if (oldValue != newValue) {
                this.#containerEl.style.maxWidth = `${newValue}px`;
            }
        }
    }

    loadNavigation(config) {
        this.#contentEl.innerHTML = "";
        for (const item of config) {
            this.#generateElement(this.#contentEl, item);
        }
    }

    setNavigationHandler(fn) {
        if (typeof fn === "function") {
            this.#navigationHandler = fn;
        } else {
            this.#navigationHandler = null;
        }
    }

    #generateElement(contentEl, config) {
        const IS_MAIN_NAV = contentEl.id == "content";
        if (config["visible"] == null || !!config["visible"]) {
            if (config["mixin"]) {
                const mixinConfig = MIXINS.get(config["mixin"]);
                if (mixinConfig != null) {
                    for (const item of mixinConfig) {
                        this.#generateElement(contentEl, item);
                    }
                }
            } else {
                const listEl = document.createElement("li");
                const btnEl = document.createElement("emc-navbar-button");
                listEl.append(btnEl);
                // content
                if (config["content"] != null) {
                    btnEl.content = config["content"];
                }
                if (config["tooltip"] != null) {
                    btnEl.tooltip = config["tooltip"];
                }
                // action
                if (isFunction(config.handler)) {
                    btnEl.addEventListener("click", (event) => {
                        this.#hamburgerEl.open = false;
                        this.#containerEl.classList.remove("cover");
                        this.#containerEl.classList.remove("open");
                        closeAll(contentEl);
                        config.handler();
                        event.stopPropagation();
                        return false;
                    });
                }
                // href
                if (isHttpUrl(config.href)) {
                    btnEl.addEventListener("click", (event) => {
                        this.#hamburgerEl.open = false;
                        this.#containerEl.classList.remove("cover");
                        this.#containerEl.classList.remove("open");
                        closeAll(contentEl);
                        const target = event.ctrlKey ? "_blank" : config.target;
                        if (target) {
                            const windowFeatures = encodeWindowFeatures(config.windowFeatures);
                            window.open(config.href, target, windowFeatures);
                        } else if (this.#navigationHandler != null) {
                            this.#navigationHandler(config.href);
                        } else {
                            window.location.href = config.href;
                        }
                        event.stopPropagation();
                        return false;
                    });
                }
                // submenu events
                if (!IS_MAIN_NAV) {
                    btnEl.addEventListener("blur", (event) => {
                        if (event.relatedTarget == null || !contentEl.contains(event.relatedTarget)) {
                            const pListEl = contentEl.parentElement;
                            const pBtnEl = pListEl.children[0];
                            pBtnEl.expand = "closed";
                            pListEl.classList.remove("open");
                            this.#containerEl.classList.remove("cover");
                            event.preventDefault();
                        }
                    });
                    btnEl.addEventListener("focus", (event) => {
                        if (event.relatedTarget != null && !contentEl.contains(event.relatedTarget)) {
                            const pListEl = contentEl.parentElement;
                            const pBtnEl = pListEl.children[0];
                            pBtnEl.expand = "open";
                            pListEl.classList.add("open");
                            this.#containerEl.classList.add("cover");
                            event.preventDefault();
                        }
                    });
                }
                // submenu
                if (config["submenu"] != null) {
                    const subcontent = document.createElement("ul");
                    for (const item of config["submenu"]) {
                        this.#generateElement(subcontent, item);
                    }
                    listEl.append(subcontent);
                    // submenu button events
                    btnEl.expand = "closed";
                    btnEl.addEventListener("click", (event) => {
                        if (btnEl.expand == "open") {
                            btnEl.expand = "closed";
                            if (IS_MAIN_NAV) {
                                listEl.classList.remove("open");
                                this.#containerEl.classList.remove("cover");
                            }
                        } else {
                            if (IS_MAIN_NAV) {
                                closeAll(contentEl);
                                listEl.classList.add("open");
                                this.#containerEl.classList.add("cover");
                            }
                            btnEl.expand = "open";
                        }
                        event.stopPropagation();
                        return false;
                    });
                }
                // add element
                contentEl.append(listEl);
            }
        }
    }

    static addMixin(name, config) {
        MIXINS.set(name, config);
    }

}

customElements.define("emc-navbar", NavBar);
