import { PointRange } from './point-range';
import * as Point from './point';
import * as Matrix from './matrix';
/** Selection from a spreadsheet */
export class Selection {
}
/** Selection of no cells */
export class EmptySelection extends Selection {
    // @ts-ignore
    toRange(data) {
        return null;
    }
    normalizeTo(_) {
        return this;
    }
    hasEntireRow() {
        return false;
    }
    hasEntireColumn() {
        return false;
    }
    size() {
        return 0;
    }
    has() {
        return false;
    }
    equals(selection) {
        return selection instanceof EmptySelection;
    }
}
/** Selection of a range of cells */
export class RangeSelection extends Selection {
    range;
    constructor(range) {
        super();
        this.range = range;
    }
    toRange(_) {
        return this.range;
    }
    normalizeTo(data) {
        const dataRange = getMatrixRange(data);
        const nextSelection = new RangeSelection(this.range.mask(dataRange));
        // @ts-expect-error
        return nextSelection;
    }
    hasEntireRow() {
        return false;
    }
    hasEntireColumn() {
        return false;
    }
    size(data) {
        const range = this.toRange(data);
        return range ? range.size() : 0;
    }
    has(data, point) {
        const range = this.toRange(data);
        return range !== null && range.has(point);
    }
    equals(selection) {
        return (selection instanceof RangeSelection && this.range.equals(selection.range));
    }
}
/** Selection of an entire part of the spreadsheet */
export class EntireSelection extends Selection {
}
/** Selection of the entire worksheet */
export class EntireWorksheetSelection extends EntireSelection {
    toRange(data) {
        return getMatrixRange(data);
    }
    normalizeTo() {
        return this;
    }
    hasEntireColumn() {
        return true;
    }
    hasEntireRow() {
        return true;
    }
    size(data) {
        return Matrix.getColumnsCount(data) * Matrix.getRowsCount(data);
    }
    has() {
        return true;
    }
    equals(selection) {
        return selection instanceof EntireWorksheetSelection;
    }
}
/** Selection of an entire axis in the spreadsheet */
export class EntireAxisSelection extends EntireSelection {
    /** Selection start index, integer */
    start;
    /** Selection end index, integer */
    end;
    /**
     * @param start - row index where the selection starts, integer
     * @param end - row index where the selection ends, integer
     * @throws {@link InvalidIndexError}
     */
    constructor(start, end) {
        if (!isIndex(start)) {
            throw new InvalidIndexError('start');
        }
        if (!isIndex(end)) {
            throw new InvalidIndexError('end');
        }
        super();
        this.start = Math.min(start, end);
        this.end = Math.max(start, end);
    }
    equals(selection) {
        return (selection instanceof EntireAxisSelection &&
            this.constructor === selection.constructor &&
            this.start === selection.start &&
            this.end === selection.end);
    }
}
/** Selection of entire rows in the spreadsheet */
export class EntireRowsSelection extends EntireAxisSelection {
    toRange(data) {
        const max = Matrix.maxPoint(data);
        return new PointRange({ row: this.start, column: 0 }, { row: this.end, column: max.column });
    }
    normalizeTo(data) {
        const count = Matrix.getRowsCount(data);
        const nextSelection = new EntireRowsSelection(Math.max(this.start, 0), Math.min(this.end, count - 1));
        // @ts-expect-error
        return nextSelection;
    }
    hasEntireRow(row) {
        return row >= this.start && row <= this.end;
    }
    hasEntireColumn() {
        return false;
    }
    size(data) {
        const rows = this.end - this.start + 1;
        return rows * Matrix.getColumnsCount(data);
    }
    has(_, point) {
        return point.row >= this.start && point.row <= this.end;
    }
}
/** Selection of entire columns in the spreadsheet */
export class EntireColumnsSelection extends EntireAxisSelection {
    toRange(data) {
        const max = Matrix.maxPoint(data);
        return new PointRange({ row: 0, column: this.start }, { row: max.row, column: this.end });
    }
    normalizeTo(data) {
        const count = Matrix.getColumnsCount(data);
        const nextSelection = new EntireColumnsSelection(Math.max(this.start, 0), Math.min(this.end, count - 1));
        // @ts-expect-error
        return nextSelection;
    }
    hasEntireRow() {
        return false;
    }
    hasEntireColumn(column) {
        return column >= this.start && column <= this.end;
    }
    size(data) {
        const columns = this.end - this.start + 1;
        return columns * Matrix.getRowsCount(data);
    }
    has(_, point) {
        return point.column >= this.start && point.column <= this.end;
    }
}
/** Get the point range of given matrix */
export function getMatrixRange(data) {
    const maxPoint = Matrix.maxPoint(data);
    return new PointRange(Point.ORIGIN, maxPoint);
}
/** Determines whether the given value is a valid index */
export function isIndex(value) {
    return Number.isInteger(value) && value >= 0;
}
/** Error thrown when passing a non-index value where an index value is expected */
export class InvalidIndexError extends Error {
    constructor(name) {
        super(`${name} is not a valid index. It must be 0 or a positive integer`);
    }
}
//# sourceMappingURL=selection.js.map