"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SnapshotDocument = void 0;
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
const combineChangeRanges_1 = require("./combineChangeRanges");
class SnapshotDocument {
    constructor(uri, languageId, version, text) {
        this.snapshots = [];
        this.document = vscode_languageserver_textdocument_1.TextDocument.create(uri, languageId, version, text);
        this.resetChanges();
    }
    get uri() {
        return this.document.uri;
    }
    get languageId() {
        return this.document.languageId;
    }
    get version() {
        return this.document.version;
    }
    get lineCount() {
        return this.document.lineCount;
    }
    getText(range) {
        return this.document.getText(range);
    }
    positionAt(offset) {
        return this.document.positionAt(offset);
    }
    offsetAt(position) {
        return this.document.offsetAt(position);
    }
    /**
     * Update the document with the given content changes and version.
     * If all changes is incremental, calculate the change range and add a new snapshot.
     * Otherwise, reset the changes.
     */
    update(contentChanges, version) {
        if (contentChanges.every(change => 'range' in change)) {
            let changeRanges = [];
            for (const contentChange of contentChanges) {
                if (!('range' in contentChange)) {
                    continue;
                }
                const start = this.offsetAt(contentChange.range.start);
                const length = contentChange.rangeLength ?? this.offsetAt(contentChange.range.end) - start;
                changeRanges.push({
                    span: { start, length },
                    newLength: contentChange.text.length,
                });
                vscode_languageserver_textdocument_1.TextDocument.update(this.document, [contentChange], version);
            }
            this.snapshots.push({
                changeRange: (0, combineChangeRanges_1.combineChangeRanges)(...changeRanges),
                version,
                ref: undefined,
            });
        }
        else {
            vscode_languageserver_textdocument_1.TextDocument.update(this.document, contentChanges, version);
            this.resetChanges();
        }
    }
    getSnapshot() {
        this.clearUnreferencedVersions();
        const lastChange = this.snapshots[this.snapshots.length - 1];
        if (!lastChange.ref) {
            const text = this.document.getText();
            const changeRangeCache = new WeakMap();
            const snapshot = {
                getText: (start, end) => text.substring(start, end),
                getLength: () => text.length,
                getChangeRange: oldSnapshot => {
                    if (!changeRangeCache.has(oldSnapshot)) {
                        const oldIndex = this.snapshots.findIndex(change => change.ref?.deref() === oldSnapshot);
                        if (oldIndex >= 0) {
                            const start = oldIndex + 1;
                            const end = this.snapshots.indexOf(lastChange) + 1;
                            const changeRanges = this.snapshots
                                .slice(start, end)
                                .map(change => change.changeRange);
                            const changeRange = (0, combineChangeRanges_1.combineChangeRanges)(...changeRanges);
                            changeRangeCache.set(oldSnapshot, changeRange);
                        }
                        else {
                            changeRangeCache.set(oldSnapshot, undefined);
                        }
                    }
                    return changeRangeCache.get(oldSnapshot);
                },
            };
            lastChange.ref = new WeakRef(snapshot);
        }
        return lastChange.ref.deref();
    }
    resetChanges() {
        this.snapshots = [
            {
                changeRange: {
                    span: {
                        start: 0,
                        length: 0,
                    },
                    newLength: this.document.getText().length,
                },
                version: this.document.version,
                ref: undefined,
            },
        ];
    }
    clearUnreferencedVersions() {
        let firstReferencedIndex = 0;
        while (firstReferencedIndex < this.snapshots.length - 1 && !this.snapshots[firstReferencedIndex].ref?.deref()) {
            firstReferencedIndex++;
        }
        this.snapshots = this.snapshots.slice(firstReferencedIndex);
    }
}
exports.SnapshotDocument = SnapshotDocument;
//# sourceMappingURL=snapshotDocument.js.map