import { EventHandler } from "../../../../event/EventHandler";

import { createElement } from "../../../../tools/dom";

import { importStyle } from "./MenuElementStyle";

import { TABLE_EVENT_TYPE } from "../../../../core/TABLE_EVENT_TYPE";

import { cellInRange } from "../../../../tools/helper";

import { isValid } from "@visactor/vutils";

import { regUrl } from "../../../../tools/global";

importStyle();

const CLASSNAME = "vtable__menu-element", ITEM_CLASSNAME = `${CLASSNAME}__item`, CONTENT_CLASSNAME = `${CLASSNAME}__content`, HIDDEN_CLASSNAME = `${CLASSNAME}--hidden`, SHOWN_CLASSNAME = `${CLASSNAME}--shown`, NORAML_CLASSNAME = `${CLASSNAME}--normal`, SELECT_CLASSNAME = `${CLASSNAME}--select`, ICOM_CLASSNAME = `${CLASSNAME}__icon`, SPLIT_CLASSNAME = `${CLASSNAME}__split`, TITLE_CLASSNAME = `${CLASSNAME}__title`, ARROW_CLASSNAME = `${CLASSNAME}__arrow`, NOEVENT_CLASSNAME = `${CLASSNAME}__no-event`, ITEMTEXT_CLASSNAME = `${CLASSNAME}__item-text`, ITEM_DISABLED_CLASSNAME = `${CLASSNAME}__item-disabled`;

function createMenuDomElement() {
    return createElement("div", [ CLASSNAME, HIDDEN_CLASSNAME ]);
}

export function isMenuHighlight(_table, cells, menuKeyCurrent, colCurrent, rowCurrent, index) {
    const cellRange = _table.getCellRange(colCurrent, rowCurrent);
    for (let i = 0; i < cells.length; i++) {
        const highlight = cells[i];
        let {col: col, row: row} = highlight;
        const {field: field, menuKey: menuKey} = highlight;
        if ("number" != typeof col || "number" != typeof row) if (_table.isPivotTable() && (Array.isArray(field), 
        1)) {
            const cellAddress = _table.internalProps.layoutMap.getPivotCellAdress(field);
            if (!cellAddress) continue;
            col = cellAddress.col, row = cellAddress.row;
        } else {
            const cellAddress = _table.internalProps.layoutMap.getHeaderCellAddressByField(field);
            if (!cellAddress) continue;
            col = cellAddress.col, row = cellAddress.row;
        }
        if (isValid(col) && isValid(row) && cellInRange(cellRange, col, row) && menuKeyCurrent === menuKey) return !0;
    }
    return !1;
}

