import { RemoveListener } from "@sheetxl/common";
/**
 * Used for transactional state.
 * This represents a single record change.
 * This is used by transactional operations, undo/redo, version control, and distributed state.
 * This also includes eventing but this is only for eventing for the final writes to the transaction
 * store any local eventing needs to be handled by the record itself.
 */
export interface ChangeSet<STATE, INPUTS> {
    state: STATE;
    /**
     * Inputs are values that are not part of the state but were used to calculate the state.
     * This is done because we want to allow different for inputs. For example
     * selection is considered an input because in a multi view environment we may
     * not want to selection to change if another view updates the data/state.
     */
    inputs?: INPUTS;
    prevState: STATE | null;
    /**Unique Identifier for the change */
    uuid: string;
}
export interface TransactionalUpdateStateOptions<STATE = any, INPUTS = undefined> {
    uuid?: string;
    description?: string;
    isUndo?: boolean;
    record: any;
    /**
     * The previous state will be:
     * The state of a previous transaction + any child transactions.
     */
    state: ((prev: STATE) => STATE) | STATE;
    /**
     * The previous input  will be:
     * The inputs from child transactions. (but not from previous transactions)
     */
    inputs?: ((prev: INPUTS) => INPUTS) | INPUTS;
}
export interface TransactionStoreListener<STATE = any, INPUTS = undefined> {
    /**
     * Called when a change set is committed to the global changeset.
     * This is a map of unique ids to change sets.
     *
     * @param changes
     * @param description
     */
    onChange(changes: Map<any, ChangeSet<STATE, INPUTS>>, description: string): void;
    /**
     * Called when all transactions are cleared. Handlers should clear their state.
     * For example undo should clear the undo stack.
     */
    onClear?(uuid: string): void;
}
export interface ChangeSetListener<STATE = any, INPUTS = undefined> {
    /**
     * Called during a transaction this is when changes should be applied
     */
    onRecordChange?(change: ChangeSet<STATE, INPUTS>, description: string, record: any, isUndo?: boolean): void;
    /**
     * Called at the end of a transaction.
     */
    onAfterRecordChange?(change: ChangeSet<STATE, INPUTS>, description: string, record: any): void;
    /**
     * Called synchronously at the beginning of a transaction before a record is changed.
     *
     * If this throws an exception then all records within the transaction will not
     * be applied.
     */
    onBeforeRecordChange?(uuid: string, description: string, record: any, newInputs: INPUTS): void;
    /**
     * Called when all transactions are cleared. Handlers should clear their state.
     * For example undo should clear the undo stack.
     */
    onClear?(uuid: string): void;
}
/**
 * Objects that support interfacing with a transactional store implement this interface.
 */
