"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PROGRESS_BAR_TARGET_SIZE = void 0;
exports.getFitValueFontSize = getFitValueFontSize;
exports.getMetricTextPartDimensions = getMetricTextPartDimensions;
exports.getFittedFontSizes = getFittedFontSizes;
exports.getFixedFontSizes = getFixedFontSizes;
exports.getSnappedFontSizes = getSnappedFontSizes;
const badge_1 = require("./badge");
const text_processing_1 = require("./text_processing");
const default_theme_attributes_1 = require("../../../../common/default_theme_attributes");
const canvas_text_bbox_calculator_1 = require("../../../../utils/bbox/canvas_text_bbox_calculator");
const common_1 = require("../../../../utils/common");
const wrap_1 = require("../../../../utils/text/wrap");
const specs_1 = require("../../specs");
exports.PROGRESS_BAR_TARGET_SIZE = 8;
const LINE_HEIGHT = 1.2;
const HEIGHT_BP = [
    [100, 150, 'xs_minus'],
    [150, 200, 'xs'],
    [200, 300, 's'],
    [300, 400, 'm'],
    [400, 500, 'l'],
    [500, 600, 'xl'],
    [600, Infinity, 'xxl'],
];
const ICON_SIZE = {
    xxxs: 16,
    xxs: 16,
    xs_minus: 16,
    xs: 16,
    s: 16,
    m: 24,
    l: 24,
    xl: 32,
    xxl: 42,
};
const TITLE_FONT_SIZE_BY_SPACING = {
    small: { xxxs: 16, xxs: 16, xs_minus: 16, xs: 16, s: 16, m: 24, l: 24, xl: 32, xxl: 42 },
    large: { xxxs: 16, xxs: 16, xs_minus: 16, xs: 16, s: 22, m: 28, l: 36, xl: 46, xxl: 64 },
};
const SUBTITLE_FONT_SIZE = {
    xxxs: 14,
    xxs: 14,
    xs_minus: 14,
    xs: 14,
    s: 14,
    m: 16,
    l: 20,
    xl: 26,
    xxl: 36,
};
const EXTRA_FONT_SIZE_BY_SPACING = {
    small: { xxxs: 14, xxs: 14, xs_minus: 14, xs: 14, s: 14, m: 16, l: 20, xl: 26, xxl: 36 },
    large: { xxxs: 16, xxs: 16, xs_minus: 16, xs: 16, s: 22, m: 28, l: 36, xl: 46, xxl: 64 },
};
const VALUE_FONT_SIZE_BY_SPACING = {
    small: {
        xxxs: 16,
        xxs: 26,
        xs_minus: 36,
        xs: 36,
        s: 42,
        m: 56,
        l: 72,
        xl: 104,
        xxl: 170,
    },
    large: {
        xxxs: 24,
        xxs: 36,
        xs_minus: 36,
        xs: 50,
        s: 64,
        m: 84,
        l: 120,
        xl: 156,
        xxl: 156,
    },
};
const VALUE_PART_FONT_RATIO = 1.3;
const BASE_TEXT_FONT = {
    fontStyle: 'normal',
    fontFamily: default_theme_attributes_1.DEFAULT_FONT_FAMILY,
    fontVariant: 'normal',
    fontWeight: 'normal',
    textColor: 'black',
};
const PROGRESS_BAR_THICKNESS = {
    xxxs: 4,
    xxs: 4,
    xs_minus: 4,
    xs: 4,
    s: 4,
    m: 8,
    l: 8,
    xl: 8,
    xxl: 16,
};
const DEFAULT_PANEL_PADDING = 8;
const DEFAULT_TITLE_SUBTITLE_GAP = 5;
const DEFAULT_EXTRA_PADDING_TOP = 5;
const DEFAULT_PRIMARY_ADJACENT_GAP = 0;
const LARGE_TITLE_SUBTITLE_GAP = 8;
const LARGE_PRIMARY_ADJACENT_GAP = 4;
const LARGE_PANEL_PADDING = {
    xxxs: 16,
    xxs: 16,
    xs_minus: 16,
    xs: 16,
    s: 24,
    m: 24,
    l: 32,
    xl: 40,
    xxl: 48,
};
function getMetricSpacingMode(style) {
    return style.spacing ?? 'small';
}
function getHeightBreakpoint(ranges, value) {
    const range = ranges.find(([min, max]) => min <= value && value < max);
    return range ? range[2] : ranges[0]?.[2] ?? 's';
}
function getValueFontSizeMap(spacingMode) {
    return VALUE_FONT_SIZE_BY_SPACING[spacingMode];
}
function getValueFontSizeSteps(spacingMode) {
    const valueFontSizeMap = getValueFontSizeMap(spacingMode);
    return [
        valueFontSizeMap.xl,
        valueFontSizeMap.l,
        valueFontSizeMap.m,
        valueFontSizeMap.s,
        valueFontSizeMap.xs,
        valueFontSizeMap.xs_minus,
        valueFontSizeMap.xxs,
        valueFontSizeMap.xxxs,
    ];
}
function getMetricSpacingLayout(breakPoint, style) {
    if (getMetricSpacingMode(style) === 'small') {
        return {
            panelPadding: DEFAULT_PANEL_PADDING,
            titleSubtitleGap: DEFAULT_TITLE_SUBTITLE_GAP,
            extraPaddingTop: style.valuePosition === 'middle' ? 0 : DEFAULT_EXTRA_PADDING_TOP,
            primaryAdjacentGap: DEFAULT_PRIMARY_ADJACENT_GAP,
            progressTextGap: DEFAULT_PANEL_PADDING,
        };
    }
    const panelPadding = LARGE_PANEL_PADDING[breakPoint];
    return {
        panelPadding,
        titleSubtitleGap: LARGE_TITLE_SUBTITLE_GAP,
        extraPaddingTop: 0,
        primaryAdjacentGap: LARGE_PRIMARY_ADJACENT_GAP,
        progressTextGap: panelPadding,
    };
}
function getMetricFont(fontFamily, fontWeight) {
    return {
        ...BASE_TEXT_FONT,
        fontFamily,
        fontWeight,
    };
}
function getFitValueFontSize(initialValueFontSize, totalWidth, availableHeight, textParts, minValueFontSize, hasIcon, isFitMode, panelPadding, fontFamily = default_theme_attributes_1.DEFAULT_FONT_FAMILY) {
    const maxWidth = (totalWidth - 2 * panelPadding) * 0.98;
    const maxHeight = (availableHeight - 2 * panelPadding) * 0.98;
    const widthConstrainedSize = (0, canvas_text_bbox_calculator_1.withTextMeasure)((textMeasure) => {
        const iconMultiplier = hasIcon ? 1 : 0;
        const valueFont = getMetricFont(fontFamily, 500);
        const textWidth = textParts.reduce((sum, { text, emphasis }) => {
            const fontSize = emphasis === 'small' ? Math.floor(initialValueFontSize / VALUE_PART_FONT_RATIO) : initialValueFontSize;
            return sum + textMeasure(text, valueFont, fontSize).width;
        }, 0);
        const ratio = textWidth / initialValueFontSize;
        return (maxWidth - iconMultiplier * panelPadding) / (ratio + iconMultiplier / VALUE_PART_FONT_RATIO);
    });
    let constrainedSize;
    if (isFitMode) {
        const heightConstrainedSize = Math.floor(maxHeight / LINE_HEIGHT);
        constrainedSize = Math.min(widthConstrainedSize, heightConstrainedSize);
    }
    else {
        constrainedSize = Math.min(initialValueFontSize, widthConstrainedSize);
    }
    return Math.floor(Math.max(constrainedSize, minValueFontSize));
}
function getMetricTextPartDimensions(datum, panel, style, locale) {
    const breakPoint = getHeightBreakpoint(HEIGHT_BP, panel.height);
    const metricSpacing = getMetricSpacingLayout(breakPoint, style);
    const heightBasedSizes = getHeightBasedFontSizes(HEIGHT_BP, panel.height, style);
    const hasProgressBar = (0, specs_1.isMetricWProgress)(datum);
    const hasTarget = !(0, common_1.isNil)(datum?.target);
    const progressBarDirection = (0, specs_1.isMetricWProgress)(datum) ? datum.progressBarDirection : undefined;
    const hasVerticalProgressBar = hasProgressBar && progressBarDirection === common_1.LayoutDirection.Vertical;
    const hasHorizontalProgressBar = hasProgressBar && progressBarDirection === common_1.LayoutDirection.Horizontal;
    const { progressBarThickness, iconSize } = heightBasedSizes;
    const progressBarTotalSpace = progressBarThickness + (hasTarget ? exports.PROGRESS_BAR_TARGET_SIZE : 0) + metricSpacing.progressTextGap;
    const progressBarWidth = hasVerticalProgressBar ? progressBarTotalSpace : 0;
    const progressBarHeight = hasHorizontalProgressBar ? progressBarTotalSpace : 0;
    const isIconVisible = !!datum.icon && style.valuePosition === 'top';
    const iconColumnWidth = iconSize + metricSpacing.panelPadding;
    const needsCenterSpacer = isIconVisible && style.valueTextAlign === 'center';
    const iconGridColumnWidth = isIconVisible ? iconColumnWidth * (needsCenterSpacer ? 2 : 1) : 0;
    return {
        heightBasedSizes,
        metricSpacing,
        hasProgressBar,
        progressBarDirection,
        progressBarWidth,
        visibility: computeMetricTextLayout(datum, panel, heightBasedSizes, locale, style.valueFontSize === 'fit', progressBarHeight, metricSpacing, style.fontFamily, style.valuePosition),
        textParts: (0, text_processing_1.getTextParts)(datum, style),
        iconGridColumnWidth,
    };
}
function getHeightBasedFontSizes(ranges, value, style) {
    const size = getHeightBreakpoint(ranges, value);
    const spacingMode = getMetricSpacingMode(style);
    const valueFontSizeMap = getValueFontSizeMap(spacingMode);
    const valueFontSize = typeof style.valueFontSize === 'number' ? style.valueFontSize : valueFontSizeMap[size];
    const valuePartFontSize = Math.floor(valueFontSize / VALUE_PART_FONT_RATIO);
    const extraFontSize = EXTRA_FONT_SIZE_BY_SPACING[spacingMode][size];
    return {
        iconSize: ICON_SIZE[size],
        titleFontSize: TITLE_FONT_SIZE_BY_SPACING[spacingMode][size],
        subtitleFontSize: SUBTITLE_FONT_SIZE[size],
        extraFontSize,
        valueFontSize,
        valuePartFontSize,
        progressBarThickness: PROGRESS_BAR_THICKNESS[size],
    };
}
function getFittedFontSizes(fittedValueFontSize) {
    return {
        valueFontSize: fittedValueFontSize,
        valuePartFontSize: Math.floor(fittedValueFontSize / VALUE_PART_FONT_RATIO),
    };
}
function getFixedFontSizes(fixedFontSize) {
    return {
        valueFontSize: fixedFontSize,
        valuePartFontSize: Math.floor(fixedFontSize / VALUE_PART_FONT_RATIO),
    };
}
function getSnappedFontSizes(fittedValueFontSize, panelHeight, style) {
    const spacingMode = getMetricSpacingMode(style);
    const valueFontSizes = getValueFontSizeSteps(spacingMode);
    const valueFontSizeMap = getValueFontSizeMap(spacingMode);
    const sizes = getHeightBasedFontSizes(HEIGHT_BP, panelHeight, style);
    const minFontSize = Math.min(fittedValueFontSize, sizes.valueFontSize);
    const fontSize = (0, common_1.clamp)(valueFontSizes.find((value) => value <= minFontSize) ?? minFontSize, valueFontSizeMap.xxxs, valueFontSizeMap.xxl);
    return {
        valueFontSize: fontSize,
        valuePartFontSize: Math.floor(fontSize / VALUE_PART_FONT_RATIO),
    };
}
const getResponsiveBreakpoints = (title, subtitle, extra) => [
    { titleMaxLines: 3, subtitleMaxLines: 2, title, subtitle, extra },
    { titleMaxLines: 3, subtitleMaxLines: 1, title, subtitle, extra },
    { titleMaxLines: 2, subtitleMaxLines: 1, title, subtitle, extra },
    { titleMaxLines: 1, subtitleMaxLines: 1, title, subtitle, extra },
    { titleMaxLines: 1, subtitleMaxLines: 0, title, subtitle: false, extra },
    { titleMaxLines: 1, subtitleMaxLines: 0, title, subtitle: false, extra: false },
    { titleMaxLines: 1, subtitleMaxLines: 0, title, subtitle: false, extra: false },
];
function computeMetricTextLayout(datum, panel, sizes, locale, fit, progressBarHeight, metricSpacing, fontFamily, valuePosition) {
    const { panelPadding, titleSubtitleGap, extraPaddingTop, primaryAdjacentGap } = metricSpacing;
    const maxTitlesWidth = 0.95 * panel.width - (datum.icon ? 24 : 0) - 2 * panelPadding;
    const titleFont = getMetricFont(fontFamily, 'bold');
    const subtitleFont = getMetricFont(fontFamily, 'normal');
    const titleLineHeight = sizes.titleFontSize * LINE_HEIGHT;
    const subtitleLineHeight = sizes.subtitleFontSize * LINE_HEIGHT;
    const hasBadge = !!(datum?.extra && 'badgeColor' in datum?.extra && datum?.extra?.badgeColor);
    const badgeHeight = hasBadge ? (badge_1.BADGE_BORDER + badge_1.BADGE_PADDING_BLOCK) * 2 : 0;
    const extraHeight = sizes.extraFontSize * LINE_HEIGHT + badgeHeight;
    const valueHeight = sizes.valueFontSize * LINE_HEIGHT;
    const responsiveBreakPoints = getResponsiveBreakpoints(!!datum.title, !!datum.subtitle, !!datum.extra);
    function computeMetricTextSize(breakpoints, measure) {
        const titleLines = datum.title
            ? (0, wrap_1.wrapText)(datum.title, titleFont, sizes.titleFontSize, maxTitlesWidth, breakpoints.titleMaxLines, measure, locale)
            : [];
        const subtitleLines = datum.subtitle
            ? (0, wrap_1.wrapText)(datum.subtitle, subtitleFont, sizes.subtitleFontSize, maxTitlesWidth, breakpoints.subtitleMaxLines, measure, locale)
            : [];
        const actualTitleHeight = titleLines.length > 0 ? titleLines.length * titleLineHeight : 0;
        const actualSubtitleHeight = subtitleLines.length > 0 ? subtitleLines.length * subtitleLineHeight + titleSubtitleGap : 0;
        const actualExtraHeight = breakpoints.extra ? extraHeight + extraPaddingTop : 0;
        const primaryToTitleGap = valuePosition === 'top' && titleLines.length > 0 ? primaryAdjacentGap : 0;
        const primaryToSecondaryGap = valuePosition === 'bottom' && breakpoints.extra ? primaryAdjacentGap : 0;
        const nonValueElementsHeight = actualTitleHeight +
            actualSubtitleHeight +
            actualExtraHeight +
            primaryToTitleGap +
            primaryToSecondaryGap +
            progressBarHeight +
            panelPadding * 2;
        const totalHeight = nonValueElementsHeight + valueHeight;
        return {
            titleLines,
            subtitleLines,
            actualTitleHeight,
            actualSubtitleHeight,
            actualExtraHeight,
            nonValueElementsHeight,
            totalHeight,
        };
    }
    const isVisible = (breakpoints, measure) => {
        const { totalHeight } = computeMetricTextSize(breakpoints, measure);
        return totalHeight <= panel.height;
    };
    return (0, canvas_text_bbox_calculator_1.withTextMeasure)((textMeasure) => {
        let visibilityBreakpoint;
        if (fit) {
            visibilityBreakpoint = responsiveBreakPoints.at(0);
        }
        else {
            const found = responsiveBreakPoints.find((breakpoint) => isVisible(breakpoint, textMeasure));
            visibilityBreakpoint = found ?? responsiveBreakPoints.at(-1);
        }
        const layoutInfo = computeMetricTextSize(visibilityBreakpoint, textMeasure);
        const availableHeightWithoutValue = Math.max(0, panel.height - layoutInfo.nonValueElementsHeight);
        const gapHeight = Math.max(0, panel.height - layoutInfo.totalHeight);
        return {
            ...visibilityBreakpoint,
            titleLines: layoutInfo.titleLines,
            subtitleLines: layoutInfo.subtitleLines,
            gapHeight,
            availableHeightWithoutValue,
        };
    });
}
//# sourceMappingURL=text_measurements.js.map