"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SelectionRangeProviderImpl = void 0;
const vscode_languageserver_1 = require("vscode-languageserver");
const documents_1 = require("../../../lib/documents");
const utils_1 = require("../utils");
const utils_2 = require("./utils");
class SelectionRangeProviderImpl {
    constructor(lsAndTsDocResolver) {
        this.lsAndTsDocResolver = lsAndTsDocResolver;
    }
    async getSelectionRange(document, position) {
        const { tsDoc, lang } = await this.lsAndTsDocResolver.getLsForSyntheticOperations(document);
        const tsSelectionRange = lang.getSmartSelectionRange(tsDoc.filePath, tsDoc.offsetAt(tsDoc.getGeneratedPosition(position)));
        const selectionRange = this.toSelectionRange(tsDoc, tsSelectionRange);
        const mappedRange = this.mapSelectionRangeToParent(tsDoc, document, selectionRange);
        return this.filterOutUnmappedRange(mappedRange);
    }
    toSelectionRange(snapshot, { textSpan, parent }) {
        return {
            range: (0, utils_1.convertRange)(snapshot, textSpan),
            parent: parent && this.toSelectionRange(snapshot, parent)
        };
    }
    mapSelectionRangeToParent(tsDoc, document, selectionRange) {
        const { range, parent } = selectionRange;
        const originalRange = (0, documents_1.mapRangeToOriginal)(tsDoc, range);
        (0, utils_2.checkRangeMappingWithGeneratedSemi)(originalRange, range, tsDoc);
        if (!parent) {
            return vscode_languageserver_1.SelectionRange.create(originalRange);
        }
        return vscode_languageserver_1.SelectionRange.create(originalRange, this.mapSelectionRangeToParent(tsDoc, document, parent));
    }
    filterOutUnmappedRange(selectionRange) {
        const flattened = this.flattenAndReverseSelectionRange(selectionRange);
        const filtered = flattened.filter((range) => range.start.line > 0 && range.end.line > 0);
        if (!filtered.length) {
            return null;
        }
        let result;
        for (const selectionRange of filtered) {
            result = vscode_languageserver_1.SelectionRange.create(selectionRange, result);
        }
        return result ?? null;
    }
    /**
     *   flatten the selection range and its parent to an array in reverse order
     * so it's easier to filter out unmapped selection and create a new tree of
     * selection range
     */
    flattenAndReverseSelectionRange(selectionRange) {
        const result = [];
        let current = selectionRange;
        while (current.parent) {
            result.unshift(current.range);
            current = current.parent;
        }
        return result;
    }
}
exports.SelectionRangeProviderImpl = SelectionRangeProviderImpl;
//# sourceMappingURL=SelectionRangeProvider.js.map