export class MenuElement {
    constructor(table) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
        this._handler = new EventHandler, this._rootElement = createMenuDomElement(), this._secondElement = createMenuDomElement(), 
        this._secondElement.sub = !0, this._showChildrenIndex = -1, this._rootElement.addEventListener("wheel", (e => {
            e.stopPropagation();
        })), null === (_a = this._rootElement) || void 0 === _a || _a.addEventListener("mousedown", (e => {
            e.stopPropagation(), e.preventDefault();
        })), null === (_b = this._rootElement) || void 0 === _b || _b.addEventListener("contextmenu", (e => {
            e.stopPropagation(), e.preventDefault();
        })), null === (_c = this._rootElement) || void 0 === _c || _c.addEventListener("touchend", (e => {
            if (e.stopPropagation(), e.preventDefault(), e.target.classList.contains(ITEM_DISABLED_CLASSNAME)) return;
            if (this._rootElement.classList.contains(HIDDEN_CLASSNAME)) return;
            const {col: col, row: row, dropDownIndex: dropDownIndex, menuKey: menuKey, text: text, hasChildren: hasChildren} = e.target;
            if ("number" != typeof dropDownIndex || hasChildren) return void e.stopPropagation();
            const field = table.isPivotTable() ? table.internalProps.layoutMap.getPivotDimensionInfo(col, row) : table.getHeaderField(col, row), highlight = table._dropDownMenuIsHighlight(col, row, dropDownIndex);
            table.fireListeners(TABLE_EVENT_TYPE.DROPDOWN_MENU_CLICK, {
                col: col,
                row: row,
                field: field,
                menuKey: menuKey,
                text: text,
                highlight: highlight,
                cellLocation: table.getCellLocation(col, row),
                event: e
            }), table.fireListeners(TABLE_EVENT_TYPE.DROPDOWN_MENU_CLEAR, null), table.fireListeners(TABLE_EVENT_TYPE.HIDE_MENU, null), 
            e.stopPropagation();
        })), null === (_d = this._rootElement) || void 0 === _d || _d.addEventListener("click", (e => {
            if (e.stopPropagation(), e.preventDefault(), e.target.classList.contains(ITEM_DISABLED_CLASSNAME)) return;
            if (this._rootElement.classList.contains(HIDDEN_CLASSNAME)) return;
            const {col: col, row: row, dropDownIndex: dropDownIndex, menuKey: menuKey, text: text, hasChildren: hasChildren} = e.target;
            if ("number" != typeof dropDownIndex || hasChildren) return void e.stopPropagation();
            const field = table.isPivotTable() ? table.internalProps.layoutMap.getPivotDimensionInfo(col, row) : table.getHeaderField(col, row), highlight = table._dropDownMenuIsHighlight(col, row, dropDownIndex);
            table.fireListeners(TABLE_EVENT_TYPE.DROPDOWN_MENU_CLICK, {
                col: col,
                row: row,
                field: field,
                menuKey: menuKey,
                text: text,
                highlight: highlight,
                cellLocation: table.getCellLocation(col, row),
                event: e
            }), table.fireListeners(TABLE_EVENT_TYPE.DROPDOWN_MENU_CLEAR, null), table.fireListeners(TABLE_EVENT_TYPE.HIDE_MENU, null), 
            e.stopPropagation();
        })), null === (_e = this._rootElement) || void 0 === _e || _e.addEventListener("mousemove", (e => {
            var _a, _b;
            if (this._rootElement.classList.contains(HIDDEN_CLASSNAME)) return;
            e.stopPropagation();
            const {hasChildren: hasChildren, dropDownIndex: dropDownIndex, col: col, row: row, sub: sub} = e.target;
            if (hasChildren) {
                this._showChildrenIndex = dropDownIndex;
                const secondElement = this._secondElement;
                null == secondElement || secondElement.classList.remove(HIDDEN_CLASSNAME), null == secondElement || secondElement.classList.add(SHOWN_CLASSNAME), 
                secondElement.innerHTML = "";
                const children = null === (_a = this._menuInstanceInfo.content[dropDownIndex]) || void 0 === _a ? void 0 : _a.children;
                for (let i = 0; i < children.length; i++) {
                    const menuItem = children[i], item = createItem(menuItem, !!table.stateManager.menu.dropDownMenuHighlight && isMenuHighlight(table, table.stateManager.menu.dropDownMenuHighlight, "object" == typeof menuItem ? (null == menuItem ? void 0 : menuItem.menuKey) || (null == menuItem ? void 0 : menuItem.text) : menuItem, col, row, i));
                    item.col = col, item.row = row, item.dropDownIndex = i, "string" == typeof menuItem ? (item.text = menuItem, 
                    item.menuKey = menuItem) : "object" == typeof menuItem && (item.text = menuItem.text, 
                    item.menuKey = menuItem.menuKey || menuItem.text), item.sub = !0, item.sub = !0, 
                    secondElement.appendChild(item);
                }
                const rect = e.target.getBoundingClientRect();
                this._bindSecondElement(table, col, row, rect.right, rect.top);
            } else if (hasChildren && this._showChildrenIndex === dropDownIndex) {
                const secondElement = this._secondElement;
                null == secondElement || secondElement.classList.remove(HIDDEN_CLASSNAME), null == secondElement || secondElement.classList.add(SHOWN_CLASSNAME);
            } else !sub && (null === (_b = this._secondElement) || void 0 === _b ? void 0 : _b.classList.contains(SHOWN_CLASSNAME)) && setTimeout((() => {
                if (!0 !== this._mouseEnterSecondElement) {
                    this._showChildrenIndex = -1;
                    const secondElement = this._secondElement;
                    null == secondElement || secondElement.classList.remove(SHOWN_CLASSNAME), null == secondElement || secondElement.classList.add(HIDDEN_CLASSNAME);
                }
            }), 300);
        })), null === (_f = this._secondElement) || void 0 === _f || _f.addEventListener("wheel", (e => {
            e.stopPropagation();
        })), null === (_g = this._secondElement) || void 0 === _g || _g.addEventListener("mousemove", (e => {
            this._rootElement.classList.contains(HIDDEN_CLASSNAME) || e.stopPropagation();
        })), null === (_h = this._secondElement) || void 0 === _h || _h.addEventListener("mouseenter", (e => {
            this._mouseEnterSecondElement = !0;
        })), null === (_j = this._secondElement) || void 0 === _j || _j.addEventListener("mouseleave", (e => {
            this._mouseEnterSecondElement = !1;
        })), null === (_k = this._secondElement) || void 0 === _k || _k.addEventListener("mousedown", (e => {
            e.stopPropagation(), e.preventDefault();
        })), null === (_l = this._secondElement) || void 0 === _l || _l.addEventListener("click", (e => {
            if (e.stopPropagation(), e.preventDefault(), e.target.classList.contains(ITEM_DISABLED_CLASSNAME)) return;
            if (this._secondElement.classList.contains(HIDDEN_CLASSNAME)) return;
            const {col: col, row: row, dropDownIndex: dropDownIndex, menuKey: menuKey, text: text, hasChildren: hasChildren} = e.target;
            if ("number" != typeof dropDownIndex || hasChildren) return void e.stopPropagation();
            const field = table.isPivotTable() ? table.internalProps.layoutMap.getPivotDimensionInfo(col, row) : table.getHeaderField(col, row);
            let highlight = !1;
            this._menuInstanceInfo.content.forEach(((menu, i) => {
                if ("object" == typeof menu && menu.children && menu.children.length) for (let j = 0; j < menu.children.length; j++) {
                    const childItem = menu.children[j];
                    if (isMenuHighlight(table, table.stateManager.menu.dropDownMenuHighlight, "object" == typeof childItem ? null == childItem ? void 0 : childItem.menuKey : childItem, col, row, -1) && menuKey === ("object" == typeof childItem ? null == childItem ? void 0 : childItem.menuKey : childItem)) return void (highlight = !0);
                }
            })), table.fireListeners(TABLE_EVENT_TYPE.DROPDOWN_MENU_CLICK, {
                col: col,
                row: row,
                field: field,
                cellHeaderPaths: table.isPivotTable() ? table.getCellHeaderPaths(col, row) : void 0,
                menuKey: menuKey,
                text: text,
                highlight: highlight,
                cellLocation: table.getCellLocation(col, row),
                event: e
            }), table.fireListeners(TABLE_EVENT_TYPE.DROPDOWN_MENU_CLEAR, null), table.fireListeners(TABLE_EVENT_TYPE.HIDE_MENU, null), 
            e.stopPropagation();
        }));
    }
    get rootElement() {
        return this._rootElement;
    }
    release() {
        this.unbindFromCell();
        const rootElement = this._rootElement;
        (null == rootElement ? void 0 : rootElement.parentElement) && rootElement.parentElement.removeChild(rootElement), 
        this._handler.release(), delete this._rootElement;
    }
    bindToCell(table, col, row, menuInstanceInfo) {
        var _a, _b;
        const rootElement = this._rootElement, secondElement = this._secondElement;
        if (this._menuInstanceInfo = menuInstanceInfo, null == rootElement || rootElement.classList.remove(SHOWN_CLASSNAME), 
        null == rootElement || rootElement.classList.add(HIDDEN_CLASSNAME), null == secondElement || secondElement.classList.remove(SHOWN_CLASSNAME), 
        null == secondElement || secondElement.classList.add(HIDDEN_CLASSNAME), this._canBindToCell(table, col, row)) {
            if (rootElement.innerHTML = "", Array.isArray(menuInstanceInfo.content)) {
                const menuListItem = menuInstanceInfo.content;
                for (let i = 0; null !== (_a = i < (null == menuListItem ? void 0 : menuListItem.length)) && void 0 !== _a && _a; i++) {
                    const menuItem = menuListItem[i];
                    let isHighlight = !!table.stateManager.menu.dropDownMenuHighlight && isMenuHighlight(table, table.stateManager.menu.dropDownMenuHighlight, "object" == typeof menuItem ? (null == menuItem ? void 0 : menuItem.menuKey) || (null == menuItem ? void 0 : menuItem.text) : menuItem, col, row, i);
                    if (table.stateManager.menu.dropDownMenuHighlight && "object" == typeof menuItem && Array.isArray(menuItem.children) && menuItem.children.length) for (let i = 0; i < menuItem.children.length; i++) {
                        const childItem = menuItem.children[i];
                        if (isMenuHighlight(table, table.stateManager.menu.dropDownMenuHighlight, "object" == typeof childItem ? (null == childItem ? void 0 : childItem.menuKey) || (null == childItem ? void 0 : childItem.text) : childItem, col, row, i)) {
                            isHighlight = !0;
                            break;
                        }
                    }
                    const item = createItem(menuItem, isHighlight);
                    item.col = col, item.row = row, item.dropDownIndex = i, "string" == typeof menuItem ? (item.text = menuItem, 
                    item.menuKey = menuItem) : "object" == typeof menuItem && (item.text = menuItem.text, 
                    item.menuKey = menuItem.menuKey || menuItem.text, (null === (_b = menuItem.children) || void 0 === _b ? void 0 : _b.length) && (item.hasChildren = !0)), 
                    rootElement.appendChild(item);
                }
            }
            if (this._bindToCell(table, col, row, menuInstanceInfo.position, menuInstanceInfo.referencePosition)) return null == rootElement || rootElement.classList.add(SHOWN_CLASSNAME), 
            null == rootElement || rootElement.classList.remove(HIDDEN_CLASSNAME), !0;
        } else this.unbindFromCell();
        return !1;
    }
    unbindFromCell() {
        const rootElement = this._rootElement, secondElement = this._secondElement;
        this._menuInstanceInfo = void 0, (null == rootElement ? void 0 : rootElement.parentElement) && (rootElement.classList.remove(SHOWN_CLASSNAME), 
        rootElement.classList.add(HIDDEN_CLASSNAME)), (null == secondElement ? void 0 : secondElement.parentElement) && (secondElement.classList.remove(SHOWN_CLASSNAME), 
        secondElement.classList.add(HIDDEN_CLASSNAME));
    }
    _canBindToCell(table, col, row) {
        var _a;
        const rect = table.getCellRangeRelativeRect({
            col: col,
            row: row
        }), element = null !== (_a = table.internalProps.menu.parentElement) && void 0 !== _a ? _a : table.getElement(), {top: top, bottom: bottom, left: left, right: right} = rect;
        if (-1 === col && -1 === row) return !0;
        if (table.isFrozenCell(col, row)) return !0;
        if (bottom < table.getFrozenRowsHeight() || right < table.getFrozenColsWidth() || left > table.tableNoFrameWidth - table.getRightFrozenColsWidth() || top > table.tableNoFrameHeight - table.getBottomFrozenRowsHeight()) return !1;
        const {offsetHeight: offsetHeight, offsetWidth: offsetWidth} = element;
        return !(offsetHeight < top) && !(offsetWidth < left);
    }
    _bindToCell(table, col, row, position, referencePosition) {
        var _a;
        const rootElement = this._rootElement, element = null !== (_a = table.internalProps.menu.parentElement) && void 0 !== _a ? _a : table.getElement(), {width: containerWidth, height: containerHeight, left: containerLeft, top: containerTop} = element.getBoundingClientRect();
        if (rootElement) {
            rootElement.parentElement !== element && element.appendChild(rootElement), rootElement.style.left = "0px";
            const maxWidth = .8 * containerWidth;
            rootElement.style.maxWidth = `${maxWidth}px`;
            const rootElementWidth = rootElement.offsetWidth, rootElementHeight = rootElement.offsetHeight;
            let rootElementLeft, rootElementTop;
            position ? (rootElementLeft = position.x, rootElementTop = position.y) : referencePosition && (rootElementLeft = referencePosition.rect.right - rootElementWidth, 
            rootElementTop = referencePosition.rect.bottom);
            const rect = element.getBoundingClientRect(), scaleX = rect.width / element.offsetWidth, scaleY = rect.height / element.offsetHeight;
            rootElementTop * scaleY + rootElementHeight > containerHeight && (rootElementTop = (containerHeight - rootElementHeight) / scaleY), 
            rootElementTop < 0 && (rootElementTop /= 2);
            let deltaTop = 0, deltaLeft = 0;
            if (table.getElement() !== element) {
                const {left: left, top: top} = table.getElement().getBoundingClientRect();
                deltaTop = top - containerTop, deltaLeft = left - containerLeft;
            }
            return rootElement.style.top = `${rootElementTop + deltaTop}px`, rootElementLeft < 0 ? rootElementLeft = 0 : rootElementLeft * scaleX + rootElementWidth > containerWidth && (rootElementLeft = (containerWidth - rootElementWidth) / scaleX), 
            rootElement.style.left = `${rootElementLeft + deltaLeft}px`, !0;
        }
        return !1;
    }
    _bindSecondElement(table, col, row, x, y) {
        var _a;
        const secondElement = this._secondElement, rootElement = this._rootElement, element = null !== (_a = table.internalProps.menu.parentElement) && void 0 !== _a ? _a : table.getElement(), {width: containerWidth, height: containerHeight, left: containerLeft, top: containerTop} = element.getBoundingClientRect(), {x: rootLeft, y: rootTop, width: rootWidth, height: rootHeight} = rootElement.getBoundingClientRect();
        if (secondElement) {
            secondElement.parentElement !== element && element.appendChild(secondElement), secondElement.style.left = "0px";
            const maxWidth = .8 * containerWidth;
            secondElement.style.maxWidth = `${maxWidth}px`;
            const secondElementWidth = secondElement.clientWidth, secondElementHeight = secondElement.clientHeight, secondElementLeft = x - containerLeft;
            let topStyle = y - 4 - containerTop;
            if (topStyle + secondElementHeight > containerHeight) {
                topStyle = topStyle - secondElementHeight + secondElement.firstElementChild.clientHeight + 4;
            }
            secondElement.style.top = `${topStyle}px`;
            let leftStyle = secondElementLeft;
            return leftStyle + secondElementWidth > containerWidth ? leftStyle = leftStyle - secondElementWidth - rootWidth : leftStyle += 4, 
            secondElement.style.left = `${leftStyle}px`, !0;
        }
        return !1;
    }
    pointInMenuElement(x, y) {
        const rootElement = this._rootElement, {x: rootLeft, y: rootTop, width: rootWidth, height: rootHeight} = rootElement.getBoundingClientRect();
        if (x > rootLeft - 5 && x < rootLeft + rootWidth + 5 && y > rootTop - 5 && y < rootTop + rootHeight + 5) return !0;
        const secondElement = this._secondElement;
        if (secondElement) {
            const {x: secondLeft, y: secondTop, width: secondWidth, height: secondHeight} = secondElement.getBoundingClientRect();
            if (x > secondLeft - 5 && x < secondLeft + secondWidth + 5 && y > secondTop - 5 && y < secondTop + secondHeight + 5) return !0;
        }
        return !1;
    }
}

