import { Observable } from 'rxjs';

/**
 * The zero-based coordinates of a character in the editor.
 * (row,column) => (0,0) is the topmost and leftmost character.
 */
interface Position {
    /**
     * The zero-based row.
     */
    row: number;
    /**
     * The zero-based column.
     */
    column: number;
}
/**
 * Constructs a position object from a zero-based row and zero-based column.
 * @param row The zero-based row.
 * @param column The zero-based column.
 */
declare function position(row: number, column: number): Position;
/**
 * Returns 0 if positions are equal, +1 if p1 comes after p2, -1 if p1 comes before p2.
 */
declare function comparePositions(p1: Position, p2: Position): 1 | -1 | 0;
/**
 * Determines whether positions p1 and p2 are equal.
 * @param p1 The first position.
 * @param p2 The second position.
 */
declare function equalPositions(p1: Position, p2: Position): boolean;

/**
 * Delta is a change that may be applied to a Document.
 */
interface Delta {
    /**
     *
     */
    action: 'insert' | 'remove';
    /**
     *
     */
    end: Position;
    /**
     *
     */
    lines: string[];
    /**
     *
     */
    start: Position;
}

declare function applyDelta(docLines: string[], delta: Delta): void;

/**
 *
 */
interface Range {
    /**
     * The starting position of the range.
     */
    start: Position;
    /**
     * The ending position of the range.
     */
    end: Position;
}
declare function range(start: Position, end: Position): Range;
/**
 * The range is empty if the start and end position coincide.
 */
declare function isEmptyRange(range: Range): boolean;

/**
 * Reference counting to manage lifetime of shared objects.
 */
interface Shareable {
    addRef(): number;
    release(): number;
}

type DocumentEventName = 'change' | 'changeNewLineMode';
type NewLineMode = 'auto' | 'unix' | 'windows';
/**
 *
 */
