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

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

const TPL = new Template(`
    <div id="container"></div>
`);

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

const STYLE = new GlobalStyle(`
    :host {
        position: relative;
        display: flex;
        min-height: 100%;
        min-width: 100%;
        overflow-wrap: break-word;
        resize: none;
    }
    
    #container {
        position: relative;
        flex: 1;
        line-height: normal;
    }
    
    .settings-option {
        display: flex;
        align-items: stretch;
        justify-content: flex-start;
        flex-direction: column;
        color: var(--form-text-color, #000000);
        background-color: var(--form-back-color, #ffffff);
    }
    
    .settings-option:hover {
        color: var(--form-hover-text-color, #ffffff);
        background-color: var(--form-hover-back-color, #696969);
    }
    
    .settings-option .option-container {
        display: flex;
        align-items: center;
        justify-content: flex-start;
        min-height: 40px;
    }
    
    .settings-option .option-container .option-text,
    .option-caption {
        display: flex;
        align-items: center;
        justify-content: flex-start;
        flex-basis: 500px;
        padding: 10px;
        user-select: none;
    }
    
    .settings-option .option-container .option-text {
        flex-shrink: 1;
        cursor: pointer;
    }
    
    .option-caption {
        flex-grow: 1;
        font-size: 1.5em;
        pointer-events: none;
    }
    
    .settings-option .option-container .option-input {
        display: flex;
        align-items: flex-start;
        justify-content: flex-start;
        flex: 1;
    }
    
    .settings-option .option-container .option-input .settings-input:focus {
        box-shadow: 0 0 2px 2px var(--input-focus-color, #06b5ff);
        outline: none;
    }
    
    .settings-option .option-container .option-input .settings-input:focus:not(:focus-visible) {
        box-shadow: none;
        outline: none;
    }
    
    .settings-option .option-container .option-input .settings-input[type="checkbox"] {
        margin-right: 10px;
    }
    
    .settings-option .option-container .option-input .settings-input:not([type="checkbox"]) {
        flex: 1;
    }
    
    .settings-option .option-container .option-input emc-listselect.settings-input {
        max-height: 300px;
    }
    
    .settings-option .option-container .option-input .option-reset button {
        position: sticky;
        top: 0px;
        bottom: 0px;
        margin-left: auto;
    }
    
    .settings-option .option-desc {
        display: block;
        flex-shrink: 0;
        padding: 0 10px 10px;
        font-size: 0.9em;
        font-style: italic;
        opacity: 0.6;
    }
    
`);

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

import CustomElement from "../../../element/CustomElement.js";
import LogicHandler from "../../../../util/logic/processor/LogicHandler.js";
import I18nLabel from "../../../i18n/I18nLabel.js";
import "../../../i18n/I18nTextbox.js";
import "../../../input/InputWrapper.js";
import "../../../input/KeyInput.js";
import "../../../input/ListSelect.js";
import "../../../input/SearchSelect.js";
import "../../../input/Option.js";

function generateField(inputId, label, desc, inputEl, storage, visible, resetEl) {
    const optionEl = document.createElement("div");
    optionEl.className = "settings-option";
    optionEl.id = `${inputId}_wrapper`;

    { // container
        const containerEl = document.createElement("div");
        containerEl.className = "option-container";

        { // label
            const labelEl = document.createElement("label");
            labelEl.className = "option-text";
            labelEl.setAttribute("for", inputEl.id);
            labelEl.append(I18nLabel.getLabel(label));
            containerEl.append(labelEl);
        }

        { // input
            const fieldEl = document.createElement("div");
            fieldEl.className = "option-input";

            { // input wrapper
                const wrapperEl = document.createElement("emc-input-wrapper");
                wrapperEl.append(inputEl);
                fieldEl.append(wrapperEl);
            }

            if (resetEl) {
                fieldEl.append(resetEl);
            }

            containerEl.append(fieldEl);
        }

        optionEl.append(containerEl);
    }

    if (desc) { // description
        const descEl = document.createElement("emc-i18n-textbox");
        descEl.className = "option-desc";
        descEl.i18nContent = desc;
        optionEl.append(descEl);
    }

    // visibility
    if (visible != null) {
        const logicHandler = new LogicHandler(storage, visible);
        logicHandler.addEventListener("change", (event) => {
            optionEl.style.display = event.value ? "" : "none";
        });
        if (!logicHandler.value) {
            optionEl.style.display = "none";
        }
    }
    // ---
    return optionEl;
}

