import { builtinSymbolsMap } from "@visactor/vrender-core/graphic/builtin-symbol";

import { calculateLineHeight } from "@visactor/vrender-core/text";

import { merge, isValid, normalizePadding, isNil } from "@visactor/vutils";

import { AbstractComponent } from "../core/base";

import { alignTextInLine, initTextMeasure } from "../util/text";

import { isVisible } from "../util";

import { getRichTextAttribute, mergeRowAttrs } from "./util";

import { defaultAttributes, TOOLTIP_POSITION_ATTRIBUTES } from "./config";

import { DEFAULT_HTML_TEXT_SPEC } from "../constant";

import { loadTooltipComponent } from "./register";

const TOOLTIP_BACKGROUND_NAME = "tooltip-background", TOOLTIP_TITLE_NAME = "tooltip-title", TOOLTIP_CONTENT_NAME = "tooltip-content", TOOLTIP_SHAPE_NAME_SUFFIX = "shape", TOOLTIP_KEY_NAME_SUFFIX = "key", TOOLTIP_VALUE_NAME_SUFFIX = "value";

loadTooltipComponent();

export class Tooltip extends AbstractComponent {
    constructor(attributes, options) {
        super((null == options ? void 0 : options.skipDefault) ? attributes : merge({}, Tooltip.defaultAttributes, attributes), options), 
        this.name = "tooltip";
    }
    render() {
        var _a;
        const {visible: visible, content: content, panel: panel, keyWidth: keyWidth, valueWidth: valueWidth, hasContentShape: hasContentShape, autoCalculatePosition: autoCalculatePosition, autoMeasure: autoMeasure, align: align} = this.attribute;
        if (!visible) return void this.hideAll();
        autoMeasure && Tooltip.measureTooltip(this.attribute), autoCalculatePosition && Tooltip.calculateTooltipPosition(this.attribute);
        const padding = normalizePadding(this.attribute.padding);
        this._tooltipPanel = this.createOrUpdateChild("tooltip-background", Object.assign({
            visible: !0
        }, panel), "rect"), this._tooltipTitleContainer = this.createOrUpdateChild("tooltip-title", {
            visible: !0,
            x: padding[3],
            y: padding[0]
        }, "group");
        const titleAttr = Tooltip.getTitleAttr(this.attribute);
        this._tooltipTitleSymbol = this._tooltipTitleContainer.createOrUpdateChild("tooltip-title-shape", merge({
            symbolType: "circle"
        }, titleAttr.shape, {
            visible: isVisible(titleAttr) && isVisible(titleAttr.shape)
        }), "symbol"), "object" != typeof titleAttr.value.text || null === titleAttr.value.text || "rich" !== titleAttr.value.text.type && "html" !== titleAttr.value.text.type ? titleAttr.value.multiLine ? this._tooltipTitle = this._tooltipTitleContainer.createOrUpdateChild("tooltip-title-value", Object.assign({
            visible: isVisible(titleAttr) && isVisible(titleAttr.value)
        }, getRichTextAttribute(titleAttr.value)), "richtext") : this._tooltipTitle = this._tooltipTitleContainer.createOrUpdateChild("tooltip-title-value", Object.assign({
            text: null !== (_a = titleAttr.value.text) && void 0 !== _a ? _a : "",
            visible: isVisible(titleAttr) && isVisible(titleAttr.value)
        }, titleAttr.value), "text") : "rich" === titleAttr.value.text.type ? this._tooltipTitle = this._tooltipTitleContainer.createOrUpdateChild("tooltip-title-value", Object.assign({
            visible: isVisible(titleAttr) && isVisible(titleAttr.value)
        }, getRichTextAttribute(titleAttr.value)), "richtext") : "html" === titleAttr.value.text.type && (this._tooltipTitle = this._tooltipTitleContainer.createOrUpdateChild("tooltip-title-value", Object.assign({
            html: Object.assign(Object.assign({
                dom: titleAttr.value.text.text
            }, DEFAULT_HTML_TEXT_SPEC), titleAttr.value),
            visible: isVisible(titleAttr) && isVisible(titleAttr.value),
            width: titleAttr.value.width,
            height: titleAttr.value.height,
            wordBreak: titleAttr.value.wordBreak,
            textAlign: titleAttr.value.textAlign,
            textBaseline: titleAttr.value.textBaseline,
            singleLine: !1,
            textConfig: []
        }, titleAttr.value), "richtext"));
        const titlePaddingLeft = isVisible(titleAttr.shape) ? titleAttr.shape.size + titleAttr.shape.spacing : 0, {textAlign: textAlign, textBaseline: textBaseline} = titleAttr.value, contentWidth = panel.width - padding[3] - padding[0] - titlePaddingLeft;
        "center" === textAlign ? this._tooltipTitle.setAttribute("x", titlePaddingLeft + contentWidth / 2) : "right" === textAlign || "end" === textAlign ? this._tooltipTitle.setAttribute("x", titlePaddingLeft + contentWidth) : this._tooltipTitle.setAttribute("x", titlePaddingLeft), 
        "bottom" === textBaseline ? this._tooltipTitle.setAttribute("y", titleAttr.height) : "middle" === textBaseline ? this._tooltipTitle.setAttribute("y", titleAttr.height / 2) : this._tooltipTitle.setAttribute("y", 0);
        const titleHeight = isVisible(titleAttr) ? titleAttr.height + titleAttr.spaceRow : 0;
        if (this._tooltipContent = this.createOrUpdateChild("tooltip-content", {
            visible: !0
        }, "group"), this._tooltipContent.removeAllChild(!0), content && content.length) {
            this._tooltipContent.setAttribute("x", padding[3]), this._tooltipContent.setAttribute("y", padding[0] + titleHeight);
            let lastYPos = 0;
            content.forEach(((item, i) => {
                const itemAttr = Tooltip.getContentAttr(this.attribute, i);
                if (!isVisible(itemAttr)) return;
                const itemGroupName = `tooltip-content-${i}`, itemGroup = this._tooltipContent.createOrUpdateChild(itemGroupName, {
                    visible: !0,
                    x: 0,
                    y: lastYPos
                }, "group"), shapeOffsetWidth = itemAttr.shape.size + itemAttr.shape.spacing;
                let x = "right" === align ? (hasContentShape ? shapeOffsetWidth : 0) + (isVisible(itemAttr.key) ? keyWidth + itemAttr.key.spacing : 0) + (isVisible(itemAttr.value) ? valueWidth : 0) : 0;
                this._createShape("right" === align ? x - itemAttr.shape.size / 2 : x + itemAttr.shape.size / 2, itemAttr, itemGroup, itemGroupName), 
                hasContentShape && ("right" === align ? x -= shapeOffsetWidth : x += shapeOffsetWidth);
                const keyGraphic = this._createKey(itemAttr, itemGroup, itemGroupName);
                keyGraphic && (alignTextInLine(align, keyGraphic, itemAttr.key.textAlign, x, keyWidth), 
                keyGraphic.setAttribute("y", 0), "right" === align ? x -= keyWidth + itemAttr.key.spacing : x += keyWidth + itemAttr.key.spacing);
                const valueGraphic = this._createValue(itemAttr, itemGroup, itemGroupName);
                if (valueGraphic) {
                    let textAlign = "right";
                    isValid(itemAttr.value.textAlign) ? textAlign = itemAttr.value.textAlign : isVisible(itemAttr.key) || "right" === align || (textAlign = "left"), 
                    valueGraphic.setAttribute("textAlign", textAlign), alignTextInLine(align, valueGraphic, textAlign, x, valueWidth), 
                    valueGraphic.setAttribute("y", 0);
                }
                lastYPos += itemAttr.height + itemAttr.spaceRow;
            }));
        }
    }
    _createShape(x, itemAttr, itemGroup, itemGroupName) {
        var _a;
        if (isVisible(itemAttr.shape)) return itemGroup.createOrUpdateChild(`${itemGroupName}-shape`, Object.assign({
            visible: !0,
            x: x,
            y: itemAttr.shape.size / 2 + ((null !== (_a = calculateLineHeight(itemAttr.key.lineHeight, itemAttr.key.fontSize)) && void 0 !== _a ? _a : itemAttr.key.fontSize) - itemAttr.shape.size) / 2
        }, itemAttr.shape), "symbol");
    }
    _createKey(itemAttr, itemGroup, itemGroupName) {
        var _a;
        if (isVisible(itemAttr.key)) {
            let element;
            return element = itemAttr.key.multiLine ? itemGroup.createOrUpdateChild(`${itemGroupName}-key`, Object.assign(Object.assign({
                visible: !0
            }, getRichTextAttribute(itemAttr.key)), {
                textBaseline: "top"
            }), "richtext") : "object" != typeof itemAttr.key.text || null === itemAttr.key.text || "rich" !== itemAttr.key.text.type && "html" !== itemAttr.key.text.type ? itemGroup.createOrUpdateChild(`${itemGroupName}-key`, Object.assign(Object.assign({
                visible: !0,
                text: null !== (_a = itemAttr.key.text) && void 0 !== _a ? _a : ""
            }, itemAttr.key), {
                textBaseline: "top"
            }), "text") : "rich" === itemAttr.key.text.type ? itemGroup.createOrUpdateChild(`${itemGroupName}-value`, Object.assign(Object.assign({
                visible: !0
            }, getRichTextAttribute(itemAttr.key)), {
                textBaseline: "top"
            }), "richtext") : itemGroup.createOrUpdateChild(`${itemGroupName}-value`, {
                html: Object.assign(Object.assign({
                    dom: itemAttr.key.text.text
                }, DEFAULT_HTML_TEXT_SPEC), itemAttr.key)
            }, "richtext"), element;
        }
    }
    _createValue(itemAttr, itemGroup, itemGroupName) {
        var _a;
        if (isVisible(itemAttr.value)) {
            let element;
            return element = itemAttr.value.multiLine ? itemGroup.createOrUpdateChild(`${itemGroupName}-value`, Object.assign(Object.assign({
                visible: !0
            }, getRichTextAttribute(itemAttr.value)), {
                textBaseline: "top"
            }), "richtext") : "object" != typeof itemAttr.value.text || null === itemAttr.value.text || "rich" !== itemAttr.value.text.type && "html" !== itemAttr.value.text.type ? itemGroup.createOrUpdateChild(`${itemGroupName}-value`, Object.assign(Object.assign({
                visible: !0,
                text: null !== (_a = itemAttr.value.text) && void 0 !== _a ? _a : ""
            }, itemAttr.value), {
                textBaseline: "top"
            }), "text") : "rich" === itemAttr.value.text.type ? itemGroup.createOrUpdateChild(`${itemGroupName}-value`, Object.assign(Object.assign({
                visible: !0
            }, getRichTextAttribute(itemAttr.value)), {
                textBaseline: "top"
            }), "richtext") : itemGroup.createOrUpdateChild(`${itemGroupName}-value`, {
                html: Object.assign({
                    dom: itemAttr.value.text.text,
                    container: "",
                    width: 30,
                    height: 30,
                    style: {}
                }, itemAttr.value)
            }, "richtext"), element;
        }
    }
    setAttributes(params, forceUpdateTag) {
        const keys = Object.keys(params);
        this.attribute.autoCalculatePosition && keys.every((key => TOOLTIP_POSITION_ATTRIBUTES.includes(key))) ? (this._mergeAttributes(params, keys), 
        isNil(this.attribute.panel.width) && this.attribute.autoMeasure && Tooltip.measureTooltip(this.attribute), 
        Tooltip.calculateTooltipPosition(this.attribute), super.setAttributes({
            x: this.attribute.x,
            y: this.attribute.y
        }, forceUpdateTag)) : super.setAttributes(params, forceUpdateTag);
    }
    static calculateTooltipPosition(attribute) {
        const {width: tooltipBoxWidth = 0, height: tooltipBoxHeight = 0} = attribute.panel, {offsetX: offsetX, offsetY: offsetY, pointerX: pointerX, pointerY: pointerY, positionX: positionX, positionY: positionY, parentBounds: parentBounds} = attribute;
        let x = pointerX, y = pointerY;
        return "left" === positionX ? x -= tooltipBoxWidth + offsetX : "center" === positionX ? x -= tooltipBoxWidth / 2 : x += offsetX, 
        "top" === positionY ? y -= tooltipBoxHeight + offsetY : "middle" === positionY ? y -= tooltipBoxHeight / 2 : y += offsetY, 
        x + tooltipBoxWidth > parentBounds.x2 && (x -= tooltipBoxWidth + offsetX), y + tooltipBoxHeight > parentBounds.y2 && (y -= tooltipBoxHeight + offsetY), 
        x < parentBounds.x1 && (x = parentBounds.x1), y < parentBounds.y1 && (y = parentBounds.y1), 
        attribute.x = x, attribute.y = y, attribute;
    }
    static measureTooltip(attribute) {
        const {content: content, contentStyle: contentStyle} = attribute, padding = normalizePadding(attribute.padding), titleAttr = Tooltip.getTitleAttr(attribute);
        let maxWidth = 0, containerHeight = padding[0] + padding[2], titleMaxHeight = 0;
        const {value: titleValue, shape: titleShape} = titleAttr, {visible: titleHasShape = !1, symbolType: titleShapeType = ""} = null != titleShape ? titleShape : {};
        if (isValid(titleValue) && "object" != typeof titleAttr.value.text) {
            const {width: width, height: height} = initTextMeasure(titleValue).quickMeasure(titleValue.text);
            maxWidth = width, titleMaxHeight = height;
        }
        if (titleHasShape && builtinSymbolsMap[titleShapeType] && (maxWidth += titleShape.size + titleShape.spacing, 
        titleMaxHeight = Math.max(titleShape.size, titleMaxHeight)), attribute.title && (attribute.title.width = maxWidth, 
        attribute.title.height = titleMaxHeight), isVisible(titleAttr) && (containerHeight += titleMaxHeight + titleAttr.spaceRow), 
        content && content.length) {
            const filteredContent = [];
            if (content.forEach(((item, i) => {
                const itemAttr = Tooltip.getContentAttr(attribute, i);
                (item.key || item.value) && isVisible(itemAttr) && filteredContent.push([ item, itemAttr ]);
            })), filteredContent.length) {
                let hasContentShape = !1;
                const shapeWidths = [], keyWidths = [], valueWidths = [];
                filteredContent.forEach((([item, itemAttr], i) => {
                    var _a;
                    const {key: key, value: value, shape: shape, spaceRow: spaceRow} = itemAttr, itemHasShape = isVisible(shape), itemShapeType = null !== (_a = null == shape ? void 0 : shape.symbolType) && void 0 !== _a ? _a : "", keyTextMeasure = initTextMeasure(key), valueTextMeasure = initTextMeasure(value);
                    let itemHeight = 0;
                    if (isVisible(key)) {
                        const {width: width, height: height} = keyTextMeasure.quickMeasure(key.text);
                        keyWidths.push(width), itemHeight = Math.max(itemHeight, height);
                    }
                    if (isVisible(value)) {
                        const {width: width, height: height} = valueTextMeasure.quickMeasure(value.text);
                        valueWidths.push(width), itemHeight = Math.max(itemHeight, height);
                    }
                    itemHasShape && builtinSymbolsMap[itemShapeType] && (hasContentShape = !0, shapeWidths.push(shape.size), 
                    itemHeight = Math.max(shape.size, itemHeight)), item.height = itemHeight, containerHeight += itemHeight, 
                    i < filteredContent.length - 1 && (containerHeight += null != spaceRow ? spaceRow : contentStyle.spaceRow);
                }));
                const maxShapeWidth = shapeWidths.length ? Math.max(...shapeWidths) : 0, maxKeyWidth = keyWidths.length ? Math.max(...keyWidths) : 0, maxValueWidth = valueWidths.length ? Math.max(...valueWidths) : 0;
                maxWidth = Math.max(maxKeyWidth + maxValueWidth + contentStyle.key.spacing + contentStyle.value.spacing + (hasContentShape ? maxShapeWidth + contentStyle.shape.spacing : 0), maxWidth), 
                content.forEach((item => {
                    item.width = maxWidth;
                })), attribute.hasContentShape = hasContentShape, attribute.keyWidth = maxKeyWidth, 
                attribute.valueWidth = maxValueWidth;
            }
        }
        return attribute.panel.width = maxWidth + padding[1] + padding[3], attribute.panel.height = containerHeight, 
        attribute;
    }
    static getTitleAttr(attribute) {
        return mergeRowAttrs({}, Tooltip.defaultAttributes.titleStyle, Tooltip.defaultAttributes.title, attribute.titleStyle, attribute.title);
    }
    static getContentAttr(attribute, index) {
        return mergeRowAttrs({}, Tooltip.defaultAttributes.contentStyle, attribute.contentStyle, attribute.content[index]);
    }
}

Tooltip.defaultAttributes = defaultAttributes;
//# sourceMappingURL=tooltip.js.map
