/**
 * Copyright 2023 schukai GmbH
 * SPDX-License-Identifier: AGPL-3.0
 */

import {Datasource} from "./datasource.mjs";
import {
    assembleMethodSymbol,
    CustomElement,
    registerCustomElement,
    getSlottedElements,
} from "../../dom/customelement.mjs";
import {findTargetElementFromEvent, fireCustomEvent} from "../../dom/events.mjs";
import {clone} from "../../util/clone.mjs";
import {
    isString,
    isFunction,
    isInstance,
    isObject,
    isArray,
} from "../../types/is.mjs";
import {validateArray, validateInteger, validateObject} from "../../types/validate.mjs";
import {Observer} from "../../types/observer.mjs";
import {
    ATTRIBUTE_DATATABLE_HEAD,
    ATTRIBUTE_DATATABLE_GRID_TEMPLATE,
    ATTRIBUTE_DATASOURCE_SELECTOR,
    ATTRIBUTE_DATATABLE_ALIGN,
    ATTRIBUTE_DATATABLE_SORTABLE,
    ATTRIBUTE_DATATABLE_MODE,
    ATTRIBUTE_DATATABLE_INDEX,
    ATTRIBUTE_DATATABLE_MODE_HIDDEN,
    ATTRIBUTE_DATATABLE_MODE_VISIBLE,
    ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
    ATTRIBUTE_DATATABLE_MODE_FIXED,
} from "./constants.mjs";
import {instanceSymbol} from "../../constants.mjs";
import {
    Header,
    createOrderStatement,
    DIRECTION_ASC,
    DIRECTION_DESC,
    DIRECTION_NONE,
} from "./datatable/header.mjs";
import {DatatableStyleSheet} from "./stylesheet/datatable.mjs";
import {
    handleDataSourceChanges,
    datasourceLinkedElementSymbol,
} from "./util.mjs";
import "./columnbar.mjs";
import "./filter-button.mjs";
import {getDocument, getWindow} from "../../dom/util.mjs";
import {addAttributeToken} from "../../dom/attributes.mjs";
import {ATTRIBUTE_ERRORMESSAGE} from "../../dom/constants.mjs";
import {getDocumentTranslations} from "../../i18n/translations.mjs";
import "../state/state.mjs";
import "../host/collapse.mjs";
import {generateUniqueConfigKey} from "../host/util.mjs";

import "./datasource/dom.mjs";
import "./datasource/rest.mjs";

export {DataTable};

/**
 * @private
 * @type {symbol}
 */
const gridElementSymbol = Symbol("gridElement");

/**
 * @private
 * @type {symbol}
 */
const gridHeadersElementSymbol = Symbol("gridHeadersElement");

/**
 * @private
 * @type {symbol}
 */
const columnBarElementSymbol = Symbol("columnBarElement");

/**
 * The DataTable component is used to show the data from a data source.
 *
 * <img src="./images/datatable.png">
 *
 * Dependencies: the system uses functions of the [monsterjs](https://monsterjs.org/) library
 *
 * You can create this control either by specifying the HTML tag <monster-datatable />` directly in the HTML or using
 * Javascript via the `document.createElement('monster-datatable');` method.
 *
 * ```html
 * <monster-datatable></monster-datatable>
 * ```
 *
 * Or you can create this CustomControl directly in Javascript:
 *
 * ```js
 * import '@schukai/component-datatable/source/datatable.mjs';
 * document.createElement('monster-datatable');
 * ```
 *
 * The Body should have a class "hidden" to ensure that the styles are applied correctly.
 *
 * ```css
 * body.hidden {
 *    visibility: hidden;
 * }
 * ```
 *
 * @startuml datatable.png
 * skinparam monochrome true
 * skinparam shadowing false
 * HTMLElement <|-- CustomElement
 * CustomElement <|-- DataTable
 * @enduml
 *
 * @copyright schukai GmbH
 * @memberOf Monster.Components.Datatable
 * @summary A data table
 * @fire Monster.Components.Datatable.event:monster-datatable-row-copied
 * @fire Monster.Components.Datatable.event:monster-datatable-row-removed
 * @fire Monster.Components.Datatable.event:monster-datatable-row-added
 */