function createResetButton(storage, ref) {
    const resetEl = document.createElement("button");
    resetEl.innerHTML = "↺";
    resetEl.setAttribute("title", "reset");
    if (typeof storage == "function") {
        resetEl.addEventListener("click", storage);
    } else {
        resetEl.addEventListener("click", () => {
            storage.resetValue(ref);
        });
    }
    const wrapperEl = document.createElement("emc-input-wrapper");
    wrapperEl.className = "option-reset";
    wrapperEl.append(resetEl);
    return wrapperEl;
}

function generateEmcOption(value, label) {
    const optionEl = document.createElement("emc-option");
    optionEl.value = value;
    if (label instanceof HTMLElement) {
        optionEl.append(label);
    } else {
        const el = document.createElement("emc-i18n-label");
        el.i18nValue = label;
        optionEl.append(el);
    }
    return optionEl;
}

function convertValueList(values = {}) {
    const opt = {};
    if (typeof values == "object") {
        if (Array.isArray(values)) {
            for (const key of values) {
                opt[key] = key;
            }
        } else {
            for (const key in values) {
                if (values[key] != null) {
                    opt[key] = values[key];
                } else {
                    opt[key] = key;
                }
            }
        }
    }
    return opt;
}

export default class SettingsTabContent extends CustomElement {

    #containerEl;

    constructor() {
        super();
        this.shadowRoot.append(TPL.generate());
        STYLE.apply(this.shadowRoot);
        /* --- */
        this.#containerEl = this.shadowRoot.getElementById("container");
    }

