"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrapText = wrapText;
const text_utils_1 = require("../../common/text_utils");
const monotonic_hill_climb_1 = require("../../solvers/monotonic_hill_climb");
function wrapText(text, font, fontSize, maxLineWidth, maxLines, measure, locale, granularity = 'word') {
    const lines = [];
    lines.meta = {
        truncated: false,
    };
    if (maxLines <= 0) {
        return lines;
    }
    const segmenter = textSegmenter(locale, granularity);
    const cleanedText = text.replaceAll('\n', ' ').replaceAll(/ +(?= )/g, '');
    const segments = Array.from(segmenter(cleanedText)).map((d) => ({
        ...d,
        width: measure(d.segment, font, fontSize).width,
    }));
    const ellipsisWidth = measure(text_utils_1.ELLIPSIS, font, fontSize).width;
    let currentLineWidth = 0;
    for (const segment of segments) {
        if (currentLineWidth + segment.width > maxLineWidth && segment.segment.trimStart().length > 0) {
            const multilineText = breakLongTextIntoLines(segment.segment, font, fontSize, maxLineWidth, Infinity, measure);
            if (multilineText.length === 0) {
                break;
            }
            lines.push(...multilineText);
            currentLineWidth = multilineText.length > 0 ? measure(multilineText.at(-1) ?? '', font, fontSize).width : 0;
        }
        else {
            const lineIndex = lines.length > 0 ? lines.length - 1 : 0;
            lines[lineIndex] = (lines[lineIndex] ?? '') + segment.segment;
            currentLineWidth += segment.width;
        }
    }
    if (lines.length > maxLines) {
        lines.meta.truncated = true;
        const lastLineMaxLineWidth = maxLineWidth - ellipsisWidth;
        const lineToTruncate = lines[maxLines - 1] ?? '';
        const lastLine = clipTextToWidth(lineToTruncate, font, fontSize, lastLineMaxLineWidth, measure);
        if (lastLine.length > 0) {
            lines.splice(maxLines - 1, Infinity, `${lastLine}${text_utils_1.ELLIPSIS}`);
        }
        else {
            if (lastLineMaxLineWidth > 0) {
                lines.splice(maxLines - 1, Infinity, maxLines > 1 ? text_utils_1.ELLIPSIS : lineToTruncate.slice(0, 1));
            }
            else {
                lines.splice(maxLines, Infinity);
            }
        }
    }
    return lines;
}
function textSegmenter(locale, granularity) {
    if ('Segmenter' in Intl) {
        const fn = new Intl.Segmenter(locale, { granularity });
        return (text) => Array.from(fn.segment(text));
    }
    else {
        return (text) => {
            return text
                .split(' ')
                .reduce((acc, segment, index, array) => {
                const currentSegment = {
                    segment,
                    index: index === 0 ? 0 : (acc.at(-1)?.index ?? 0) + 1,
                    isWordLike: true,
                };
                acc.push(currentSegment);
                if (index < array.length - 1) {
                    acc.push({ segment: ' ', index: currentSegment.index + segment.length, isWordLike: false });
                }
                return acc;
            }, []);
        };
    }
}
function breakLongTextIntoLines(text, font, fontSize, lineWidth, maxLines, measure) {
    const lines = [];
    let remainingText = text;
    while (maxLines > lines.length && remainingText.length > 0) {
        const lineClippedText = clipTextToWidth(remainingText, font, fontSize, lineWidth, measure);
        if (lineClippedText.length === 0) {
            break;
        }
        else {
            lines.push(lineClippedText.trimStart());
            remainingText = remainingText.slice(lineClippedText.length, Infinity);
        }
    }
    return lines;
}
function clipTextToWidth(text, font, fontSize, width, measure) {
    const maxCharsInLine = (0, monotonic_hill_climb_1.monotonicHillClimb)((chars) => measure(text.slice(0, chars), font, fontSize).width, text.length, width, (n) => Math.floor(n), 0);
    return text.slice(0, maxCharsInLine || 0);
}
//# sourceMappingURL=wrap.js.map