import { isContinuous, isDiscrete } from "@visactor/vscale";

import { getDatumByValue } from "./common";

import { getAxisLabelOffset } from "../../axis/util";

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

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

export const layoutByValue = (stateByField, series, layoutStartPoint, enableRemain = !1) => (layoutStartPoint || (layoutStartPoint = {
    x: 0,
    y: 0
}), Object.keys(stateByField).forEach((field => {
    var _a, _b, _c, _d, _e;
    const {currentValue: currentValue, cacheInfo: cacheInfo, labelsComp: labelsComp, attributes: attributes, coordKey: coordKey} = stateByField[field];
    let axis = null, coord = 0, axisLabel = null;
    if (currentValue.size) {
        const item = Array.from(currentValue.values())[0];
        coord = item.axis.getScale().scale(item.datum) + item.axis.getLayoutStartPoint()[coordKey] - layoutStartPoint[coordKey], 
        axis = item.axis, axisLabel = null === (_e = null === (_d = null === (_c = null === (_b = null === (_a = axis.getVRenderComponents()[0]) || void 0 === _a ? void 0 : _a.children[0]) || void 0 === _b ? void 0 : _b.children[0]) || void 0 === _c ? void 0 : _c.getChildByName("axis-label-container")) || void 0 === _d ? void 0 : _d.getChildByName("axis-label-container-layer-0")) || void 0 === _e ? void 0 : _e.children[0];
    }
    const isVisible = !!currentValue.size && Number.isFinite(coord) && !Number.isNaN(coord), useCache = enableRemain && !isVisible && isValid(cacheInfo), newCacheInfo = useCache ? cacheInfo : {
        coordRange: [ 0, 0 ],
        sizeRange: [ 0, 0 ],
        coord: coord,
        labelsTextStyle: {},
        labels: labelsComp ? Object.keys(labelsComp).reduce(((res, labelKey) => (res[labelKey] = {
            visible: !1,
            text: "",
            dx: 0,
            dy: 0
        }, res)), {}) : null,
        visible: isVisible,
        axis: axis,
        axisLabel: axisLabel
    };
    let bandSize;
    newCacheInfo && (newCacheInfo._isCache = useCache);
    let offsetSize = 0;
    if (attributes && currentValue.forEach((({axis: axis, datum: value = ""}) => {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
        let niceLabelFormatter = null;
        const scale = axis.getScale();
        if (isDiscrete(scale.type)) bandSize = scale.bandwidth(), 0 === bandSize && scale.step && (offsetSize = scale.step()); else if (isContinuous(scale.type)) {
            const field1 = "xField" === field ? series.fieldX[0] : series.fieldY[0], field2 = "xField" === field ? series.fieldX2 : series.fieldY2, datum = getDatumByValue(series.getViewData().latestData, +value, field1, field2);
            if (datum) {
                const startX = "xField" === field ? series.dataToPositionX(datum) : series.dataToPositionY(datum);
                field2 ? (bandSize = Math.abs(startX - ("xField" === field ? series.dataToPositionX1(datum) : series.dataToPositionY1(datum))), 
                value = `${datum[field1]} ~ ${datum[field2]}`) : bandSize = 1, coord = startX;
            }
            niceLabelFormatter = axis.niceLabelFormatter;
        }
        if (newCacheInfo && (null === (_a = attributes.label) || void 0 === _a ? void 0 : _a.visible) && !useCache) {
            const labelOffset = getAxisLabelOffset(axis.getSpec()), axisOrient = axis.getOrient(), syncAxisLabelAngle = null === (_b = attributes.label) || void 0 === _b ? void 0 : _b.syncAxisLabelAngle;
            newCacheInfo.labels[axisOrient] && (newCacheInfo.labels[axisOrient].visible = !0, 
            newCacheInfo.labels[axisOrient].text = value, "left" === axisOrient ? (newCacheInfo.labels[axisOrient].dx = -labelOffset, 
            newCacheInfo.labelsTextStyle[axisOrient] = {
                textAlign: syncAxisLabelAngle && axisLabel && null !== (_c = axisLabel.attribute.textAlign) && void 0 !== _c ? _c : "right",
                textBaseline: syncAxisLabelAngle && axisLabel && null !== (_d = axisLabel.attribute.textBaseline) && void 0 !== _d ? _d : "middle"
            }) : "right" === axisOrient ? (newCacheInfo.labels[axisOrient].dx = labelOffset, 
            newCacheInfo.labelsTextStyle[axisOrient] = {
                textAlign: syncAxisLabelAngle && axisLabel && null !== (_e = axisLabel.attribute.textAlign) && void 0 !== _e ? _e : "left",
                textBaseline: syncAxisLabelAngle && axisLabel && null !== (_f = axisLabel.attribute.textBaseline) && void 0 !== _f ? _f : "middle"
            }) : "top" === axisOrient ? (newCacheInfo.labels[axisOrient].y = 0, newCacheInfo.labels[axisOrient].dy = -labelOffset, 
            newCacheInfo.labelsTextStyle[axisOrient] = {
                textAlign: syncAxisLabelAngle && axisLabel && null !== (_g = axisLabel.attribute.textAlign) && void 0 !== _g ? _g : "center",
                textBaseline: syncAxisLabelAngle && axisLabel && null !== (_h = axisLabel.attribute.textBaseline) && void 0 !== _h ? _h : "bottom"
            }) : "bottom" === axisOrient && (newCacheInfo.labels[axisOrient].dy = labelOffset, 
            newCacheInfo.labelsTextStyle[axisOrient] = {
                textAlign: syncAxisLabelAngle && axisLabel && null !== (_j = axisLabel.attribute.textAlign) && void 0 !== _j ? _j : "center",
                textBaseline: syncAxisLabelAngle && axisLabel && null !== (_k = axisLabel.attribute.textBaseline) && void 0 !== _k ? _k : "top"
            }), newCacheInfo.labels[axisOrient].defaultFormatter = niceLabelFormatter);
        }
    })), newCacheInfo && !useCache) {
        const region = {
            x1: 1 / 0,
            y1: 1 / 0,
            x2: -1 / 0,
            y2: -1 / 0
        };
        setRegionArea(region, currentValue), "xField" === field ? (newCacheInfo.coordRange = [ region.x1, region.x2 ], 
        newCacheInfo.sizeRange = [ region.y1, region.y2 ], newCacheInfo.coord = coord + layoutStartPoint.x, 
        newCacheInfo.labels && (newCacheInfo.labels.top.y = region.y1, newCacheInfo.labels.bottom.y = region.y2)) : (newCacheInfo.coordRange = [ region.y1, region.y2 ], 
        newCacheInfo.sizeRange = [ region.x1, region.x2 ], newCacheInfo.coord = coord + layoutStartPoint.y, 
        newCacheInfo.labels && (newCacheInfo.labels.left.x = region.x1, newCacheInfo.labels.right.x = region.x2)), 
        (newCacheInfo.coord < newCacheInfo.coordRange[0] || newCacheInfo.coord > newCacheInfo.coordRange[1]) && (newCacheInfo.visible = !1), 
        attributes && attributes.label && Object.keys(newCacheInfo.labels).forEach((labelKey => {
            newCacheInfo.labels[labelKey].visible && setFormattedCrosshairLabel(newCacheInfo.labels[labelKey], labelKey, attributes.label);
        }));
    }
    stateByField[field].bandSize = null != bandSize ? bandSize : 0, stateByField[field].offsetSize = offsetSize, 
    stateByField[field].cacheInfo = newCacheInfo;
})), stateByField);

