import * as wordgard_state from 'wordgard/state';
import { GardState, GardSelection, Transaction } from 'wordgard/state';
import { Menu, Command } from 'wordgard/command';
import { ChangeSet, Plot, Slice } from 'wordgard/doc';

/**
Enable table support with the given configuration. The returned
extension will include the necessary schema elements, the {@link
CellSelection cell selection}, {@link tables.correction correction},
{@link tables.pasteHandler paste} and {@link tables.dropHandler
drop} handlers, and {@link tableMenu menu items}.
*/
declare function tables(config?: tables.Spec): GardState.Extension;
declare namespace tables {
    /**
    Configuration options for the {@link tables} function.
    */
    type Spec = {
        /**
        Controls whether headers cells are enabled. Defaults to true.
        */
        headerCells?: boolean;
        /**
        By default, cells can be {@link mergeCells merged}, making
        them span more than one row or column. Set this to false to
        disable that.
        */
        cellSpanning?: boolean;
        /**
        Determines whether cells contain inline content or block
        content. Defaults to `"inline"`.
        */
        cellContent?: "inline" | "block";
    };
    /**
    Correct tables where the cells do not form a proper rectangle.
    */
    const correction: wordgard_state.Correction;
    /**
    A paste handler that makes pasting into tables fill the entire
    cell selection or, if table cell content is being pasted into a
    cell, to expand the pasted region over the shape covered by the
    pasted content.
    */
    const pasteHandler: GardState.Extension;
    /**
    A drop handler that overrides drops that move table cells.
    */
    const dropHandler: GardState.Extension;
}

/**
Returns the full table menu. This consists of two buttons that
look the same but behave differently. When the selection is not in
a table, {@link tableMenu.createTable} is shown, which provides an
interface for creating a new table. Otherwise, {@link
tableMenu.modifyTable} is visible, which contains menu items for
manipulating the current table.
*/
declare function tableMenu(): GardState.Extension;
declare namespace tableMenu {
    /**
    A menu button that expands into a dimension picker when
    activated, which inserts a table with the given dimensions when
    confirmed.
    */
    const createTable: Menu.Submenu;
    /**
    A submenu with for table manipulation items.
    */
    const modifyTable: Menu.Submenu;
    /**
    A button that toggles the selected cells between header and
    normal cells.
    */
    const toggleHeader: Menu.Button;
    /**
    Adds a row above the selected cell(s).
    */
    const addRowAbove: Menu.Button;
    /**
    Adds a row below the selected cell(s).
    */
    const addRowBelow: Menu.Button;
    /**
    Deletes the row(s) that hold the selection.
    */
    const deleteRow: Menu.Button;
    /**
    Button to insert a column before the selection.
    */
    const addColumnBefore: Menu.Button;
    /**
    Add a column after the selection.
    */
    const addColumnAfter: Menu.Button;
    /**
    Delete the selected column(s).
    */
    const deleteColumn: Menu.Button;
    /**
    When multiple cells are selected, merge them into a single cell.
    */
    const mergeCells: Menu.Button;
    /**
    When a merged cell is selected, split it into its smallest
    elements again.
    */
    const splitCell: Menu.Button;
}

/**
A cell selection is a custom selection type that, instead of
spanning the range between two document positions, spans the
rectangle between two cells in the same table. It comes with
extensions that make sure it is drawn in a recognizeable way,
automatically created when a selection crosses cell boundaries,
and adjusted appropriately in response to keyboard and mouse
actions.
*/
declare class CellSelection extends GardSelection {
    /**
    The position directly in front of the cell that acts as this
    selection's anchor.
    */
    readonly anchorCell: number;
    /**
    The position directly in front of the cell acting as the
    selection head.
    */
    readonly headCell: number;
    private constructor();
    get ranges(): readonly {
        from: number;
        to: number;
    }[];
    get replacementRange(): {
        from: number;
        to: number;
    };
    get domSelection(): {
        readonly anchor: number;
        readonly anchorSide: 1;
        readonly head: number;
        readonly headSide: -1;
    };
    eq(other: GardSelection): boolean;
    map(changes: ChangeSet, cx: GardSelection.Context, assoc?: -1 | 1): GardSelection.Text | CellSelection;
    /**
    Move the head cell in the given direction, returning a new cell
    selection if the selection can be extended that way.
    */
    moveHead(doc: Plot.Doc, dir: "up" | "down" | "forward" | "backward"): CellSelection | null;
    /**
    Create a table selection between the given points. They should
    point before and after the first and last cell of the selection
    (`anchor` may be before or after `head`, as long as the lower
    sits before a cell and the higher after a cell). Returns `null`
    if the given range does not wrap a range of cells in a single
    table.
    */
    static between(doc: Plot.Doc, anchor: number, head: number): CellSelection | null;
    /**
    Given a selection, this returns null if that selection is valid
    (is a cell selection, or a selection that starts and ends outside
    of tables, or in the same table cell). Otherwise, it will expand a
    selection within a single table to a cell selection, or expand a
    selection that crosses table boundaries to cover the entire table(s).
    */
    static normalize(sel: GardSelection, doc: Plot.Doc): GardSelection | null;
    /**
    This object can be used as an extension to enable cell selection.
    */
    static extension: GardState.Extension;
}

declare const toggleHeaderCell: Command.Pure;
/**
Add a column at the given side of the selection. The selection may
either be a cell selection or another type of selection inside a
table cell.
*/
declare const addColumn: Command.Pure<"before" | "after">;
/**
Delete the selected columns. Will act on a cell selection or
another type of selection inside a cell.
*/
declare const deleteColumn: Command.Pure;
/**
Add a row next to the selected cells, on the side indicated.
*/
declare const addRow: Command.Pure<"before" | "after">;
/**
Delete the selected row(s).
*/
declare const deleteRow: Command.Pure;
/**
If the current selection is a multi-cell cell selection, merge the
cells into a single cell by giving it a {@link types.RowSpan}
and/or {@link types.ColSpan}. The content from the cells is all
put into the resulting merged cell.
*/
declare const mergeCells: Command.Pure;
/**
When the selection is in or on a merged cell, split it again. Any
content is left in the first split-off cell.
*/
declare const splitCell: Command.Pure;

/**
@hidden exported for testing
*/
declare function handleTablePaste(state: GardState, slice: Slice, context: readonly Plot.Tag[], drop?: number): false | Transaction.Spec;

export { CellSelection, addColumn, addRow, deleteColumn, deleteRow, handleTablePaste, mergeCells, splitCell, tableMenu, tables, toggleHeaderCell };