    #insertField(inputId, label, desc, inputEl, storage, visible, resetEl) {
        const newFieldEl = generateField(inputId, label, desc, inputEl, storage, visible, resetEl);
        const oldFieldEl = this.shadowRoot.getElementById(`${inputId}_wrapper`);
        if (oldFieldEl) {
            oldFieldEl.replaceWith(newFieldEl);
        } else {
            this.#containerEl.append(newFieldEl);
        }
    }

    addStringInput(storage, ref, label, desc, visible, resettable) {
        const inputEl = document.createElement("input");
        const inputId = `${this.id}_${ref}`;
        inputEl.id = inputId;
        inputEl.className = "settings-input";
        inputEl.setAttribute("type", "text");
        inputEl.value = storage.get(ref);
        inputEl.dataset.ref = ref;
        // events
        storage.addEventListener("clear", (event) => {
            inputEl.value = event.data[ref];
        });
        storage.addEventListener("load", (event) => {
            inputEl.value = event.data[ref];
        });
        storage.addEventListener("change", (event) => {
            if (event.data[ref] != null) {
                inputEl.value = event.data[ref];
            }
        });
        inputEl.addEventListener("change", () => {
            storage.set(ref, inputEl.value);
        });
        // add element
        const resetEl = resettable && createResetButton(storage, ref);
        this.#insertField(inputId, label, desc, inputEl, storage, visible, resetEl);
    }

    addNumberInput(storage, ref, label, desc, visible, resettable, min, max) {
        const inputEl = document.createElement("input");
        const inputId = `${this.id}_${ref}`;
        inputEl.id = inputId;
        inputEl.className = "settings-input";
        inputEl.setAttribute("type", "number");
        inputEl.value = storage.get(ref);
        if (!isNaN(min)) {
            inputEl.setAttribute("min", min);
        }
        if (!isNaN(max)) {
            inputEl.setAttribute("max", max);
        }
        inputEl.dataset.ref = ref;
        // events
        storage.addEventListener("clear", (event) => {
            inputEl.value = parseFloat(event.data[ref]) || 0;
        });
        storage.addEventListener("load", (event) => {
            inputEl.value = parseFloat(event.data[ref]) || 0;
        });
        storage.addEventListener("change", (event) => {
            if (event.data[ref] != null) {
                inputEl.value = parseFloat(event.data[ref]) || 0;
            }
        });
        inputEl.addEventListener("change", () => {
            storage.set(ref, parseFloat(inputEl.value));
        });
        // add element
        const resetEl = resettable && createResetButton(storage, ref);
        this.#insertField(inputId, label, desc, inputEl, storage, visible, resetEl);
    }

    addRangeInput(storage, ref, label, desc, visible, resettable, min, max) {
        const inputEl = document.createElement("input");
        const inputId = `${this.id}_${ref}`;
        inputEl.id = inputId;
        inputEl.className = "settings-input";
        inputEl.setAttribute("type", "range");
        inputEl.value = storage.get(ref);
        if (!isNaN(min)) {
            inputEl.setAttribute("min", min);
        }
        if (!isNaN(max)) {
            inputEl.setAttribute("max", max);
        }
        inputEl.dataset.ref = ref;
        // events
        storage.addEventListener("clear", (event) => {
            inputEl.value = parseFloat(event.data[ref]) || 0;
        });
        storage.addEventListener("load", (event) => {
            inputEl.value = parseFloat(event.data[ref]) || 0;
        });
        storage.addEventListener("change", (event) => {
            if (event.data[ref] != null) {
                inputEl.value = parseFloat(event.data[ref]) || 0;
            }
        });
        inputEl.addEventListener("change", () => {
            storage.set(ref, parseFloat(inputEl.value));
        });
        // add element
        const resetEl = resettable && createResetButton(storage, ref);
        this.#insertField(inputId, label, desc, inputEl, storage, visible, resetEl);
    }

    addCheckInput(storage, ref, label, desc, visible, resettable) {
        const inputEl = document.createElement("input");
        const inputId = `${this.id}_${ref}`;
        inputEl.id = inputId;
        inputEl.className = "settings-input";
        inputEl.setAttribute("type", "checkbox");
        inputEl.checked = !!storage.get(ref);
        inputEl.dataset.ref = ref;
        // events
        storage.addEventListener("clear", (event) => {
            inputEl.checked = !!event.data[ref];
        });
        storage.addEventListener("load", (event) => {
            inputEl.checked = !!event.data[ref];
        });
        storage.addEventListener("change", (event) => {
            if (event.data[ref] != null) {
                inputEl.checked = !!event.data[ref];
            }
        });
        inputEl.addEventListener("change", () => {
            storage.set(ref, !!inputEl.checked);
        });
        // add element
        const resetEl = resettable && createResetButton(storage, ref);
        this.#insertField(inputId, label, desc, inputEl, storage, visible, resetEl);
    }

    addColorInput(storage, ref, label, desc, visible, resettable) {
        const inputEl = document.createElement("input");
        const inputId = `${this.id}_${ref}`;
        inputEl.id = inputId;
        inputEl.className = "settings-input";
        inputEl.setAttribute("type", "color");
        inputEl.value = storage.get(ref);
        inputEl.dataset.ref = ref;
        // events
        storage.addEventListener("clear", (event) => {
            inputEl.value = event.data[ref];
        });
        storage.addEventListener("load", (event) => {
            inputEl.value = event.data[ref];
        });
        storage.addEventListener("change", (event) => {
            if (event.data[ref] != null) {
                inputEl.value = event.data[ref];
            }
        });
        inputEl.addEventListener("change", () => {
            storage.set(ref, inputEl.value);
        });
        // add element
        const resetEl = resettable && createResetButton(storage, ref);
        this.#insertField(inputId, label, desc, inputEl, storage, visible, resetEl);
    }

    addKeyInput(storage, ref, label, desc, visible, resettable) {
        const inputEl = document.createElement("emc-keyinput");
        const inputId = `${this.id}_${ref}`;
        inputEl.id = inputId;
        inputEl.className = "settings-input";
        inputEl.setAttribute("type", "input");
        inputEl.value = storage.get(ref);
        inputEl.dataset.ref = ref;
        // events
        storage.addEventListener("clear", (event) => {
            inputEl.value = event.data[ref];
        });
        storage.addEventListener("load", (event) => {
            inputEl.value = event.data[ref];
        });
        storage.addEventListener("change", (event) => {
            if (event.data[ref] != null) {
                inputEl.value = event.data[ref];
            }
        });
        inputEl.addEventListener("change", () => {
            storage.set(ref, inputEl.value);
        });
        // add element
        const resetEl = resettable && createResetButton(storage, ref);
        this.#insertField(inputId, label, desc, inputEl, storage, visible, resetEl);
    }

    addChoiceInput(storage, ref, label, desc, visible, resettable, values = {}) {
        const convertedValues = convertValueList(values);
        const inputEl = document.createElement("emc-searchselect");
        const inputId = `${this.id}_${ref}`;
        inputEl.id = inputId;
        inputEl.className = "settings-input";
        inputEl.setAttribute("type", "input");
        for (const value in convertedValues) {
            inputEl.append(generateEmcOption(value, convertedValues[value]));
        }
        inputEl.value = storage.get(ref);
        inputEl.dataset.ref = ref;
        // events
        storage.addEventListener("clear", (event) => {
            inputEl.value = event.data[ref];
        });
        storage.addEventListener("load", (event) => {
            inputEl.value = event.data[ref];
        });
        storage.addEventListener("change", (event) => {
            if (event.data[ref] != null) {
                inputEl.value = event.data[ref];
            }
        });
        inputEl.addEventListener("change", () => {
            storage.set(ref, inputEl.value);
        });
        // add element
        const resetEl = resettable && createResetButton(storage, ref);
        this.#insertField(inputId, label, desc, inputEl, storage, visible, resetEl);
    }

    addListSelectInput(storage, ref, label, desc, visible, resettable, multiple = true, values = {}) {
        const convertedValues = convertValueList(values);
        const inputEl = document.createElement("emc-listselect");
        const inputId = `${this.id}_${ref}`;
        inputEl.id = inputId;
        inputEl.className = "settings-input";
        inputEl.setAttribute("type", "list");
        inputEl.multiple = multiple;
        inputEl.dataset.ref = ref;
        const valueCache = new Set();
        for (const value in convertedValues) {
            inputEl.append(generateEmcOption(value, convertedValues[value]));
            if (storage.get(value)) {
                valueCache.add(value);
            }
        }
        inputEl.value = Array.from(valueCache);
        // events
        storage.addEventListener("change", (event) => {
            for (const value in convertedValues) {
                const evValue = event.data[value];
                if (evValue != null) {
                    if (evValue) {
                        valueCache.add(value);
                    } else {
                        valueCache.delete(value);
                    }
                }
            }
            inputEl.value = Array.from(valueCache);
        });
        storage.addEventListener("clear", (event) => {
            valueCache.clear();
            for (const value in convertedValues) {
                const evValue = event.data[value];
                if (evValue) {
                    valueCache.add(value);
                }
            }
            inputEl.value = Array.from(valueCache);
        });
        storage.addEventListener("load", (event) => {
            valueCache.clear();
            for (const value in convertedValues) {
                const evValue = event.data[value];
                if (evValue) {
                    valueCache.add(value);
                }
            }
            inputEl.value = Array.from(valueCache);
        });
        inputEl.addEventListener("change", () => {
            const data = new Set(inputEl.value);
            const res = {};
            for (const value in convertedValues) {
                res[value] = data.has(value);
            }
            storage.setAll(res);
        });
        // add element
        const resetEl = resettable && createResetButton(() => {
            storage.resetAll(Object.keys(convertedValues));
        });
        this.#insertField(inputId, label, desc, inputEl, storage, visible, resetEl);
    }

    addButton(storage, ref, label, desc, visible, text = "", callback = null) {
        const inputEl = document.createElement("button");
        const inputId = `${this.id}_${ref}`;
        inputEl.id = inputId;
        inputEl.className = "settings-button";
        inputEl.setAttribute("type", "button");
        inputEl.dataset.ref = ref;
        if (text instanceof HTMLElement) {
            inputEl.append(text);
        } else {
            inputEl.innerHTML = text;
        }
        if (typeof callback == "function") {
            inputEl.addEventListener("click", callback);
        }
        // add element
        this.#insertField(inputId, label, desc, inputEl, storage, visible);
    }

    addCustomInput(inputEl, storage, ref, label, desc, visible, resettable) {
        const inputId = `${this.id}_${ref}`;
        inputEl.id = inputId;
        inputEl.className = "settings-input";
        inputEl.setAttribute("type", "custom");
        inputEl.value = storage.get(ref);
        inputEl.dataset.ref = ref;
        // events
        storage.addEventListener("clear", (event) => {
            inputEl.value = event.data[ref];
        });
        storage.addEventListener("load", (event) => {
            inputEl.value = event.data[ref];
        });
        storage.addEventListener("change", (event) => {
            if (event.data[ref] != null) {
                inputEl.value = event.data[ref];
            }
        });
        inputEl.addEventListener("change", () => {
            storage.set(ref, inputEl.value);
        });
        // add element
        const resetEl = resettable && createResetButton(storage, ref);
        this.#insertField(inputId, label, desc, inputEl, storage, visible, resetEl);
    }

    addElements(content) {
        // add element
        this.#containerEl.append(content);
    }

}

customElements.define("emc-window-settings-tab", SettingsTabContent);
