"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const cursorCommon = require("../cursorCommon.js");
const cursorColumns = require("../core/cursorColumns.js");
const position = require("../core/position.js");
const range = require("../core/range.js");
const strings = require("../../../base/common/strings.js");
const cursorAtomicMoveOperations = require("./cursorAtomicMoveOperations.js");
class CursorPosition {
  constructor(lineNumber, column, leftoverVisibleColumns) {
    this._cursorPositionBrand = void 0;
    this.lineNumber = lineNumber;
    this.column = column;
    this.leftoverVisibleColumns = leftoverVisibleColumns;
  }
}
class MoveOperations {
  static leftPosition(model, position$1) {
    if (position$1.column > model.getLineMinColumn(position$1.lineNumber)) {
      return position$1.delta(void 0, -strings.prevCharLength(model.getLineContent(position$1.lineNumber), position$1.column - 1));
    } else if (position$1.lineNumber > 1) {
      const newLineNumber = position$1.lineNumber - 1;
      return new position.Position(newLineNumber, model.getLineMaxColumn(newLineNumber));
    } else {
      return position$1;
    }
  }
  static leftPositionAtomicSoftTabs(model, position$1, tabSize) {
    if (position$1.column <= model.getLineIndentColumn(position$1.lineNumber)) {
      const minColumn = model.getLineMinColumn(position$1.lineNumber);
      const lineContent = model.getLineContent(position$1.lineNumber);
      const newPosition = cursorAtomicMoveOperations.AtomicTabMoveOperations.atomicPosition(
        lineContent,
        position$1.column - 1,
        tabSize,
        0
        /* Left */
      );
      if (newPosition !== -1 && newPosition + 1 >= minColumn) {
        return new position.Position(position$1.lineNumber, newPosition + 1);
      }
    }
    return this.leftPosition(model, position$1);
  }
  static left(config, model, position2) {
    const pos = config.stickyTabStops ? MoveOperations.leftPositionAtomicSoftTabs(model, position2, config.tabSize) : MoveOperations.leftPosition(model, position2);
    return new CursorPosition(pos.lineNumber, pos.column, 0);
  }
  /**
   * @param noOfColumns Must be either `1`
   * or `Math.round(viewModel.getLineContent(viewLineNumber).length / 2)` (for half lines).
  */
  static moveLeft(config, model, cursor, inSelectionMode, noOfColumns) {
    let lineNumber, column;
    if (cursor.hasSelection() && !inSelectionMode) {
      lineNumber = cursor.selection.startLineNumber;
      column = cursor.selection.startColumn;
    } else {
      const pos = cursor.position.delta(void 0, -(noOfColumns - 1));
      const normalizedPos = model.normalizePosition(
        MoveOperations.clipPositionColumn(pos, model),
        0
        /* Left */
      );
      const p = MoveOperations.left(config, model, normalizedPos);
      lineNumber = p.lineNumber;
      column = p.column;
    }
    return cursor.move(inSelectionMode, lineNumber, column, 0);
  }
  /**
   * Adjusts the column so that it is within min/max of the line.
  */
  static clipPositionColumn(position$1, model) {
    return new position.Position(position$1.lineNumber, MoveOperations.clipRange(position$1.column, model.getLineMinColumn(position$1.lineNumber), model.getLineMaxColumn(position$1.lineNumber)));
  }
  static clipRange(value, min, max) {
    if (value < min) {
      return min;
    }
    if (value > max) {
      return max;
    }
    return value;
  }
  static rightPosition(model, lineNumber, column) {
    if (column < model.getLineMaxColumn(lineNumber)) {
      column = column + strings.nextCharLength(model.getLineContent(lineNumber), column - 1);
    } else if (lineNumber < model.getLineCount()) {
      lineNumber = lineNumber + 1;
      column = model.getLineMinColumn(lineNumber);
    }
    return new position.Position(lineNumber, column);
  }
  static rightPositionAtomicSoftTabs(model, lineNumber, column, tabSize, indentSize) {
    if (column < model.getLineIndentColumn(lineNumber)) {
      const lineContent = model.getLineContent(lineNumber);
      const newPosition = cursorAtomicMoveOperations.AtomicTabMoveOperations.atomicPosition(
        lineContent,
        column - 1,
        tabSize,
        1
        /* Right */
      );
      if (newPosition !== -1) {
        return new position.Position(lineNumber, newPosition + 1);
      }
    }
    return this.rightPosition(model, lineNumber, column);
  }
  static right(config, model, position2) {
    const pos = config.stickyTabStops ? MoveOperations.rightPositionAtomicSoftTabs(model, position2.lineNumber, position2.column, config.tabSize, config.indentSize) : MoveOperations.rightPosition(model, position2.lineNumber, position2.column);
    return new CursorPosition(pos.lineNumber, pos.column, 0);
  }
  static moveRight(config, model, cursor, inSelectionMode, noOfColumns) {
    let lineNumber, column;
    if (cursor.hasSelection() && !inSelectionMode) {
      lineNumber = cursor.selection.endLineNumber;
      column = cursor.selection.endColumn;
    } else {
      const pos = cursor.position.delta(void 0, noOfColumns - 1);
      const normalizedPos = model.normalizePosition(
        MoveOperations.clipPositionColumn(pos, model),
        1
        /* Right */
      );
      const r = MoveOperations.right(config, model, normalizedPos);
      lineNumber = r.lineNumber;
      column = r.column;
    }
    return cursor.move(inSelectionMode, lineNumber, column, 0);
  }
  static vertical(config, model, lineNumber, column, leftoverVisibleColumns, newLineNumber, allowMoveOnEdgeLine, normalizationAffinity) {
    const currentVisibleColumn = cursorColumns.CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize) + leftoverVisibleColumns;
    const lineCount = model.getLineCount();
    const wasOnFirstPosition = lineNumber === 1 && column === 1;
    const wasOnLastPosition = lineNumber === lineCount && column === model.getLineMaxColumn(lineNumber);
    const wasAtEdgePosition = newLineNumber < lineNumber ? wasOnFirstPosition : wasOnLastPosition;
    lineNumber = newLineNumber;
    if (lineNumber < 1) {
      lineNumber = 1;
      if (allowMoveOnEdgeLine) {
        column = model.getLineMinColumn(lineNumber);
      } else {
        column = Math.min(model.getLineMaxColumn(lineNumber), column);
      }
    } else if (lineNumber > lineCount) {
      lineNumber = lineCount;
      if (allowMoveOnEdgeLine) {
        column = model.getLineMaxColumn(lineNumber);
      } else {
        column = Math.min(model.getLineMaxColumn(lineNumber), column);
      }
    } else {
      column = config.columnFromVisibleColumn(model, lineNumber, currentVisibleColumn);
    }
    if (wasAtEdgePosition) {
      leftoverVisibleColumns = 0;
    } else {
      leftoverVisibleColumns = currentVisibleColumn - cursorColumns.CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize);
    }
    if (normalizationAffinity !== void 0) {
      const position$1 = new position.Position(lineNumber, column);
      const newPosition = model.normalizePosition(position$1, normalizationAffinity);
      leftoverVisibleColumns = leftoverVisibleColumns + (column - newPosition.column);
      lineNumber = newPosition.lineNumber;
      column = newPosition.column;
    }
    return new CursorPosition(lineNumber, column, leftoverVisibleColumns);
  }
  static down(config, model, lineNumber, column, leftoverVisibleColumns, count, allowMoveOnLastLine) {
    return this.vertical(
      config,
      model,
      lineNumber,
      column,
      leftoverVisibleColumns,
      lineNumber + count,
      allowMoveOnLastLine,
      1
      /* Right */
    );
  }
  static moveDown(config, model, cursor, inSelectionMode, linesCount) {
    let lineNumber, column;
    if (cursor.hasSelection() && !inSelectionMode) {
      lineNumber = cursor.selection.endLineNumber;
      column = cursor.selection.endColumn;
    } else {
      lineNumber = cursor.position.lineNumber;
      column = cursor.position.column;
    }
    const r = MoveOperations.down(config, model, lineNumber, column, cursor.leftoverVisibleColumns, linesCount, true);
    return cursor.move(inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns);
  }
  static translateDown(config, model, cursor) {
    const selection = cursor.selection;
    const selectionStart = MoveOperations.down(config, model, selection.selectionStartLineNumber, selection.selectionStartColumn, cursor.selectionStartLeftoverVisibleColumns, 1, false);
    const position$1 = MoveOperations.down(config, model, selection.positionLineNumber, selection.positionColumn, cursor.leftoverVisibleColumns, 1, false);
    return new cursorCommon.SingleCursorState(new range.Range(selectionStart.lineNumber, selectionStart.column, selectionStart.lineNumber, selectionStart.column), selectionStart.leftoverVisibleColumns, new position.Position(position$1.lineNumber, position$1.column), position$1.leftoverVisibleColumns);
  }
  static up(config, model, lineNumber, column, leftoverVisibleColumns, count, allowMoveOnFirstLine) {
    return this.vertical(
      config,
      model,
      lineNumber,
      column,
      leftoverVisibleColumns,
      lineNumber - count,
      allowMoveOnFirstLine,
      0
      /* Left */
    );
  }
  static moveUp(config, model, cursor, inSelectionMode, linesCount) {
    let lineNumber, column;
    if (cursor.hasSelection() && !inSelectionMode) {
      lineNumber = cursor.selection.startLineNumber;
      column = cursor.selection.startColumn;
    } else {
      lineNumber = cursor.position.lineNumber;
      column = cursor.position.column;
    }
    const r = MoveOperations.up(config, model, lineNumber, column, cursor.leftoverVisibleColumns, linesCount, true);
    return cursor.move(inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns);
  }
  static translateUp(config, model, cursor) {
    const selection = cursor.selection;
    const selectionStart = MoveOperations.up(config, model, selection.selectionStartLineNumber, selection.selectionStartColumn, cursor.selectionStartLeftoverVisibleColumns, 1, false);
    const position$1 = MoveOperations.up(config, model, selection.positionLineNumber, selection.positionColumn, cursor.leftoverVisibleColumns, 1, false);
    return new cursorCommon.SingleCursorState(new range.Range(selectionStart.lineNumber, selectionStart.column, selectionStart.lineNumber, selectionStart.column), selectionStart.leftoverVisibleColumns, new position.Position(position$1.lineNumber, position$1.column), position$1.leftoverVisibleColumns);
  }
  static _isBlankLine(model, lineNumber) {
    if (model.getLineFirstNonWhitespaceColumn(lineNumber) === 0) {
      return true;
    }
    return false;
  }
  static moveToPrevBlankLine(config, model, cursor, inSelectionMode) {
    let lineNumber = cursor.position.lineNumber;
    while (lineNumber > 1 && this._isBlankLine(model, lineNumber)) {
      lineNumber--;
    }
    while (lineNumber > 1 && !this._isBlankLine(model, lineNumber)) {
      lineNumber--;
    }
    return cursor.move(inSelectionMode, lineNumber, model.getLineMinColumn(lineNumber), 0);
  }
  static moveToNextBlankLine(config, model, cursor, inSelectionMode) {
    const lineCount = model.getLineCount();
    let lineNumber = cursor.position.lineNumber;
    while (lineNumber < lineCount && this._isBlankLine(model, lineNumber)) {
      lineNumber++;
    }
    while (lineNumber < lineCount && !this._isBlankLine(model, lineNumber)) {
      lineNumber++;
    }
    return cursor.move(inSelectionMode, lineNumber, model.getLineMinColumn(lineNumber), 0);
  }
  static moveToBeginningOfLine(config, model, cursor, inSelectionMode) {
    const lineNumber = cursor.position.lineNumber;
    const minColumn = model.getLineMinColumn(lineNumber);
    const firstNonBlankColumn = model.getLineFirstNonWhitespaceColumn(lineNumber) || minColumn;
    let column;
    const relevantColumnNumber = cursor.position.column;
    if (relevantColumnNumber === firstNonBlankColumn) {
      column = minColumn;
    } else {
      column = firstNonBlankColumn;
    }
    return cursor.move(inSelectionMode, lineNumber, column, 0);
  }
  static moveToEndOfLine(config, model, cursor, inSelectionMode, sticky) {
    const lineNumber = cursor.position.lineNumber;
    const maxColumn = model.getLineMaxColumn(lineNumber);
    return cursor.move(inSelectionMode, lineNumber, maxColumn, sticky ? 1073741824 - maxColumn : 0);
  }
  static moveToBeginningOfBuffer(config, model, cursor, inSelectionMode) {
    return cursor.move(inSelectionMode, 1, 1, 0);
  }
  static moveToEndOfBuffer(config, model, cursor, inSelectionMode) {
    const lastLineNumber = model.getLineCount();
    const lastColumn = model.getLineMaxColumn(lastLineNumber);
    return cursor.move(inSelectionMode, lastLineNumber, lastColumn, 0);
  }
}
exports.CursorPosition = CursorPosition;
exports.MoveOperations = MoveOperations;
