import { Observable, Subject } from 'rxjs';
import { ClearCacheOptions, DispatchOptions, DispatchValueProducer, UnitConfig, UnitEvents, UnitStreamObservableProducer } from '../models';
import { Base } from './abstract-base';
import { Stream } from './stream';
/**
 * UnitBase serves as the base for all the ActiveJS Units: GenericUnit, BoolUnit, ListUnit, etc.
 * It extends {@link Base}.
 *
 * This is an internal construct, normally you'd never have to use this class directly.
 * However, if you're just reading the documentation, or want to learn more about how ActiveJS works,
 * or want to extend this class to build something on your own, please continue.
 *
 * UnitBase creates the foundation of all the ActiveJS Units.
 * It implements the features like:
 * - dispatching, clearing and resetting the value
 * - caching the dispatched values
 * - navigating through the cached values, by methods like goBack, goForward, jump etc.
 * - observable events to listen to including but not limited to the above mentioned actions
 * - freezing/unfreezing the Unit
 * - muting/unmuting the Unit
 * - persisting and retrieving the value to/from persistent-storage
 * - debouncing the dispatch
 * - resetting the Unit
 * - etc.
 *
 * @category 2. Abstract
 */
export declare abstract class UnitBase<T> extends Base<T> {
    /**
     * Configured options.
     * Combination of global-options {@link GlobalUnitConfig} and the options passed on instantiation.
     */
    readonly config: Readonly<UnitConfig<T>>;
    /**
     * @internal please do not use.
     */
    protected readonly eventsSubject: Subject<UnitEvents<T>>;
    /**
     * On-demand observable events.
     */
    readonly events$: Observable<UnitEvents<T>>;
    /**
     * @internal please do not use.
     */
    private _isFrozen;
    /**
     * Indicates whether the Unit is frozen or not.
     * See {@link freeze} for more details.
     *
     * Note: It's not the same as [Object.isFrozen](https://cutt.ly/WyFdzPD).
     */
    get isFrozen(): boolean;
    /**
     * @internal please do not use.
     */
    private emitOnUnmute;
    /**
     * @internal please do not use.
     */
    private _isMuted;
    /**
     * Indicates whether the Unit is muted or not.
     * See {@link mute} for more details.
     */
    get isMuted(): boolean;
    /**
     * Indicates whether the value is undefined or not.
     *
     * It should be preferred if the Unit is configured to be immutable, as it doesn't create a copy.
     */
    get isEmpty(): boolean;
    /**
     * Size of the cache, dictating how many values can be cached at a given time.
     *
     * @default `2`
     * @minimum `1`
     * @maximum `Infinity`
     */
    readonly cacheSize: number;
    /**
     * @internal please do not use.
     */
    protected readonly _cachedValues: T[];
    /**
     * Count of all the cached values.
     */
    get cachedValuesCount(): number;
    /**
     * @internal please do not use.
     */
    private _cacheIndex;
    /**
     * Index of the current {@link value} in the {@link UnitBase.cachedValues}
     */
    get cacheIndex(): number;
    /**
     * @internal please do not use.
     */
    private _initialValue;
    /**
     * @internal please do not use.
     */
    protected _value: T;
    /**
     * The initialValue provided on instantiation.
     * Creates a copy if the Unit is configured to be immutable.
     *
     * @category Access Value
     */
    initialValue(): T;
    /**
     * Current value of the Unit.
     * Creates a copy if the Unit is configured to be immutable.
     *
     * @default
     * BoolUnit: `false` \
     * NumUnit: `0` \
     * StringUnit: `''` \
     * ListUnit: `[]` \
     * DictUnit: `{}` \
     * GenericUnit: `undefined`
     *
     * @category Access Value
     */
    value(): T;
    /**
     * If the Unit has a non-primitive value,
     * use it to get access to the current {@link value}, without creating a deep-copy.
     *
     * This can come in handy if the Unit is configured to be immutable, and you want to perform a non-mutating action
     * without creating a deep-copy of the value.
     *
     * @category Access Value
     */
    rawValue(): T;
    /**
     * All the cached values.
     * Creates a copy if the Unit is configured to be immutable.
     *
     * @category Access Value
     */
    cachedValues(): T[];
    /**
     * @internal please do not use.
     */
    private initialValueRaw;
    /**
     * @internal please do not use.
     */
    protected defaultValue(): T;
    /**
     * @internal please do not use.
     */
    protected constructor(config?: UnitConfig<T>);
    /**
     * A helper method that creates a stream by subscribing to the Observable returned by the param `observableProducer` callback.
     *
     * Ideally the callback function creates an Observable by applying `Observable.pipe`.
     *
     * Just know that you should catch the error in a sub-pipe (ie: do not let it propagate to the main-pipe), otherwise
     * as usual the stream will stop working, and will not react on any further emissions.
     *
     * @param observableProducer A callback function that should return an Observable.
     *
     * @category Common
     */
    createStream<R>(observableProducer: UnitStreamObservableProducer<this, R>): Stream;
    /**
     * Given a value, this function determines whether it should be dispatched or not. \
     * The dispatch is denied in following circumstances:
     * - If the Unit is frozen. {@link isFrozen}
     * - If {@link UnitConfig.distinctDispatchCheck} is set to `true`, and the new-value === current-value,
     * - If {@link UnitConfig.customDispatchCheck} returns a `falsy` value.
     *
     * If the Unit is not frozen, you can bypass other dispatch-checks by passing param `force = true`.
     *
     * This function is used internally, when a value is dispatched {@link dispatch}. \
     * Even initialValue {@link UnitConfig.initialValue} dispatch has to pass this check.
     *
     * You can also use it to check if the value will be dispatched or not before dispatching it.
     *
     * @param value The value to be dispatched.
     * @param force Whether dispatch-checks should be bypassed or not.
     * @returns A boolean indicating whether the param `value` would pass the dispatch-checks if dispatched.
     *
     * @category Common Units
     */
    wouldDispatch(value: T, force?: boolean): boolean;
    dispatch(value: T, options?: DispatchOptions): boolean | undefined;
    dispatch(valueProducer: DispatchValueProducer<T>, options?: DispatchOptions): boolean | undefined;
    /**
     * To manually re-emit the last emitted value again. \
     * It doesn't work if the Unit is frozen {@link isFrozen} or muted {@link isMuted}.
     *
     * Note: Even if the Unit is immutable, it does not create a copy of the Unit's value,
     * it merely re-emits the last emitted value.
     *
     * @returns `true` if replayed successfully, otherwise `false`.
     *
     * @triggers {@link EventReplay}
     * @category Common
     */
    replay(): boolean;
    /**
     * Go back in the cache and re-emit the previous value from the cache, \
     * without creating a new entry in the cache.
     *
     * It can be used as Undo.
     *
     * It doesn't work if the Unit is frozen {@link isFrozen}.
     * It only works if there's a previously dispatched value in the cache. \
     * ie: the {@link cacheIndex} is not 0
     *
     * @returns `true` if the cache-navigation was successful, otherwise `false`.
     *
     * @triggers {@link EventUnitJump}
     * @category Cache Navigation
     */
    goBack(): boolean;
    /**
     * After going back in the cache (ie: re-emitting an old value from the cache), \
     * use this method to go to the next value, without creating a new entry in the cache.
     *
     * It can be used as Redo.
     *
     * It doesn't work if the Unit is frozen {@link isFrozen}.
     * It only works if the current {@link value} is not the last value in the cache. \
     * ie: the {@link cacheIndex} is not equal to `cachedValuesCount - 1`
     *
     * @returns `true` if the cache-navigation was successful, otherwise `false`
     *
     * @triggers {@link EventUnitJump}
     * @category Cache Navigation
     */
    goForward(): boolean;
    /**
     * Use this method to re-emit the first value in the cache, \
     * without creating a new entry in the cache.
     *
     * It doesn't work if the Unit is frozen {@link isFrozen}.
     * It only works if the {@link cacheIndex} is not already at the last value in the cache. \
     * ie: the {@link cacheIndex} is not 0.
     *
     * @returns `true` if the cache-navigation was successful, otherwise `false`
     *
     * @triggers {@link EventUnitJump}
     * @category Cache Navigation
     */
    jumpToStart(): boolean;
    /**
     * After going back in the cache (ie: re-emitting an old value from the cache), \
     * use this method to re-dispatch the last (latest) value in the cache, \
     * without creating a new entry in the cache.
     *
     * It doesn't work if the Unit is frozen {@link isFrozen}.
     * It only works if the {@link cacheIndex} is not already at the last value in the cache.
     *
     * @returns `true` if the cache-navigation was successful, otherwise `false`
     *
     * @triggers {@link EventUnitJump}
     * @category Cache Navigation
     */
    jumpToEnd(): boolean;
    /**
     * Use this method to re-emit a value from the cache, by jumping specific steps backwards or forwards, \
     * without creating a new entry in the cache.
     *
     * It doesn't work if the Unit is frozen {@link isFrozen} or `steps` is not a `number`.
     * It only works if the new calculated index is in the bounds of {@link cachedValues}, \
     * ie: the new-index is >= 0, and less than {@link cachedValuesCount}, but \
     * not equal to current {@link cacheIndex}.
     *
     * @param steps Number of steps to jump in the cache, negative to jump backwards, positive to jump forwards
     * @returns `true` if the cache-navigation was successful, otherwise `false`.
     *
     * @triggers {@link EventUnitJump}
     * @category Cache Navigation
     */
    jump(steps: number): boolean;
    /**
     * Get cached value at a given index.
     *
     * @param index The index of cached value
     * @returns The cached value if it exists, otherwise undefined
     *
     * @category Common Units
     */
    getCachedValue(index: number): T | undefined;
    /**
     * Clears the cached values, current {@link value} stays intact, but it gets removed from the cache. \
     * Meaning, if you dispatch a new value you can't {@link goBack}. \
     * To keep the last value in the cache, pass `{leaveLast: true}` in the param `options`.
     *
     * It only works if the Unit is not frozen and there's something left to clear after evaluating the param `options`.
     *
     * Similar to preserving the last value, you can preserve the first value by passing `{leaveFirst: true}`.
     * Or preserve both first and last value by passing both options together.
     *
     * @param options Clear cache options
     * @returns `true` if the cache was cleared, otherwise `false`
     *
     * @triggers {@link EventUnitClearCache}
     * @category Common Units
     */
    clearCache(options?: ClearCacheOptions): boolean;
    /**
     * Clears the value by dispatching the default value. \
     * It only works if the Unit is not frozen, and {@link emitCount} is not 0, and value is not empty {@link isEmpty}.
     *
     * @returns `true` if the value was cleared, otherwise `false`
     *
     * @triggers {@link EventUnitClearValue}
     * @category Common Units
     */
    clearValue(): boolean;
    /**
     * Holistically clears the Unit, \
     * unfreezes using {@link unfreeze}, \
     * clears the value using {@link clearValue}, \
     * completely clears cache using {@link clearCache}, \
     * in that specific order.
     *
     * @param options Clear cache options for {@link clearCache}.
     *
     * @triggers {@link EventUnitClear}
     * @category Common Units
     */
    clear(options?: ClearCacheOptions): void;
    /**
     * Resets the value by dispatching the initial-value, {@link UnitConfig.initialValue} if provided, \
     * otherwise dispatches the default value.
     *
     * It only works if the Unit is not frozen, \
     * and the {@link value} is not equal to the {@link initialValue}.
     *
     * @returns `true` if the reset was successful, otherwise `false`
     *
     * @triggers {@link EventUnitResetValue}
     * @category Common Units
     */
    resetValue(): boolean;
    /**
     * Holistically resets the Unit, \
     * unfreezes using {@link unfreeze}, \
     * resets the value using {@link resetValue}, \
     * clears cache using {@link clearCache} and by default leaves last value; \
     * in that specific order.
     *
     * @param options Clear cache options for {@link clearCache}. default is `{leaveLast: true}`
     *
     * @triggers {@link EventUnitReset}
     * @category Common Units
     */
    reset(options?: ClearCacheOptions): void;
    /**
     * Temporarily disables most of the functions of the Unit, except {@link unfreeze}, \
     * {@link mute}/{@link unmute}, {@link clear} and {@link reset}.
     *
     * It's not the same as `Object.freeze`.
     *
     * Freezing prevents any new values from getting dispatched, \
     * it disables all the mutating functions. \
     * Which eventually ensures that no event is emitted while the Unit is frozen, \
     * however all the read operations and operations that do not emit a value are allowed.
     *
     * @triggers {@link EventUnitFreeze}
     * @category Common Units
     */
    freeze(): void;
    /**
     * Unfreezes the Unit, and re-enables all the functions disabled by {@link freeze}. \
     * It only works if the Unit is frozen.
     *
     * @triggers {@link EventUnitUnfreeze}
     * @category Common Units
     */
    unfreeze(): void;
    /**
     * Mute the Unit, to stop emitting values as well as events, so that the subscribers are not triggered. \
     * All other functionalities stay unaffected. ie: cache it still updated, value is still updated.
     *
     * Note: If you subscribe to the default Observable while the Unit is muted, \
     * it will replay the last value emitted before muting the Unit, \
     * because new values are not being emitted.
     *
     * @category Common Units
     */
    mute(): void;
    /**
     * Unmute the Unit, to resume emitting values, and events. \
     * If a value was dispatched while the Unit was muted, the most recent value immediately gets emitted, \
     * so that subscribers can be in sync again. \
     * However, other {@link events$} are lost, and they will only emit on the next event.
     *
     * It only works if the Unit is muted. \
     * Moreover, it works even if the Unit is frozen, \
     * but no value will be emitted because no values would have been dispatched while the Unit was frozen.
     *
     * @triggers {@link EventUnitUnmute}
     * @category Common Units
     */
    unmute(): void;
    /**
     * Clears persisted value from persistent storage. \
     * It doesn't turn off persistence, future values will get persisted again.
     *
     * It only works if the Unit is configured to be persistent. ie: `options.persistent` is true.
     *
     * @returns `true` if the Unit is configured to be persistent, otherwise `false`.
     *
     * @triggers {@link EventUnitClearPersistedValue}
     * @category Common Units
     */
    clearPersistedValue(): boolean;
    /**
     * @internal please do not use.
     */
    protected abstract isValidValue(value: any): boolean;
    /**
     * @internal please do not use.
     */
    protected deepCopyMaybe<U>(o: U): U;
    /**
     * @internal please do not use.
     */
    protected checkSerializabilityMaybe(o: any): void;
    /**
     * @internal please do not use.
     */
    protected updateValueAndCache(value: T, options?: DispatchOptions, skipCache?: boolean): void;
    /**
     * @internal please do not use.
     */
    protected applyFallbackValue(value: T): T;
    /**
     * @internal please do not use.
     */
    private distinctCheck;
    /**
     * @internal please do not use.
     */
    private dispatchMiddleware;
    /**
     * @internal please do not use.
     */
    private dispatchActual;
    /**
     * @internal please do not use.
     */
    private shouldDispatchInitialValue;
    /**
     * @internal please do not use.
     */
    private updateCache;
    /**
     * @internal please do not use.
     */
    private dispatchInitialValue;
    /**
     * @internal please do not use.
     */
    private updateValueInPersistentStorage;
    /**
     * @internal please do not use.
     */
    private restoreValueFromPersistentStorage;
}
