import { compareRangeCovs } from "./compare";
export function emitForest(trees) {
    return emitForestLines(trees).join("\n");
}
export function emitForestLines(trees) {
    const colMap = getColMap(trees);
    const header = emitOffsets(colMap);
    return [header, ...trees.map(tree => emitTree(tree, colMap).join("\n"))];
}
function getColMap(trees) {
    const eventSet = new Set();
    for (const tree of trees) {
        const stack = [tree];
        while (stack.length > 0) {
            const cur = stack.pop();
            eventSet.add(cur.start);
            eventSet.add(cur.end);
            for (const child of cur.children) {
                stack.push(child);
            }
        }
    }
    const events = [...eventSet];
    events.sort((a, b) => a - b);
    let maxDigits = 1;
    for (const event of events) {
        maxDigits = Math.max(maxDigits, event.toString(10).length);
    }
    const colWidth = maxDigits + 3;
    const colMap = new Map();
    for (const [i, event] of events.entries()) {
        colMap.set(event, i * colWidth);
    }
    return colMap;
}
function emitTree(tree, colMap) {
    const layers = [];
    let nextLayer = [tree];
    while (nextLayer.length > 0) {
        const layer = nextLayer;
        layers.push(layer);
        nextLayer = [];
        for (const node of layer) {
            for (const child of node.children) {
                nextLayer.push(child);
            }
        }
    }
    return layers.map(layer => emitTreeLayer(layer, colMap));
}
export function parseFunctionRanges(text, offsetMap) {
    const result = [];
    for (const line of text.split("\n")) {
        for (const range of parseTreeLayer(line, offsetMap)) {
            result.push(range);
        }
    }
    result.sort(compareRangeCovs);
    return result;
}
/**
 *
 * @param layer Sorted list of disjoint trees.
 * @param colMap
 */
function emitTreeLayer(layer, colMap) {
    const line = [];
    let curIdx = 0;
    for (const { start, end, count } of layer) {
        const startIdx = colMap.get(start);
        const endIdx = colMap.get(end);
        if (startIdx > curIdx) {
            line.push(" ".repeat(startIdx - curIdx));
        }
        line.push(emitRange(count, endIdx - startIdx));
        curIdx = endIdx;
    }
    return line.join("");
}
function parseTreeLayer(text, offsetMap) {
    const result = [];
    const regex = /\[(\d+)-*\)/gs;
    while (true) {
        const match = regex.exec(text);
        if (match === null) {
            break;
        }
        const startIdx = match.index;
        const endIdx = startIdx + match[0].length;
        const count = parseInt(match[1], 10);
        const startOffset = offsetMap.get(startIdx);
        const endOffset = offsetMap.get(endIdx);
        if (startOffset === undefined || endOffset === undefined) {
            throw new Error(`Invalid offsets for: ${JSON.stringify(text)}`);
        }
        result.push({ startOffset, endOffset, count });
    }
    return result;
}
function emitRange(count, len) {
    const rangeStart = `[${count.toString(10)}`;
    const rangeEnd = ")";
    const hyphensLen = len - (rangeStart.length + rangeEnd.length);
    const hyphens = "-".repeat(Math.max(0, hyphensLen));
    return `${rangeStart}${hyphens}${rangeEnd}`;
}
function emitOffsets(colMap) {
    let line = "";
    for (const [event, col] of colMap) {
        if (line.length < col) {
            line += " ".repeat(col - line.length);
        }
        line += event.toString(10);
    }
    return line;
}
export function parseOffsets(text) {
    const result = new Map();
    const regex = /\d+/gs;
    while (true) {
        const match = regex.exec(text);
        if (match === null) {
            break;
        }
        result.set(match.index, parseInt(match[0], 10));
    }
    return result;
}

//# sourceMappingURL=data:application/json;charset=utf8;base64,[encoded data, 12548 characters]