class DataTable extends CustomElement {
    /**
     * This method is called by the `instanceof` operator.
     * @returns {symbol}
     */
    static get [instanceSymbol]() {
        return Symbol.for("@schukai/monster/components/datatable@@instance");
    }

    /**
     * To set the options via the html tag the attribute `data-monster-options` must be used.
     * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
     *
     * The individual configuration values can be found in the table.
     *
     * @property {Object} templates Template definitions
     * @property {string} templates.main Main template
     * @property {Object} datasource Datasource configuration
     * @property {string} datasource.selector Selector for the datasource
     * @property {Object} mapping Mapping configuration
     * @property {string} mapping.data Data mapping
     * @property {Array} data Data
     * @property {Array} headers Headers
     * @property {Object} responsive Responsive configuration
     * @property {number} responsive.breakpoint Breakpoint for responsive mode
     * @property {Object} labels Labels
     * @property {string} labels.theListContainsNoEntries Label for empty state
     * @property {Object} classes Classes
     * @property {string} classes.container Container class
     * @property {Object} features Features
     * @property {boolean} features.settings Settings feature
     * @property {boolean} features.footer Footer feature
     * @property {boolean} features.autoInit Auto init feature (init datasource automatically)
     * @property {Object} templateMapping Template mapping
     * @property {string} templateMapping.row-key Row key
     * @property {string} templateMapping.filter-id Filter id
     **/
    get defaults() {
        return Object.assign(
            {},
            super.defaults,
            {
                templates: {
                    main: getTemplate(),
                    emptyState: getEmptyTemplate(),
                },

                datasource: {
                    selector: null,
                },

                mapping: {
                    data: "dataset",
                },

                data: [],
                headers: [],

                responsive: {
                    breakpoint: 800,
                },

                labels: {
                    theListContainsNoEntries: "The list contains no entries",
                },

                classes : {
                    control: "monster-theme-table-container-1",
                    container: "monster-theme-table-container-1",
                    row: "monster-theme-table-row-1",
                },

                features: {
                    settings: true,
                    footer: true,
                    autoInit: true,
                },

                templateMapping: {
                    "row-key": null,
                    "filter-id": null,
                },
            },
            initOptionsFromArguments.call(this),
        );
    }

    /**
     *
     * @param {string} selector
     * @returns {NodeListOf<*>}
     */
    getGridElements(selector) {
        return this[gridElementSymbol].querySelectorAll(selector);
    }

    /**
     *
     * @return {string}
     */
    static getTag() {
        return "monster-datatable";
    }

