import { addToRow } from './util/tree';
// The most recent requestId
let requestId = 0;
self.addEventListener('message', (event) => {
    const data = event.data;
    requestId = Math.max(requestId, data?.requestId || 0);
    switch (data.type) {
        case 'calculateSpanPositions':
            calculateSpanPositions(data.root);
            break;
        case 'filterSpans':
            filterSpans(data.root, data.filter);
            break;
        default:
            break;
    }
});
const positionHelper = (node, pending) => {
    if ('parent' in node) {
        const n = node;
        n.row = -1;
        n.isVisible = true;
        pending.push(n);
    }
    const sortedChildren = node.children
        .slice()
        .sort((a, b) => a.startTime - b.startTime || b.duration - a.duration);
    for (const child of sortedChildren) {
        positionHelper(child, pending);
    }
};
const calculateSpanPositions = (root) => {
    const responseId = requestId;
    const placed = [];
    const pending = [];
    positionHelper(root, pending);
    let lastFlushT = Date.now() - 10;
    let lastFlushC = -64;
    let count = 0;
    const flush = () => {
        for (const row of placed) {
            row.sort((a, b) => a.startTime - b.startTime);
        }
        const message = {
            requestId: responseId,
            type: 'setRowsResult',
            rows: placed,
            isEnd: !pending.length,
        };
        postMessage(message);
        lastFlushT = Date.now();
        lastFlushC = count;
    };
    while (true) {
        const node = pending.shift();
        if (!node) {
            flush();
            return;
        }
        addToRow(placed, node, 0.001);
        ++count;
        if (Date.now() - lastFlushT >= 15 || count - lastFlushC >= 256) {
            flush();
        }
    }
};
const ATTR_FILTER_REGEX = /(?<=^|\s)(?<pair>(?<key>[\w.]+):(?<value>\S*))/g;
const filterSpans = (root, filter) => {
    const responseId = requestId;
    const matches = new Set();
    const name = filter
        .replace(ATTR_FILTER_REGEX, '')
        .replace(/\s{2,}/g, ' ')
        .trim();
    const attrs = [];
    for (const m of filter.matchAll(ATTR_FILTER_REGEX)) {
        const { key = '', value = '' } = m.groups || {};
        attrs.push([key, value.toLocaleLowerCase()]);
    }
    const match = (span) => {
        if (!span.name.toLocaleLowerCase().includes(name))
            return false;
        // TODO: support resource attribute filtering
        return attrs.every(([key, value]) => {
            const v = span.attributes[key];
            if (!v)
                return false;
            return String(v).toLocaleLowerCase().includes(value);
        });
    };
    const helper = (node) => {
        for (const child of node.children) {
            if (match(child.span)) {
                matches.add(child.span.spanId);
            }
            helper(child);
        }
    };
    helper(root);
    const message = {
        requestId: responseId,
        type: 'updateHighlight',
        matches,
    };
    postMessage(message);
};
//# sourceMappingURL=worker.js.map