const setFormattedCrosshairLabel = (labelInfo, position, labelSpec) => {
    const {formatMethod: formatMethod, formatter: formatter} = labelSpec, {formatFunc: formatFunc, args: args} = getFormatFunction(formatMethod, formatter, labelInfo.text, {
        label: labelInfo.text,
        position: position
    });
    formatFunc ? labelInfo.text = formatFunc(...args) : labelInfo.defaultFormatter && (labelInfo.text = labelInfo.defaultFormatter(labelInfo.text));
}, setRegionArea = (outRegion, currentValue) => {
    currentValue.forEach((({axis: axis}) => {
        axis.getRegions().forEach((r => {
            const {x: x, y: y} = r.getLayoutStartPoint(), {width: width, height: height} = r.getLayoutRect();
            outRegion.x1 = Math.min(outRegion.x1, x), outRegion.y1 = Math.min(outRegion.y1, y), 
            outRegion.x2 = Math.max(outRegion.x2, x + width), outRegion.y2 = Math.max(outRegion.y2, y + height);
        }));
    }));
};

export const layoutCrosshair = stateItem => {
    const {cacheInfo: cacheInfo, attributes: attributes, bandSize: bandSize, offsetSize: offsetSize, coordKey: coordKey, anotherAxisKey: anotherAxisKey} = stateItem, {coord: coord, sizeRange: sizeRange} = cacheInfo, type = attributes.type;
    let positionAttribute;
    if ("line" === type) {
        const pos = coord + bandSize / 2;
        positionAttribute = {
            visible: !0,
            start: {
                [coordKey]: pos,
                [anotherAxisKey]: sizeRange[0]
            },
            end: {
                [coordKey]: pos,
                [anotherAxisKey]: sizeRange[1]
            }
        };
    } else if ("rect" === type) {
        const [offset0, offset1] = getRectSize(attributes, bandSize, offsetSize, cacheInfo.axis), {coordRange: coordRange} = cacheInfo;
        positionAttribute = {
            visible: !0,
            start: {
                [coordKey]: Math.max(coord + offset0, coordRange[0]),
                [anotherAxisKey]: sizeRange[0]
            },
            end: {
                [coordKey]: Math.min(coord + offset1, coordRange[1]),
                [anotherAxisKey]: sizeRange[1]
            }
        };
    }
    return positionAttribute;
};

const getRectSize = (hair, bandSize, offsetSize, axis) => {
    var _a, _b, _c;
    const visualSize = 0 === bandSize ? offsetSize : bandSize;
    let size = visualSize;
    if (null === (_a = hair.style) || void 0 === _a ? void 0 : _a.sizePercent) size = visualSize * hair.style.sizePercent; else if ("number" == typeof (null === (_b = hair.style) || void 0 === _b ? void 0 : _b.size)) size = hair.style.size; else if ("function" == typeof (null === (_c = hair.style) || void 0 === _c ? void 0 : _c.size)) {
        const axisRect = axis.getLayoutRect();
        size = hair.style.size(axisRect, axis);
    }
    return 0 === bandSize ? [ -size / 2, size / 2 ] : [ bandSize / 2 - size / 2, size / 2 + bandSize / 2 ];
};
//# sourceMappingURL=cartesian.js.map