    /**
     *
     * @return {Monster.Components.Form.Form}
     */
    [assembleMethodSymbol]() {
        const rawKey = this.getOption("templateMapping.row-key");

        if (rawKey === null) {
            if (this.id !== null && this.id !== "") {
                const rawKey = this.getOption("templateMapping.row-key");
                if (rawKey === null) {
                    this.setOption("templateMapping.row-key", this.id + "-row");
                }
            } else {
                this.setOption("templateMapping.row-key", "row");
            }
        }

        if (this.id !== null && this.id !== "") {
            this.setOption("templateMapping.filter-id", "" + this.id + "-filter");
        } else {
            this.setOption("templateMapping.filter-id", "filter");
        }

        super[assembleMethodSymbol]();

        initControlReferences.call(this);
        initEventHandler.call(this);

        const selector = this.getOption("datasource.selector");

        if (isString(selector)) {
            const elements = document.querySelectorAll(selector);
            if (elements.length !== 1) {
                throw new Error("the selector must match exactly one element");
            }

            const element = elements[0];

            if (!isInstance(element, Datasource)) {
                throw new TypeError("the element must be a datasource");
            }

            this[datasourceLinkedElementSymbol] = element;

            setTimeout(() => {
                handleDataSourceChanges.call(this);
                element.datasource.attachObserver(
                    new Observer(handleDataSourceChanges.bind(this)),
                );
            }, 0);
        }

        getHostConfig
            .call(this, getColumnVisibilityConfigKey)
            .then((config) => {
                const headerOrderMap = new Map();

                getHostConfig
                    .call(this, getStoredOrderConfigKey)
                    .then((orderConfig) => {
                        if (isArray(orderConfig) || orderConfig.length > 0) {
                            for (let i = 0; i < orderConfig.length; i++) {
                                const item = orderConfig[i];
                                const parts = item.split(" ");
                                const field = parts[0];
                                const direction = parts[1] || DIRECTION_ASC;
                                headerOrderMap.set(field, direction);
                            }
                        }
                    })
                    .then(() => {
                        try {
                            initGridAndStructs.call(this, config, headerOrderMap);
                        } catch (error) {
                            addAttributeToken(
                                this,
                                ATTRIBUTE_ERRORMESSAGE,
                                error?.message || error.toString(),
                            );
                        }

                        updateColumnBar.call(this);
                    })
                    .catch((error) => {
                        addAttributeToken(
                            this,
                            ATTRIBUTE_ERRORMESSAGE,
                            error?.message || error.toString(),
                        );
                    });
            })
            .catch((error) => {
                addAttributeToken(
                    this,
                    ATTRIBUTE_ERRORMESSAGE,
                    error?.message || error.toString(),
                );
            });
    }

    /**
     *
     * @return {CSSStyleSheet[]}
     */
    static getCSSStyleSheet() {
        return [DatatableStyleSheet];
    }

    /**
     * Copy a row from the datatable
     * @param {number} fromIndex
     * @param {number} toIndex
     * @returns {Monster.Components.Datatable.DataTable}
     * @fire Monster.Components.Datatable.event:monster-datatable-row-copied
     */
    copyRow(fromIndex, toIndex) {

        const datasource = this[datasourceLinkedElementSymbol];
        if (!datasource) {
            return this;
        }
        let d = datasource.data;
        let c = clone(d);

        let rows = c
        const mapping = this.getOption("mapping.data");

        if (mapping) {
            rows=c?.[mapping];
        }

        if (rows === undefined || rows === null) {
            rows = [];
        }

        if (toIndex===undefined) {
            toIndex = rows.length;
        }

        fromIndex = parseInt(fromIndex);
        toIndex = parseInt(toIndex);
        
        if (toIndex < 0 || toIndex > rows.length) {
            throw new RangeError("index out of bounds");
        }

        validateArray(rows);
        validateInteger(fromIndex);
        validateInteger(toIndex);

        if (fromIndex < 0 || fromIndex >= rows.length) {
            throw new RangeError("index out of bounds");
        }
        
        rows.splice(toIndex, 0, clone(rows[fromIndex]));
        datasource.data=c;

        fireCustomEvent(this, "monster-datatable-row-copied", {
            index: toIndex,
        });        
        
        return this;
    }

    /**
     * Remove a row from the datatable
     * @param index
     * @returns {Monster.Components.Datatable.DataTable}
     * @fire Monster.Components.Datatable.event:monster-datatable-row-removed
     */
    removeRow(index) {
        const datasource = this[datasourceLinkedElementSymbol];
        if (!datasource) {
            return this;
        }
        let d = datasource.data;
        let c = clone(d);

        let rows = c
        const mapping = this.getOption("mapping.data");

        if (mapping) {
            rows=c?.[mapping];
        }

        if (rows === undefined || rows === null) {
            rows = [];
        }

        index = parseInt(index);
        
        validateArray(rows);
        validateInteger(index);
        if (index < 0 || index >= rows.length) {
            throw new RangeError("index out of bounds");
        }
        if (mapping) {
            rows=c?.[mapping];
        }

        rows.splice(index, 1)
        datasource.data=c;

        fireCustomEvent(this, "monster-datatable-row-removed", {
            index: index,
        });        
        
        return this;
    }

