import { Block } from './Block';
import { commonLength } from '../util/commonLength';
import { printTree } from 'tree-dump/lib/printTree';
import { LeafBlock } from './LeafBlock';
import { Range } from '../rga/Range';
import { CommonSliceType } from '../slice';
/**
 * A *fragment* represents a structural slice of a rich-text document. A
 * fragment can be bound to a specific range of text contents, however it
 * always constructs a tree of {@link Block}s, which represent the nested
 * structure of the text contents.
 */
export class Fragment extends Range {
    txt;
    root;
    constructor(txt, start, end) {
        super(txt.str, start, end);
        this.txt = txt;
        this.root = new Block(txt, [], void 0, start, end);
    }
    // ------------------------------------------------------------------- export
    toJson() {
        const node = this.root.toJson();
        node[0] = '';
        return node;
    }
    // ---------------------------------------------------------------- Printable
    toString(tab = '') {
        return 'Fragment' + printTree(tab, [(tab) => this.root.toString(tab)]);
    }
    // ----------------------------------------------------------------- Stateful
    hash = 0;
    refresh() {
        this.build();
        return (this.hash = this.root.refresh());
    }
    insertBlock(parent, path, marker, end = this.end) {
        const txt = this.txt;
        const common = commonLength(path, parent.path);
        const start = marker ? marker : this.start;
        while (parent.path.length > common && parent.parent)
            parent = parent.parent;
        while (parent.path.length + 1 < path.length) {
            const block = new Block(txt, path.slice(0, parent.path.length + 1), void 0, start, end);
            block.parent = parent;
            parent.children.push(block);
            parent = block;
        }
        const block = new LeafBlock(txt, path, marker, start, end);
        block.parent = parent;
        parent.children.push(block);
        return block;
    }
    build() {
        const { root } = this;
        root.children = [];
        let parent = this.root;
        const txt = this.txt;
        const overlay = txt.overlay;
        const iterator = overlay.markerPairs0(this.start, this.end);
        let pair;
        while ((pair = iterator())) {
            const [p1, p2] = pair;
            const skipFirstVirtualBlock = !p1 && this.start.isAbsStart() && p2 && p2.viewPos() === 0;
            if (skipFirstVirtualBlock)
                continue;
            const type = p1 ? p1.type() : CommonSliceType.p;
            const path = type instanceof Array ? type : [type];
            const block = this.insertBlock(parent, path, p1, p2);
            if (block.parent)
                parent = block.parent;
        }
    }
}
//# sourceMappingURL=Fragment.js.map