"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const event = require("../../../../../base/common/event.js");
const lifecycle = require("../../../../../base/common/lifecycle.js");
const range = require("../../../core/range.js");
const textModelBracketPairs = require("../../../textModelBracketPairs.js");
const beforeEditPositionMapper = require("./beforeEditPositionMapper.js");
const brackets = require("./brackets.js");
const length = require("./length.js");
const parser = require("./parser.js");
const smallImmutableSet = require("./smallImmutableSet.js");
const tokenizer = require("./tokenizer.js");
class BracketPairsTree extends lifecycle.Disposable {
  constructor(textModel, getLanguageConfiguration) {
    super();
    this.textModel = textModel;
    this.getLanguageConfiguration = getLanguageConfiguration;
    this.didChangeEmitter = new event.Emitter();
    this.denseKeyProvider = new smallImmutableSet.DenseKeyProvider();
    this.brackets = new brackets.LanguageAgnosticBracketTokens(this.denseKeyProvider, this.getLanguageConfiguration);
    this.onDidChange = this.didChangeEmitter.event;
    if (textModel.backgroundTokenizationState === 0) {
      const brackets2 = this.brackets.getSingleLanguageBracketTokens(this.textModel.getLanguageId());
      const tokenizer$1 = new tokenizer.FastTokenizer(this.textModel.getValue(), brackets2);
      this.initialAstWithoutTokens = parser.parseDocument(tokenizer$1, [], void 0, true);
      this.astWithTokens = this.initialAstWithoutTokens;
    } else if (textModel.backgroundTokenizationState === 2) {
      this.initialAstWithoutTokens = void 0;
      this.astWithTokens = this.parseDocumentFromTextBuffer([], void 0, false);
    } else if (textModel.backgroundTokenizationState === 1) {
      this.initialAstWithoutTokens = this.parseDocumentFromTextBuffer([], void 0, true);
      this.astWithTokens = this.initialAstWithoutTokens;
    }
  }
  didLanguageChange(languageId) {
    return this.brackets.didLanguageChange(languageId);
  }
  //#region TextModel events
  handleDidChangeBackgroundTokenizationState() {
    if (this.textModel.backgroundTokenizationState === 2) {
      const wasUndefined = this.initialAstWithoutTokens === void 0;
      this.initialAstWithoutTokens = void 0;
      if (!wasUndefined) {
        this.didChangeEmitter.fire();
      }
    }
  }
  handleDidChangeTokens({ ranges }) {
    const edits = ranges.map((r) => new beforeEditPositionMapper.TextEditInfo(length.toLength(r.fromLineNumber - 1, 0), length.toLength(r.toLineNumber, 0), length.toLength(r.toLineNumber - r.fromLineNumber + 1, 0)));
    this.astWithTokens = this.parseDocumentFromTextBuffer(edits, this.astWithTokens, false);
    if (!this.initialAstWithoutTokens) {
      this.didChangeEmitter.fire();
    }
  }
  handleContentChanged(change) {
    const edits = change.changes.map((c) => {
      const range$1 = range.Range.lift(c.range);
      return new beforeEditPositionMapper.TextEditInfo(length.positionToLength(range$1.getStartPosition()), length.positionToLength(range$1.getEndPosition()), length.lengthOfString(c.text));
    }).reverse();
    this.astWithTokens = this.parseDocumentFromTextBuffer(edits, this.astWithTokens, false);
    if (this.initialAstWithoutTokens) {
      this.initialAstWithoutTokens = this.parseDocumentFromTextBuffer(edits, this.initialAstWithoutTokens, false);
    }
  }
  //#endregion
  /**
   * @pure (only if isPure = true)
  */
  parseDocumentFromTextBuffer(edits, previousAst, immutable) {
    const previousAstClone = previousAst;
    const tokenizer$1 = new tokenizer.TextBufferTokenizer(this.textModel, this.brackets);
    const result = parser.parseDocument(tokenizer$1, edits, previousAstClone, immutable);
    return result;
  }
  getBracketsInRange(range2) {
    const startOffset = length.toLength(range2.startLineNumber - 1, range2.startColumn - 1);
    const endOffset = length.toLength(range2.endLineNumber - 1, range2.endColumn - 1);
    const result = new Array();
    const node = this.initialAstWithoutTokens || this.astWithTokens;
    collectBrackets(node, length.lengthZero, node.length, startOffset, endOffset, result);
    return result;
  }
  getBracketPairsInRange(range2, includeMinIndentation) {
    const result = new Array();
    const startLength = length.positionToLength(range2.getStartPosition());
    const endLength = length.positionToLength(range2.getEndPosition());
    const node = this.initialAstWithoutTokens || this.astWithTokens;
    const context = new CollectBracketPairsContext(result, includeMinIndentation, this.textModel);
    collectBracketPairs(node, length.lengthZero, node.length, startLength, endLength, context);
    return result;
  }
}
function collectBrackets(node, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, result, level = 0) {
  if (node.kind === 4) {
    for (const child of node.children) {
      nodeOffsetEnd = length.lengthAdd(nodeOffsetStart, child.length);
      if (length.lengthLessThanEqual(nodeOffsetStart, endOffset) && length.lengthGreaterThanEqual(nodeOffsetEnd, startOffset)) {
        collectBrackets(child, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, result, level);
      }
      nodeOffsetStart = nodeOffsetEnd;
    }
  } else if (node.kind === 2) {
    level++;
    {
      const child = node.openingBracket;
      nodeOffsetEnd = length.lengthAdd(nodeOffsetStart, child.length);
      if (length.lengthLessThanEqual(nodeOffsetStart, endOffset) && length.lengthGreaterThanEqual(nodeOffsetEnd, startOffset)) {
        const range2 = length.lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
        result.push(new textModelBracketPairs.BracketInfo(range2, level - 1, !node.closingBracket));
      }
      nodeOffsetStart = nodeOffsetEnd;
    }
    if (node.child) {
      const child = node.child;
      nodeOffsetEnd = length.lengthAdd(nodeOffsetStart, child.length);
      if (length.lengthLessThanEqual(nodeOffsetStart, endOffset) && length.lengthGreaterThanEqual(nodeOffsetEnd, startOffset)) {
        collectBrackets(child, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, result, level);
      }
      nodeOffsetStart = nodeOffsetEnd;
    }
    if (node.closingBracket) {
      const child = node.closingBracket;
      nodeOffsetEnd = length.lengthAdd(nodeOffsetStart, child.length);
      if (length.lengthLessThanEqual(nodeOffsetStart, endOffset) && length.lengthGreaterThanEqual(nodeOffsetEnd, startOffset)) {
        const range2 = length.lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
        result.push(new textModelBracketPairs.BracketInfo(range2, level - 1, false));
      }
      nodeOffsetStart = nodeOffsetEnd;
    }
  } else if (node.kind === 3) {
    const range2 = length.lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
    result.push(new textModelBracketPairs.BracketInfo(range2, level - 1, true));
  } else if (node.kind === 1) {
    const range2 = length.lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
    result.push(new textModelBracketPairs.BracketInfo(range2, level - 1, false));
  }
}
class CollectBracketPairsContext {
  constructor(result, includeMinIndentation, textModel) {
    this.result = result;
    this.includeMinIndentation = includeMinIndentation;
    this.textModel = textModel;
  }
}
function collectBracketPairs(node, nodeOffset, nodeOffsetEnd, startOffset, endOffset, context, level = 0) {
  var _a;
  if (node.kind === 2) {
    const openingBracketEnd = length.lengthAdd(nodeOffset, node.openingBracket.length);
    let minIndentation = -1;
    if (context.includeMinIndentation) {
      minIndentation = node.computeMinIndentation(nodeOffset, context.textModel);
    }
    context.result.push(new textModelBracketPairs.BracketPairWithMinIndentationInfo(length.lengthsToRange(nodeOffset, nodeOffsetEnd), length.lengthsToRange(nodeOffset, openingBracketEnd), node.closingBracket ? length.lengthsToRange(length.lengthAdd(openingBracketEnd, ((_a = node.child) === null || _a === void 0 ? void 0 : _a.length) || length.lengthZero), nodeOffsetEnd) : void 0, level, minIndentation));
    level++;
  }
  let curOffset = nodeOffset;
  for (const child of node.children) {
    const childOffset = curOffset;
    curOffset = length.lengthAdd(curOffset, child.length);
    if (length.lengthLessThanEqual(childOffset, endOffset) && length.lengthLessThanEqual(startOffset, curOffset)) {
      collectBracketPairs(child, childOffset, curOffset, startOffset, endOffset, context, level);
    }
  }
}
exports.BracketPairsTree = BracketPairsTree;