    /**
     * Add a row to the datatable 
     * @param {Object} data
     * @returns {Monster.Components.Datatable.DataTable}
     * @fire Monster.Components.Datatable.event:monster-datatable-row-added
     **/
    addRow(data) {
        const datasource = this[datasourceLinkedElementSymbol];
        if (!datasource) {
            return this;
        }
        let d = datasource.data;
        let c = clone(d);
        
        let rows = c
        
        const mapping = this.getOption("mapping.data");
        if (mapping) {
            rows=c?.[mapping];
        }
        
        if (rows === undefined || rows === null) {
            rows = [];
        }

        validateArray(rows);
        validateObject(data);
        
        rows.push(data)
        datasource.data=c;

        fireCustomEvent(this, "monster-datatable-row-added", {
            index: rows.length - 1,
        });
        
        return this;
    }

}

/**
 * @private
 * @returns {string}
 */
function getColumnVisibilityConfigKey() {
    return generateUniqueConfigKey("datatable", this?.id, "columns-visibility");
}

/**
 * @private
 * @returns {string}
 */
function getFilterConfigKey() {
    return generateUniqueConfigKey("datatable", this?.id, "filter");
}

/**
 * @private
 * @returns {Promise}
 */
function getHostConfig(callback) {
    const document = getDocument();
    const host = document.querySelector("monster-host");

    if (!(host && this.id)) {
        return Promise.resolve({});
    }

    if (!host || !isFunction(host?.getConfig)) {
        throw new TypeError("the host must be a monster-host");
    }

    const configKey = callback.call(this);
    return host.hasConfig(configKey).then((hasConfig) => {
        if (hasConfig) {
            return host.getConfig(configKey);
        } else {
            return {};
        }
    });
}

/**
 * @private
 */
function updateColumnBar() {
    if (!this[columnBarElementSymbol]) {
        return;
    }

    const columns = [];
    for (const header of this.getOption("headers")) {
        const mode = header.getInternal("mode");

        if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
            continue;
        }

        columns.push({
            visible: mode !== ATTRIBUTE_DATATABLE_MODE_HIDDEN,
            name: header.label,
            index: header.index,
        });
    }

    this[columnBarElementSymbol].setOption("columns", columns);
}

/**
 * @private
 */
function updateHeaderFromColumnBar() {
    if (!this[columnBarElementSymbol]) {
        return;
    }

    const options = this[columnBarElementSymbol].getOption("columns");
    if (!isArray(options)) return;

    const invisibleMap = {};

    for (let i = 0; i < options.length; i++) {
        const option = options[i];
        invisibleMap[option.index] = option.visible;
    }

    for (const header of this.getOption("headers")) {
        const mode = header.getInternal("mode");

        if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
            continue;
        }

        if (invisibleMap[header.index] === false) {
            header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_HIDDEN);
        } else {
            header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_VISIBLE);
        }
    }
}

/**
 * @private
 */
function updateConfigColumnBar() {
    if (!this[columnBarElementSymbol]) {
        return;
    }

    const options = this[columnBarElementSymbol].getOption("columns");
    if (!isArray(options)) return;

    const map = {};
    for (let i = 0; i < options.length; i++) {
        const option = options[i];
        map[option.name] = option.visible;
    }

    const document = getDocument();
    const host = document.querySelector("monster-host");
    if (!(host && this.id)) {
        return;
    }
    const configKey = getColumnVisibilityConfigKey.call(this);

    try {
        host.setConfig(configKey, map);
    } catch (error) {
        addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
    }
}

/**
 * @private
 */
