import { BaseTooltipHandler } from "./base";

import { getDomStyle, getTextStyle, setStyleToDom } from "./utils/style";

import { TOOLTIP_CONTAINER_EL_CLASS_NAME, DEFAULT_TOOLTIP_Z_INDEX, TOOLTIP_PREFIX, TOOLTIP_CONTENT_BOX_CLASS_NAME, TOOLTIP_TITLE_CLASS_NAME } from "./constants";

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

import { domDocument } from "../../../util/env";

import { registerComponentPlugin } from "../register";

import { TooltipHandlerType } from "../../../component/tooltip/constant";

import { getSvgHtml } from "./utils/svg";

import { formatContent } from "./utils/common";

import { token } from "../../../theme/token";

import { calcLayoutNumber } from "../../../util/space";

export class DomTooltipHandler extends BaseTooltipHandler {
    getVisibility() {
        return !!this._rootDom && "visible" === this._rootDom.style.visibility;
    }
    setVisibility(_value) {
        _value !== this.getVisibility() && this._rootDom && (this._rootDom.style.visibility = _value ? "visible" : "hidden");
    }
    getRootDom() {
        return this._rootDom;
    }
    constructor() {
        super(DomTooltipHandler.type), this.type = TooltipHandlerType.dom, this._tooltipContainer = null == domDocument ? void 0 : domDocument.body;
    }
    onAdd(service) {
        super.onAdd(service), this._initStyle(), this.initEl();
    }
    initEl() {
        const parentElement = this._component.getSpec().parentElement;
        if (domDocument && parentElement && parentElement.children && parentElement.children.length) {
            for (let i = 0; i < parentElement.children.length; i++) if (parentElement.children[i].classList.contains(TOOLTIP_CONTAINER_EL_CLASS_NAME)) {
                this._container = parentElement.children[i];
                break;
            }
            this._container || (this._container = domDocument.createElement("div"), this._container.style.position = "relative", 
            this._container.style.zIndex = DEFAULT_TOOLTIP_Z_INDEX, this._container.classList.add(TOOLTIP_CONTAINER_EL_CLASS_NAME), 
            parentElement.appendChild(this._container));
        }
    }
    initRootDom() {
        var _a, _b, _c;
        const tooltipSpec = this._component.getSpec(), tooltipElement = document.createElement("div"), globalTheme = null !== (_b = null === (_a = this._chartOption) || void 0 === _a ? void 0 : _a.getTheme()) && void 0 !== _b ? _b : {};
        setStyleToDom(tooltipElement, Object.assign({
            left: "0",
            top: "0",
            pointerEvents: "none",
            padding: "12px",
            position: "absolute",
            zIndex: DEFAULT_TOOLTIP_Z_INDEX,
            fontFamily: null !== (_c = null == globalTheme ? void 0 : globalTheme.fontFamily) && void 0 !== _c ? _c : token.fontFamily,
            fontSize: "11px",
            borderRadius: "3px",
            borderStyle: "solid",
            lineHeight: "initial",
            background: "#fff",
            boxShadow: "2px 2px 4px rgba(0, 0, 0, 0.1)",
            maxWidth: "100wh",
            maxHeight: "100vh",
            visibility: "hidden"
        }, this._domStyle.panel)), tooltipElement.classList.add(tooltipSpec.className), 
        tooltipElement.setAttribute("vchart-tooltip-id", `${this.id}`), this._container.appendChild(tooltipElement), 
        this._rootDom = tooltipElement;
    }
    _getTooltipBoxSize(actualTooltip, changePositionOnly) {
        var _a;
        this._rootDom || this.initRootDom(), changePositionOnly || this._updateDomStringByCol(actualTooltip), 
        this._updateDomStyle("height", changePositionOnly);
        const rect = null === (_a = this._rootDom) || void 0 === _a ? void 0 : _a.getBoundingClientRect();
        return {
            width: null == rect ? void 0 : rect.width,
            height: null == rect ? void 0 : rect.height
        };
    }
    _removeTooltip() {
        this._rootDom && this._rootDom.parentNode && (this._rootDom.parentNode.removeChild(this._rootDom), 
        this._rootDom = null), this._container = null;
    }
    _updateTooltip(visible, params) {
        var _a, _b, _c;
        if (visible && this._rootDom) {
            const {tooltipSpec: tooltipSpec, activeTooltipSpec: activeTooltipSpec} = params;
            params.changePositionOnly || (this._tooltipActual = activeTooltipSpec);
            const currentVisible = this.getVisibility(), el = this._rootDom;
            if (el) {
                const {x: x = 0, y: y = 0} = null !== (_a = activeTooltipSpec.position) && void 0 !== _a ? _a : {};
                if (tooltipSpec.updateElement) {
                    this._updatePosition(null !== (_b = this._cacheCustomTooltipPosition) && void 0 !== _b ? _b : {
                        x: x,
                        y: y
                    }), tooltipSpec.updateElement(el, activeTooltipSpec, params);
                    const position = this._getActualTooltipPosition(activeTooltipSpec, params, {
                        width: el.offsetWidth,
                        height: el.offsetHeight
                    });
                    this._updatePosition(position), this._cacheCustomTooltipPosition = position;
                } else this._rootDom.style.transitionDuration = currentVisible ? null !== (_c = this._domStyle.panel.transitionDuration) && void 0 !== _c ? _c : "initial" : "0ms", 
                this._updatePosition({
                    x: x,
                    y: y
                });
            }
            this.setVisibility(visible);
        } else this.setVisibility(visible), this._cacheCustomTooltipPosition = void 0;
    }
    _initStyle() {
        const tooltipSpec = this._component.getSpec();
        this._domStyle = getDomStyle(tooltipSpec);
    }
    _updateDomStringByCol(actualTooltip) {
        var _a;
        const {title: title = {}, content: content} = actualTooltip, hasContent = content && content.length, rowStyle = this._domStyle.row, chilren = [ ...this._rootDom.children ];
        let titleDom = chilren.find((child => child.className.includes(TOOLTIP_TITLE_CLASS_NAME))), contentDom = chilren.find((child => child.className.includes(TOOLTIP_CONTENT_BOX_CLASS_NAME)));
        if (!titleDom && !1 !== title.visible) {
            titleDom = document.createElement("h2");
            const span = document.createElement("span");
            titleDom.appendChild(span), titleDom.classList.add(TOOLTIP_TITLE_CLASS_NAME), this._rootDom.firstChild ? this._rootDom.insertBefore(titleDom, this._rootDom.firstChild) : this._rootDom.appendChild(titleDom);
        }
        titleDom && !1 !== title.visible ? (setStyleToDom(titleDom, Object.assign(Object.assign(Object.assign({}, this._domStyle.title), hasContent ? rowStyle : {
            marginBottom: "0px"
        }), {
            marginTop: "0px"
        })), titleDom.firstChild.innerHTML = `${null !== (_a = title.value) && void 0 !== _a ? _a : ""}`) : titleDom && !1 === title.visible && titleDom.parentNode.removeChild(titleDom);
        const columns = [ "shape", "key", "value" ];
        if (!contentDom && hasContent && (contentDom = document.createElement("div"), columns.forEach((col => {
            const colDiv = document.createElement("div");
            colDiv.classList.add(`${TOOLTIP_PREFIX}-column`), colDiv.classList.add(`${TOOLTIP_PREFIX}-${col}-column`), 
            colDiv.setAttribute("data-col", col), contentDom.appendChild(colDiv);
        })), contentDom.classList.add(TOOLTIP_CONTENT_BOX_CLASS_NAME), this._rootDom.appendChild(contentDom)), 
        contentDom && hasContent) {
            const columnDivs = [ ...contentDom.children ];
            setStyleToDom(contentDom, {
                whiteSpace: "nowrap"
            }), columnDivs.forEach(((colDiv, index) => {
                const colName = colDiv.getAttribute("data-col");
                if (colName && columns.includes(colName)) {
                    const hideColumn = "shape" === colName && content.every((c => !c.hasShape || !c.shapeType));
                    setStyleToDom(colDiv, Object.assign(Object.assign({}, this._domStyle[colName]), {
                        display: hideColumn ? "none" : "inline-block",
                        verticalAlign: "top"
                    }));
                    const rows = [ ...colDiv.children ];
                    rows.slice(content.length).forEach((extraRow => {
                        extraRow.parentNode.removeChild(extraRow);
                    })), content.forEach(((entry, index) => {
                        let row = rows[index];
                        row || (row = document.createElement("div"), row.classList.add(`${TOOLTIP_PREFIX}-${colName}`), 
                        colDiv.appendChild(row));
                        const styleByRow = Object.assign({}, rowStyle);
                        index === content.length - 1 && (styleByRow.marginBottom = "0px"), styleByRow.display = !1 === entry.visible ? "none" : "block", 
                        styleByRow.height = "initial", "key" === colName ? (row.innerHTML = formatContent(entry.key), 
                        entry.keyStyle && getTextStyle(entry.keyStyle, styleByRow)) : "value" === colName ? (row.innerHTML = formatContent(entry.value), 
                        entry.valueStyle && getTextStyle(entry.valueStyle, styleByRow)) : "shape" === colName && (row.innerHTML = getSvgHtml(entry, `${this.id}_${index}`)), 
                        setStyleToDom(row, styleByRow);
                    }));
                }
            }));
        } else contentDom && !hasContent && contentDom.parentNode.removeChild(contentDom);
    }
    _updateDomStyle(sizeKey = "width", refreshSize) {
        var _a, _b, _c, _d, _e;
        const rootDom = this._rootDom, contentDom = [ ...rootDom.children ].find((child => child.className.includes(TOOLTIP_CONTENT_BOX_CLASS_NAME))), titleDom = [ ...rootDom.children ].find((child => child.className.includes(TOOLTIP_TITLE_CLASS_NAME)));
        if (contentDom) {
            const tooltipSpec = this._component.getSpec(), contentStyle = {}, titleLabel = null === (_a = tooltipSpec.style) || void 0 === _a ? void 0 : _a.titleLabel;
            if (titleLabel && titleLabel.autoWidth && !1 !== titleLabel.multiLine && titleDom) {
                const maxWidth = [ ...contentDom.children ].reduce(((res, col) => "height" === sizeKey ? res + col.getBoundingClientRect().width : Math.max(res, col.getBoundingClientRect().width)), 0);
                maxWidth > 0 && (titleDom.style.maxWidth = `${maxWidth}px`, titleDom.style.maxWidth = `${Math.ceil(contentDom.getBoundingClientRect().width)}px`);
            }
            if (isValid(null === (_b = null == tooltipSpec ? void 0 : tooltipSpec.style) || void 0 === _b ? void 0 : _b.maxContentHeight)) {
                const titleHeight = titleDom && titleDom.className.includes(TOOLTIP_TITLE_CLASS_NAME) ? titleDom.getBoundingClientRect().height + (null !== (_c = tooltipSpec.style.spaceRow) && void 0 !== _c ? _c : 0) : 0, viewRect = this._chartOption.getChartViewRect(), maxHeight = calcLayoutNumber(tooltipSpec.style.maxContentHeight, Math.min(viewRect.height, document.body.clientHeight) - titleHeight - (this._domStyle.panelPadding ? this._domStyle.panelPadding[0] + this._domStyle.panelPadding[1] : 0));
                maxHeight > 0 && (contentStyle.maxHeight = `${maxHeight}px`, contentStyle.overflowY = "auto", 
                contentStyle.width = `calc(100% + ${this._domStyle.panelPadding ? this._domStyle.panelPadding[1] + "px" : "10px"})`, 
                setStyleToDom(contentDom, contentStyle));
            }
            const rows = contentDom.children, widthByCol = [];
            if (rows) {
                for (let i = 0; i < rows.length; i++) {
                    const cols = null !== (_d = rows[i].children) && void 0 !== _d ? _d : [];
                    for (let j = 0; j < cols.length; j++) {
                        refreshSize && (cols[j].style[sizeKey] = "initial");
                        const width = cols[j].getBoundingClientRect()[sizeKey];
                        (void 0 === widthByCol[j] || widthByCol[j] < width) && (widthByCol[j] = width);
                    }
                }
                for (let i = 0; i < rows.length; i++) {
                    const cols = null !== (_e = rows[i].children) && void 0 !== _e ? _e : [];
                    for (let j = 0; j < cols.length; j++) cols[j].style[sizeKey] = `${widthByCol[j]}px`;
                }
            }
        }
    }
    _getParentElement(spec) {
        var _a;
        return null !== (_a = this._container) && void 0 !== _a ? _a : super._getParentElement(spec);
    }
    isTooltipShown() {
        return this.getVisibility();
    }
    reInit() {
        super.reInit(), this._initStyle(), this._rootDom && setStyleToDom(this._rootDom, this._domStyle.panel), 
        this.getVisibility() && (this._updateDomStringByCol(this._tooltipActual), this._updateDomStyle("height", !1));
    }
    _updatePosition({x: x, y: y}) {
        this._rootDom && (this._rootDom.style.transform = `translate3d(${x}px, ${y}px, 0)`);
    }
}

DomTooltipHandler.type = TooltipHandlerType.dom;

export const registerDomTooltipHandler = () => {
    registerComponentPlugin(DomTooltipHandler);
};
//# sourceMappingURL=dom-tooltip-handler.js.map
