import '../../chipper/js/initialize-globals.js';
import '../../assert/js/assert.js';
import '../../globals.js';
import TEmitter, { TEmitterListener, TEmitterParameter } from './TEmitter.js';
/**
 * How to handle the notification of listeners in reentrant emit() cases. There are two possibilities:
 * 'stack': Each new reentrant call to emit (from a listener), takes precedent. This behaves like a "depth first"
 *        algorithm because it will not finish calling all listeners from the original call until nested emit() calls
 *        notify fully. Notify listeners from the emit call with "stack-like" behavior. We also sometimes call this
 *        "depth-first" notification. This algorithm will prioritize the most recent emit call's listeners, such that
 *        reentrant emits will cause a full recursive call to emit() to complete before continuing to notify the
 *        rest of the listeners from the original call.
 *        Note: This was the only method of notifying listeners on emit before 2/2024.
 *
 * 'queue': Each new reentrant call to emit queues those listeners to run once the current notifications are done
 *        firing. Here a recursive (reentrant) emit is basically a noop, because the original call will continue
 *        looping through listeners from each new emit() call until there are no more. See notifyAsQueue().
 *        Notify listeners from the emit call with "queue-like" behavior (FIFO). We also sometimes call this "breadth-first"
 *        notification. In this function, listeners for an earlier emit call will be called before any newer emit call that
 *        may occur inside of listeners (in a reentrant case).
 *
 *        This is a better strategy in cases where order may matter, for example:
 *        const emitter = new TinyEmitter<[ number ]>(  null, null, 'queue' );
 *        emitter.addListener( number => {
 *          if ( number < 10 ) {
 *            emitter.emit( number + 1 );
 *            console.log( number );
 *          }
 *        } );
 *        emitter.emit( 1 );
 *        -> 1,2,3,4,5,6,7,8,9
 *
 *        Whereas stack-based notification would yield the oppose order: 9->1, since the most recently called emit
 *        would be the very first one notified.
 *
 *        Note, this algorithm does involve queueing a reentrant emit() calls' listeners for later notification. So in
 *        effect, reentrant emit() calls are no-ops. This could potentially lead some awkward or confusing cases. As a
 *        result it is recommended to use this predominantly with Properties, in which their stateful value makes more
 *        sense to notify changes on in order (preserving the correct oldValue through all notifications).
 */
export type ReentrantNotificationStrategy = 'queue' | 'stack';
export type TinyEmitterOptions<T extends TEmitterParameter[] = []> = {
    onBeforeNotify?: TEmitterListener<T>;
    hasListenerOrderDependencies?: boolean;
    reentrantNotificationStrategy?: ReentrantNotificationStrategy;
};
export default class TinyEmitter<T extends TEmitterParameter[] = []> implements TEmitter<T> {
    changeCount?: (count: number) => void;
    isDisposed?: boolean;
    private readonly onBeforeNotify?;
    private readonly hasListenerOrderDependencies?;
    private readonly reentrantNotificationStrategy?;
    private listeners;
    private emitContexts;
    constructor(onBeforeNotify?: TinyEmitterOptions<T>['onBeforeNotify'] | null, hasListenerOrderDependencies?: TinyEmitterOptions<T>['hasListenerOrderDependencies'] | null, reentrantNotificationStrategy?: TinyEmitterOptions<T>['reentrantNotificationStrategy'] | null);
    /**
     * Disposes an Emitter. All listeners are removed.
     */
    dispose(): void;
    /**
     * Notify listeners
     */
    emit(...args: T): void;
    /**
     * Execute the notification of listeners (from the provided context and list). This function supports guarding against
     * if listener order changes during the notification process, see guardListeners.
     */
    private notifyLoop;
    /**
     * Adds a listener which will be called during emit.
     */
    addListener(listener: TEmitterListener<T>): void;
    /**
     * Removes a listener
     */
    removeListener(listener: TEmitterListener<T>): void;
    /**
     * Removes all the listeners
     */
    removeAllListeners(): void;
    /**
     * If listeners are added/removed while emit() is in progress, we must make a defensive copy of the array of listeners
     * before changing the array, and use it for the rest of the notifications until the emit call has completed.
     */
    private guardListeners;
    /**
     * Checks whether a listener is registered with this Emitter
     */
    hasListener(listener: TEmitterListener<T>): boolean;
    /**
     * Returns true if there are any listeners.
     */
    hasListeners(): boolean;
    /**
     * Returns the number of listeners.
     */
    getListenerCount(): number;
    /**
     * Invokes a callback once for each listener - meant for Property's use
     */
    forEachListener(callback: (listener: TEmitterListener<T>) => void): void;
}
//# sourceMappingURL=TinyEmitter.d.ts.map