function initEventHandler() {
    const self = this;

    getWindow().addEventListener("resize", (event) => {
        updateGrid.call(self);
    });

    self[columnBarElementSymbol].attachObserver(
        new Observer((e) => {
            updateHeaderFromColumnBar.call(self);
            updateGrid.call(self);
            updateConfigColumnBar.call(self);
        }),
    );

    self[gridHeadersElementSymbol].addEventListener("click", function (event) {
        let element = null;
        const datasource = self[datasourceLinkedElementSymbol];
        if (!datasource) {
            return;
        }

        element = findTargetElementFromEvent(event, ATTRIBUTE_DATATABLE_SORTABLE);
        if (element) {
            const index = element.parentNode.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
            const headers = self.getOption("headers");

            event.preventDefault();

            headers[index].changeDirection();

            setTimeout(function () {
                /** hotfix, normally this should be done via the updater, no idea why this is not possible. */
                element.setAttribute(
                    ATTRIBUTE_DATATABLE_SORTABLE,
                    `${headers[index].field} ${headers[index].direction}`,
                );

                storeOrderStatement.call(self, true);
            }, 0);
        }
    });
}

/**
 * @private
 */
function initGridAndStructs(hostConfig, headerOrderMap) {
    const rowID = this.getOption("templateMapping.row-key");

    if (!this[gridElementSymbol]) {
        throw new Error("no grid element is defined");
    }

    let template;
    getSlottedElements.call(this).forEach((e) => {
        if (e instanceof HTMLTemplateElement && e.id === rowID) {
            template = e;
        }
    });

    if (!template) {
        throw new Error("no template is defined");
    }

    const rowCount = template.content.children.length;

    const headers = [];

    for (let i = 0; i < rowCount; i++) {
        let hClass = "";
        const row = template.content.children[i];

        let mode = "";
        if (row.hasAttribute(ATTRIBUTE_DATATABLE_MODE)) {
            mode = row.getAttribute(ATTRIBUTE_DATATABLE_MODE);
        }

        let grid = row.getAttribute(ATTRIBUTE_DATATABLE_GRID_TEMPLATE);
        if (!grid || grid === "" || grid === "auto") {
            grid = "minmax(0, 1fr)";
        }

        let label = "";
        let labelKey = "";

        if (row.hasAttribute(ATTRIBUTE_DATATABLE_HEAD)) {
            label = row.getAttribute(ATTRIBUTE_DATATABLE_HEAD);
            labelKey = label;

            try {
                if (label.startsWith("i18n:")) {
                    label = label.substring(5, label.length);
                    label = getDocumentTranslations().getText(label, label);
                }
            } catch (e) {
                label = "i18n error " + label;
            }
        }

        if (!label) {
            label = i + 1 + "";
            mode = ATTRIBUTE_DATATABLE_MODE_FIXED;
            labelKey = label;
        }

        if (isObject(hostConfig) && hostConfig.hasOwnProperty(label)) {
            if (hostConfig[label] === false) {
                mode = ATTRIBUTE_DATATABLE_MODE_HIDDEN;
            } else {
                mode = ATTRIBUTE_DATATABLE_MODE_VISIBLE;
            }
        }

        let align = "";
        if (row.hasAttribute(ATTRIBUTE_DATATABLE_ALIGN)) {
            align = row.getAttribute(ATTRIBUTE_DATATABLE_ALIGN);
        }

        switch (align) {
            case "center":
                hClass = "flex-center";
                break;
            case "end":
                hClass = "flex-end";
                break;
            case "start":
                hClass = "flex-start";
                break;
            default:
                hClass = "flex-start";
        }

        let field = "";
        let direction = DIRECTION_NONE;
        if (row.hasAttribute(ATTRIBUTE_DATATABLE_SORTABLE)) {
            field = row.getAttribute(ATTRIBUTE_DATATABLE_SORTABLE).trim();
            const parts = field.split(" ").map((item) => item.trim());
            field = parts[0];

            if (headerOrderMap.has(field)) {
                direction = headerOrderMap.get(field);
            } else if (
                parts.length === 2 &&
                [DIRECTION_ASC, DIRECTION_DESC].indexOf(parts[1]) !== -1
            ) {
                direction = parts[1];
            }
        }

        if (mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
            hClass += " hidden";
        }

        const header = new Header();
        header.setInternals({
            field: field,
            label: label,
            classes: hClass,
            index: i,
            mode: mode,
            grid: grid,
            labelKey: labelKey,
            direction: direction,
        });

        headers.push(header);
    }

    this.setOption("headers", headers);
    setTimeout(() => {
        storeOrderStatement.call(this, this.getOption("features.autoInit"));
    }, 0);
}

