(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "vscode-languageserver-types", "../htmlLanguageTypes", "../parser/htmlScanner", "../languageFacts/fact"], factory);
    }
})(function (require, exports) {
    /*---------------------------------------------------------------------------------------------
     *  Copyright (c) Microsoft Corporation. All rights reserved.
     *  Licensed under the MIT License. See License.txt in the project root for license information.
     *--------------------------------------------------------------------------------------------*/
    'use strict';
    Object.defineProperty(exports, "__esModule", { value: true });
    var vscode_languageserver_types_1 = require("vscode-languageserver-types");
    var htmlLanguageTypes_1 = require("../htmlLanguageTypes");
    var htmlScanner_1 = require("../parser/htmlScanner");
    var fact_1 = require("../languageFacts/fact");
    function limitRanges(ranges, rangeLimit) {
        ranges = ranges.sort(function (r1, r2) {
            var diff = r1.startLine - r2.startLine;
            if (diff === 0) {
                diff = r1.endLine - r2.endLine;
            }
            return diff;
        });
        // compute each range's nesting level in 'nestingLevels'.
        // count the number of ranges for each level in 'nestingLevelCounts'
        var top = void 0;
        var previous = [];
        var nestingLevels = [];
        var nestingLevelCounts = [];
        var setNestingLevel = function (index, level) {
            nestingLevels[index] = level;
            if (level < 30) {
                nestingLevelCounts[level] = (nestingLevelCounts[level] || 0) + 1;
            }
        };
        // compute nesting levels and sanitize
        for (var i = 0; i < ranges.length; i++) {
            var entry = ranges[i];
            if (!top) {
                top = entry;
                setNestingLevel(i, 0);
            }
            else {
                if (entry.startLine > top.startLine) {
                    if (entry.endLine <= top.endLine) {
                        previous.push(top);
                        top = entry;
                        setNestingLevel(i, previous.length);
                    }
                    else if (entry.startLine > top.endLine) {
                        do {
                            top = previous.pop();
                        } while (top && entry.startLine > top.endLine);
                        if (top) {
                            previous.push(top);
                        }
                        top = entry;
                        setNestingLevel(i, previous.length);
                    }
                }
            }
        }
        var entries = 0;
        var maxLevel = 0;
        for (var i = 0; i < nestingLevelCounts.length; i++) {
            var n = nestingLevelCounts[i];
            if (n) {
                if (n + entries > rangeLimit) {
                    maxLevel = i;
                    break;
                }
                entries += n;
            }
        }
        var result = [];
        for (var i = 0; i < ranges.length; i++) {
            var level = nestingLevels[i];
            if (typeof level === 'number') {
                if (level < maxLevel || (level === maxLevel && entries++ < rangeLimit)) {
                    result.push(ranges[i]);
                }
            }
        }
        return result;
    }
    function getFoldingRanges(document, context) {
        var scanner = htmlScanner_1.createScanner(document.getText());
        var token = scanner.scan();
        var ranges = [];
        var stack = [];
        var lastTagName = null;
        var prevStart = -1;
        function addRange(range) {
            ranges.push(range);
            prevStart = range.startLine;
        }
        while (token !== htmlLanguageTypes_1.TokenType.EOS) {
            switch (token) {
                case htmlLanguageTypes_1.TokenType.StartTag: {
                    var tagName = scanner.getTokenText();
                    var startLine = document.positionAt(scanner.getTokenOffset()).line;
                    stack.push({ startLine: startLine, tagName: tagName });
                    lastTagName = tagName;
                    break;
                }
                case htmlLanguageTypes_1.TokenType.EndTag: {
                    lastTagName = scanner.getTokenText();
                    break;
                }
                case htmlLanguageTypes_1.TokenType.StartTagClose:
                    if (!lastTagName || !fact_1.isVoidElement(lastTagName)) {
                        break;
                    }
                // fallthrough
                case htmlLanguageTypes_1.TokenType.EndTagClose:
                case htmlLanguageTypes_1.TokenType.StartTagSelfClose: {
                    var i = stack.length - 1;
                    while (i >= 0 && stack[i].tagName !== lastTagName) {
                        i--;
                    }
                    if (i >= 0) {
                        var stackElement = stack[i];
                        stack.length = i;
                        var line = document.positionAt(scanner.getTokenOffset()).line;
                        var startLine = stackElement.startLine;
                        var endLine = line - 1;
                        if (endLine > startLine && prevStart !== startLine) {
                            addRange({ startLine: startLine, endLine: endLine });
                        }
                    }
                    break;
                }
                case htmlLanguageTypes_1.TokenType.Comment: {
                    var startLine = document.positionAt(scanner.getTokenOffset()).line;
                    var text = scanner.getTokenText();
                    var m = text.match(/^\s*#(region\b)|(endregion\b)/);
                    if (m) {
                        if (m[1]) { // start pattern match
                            stack.push({ startLine: startLine, tagName: '' }); // empty tagName marks region
                        }
                        else {
                            var i = stack.length - 1;
                            while (i >= 0 && stack[i].tagName.length) {
                                i--;
                            }
                            if (i >= 0) {
                                var stackElement = stack[i];
                                stack.length = i;
                                var endLine = startLine;
                                startLine = stackElement.startLine;
                                if (endLine > startLine && prevStart !== startLine) {
                                    addRange({ startLine: startLine, endLine: endLine, kind: vscode_languageserver_types_1.FoldingRangeKind.Region });
                                }
                            }
                        }
                    }
                    else {
                        var endLine = document.positionAt(scanner.getTokenOffset() + scanner.getTokenLength()).line;
                        if (startLine < endLine) {
                            addRange({ startLine: startLine, endLine: endLine, kind: vscode_languageserver_types_1.FoldingRangeKind.Comment });
                        }
                    }
                    break;
                }
            }
            token = scanner.scan();
        }
        var rangeLimit = context && context.rangeLimit || Number.MAX_VALUE;
        if (ranges.length > rangeLimit) {
            ranges = limitRanges(ranges, rangeLimit);
        }
        return ranges;
    }
    exports.getFoldingRanges = getFoldingRanges;
});
//# sourceMappingURL=htmlFolding.js.map