"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderBars = renderBars;
exports.getBarStyleOverrides = getBarStyleOverrides;
const points_1 = require("./points");
const utils_1 = require("./utils");
const common_1 = require("../../../utils/common");
const geometry_1 = require("../../../utils/geometry");
const indexed_geometry_map_1 = require("../utils/indexed_geometry_map");
const series_1 = require("../utils/series");
const specs_1 = require("../utils/specs");
const PADDING = 1;
const FONT_SIZE_FACTOR = 0.7;
function renderBars(measureText, orderIndex, dataSeries, xScale, yScale, panel, chartRotation, minBarHeight, color, isBandedSpec, sharedSeriesStyle, displayValueSettings, styleAccessor, stackMode) {
    const initialBarTuple = { barGeometries: [], indexedGeometryMap: new indexed_geometry_map_1.IndexedGeometryMap() };
    const y1Fn = (0, utils_1.getY1ScaledValueFn)(yScale);
    const y0Fn = (0, utils_1.getY0ScaledValueFn)(yScale);
    const seriesIdentifier = (0, series_1.getSeriesIdentifierFromDataSeries)(dataSeries);
    return dataSeries.data.reduce((barTuple, datum) => {
        const xScaled = xScale.scale(datum.x);
        if (!xScale.isValueInDomain(datum.x) || Number.isNaN(xScaled)) {
            return barTuple;
        }
        const { barGeometries, indexedGeometryMap } = barTuple;
        const { y1, initialY1, filled } = datum;
        const y1Scaled = y1Fn(datum);
        const y0Scaled = y0Fn(datum);
        const yDiff = Math.abs(y1Scaled - y0Scaled);
        const addedMinBarHeight = yDiff === 0 || yDiff >= minBarHeight ? 0 : minBarHeight - yDiff;
        const yScreenSpaceCoord = Math.min(y1Scaled, y0Scaled) +
            (isBandedSpec ? -addedMinBarHeight / 2 : -addedMinBarHeight * ((y1 ?? 0) >= 0 ? 1 : 0));
        const height = yDiff + addedMinBarHeight;
        const seriesStyle = getBarStyleOverrides(datum, seriesIdentifier, sharedSeriesStyle, styleAccessor);
        const maxPixelWidth = (0, common_1.clamp)(seriesStyle.rect.widthRatio ?? 1, 0, 1) * xScale.bandwidth;
        const minPixelWidth = (0, common_1.clamp)(seriesStyle.rect.widthPixel ?? 0, 0, maxPixelWidth);
        const width = (0, common_1.clamp)(seriesStyle.rect.widthPixel ?? xScale.bandwidth, minPixelWidth, maxPixelWidth);
        const x = xScaled + xScale.bandwidth * orderIndex + xScale.bandwidth / 2 - width / 2;
        const y1Value = (0, points_1.getDatumYValue)(datum, false, isBandedSpec, stackMode);
        const shouldDisplayValue = displayValueSettings?.showValueLabel &&
            !(displayValueSettings?.isAlternatingValueLabel && barGeometries.length % 2);
        const barGeometry = {
            displayValue: shouldDisplayValue
                ? computeDisplayValue(y1Value, sharedSeriesStyle, measureText, chartRotation, width, displayValueSettings)
                : undefined,
            x,
            y: yScreenSpaceCoord,
            transform: { x: 0, y: 0 },
            width,
            height,
            color,
            value: { x: datum.x, y: y1Value, mark: null, accessor: geometry_1.BandedAccessorType.Y1, datum: datum.datum },
            seriesIdentifier,
            seriesStyle,
            panel,
        };
        if (isBandedSpec) {
            indexedGeometryMap.set({
                ...barGeometry,
                value: {
                    x: datum.x,
                    y: (0, points_1.getDatumYValue)(datum, true, isBandedSpec, stackMode),
                    mark: null,
                    accessor: geometry_1.BandedAccessorType.Y0,
                    datum: datum.datum,
                },
            });
        }
        indexedGeometryMap.set(barGeometry);
        if (y1 !== null && initialY1 !== null && filled?.y1 === undefined) {
            barGeometries.push(barGeometry);
        }
        return barTuple;
    }, initialBarTuple);
}
function computeDisplayValue(y1Value, sharedSeriesStyle, measureText, chartRotation, width, displayValueSettings) {
    const { fontSize, fontFamily } = sharedSeriesStyle.displayValue;
    const displayValueText = displayValueSettings.valueFormatter(y1Value);
    if (displayValueText.length === 0) {
        return;
    }
    const { displayValueWidth, fixedFontScale } = computeBoxWidth(displayValueText, {
        padding: PADDING,
        fontSize,
        fontFamily,
        measureText,
    });
    const isHorizontalRotation = chartRotation % 180 === 0;
    const referenceWidth = Math.max(isHorizontalRotation ? displayValueWidth : fixedFontScale, 1);
    const textScalingFactor = getFinalFontScalingFactor((width * FONT_SIZE_FACTOR) / referenceWidth, fixedFontScale, fontSize);
    const overflowConstraints = new Set(displayValueSettings?.overflowConstraints ?? [
        specs_1.LabelOverflowConstraint.ChartEdges,
        specs_1.LabelOverflowConstraint.BarGeometry,
    ]);
    const bboxWidthFactor = isHorizontalRotation ? textScalingFactor : 1;
    return {
        fontScale: textScalingFactor,
        fontSize: fixedFontScale,
        text: displayValueText,
        width: bboxWidthFactor * displayValueWidth,
        height: textScalingFactor * fixedFontScale,
        overflowConstraints,
    };
}
function computeBoxWidth(text, { padding, fontSize, fontFamily, measureText, }) {
    const fixedFontScale = Math.max(typeof fontSize === 'number' ? fontSize : fontSize.min, 1);
    if (text.length === 0) {
        return { fixedFontScale, displayValueWidth: 0 };
    }
    const computedDisplayValueWidth = measureText(text, { fontFamily, fontWeight: 'normal', fontStyle: 'normal', fontVariant: 'normal' }, fixedFontScale).width;
    if (typeof fontSize !== 'number') {
        return {
            fixedFontScale,
            displayValueWidth: computedDisplayValueWidth + padding,
        };
    }
    return {
        fixedFontScale,
        displayValueWidth: computedDisplayValueWidth,
    };
}
function getFinalFontScalingFactor(scale, fixedFontSize, limits) {
    if (typeof limits === 'number') {
        return 1;
    }
    const finalFontSize = scale * fixedFontSize;
    if (finalFontSize > limits.max) {
        return limits.max / fixedFontSize;
    }
    if (finalFontSize < limits.min) {
        return limits.min / fixedFontSize;
    }
    return scale;
}
function getBarStyleOverrides(datum, seriesIdentifier, seriesStyle, styleAccessor) {
    const styleOverride = styleAccessor && styleAccessor(datum, seriesIdentifier);
    if (!styleOverride) {
        return seriesStyle;
    }
    if (typeof styleOverride === 'string') {
        return { ...seriesStyle, rect: { ...seriesStyle.rect, fill: styleOverride } };
    }
    return (0, common_1.mergePartial)(seriesStyle, styleOverride);
}
//# sourceMappingURL=bars.js.map