/**
 * @private
 * @returns {string}
 */
export function getStoredOrderConfigKey() {
    return generateUniqueConfigKey("datatable", this?.id, "stored-order");
}

/**
 * @private
 */
function storeOrderStatement(doFetch) {
    const headers = this.getOption("headers");
    const statement = createOrderStatement(headers);
    setDataSource.call(this, {orderBy: statement}, doFetch);

    const document = getDocument();
    const host = document.querySelector("monster-host");
    if (!(host && this.id)) {
        return;
    }

    const configKey = getStoredOrderConfigKey.call(this);

    // statement explode with , and remove all empty
    const list = statement.split(",").filter((item) => item.trim() !== "");
    if (list.length === 0) {
        return;
    }

    host.setConfig(configKey, list);
}

/**
 * @private
 */
function updateGrid() {
    if (!this[gridElementSymbol]) {
        throw new Error("no grid element is defined");
    }

    let gridTemplateColumns = "";

    const headers = this.getOption("headers");

    let styles = "";

    for (let i = 0; i < headers.length; i++) {
        const header = headers[i];

        if (header.mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
            styles += `[data-monster-role=datatable]>[data-monster-head="${header.labelKey}"] { display: none; }\n`;
            styles += `[data-monster-role=datatable-headers]>[data-monster-index="${header.index}"] { display: none; }\n`;
        } else {
            gridTemplateColumns += `${header.grid} `;
        }
    }

    const sheet = new CSSStyleSheet();
    if (styles !== "") sheet.replaceSync(styles);
    this.shadowRoot.adoptedStyleSheets = [...DataTable.getCSSStyleSheet(), sheet];

    const bodyWidth = getDocument().body.getBoundingClientRect().width;

    const breakpoint = this.getOption("responsive.breakpoint");

    if (bodyWidth > breakpoint) {
        this[
            gridElementSymbol
            ].style.gridTemplateColumns = `${gridTemplateColumns}`;
        this[
            gridHeadersElementSymbol
            ].style.gridTemplateColumns = `${gridTemplateColumns}`;
    } else {
        this[gridElementSymbol].style.gridTemplateColumns = "auto";
        this[gridHeadersElementSymbol].style.gridTemplateColumns = "auto";
    }
}

/**
 * @private
 * @param {Monster.Components.Datatable.Header[]} headers
 * @param {bool} doFetch
 */
function setDataSource({orderBy}, doFetch) {
    const datasource = this[datasourceLinkedElementSymbol];

    if (!datasource) {
        return;
    }

    if (isFunction(datasource?.setParameters)) {
        datasource.setParameters({orderBy});
    }

    if (doFetch !== false && isFunction(datasource?.fetch)) {
        datasource.fetch();
    }
}

/**
 * @private
 * @return {Monster.Components.Datatable.Form}
 */
function initControlReferences() {
    if (!this.shadowRoot) {
        throw new Error("no shadow-root is defined");
    }

    this[gridElementSymbol] = this.shadowRoot.querySelector(
        "[data-monster-role=datatable]",
    );
    this[gridHeadersElementSymbol] = this.shadowRoot.querySelector(
        "[data-monster-role=datatable-headers]",
    );
    this[columnBarElementSymbol] =
        this.shadowRoot.querySelector("monster-column-bar");

    return this;
}