export interface ITransactionStack {
    /**
     * Begins a transaction but puts it onto a global stack.
     * This will batch all 'transactional' changes until they have all be committed or rolled back.
     *
     * @remarks
     * Any changes that are made to this object will be reflected in the local sheet but
     * not committed to the transactional store until the batch is popped.
     *
     * @param description
     */
    pushTransaction(description?: string): ITransaction;
}
export declare const setTransactionStoreSync: (isSync: boolean) => void;
export interface ITransaction {
    /**
     * Begin a transaction with self contained, non-eventing updates
     * @remarks
     *
     * Context is useful for debugging and logging.
     * This is treated as a stack so it's fifo. This means
     * that when finally committed to global changeset
     * that only the final context will be maintained.
     * @param description The description of the transaction
     * @param onClose A callback for when the transaction is closed (due to either a commit or rollback)
     * @param isUndo A hint to indicate if the transaction should be support undo.
     */
    beginTransaction(description?: string, onClose?: (transaction: ITransaction) => void, isUndo?: boolean): ITransaction;
    /**
     * Commit the transaction and all children transactions to the parent changeset.
     */
    commit(): ITransaction;
    /**
     * Discard all changes and children transaction changes.
     */
    rollback(): ITransaction;
    /**
     * If root transaction will return self
     */
    parent(): ITransaction;
    /**
     * unique id for this transaction. This will be the same id for all sub transactions.
     */
    readonly uuid: string;
    readonly depth: number;
    readonly description: string;
    readonly isUndo: boolean;
    updateState<STATE = any, INPUTS = undefined>(options: TransactionalUpdateStateOptions<STATE, INPUTS>): ChangeSet<STATE, INPUTS>;
    getChangeSet<STATE = any, INPUTS = undefined>(record: any): ChangeSet<STATE, INPUTS>;
    getState<STATE = any>(record: any): STATE;
}
declare abstract class AbstractTransaction implements ITransaction {
    protected _mapRecordToChanges: Map<any, ChangeSet<any, any>>;
    protected _children: Set<AbstractTransaction>;
    protected _updatingStates: any[];
    protected _depth: number;
    protected _lookupCache: any;
    protected _description: string;
    protected _isUndo: boolean;
    constructor(description?: string, isUndo?: boolean);
    get depth(): number;
    /**
     * Creates a child transaction
     */
    beginTransaction(description?: string, onClose?: (transaction: ITransaction) => void, isUndo?: boolean): ITransaction;
    protected _removeChild(child: AbstractTransaction): void;
    updateStates<STATE = any, INPUTS = undefined>(uuid: string, recordsToChanges: Map<any, ChangeSet<any, any>>, options: Omit<TransactionalUpdateStateOptions<STATE, INPUTS>, 'record' | 'state'>): Map<any, ChangeSet<any, any>>;
    updateState<STATE = any, INPUTS = undefined>(options: TransactionalUpdateStateOptions<STATE, INPUTS>): ChangeSet<STATE, INPUTS>;
    getState<STATE = any>(record: any): STATE;
    abstract getChangeSet<STATE = any, INPUTS = undefined>(record: any): ChangeSet<STATE, INPUTS>;
    abstract commit(): ITransaction;
    abstract rollback(): ITransaction;
    /**
     * If root transaction will return self
     */
    abstract parent(): ITransaction;
    abstract get uuid(): string;
    get description(): string;
    get isUndo(): boolean;
}
/**
 * Events are never fired on sub transactions. Only when making changes to the root
 * either directly or through a final commit. Any models that want to fire non transactional
 * events should do this directly.
 */
export default class TransactionStore extends AbstractTransaction implements ITransaction {
    private _listeners;
    private _listenersChangeSet;
    private _transactionStack;
    private _isSync;
    constructor(isSync?: boolean);
    peekTransaction(): ITransaction;
    get uuid(): string;
    /**
     * calls beginTransaction but adds to a shared stack
     */
    pushTransaction(description: string, onClose?: (transaction: ITransaction) => void, isUndo?: boolean): ITransaction;
    clear(record: any): void;
    commit(): ITransaction;
    rollback(): ITransaction;
    parent(): ITransaction;
    getChangeSet<STATE = any, INPUTS = undefined>(record: any): ChangeSet<STATE, INPUTS>;
    updateState<STATE = any, INPUTS = undefined>(options: TransactionalUpdateStateOptions<STATE, INPUTS>): ChangeSet<STATE, INPUTS>;
    updateStates<STATE = any, INPUTS = undefined>(uuid: string, recordsToChanges: Map<any, ChangeSet<any, any>>, options: TransactionalUpdateStateOptions<STATE, INPUTS>): Map<any, ChangeSet<any, any>>;
    addListener(listener: TransactionStoreListener): RemoveListener;
    /**
     * Fired when information at a specific record is changed.
     * This will be fired both during a commit and during a change to the global store
     */
    addChangeSetListener<STATE = any, INPUTS = undefined>(record: any, listener: ChangeSetListener<STATE, INPUTS>): RemoveListener;
    private dispatchEvents;
    notifyRecordChange(changes: ChangeSet<any, any>, description: string, record: any, isUndo: boolean): void;
    notifyBeforeChange(uuid: string, description: string, record: any, newInputs: any): void;
    notifyAfterChange(changes: ChangeSet<any, any>, description: string, record: any): void;
    notifyChange(changes: Map<any, ChangeSet<any, any>>, description: string): void;
    notifyClear(uuid: string, record: any): void;
}
export { TransactionStore };
//# sourceMappingURL=Transaction.d.ts.map