"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.format = format;
const languageModes_1 = require("./languageModes");
const arrays_1 = require("../utils/arrays");
const strings_1 = require("../utils/strings");
function format(languageModes, document, formatRange, formattingOptions, settings, enabledModes) {
    return __awaiter(this, void 0, void 0, function* () {
        const result = [];
        const endPos = formatRange.end;
        let endOffset = document.offsetAt(endPos);
        const content = document.getText();
        if (endPos.character === 0 && endPos.line > 0 && endOffset !== content.length) {
            const prevLineStart = document.offsetAt(languageModes_1.Position.create(endPos.line - 1, 0));
            while ((0, strings_1.isEOL)(content, endOffset - 1) && endOffset > prevLineStart) {
                endOffset--;
            }
            formatRange = languageModes_1.Range.create(formatRange.start, document.positionAt(endOffset));
        }
        const allRanges = languageModes.getModesInRange(document, formatRange);
        let i = 0;
        let startPos = formatRange.start;
        const isHTML = (range) => range.mode && range.mode.getId() === 'html';
        while (i < allRanges.length && !isHTML(allRanges[i])) {
            const range = allRanges[i];
            if (!range.attributeValue && range.mode && range.mode.format) {
                const edits = yield range.mode.format(document, languageModes_1.Range.create(startPos, range.end), formattingOptions, settings);
                (0, arrays_1.pushAll)(result, edits);
            }
            startPos = range.end;
            i++;
        }
        if (i === allRanges.length) {
            return result;
        }
        formatRange = languageModes_1.Range.create(startPos, formatRange.end);
        const htmlMode = languageModes.getMode('html');
        const htmlEdits = yield htmlMode.format(document, formatRange, formattingOptions, settings);
        let htmlFormattedContent = languageModes_1.TextDocument.applyEdits(document, htmlEdits);
        if (formattingOptions.insertFinalNewline && endOffset === content.length && !htmlFormattedContent.endsWith('\n')) {
            htmlFormattedContent = htmlFormattedContent + '\n';
            htmlEdits.push(languageModes_1.TextEdit.insert(endPos, '\n'));
        }
        const newDocument = languageModes_1.TextDocument.create(document.uri + '.tmp', document.languageId, document.version, htmlFormattedContent);
        try {
            const afterFormatRangeLength = document.getText().length - document.offsetAt(formatRange.end);
            const newFormatRange = languageModes_1.Range.create(formatRange.start, newDocument.positionAt(htmlFormattedContent.length - afterFormatRangeLength));
            const embeddedRanges = languageModes.getModesInRange(newDocument, newFormatRange);
            const embeddedEdits = [];
            for (const r of embeddedRanges) {
                const mode = r.mode;
                if (mode && mode.format && enabledModes[mode.getId()] && !r.attributeValue) {
                    const edits = yield mode.format(newDocument, r, formattingOptions, settings);
                    for (const edit of edits) {
                        embeddedEdits.push(edit);
                    }
                }
            }
            if (embeddedEdits.length === 0) {
                (0, arrays_1.pushAll)(result, htmlEdits);
                return result;
            }
            const resultContent = languageModes_1.TextDocument.applyEdits(newDocument, embeddedEdits);
            const resultReplaceText = resultContent.substring(document.offsetAt(formatRange.start), resultContent.length - afterFormatRangeLength);
            result.push(languageModes_1.TextEdit.replace(formatRange, resultReplaceText));
            return result;
        }
        finally {
            languageModes.onDocumentRemoved(newDocument);
        }
    });
}