/**
 * @private
 * @return {object}
 * @throws {TypeError} incorrect arguments passed for the datasource
 * @throws {Error} the datasource could not be initialized
 */
function initOptionsFromArguments() {
    const options = {};
    const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);

    if (selector) {
        options.datasource = {selector: selector};
    }

    const breakpoint = this.getAttribute(
        ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
    );
    if (breakpoint) {
        options.responsive = {};
        options.responsive.breakpoint = parseInt(breakpoint);
    }

    return options;
}

/**
 * @private
 * @return {string}
 */
function getEmptyTemplate() {
    return `<monster-state data-monster-role="empty-without-action">
    <div part="visual">
    <style>
      path {
        fill: var(--monster-bg-color-primary-4);
        }
    </style>
        <svg width="4rem" height="4rem" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
            <path d="m21.5 22h-19c-1.378 0-2.5-1.121-2.5-2.5v-7c0-.07.015-.141.044-.205l3.969-8.82c.404-.896 1.299-1.475 2.28-1.475h11.414c.981 0 1.876.579 2.28 1.475l3.969 8.82c.029.064.044.135.044.205v7c0 1.379-1.122 2.5-2.5 2.5zm-20.5-9.393v6.893c0 .827.673 1.5 1.5 1.5h19c.827 0 1.5-.673 1.5-1.5v-6.893l-3.925-8.723c-.242-.536-.779-.884-1.368-.884h-11.414c-.589 0-1.126.348-1.368.885z"/>
            <path d="m16.807 17h-9.614c-.622 0-1.186-.391-1.404-.973l-1.014-2.703c-.072-.194-.26-.324-.468-.324h-3.557c-.276 0-.5-.224-.5-.5s.224-.5.5-.5h3.557c.622 0 1.186.391 1.405.973l1.013 2.703c.073.194.261.324.468.324h9.613c.208 0 .396-.13.468-.324l1.013-2.703c.22-.582.784-.973 1.406-.973h3.807c.276 0 .5.224.5.5s-.224.5-.5.5h-3.807c-.208 0-.396.13-.468.324l-1.013 2.703c-.219.582-.784.973-1.405.973z"/>
        </svg>
    </div>
    <div part="content" data-monster-replace="path:labels.theListContainsNoEntries">
        The list contains no entries.
    </div>
</monster-state>`;
}

/**
 * @private
 * @return {string}
 */
function getTemplate() {
    // language=HTML
    return `
        <div data-monster-role="control" part="control" data-monster-attributes="class path:classes.control">
            <template id="headers-row">
                <div data-monster-attributes="class path:headers-row.classes,
                                              data-monster-index path:headers-row.index"
                     data-monster-replace="path:headers-row.html"></div>
            </template>
            <slot></slot>
            <div data-monster-attributes="class path:classes.container"
                    data-monster-role="table-container" part="table-container">
                <div class="filter">
                    <slot name="filter"></slot>
                </div>
                <div class="bar">
                    <monster-column-bar
                            data-monster-attributes="class path:features.settings | ?::hidden"></monster-column-bar>
                    <slot name="bar"></slot>

                </div>
                <div data-monster-role="datatable-headers" data-monster-insert="headers-row path:headers"></div>
                <div data-monster-replace="path:templates.emptyState"
                     data-monster-attributes="class path:data | has-entries | ?:hidden:empty-state-container"></div>
                <div data-monster-role="datatable" data-monster-insert="\${row-key} path:data">
                </div>
            </div>
            <div data-monster-role="footer" data-monster-select-this="true"
                 data-monster-attributes="class path:data | has-entries | ?::hidden">
                <slot name="footer" data-monster-attributes="class path:features.footer | ?::hidden"></slot>
            </div>

        </div>
    `;
}

registerCustomElement(DataTable);