declare class Document implements Shareable {
    #private;
    readonly change$: Observable<Delta>;
    readonly changeNewLineMode$: Observable<string>;
    /**
     * If text is included, the Document contains those strings; otherwise, it's empty.
     * A `change` event will be emitted. But does anyone see it?
     *
     * @param textOrLines
     */
    constructor(textOrLines: string | Array<string>);
    addRef(): number;
    release(): number;
    /**
     * Replaces all the lines in the current `Document` with the value of `text`.
     * A `change` event will be emitted.
     */
    setValue(text: string): void;
    /**
     * Returns all the lines in the document as a single string, joined by the new line character.
     */
    getValue(): string;
    /**
     * Returns the newline character that's being used, depending on the value of `newLineMode`.
     *  If `newLineMode == windows`, `\r\n` is returned.
     *  If `newLineMode == unix`, `\n` is returned.
     *  If `newLineMode == auto`, the value of `autoNewLine` is returned.
     */
    getNewLineCharacter(): string;
    /**
     * Sets the new line mode.
     *
     * newLineMode is the newline mode to use; can be either `windows`, `unix`, or `auto`.
     * Emits 'changeNewLineMode'
     */
    setNewLineMode(newLineMode: NewLineMode): void;
    /**
     * Returns the type of newlines being used; either `windows`, `unix`, or `auto`.
     */
    getNewLineMode(): NewLineMode;
    /**
     * Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`).
     *
     * @param text The text to check.
     */
    isNewLine(text: string): boolean;
    /**
     * Returns a verbatim copy of the given line as it is in the document.
     *
     * @param row The row index to retrieve.
     */
    getLine(row: number): string;
    /**
     * Returns a COPY of the lines between and including `firstRow` and `lastRow`.
     * These lines do not include the line terminator.
     *
     * @param firstRow The first row index to retrieve.
     * @param lastRow The final row index to retrieve.
     */
    getLines(firstRow: number, lastRow: number): string[];
    /**
     * Returns a COPY of the lines in the document.
     * These lines do not include the line terminator.
     */
    getAllLines(): string[];
    /**
     * Returns the number of rows in the document.
     */
    getLength(): number;
    /**
     * Returns all the text corresponding to the range with line terminators.
     */
    getTextRange(range: Readonly<Range>): string;
    /**
     * Returns all the text within `range` as an array of lines.
     */
    getLinesForRange(range: Readonly<Range>): string[];
    /**
     * Inserts a block of `text` at the indicated `position`.
     * Returns the end position of the inserted text, the character immediately after the last character inserted.
     * This method also triggers the 'change' event.
     */
    insert(position: Position, text: string): Position;
    /**
     * Inserts `text` into the `position` at the current row. This method also triggers the `"change"` event.
     *
     * This differs from the `insert` method in two ways:
     *   1. This does NOT handle newline characters (single-line text only).
     *   2. This is faster than the `insert` method for single-line text insertions.
     */
    insertInLine(position: Readonly<Position>, text: string): Position;
    /**
     * Clips the position so that it refers to the nearest valid position.
     */
    clippedPos(row: number, column: number): Position;
    /**
     * Inserts the elements in `lines` into the document as full lines (does not merge with existing line), starting at the row index given by `row`.
     * This method also triggers the `"change"` event.
     */
    insertFullLines(row: number, lines: string[]): Position;
    /**
     * Inserts the text in `lines` into the document, starting at the `position` given.
     * Returns the end position of the inserted text.
     * This method also triggers the 'change' event.
     */
    insertMergedLines(position: Readonly<Position>, lines: string[]): Position;
    /**
     * Removes the `range` from the document.
     * This method triggers a 'change' event.
     *
     * @param range A specified Range to remove
     * @return Returns the new `start` property of the range.
     * If `range` is empty, this function returns the unmodified value of `range.start`.
     */
    remove(range: Readonly<Range>): Position;
    /**
     * Removes the specified columns from the `row`.
     * This method also triggers the `'change'` event.
     *
     * @param row The row to remove from.
     * @param startColumn The column to start removing at.
     * @param endColumn The column to stop removing at.
     * @returns An object containing `startRow` and `startColumn`, indicating the new row and column values.<br/>If `startColumn` is equal to `endColumn`, this function returns nothing.
     */
    removeInLine(row: number, startColumn: number, endColumn: number): Position;
    /**
     * Removes a range of full lines and returns a COPY of the removed lines.
     * This method also triggers the `"change"` event.
     *
     * @param firstRow The first row to be removed
     * @param lastRow The last row to be removed
     */
    removeFullLines(firstRow: number, lastRow: number): string[];
    /**
     * Removes the new line between `row` and the row immediately following it.
     *
     * @param row The row to check.
     */
    removeNewLine(row: number): void;
    /**
     * Replaces a range in the document with the new `text`.
     * Returns the end position of the change.
     * This method triggers a 'change' event for the removal.
     * This method triggers a 'change' event for the insertion.
     */
    replace(range: Range, newText: string): Position;
    /**
     * Applies all the changes previously accumulated.
     */
    applyDeltas(deltas: Delta[]): void;
    /**
     * Reverts any changes previously applied.
     */
    revertDeltas(deltas: Delta[]): void;
    /**
     * Applies `delta` (insert and remove actions) to the document and triggers the 'change' event.
     */
    applyDelta(delta: Delta): void;
    /**
     * Reverts `delta` from the document.
     * A delta object (can include "insert" and "remove" actions)
     */
    revertDelta(delta: Readonly<Delta>): void;
    /**
     * Converts an index position in a document to a `{row, column}` object.
     *
     * Index refers to the "absolute position" of a character in the document. For example:
     *
     * ```javascript
     * x = 0; // 10 characters, plus one for newline
     * y = -1;
     * ```
     *
     * Here, `y` is an index 15: 11 characters for the first row, and 5 characters until `y` in the second.
     *
     * @param index An index to convert
     * @param startRow The row from which to start the conversion
     * @returns An object of the `index` position.
     */
    indexToPosition(index: number, startRow?: number): Position;
    /**
     * Converts the `position` in a document to the character's zero-based index.
     *
     * Index refers to the "absolute position" of a character in the document. For example:
     *
     * ```javascript
     * x = 0; // 10 characters, plus one for newline
     * y = -1;
     * ```
     *
     * Here, `y` is an index 15: 11 characters for the first row, and 5 characters until `y` in the second.
     *
     * @param position The `{row, column}` to convert.
     * @param startRow The row from which to start the conversion. Defaults to zero.
     */
    positionToIndex(position: Readonly<Position>, startRow?: number): number;
}

export { type Delta, Document, type DocumentEventName, type NewLineMode, type Position, type Range, type Shareable, applyDelta, comparePositions, equalPositions, isEmptyRange, position, range };