function createItem(info, isHighlight) {
    var _a, _b, _c;
    const itemContainer = createElement("div", [ ITEM_CLASSNAME, isHighlight ? SELECT_CLASSNAME : NORAML_CLASSNAME ]);
    if ("object" == typeof info && info.disabled && itemContainer.classList.add(ITEM_DISABLED_CLASSNAME), 
    "string" == typeof info) {
        const item = createElement("span", [ CONTENT_CLASSNAME, NOEVENT_CLASSNAME, ITEMTEXT_CLASSNAME ]);
        item.innerHTML = info, itemContainer.appendChild(item);
    } else if ("object" == typeof info) {
        const type = null !== (_a = info.type) && void 0 !== _a ? _a : "item";
        if ("split" === type) return null == itemContainer || itemContainer.classList.add(SPLIT_CLASSNAME), 
        itemContainer;
        if (null === (_b = null == info ? void 0 : info.icon) || void 0 === _b ? void 0 : _b.svg) if (regUrl.test(info.icon.svg)) {
            const image = new Image;
            info.icon.width ? image.style.width = info.icon.width.toString() + "px" : image.style.width = "16px", 
            info.icon.height ? image.style.height = info.icon.height.toString() + "px" : image.style.height = "16px", 
            image.src = info.icon.svg, itemContainer.appendChild(image);
        } else {
            const svg = createElement("span", [ ICOM_CLASSNAME, NOEVENT_CLASSNAME ]);
            svg.innerHTML = isHighlight && info.selectedIcon && info.selectedIcon.svg ? info.selectedIcon.svg : info.icon.svg, 
            info.icon.width && svg.children[0].setAttribute("width", info.icon.width.toString()), 
            info.icon.height && svg.children[0].setAttribute("height", info.icon.height.toString()), 
            itemContainer.appendChild(svg);
        }
        const item = createElement("span", [ CONTENT_CLASSNAME, NOEVENT_CLASSNAME, ITEMTEXT_CLASSNAME ]);
        if (item.innerHTML = info.text, itemContainer.appendChild(item), "title" === type) null == itemContainer || itemContainer.classList.add(NOEVENT_CLASSNAME, TITLE_CLASSNAME); else if (null === (_c = null == info ? void 0 : info.children) || void 0 === _c ? void 0 : _c.length) {
            const arrow = createElement("span", [ CONTENT_CLASSNAME, NOEVENT_CLASSNAME, ARROW_CLASSNAME ]);
            arrow.innerHTML = isHighlight ? '<svg width="8" height="12" viewBox="0 0 10 17" fill="none" xmlns="http://www.w3.org/2000/svg" style="vertical-align: baseline"><path d="M1.78186 16.7729L0.300378 15.2915L6.8189 8.77295L0.300377 2.25443L1.78186 0.77295L9.78186 8.77295L1.78186 16.7729Z" fill="#2E68CF" fill-opacity="0.65"></path></svg>' : '<svg width="8" height="12" viewBox="0 0 10 17" fill="none" xmlns="http://www.w3.org/2000/svg" style="vertical-align: baseline"><path d="M1.78186 16.7729L0.300378 15.2915L6.8189 8.77295L0.300377 2.25443L1.78186 0.77295L9.78186 8.77295L1.78186 16.7729Z" fill="#141414" fill-opacity="0.65"></path></svg>', 
            itemContainer.appendChild(arrow);
        }
    }
    return itemContainer;
}
//# sourceMappingURL=MenuElement.js.map
