
import '../../errors.js';
import '../../arrays.js';
import '../../event.js';
import { DisposableStore, toDisposable } from '../../lifecycle.js';
import { DebugNameData } from '../debugName.js';
import { AutorunObserver } from './autorunImpl.js';

function autorun(fn) {
    return ( new AutorunObserver(( new DebugNameData(undefined, undefined, fn)), fn, undefined));
}
function autorunOpts(options, fn) {
    return ( new AutorunObserver(( new DebugNameData(options.owner, options.debugName, options.debugReferenceFn ?? fn)), fn, undefined));
}
function autorunHandleChanges(options, fn) {
    return ( new AutorunObserver(( new DebugNameData(options.owner, options.debugName, options.debugReferenceFn ?? fn)), fn, options.changeTracker));
}
function autorunWithStoreHandleChanges(options, fn) {
    const store = ( new DisposableStore());
    const disposable = autorunHandleChanges({
        owner: options.owner,
        debugName: options.debugName,
        debugReferenceFn: options.debugReferenceFn ?? fn,
        changeTracker: options.changeTracker,
    }, (reader, changeSummary) => {
        store.clear();
        fn(reader, changeSummary, store);
    });
    return toDisposable(() => {
        disposable.dispose();
        store.dispose();
    });
}
function autorunWithStore(fn) {
    const store = ( new DisposableStore());
    const disposable = autorunOpts({
        owner: undefined,
        debugName: undefined,
        debugReferenceFn: fn,
    }, reader => {
        store.clear();
        fn(reader, store);
    });
    return toDisposable(() => {
        disposable.dispose();
        store.dispose();
    });
}
function autorunDelta(observable, handler) {
    let _lastValue;
    return autorunOpts({ debugReferenceFn: handler }, (reader) => {
        const newValue = observable.read(reader);
        const lastValue = _lastValue;
        _lastValue = newValue;
        handler({ lastValue, newValue });
    });
}
function autorunIterableDelta(getValue, handler, getUniqueIdentifier = v => v) {
    const lastValues = ( new Map());
    return autorunOpts({ debugReferenceFn: getValue }, (reader) => {
        const newValues = ( new Map());
        const removedValues = ( new Map(lastValues));
        for (const value of getValue(reader)) {
            const id = getUniqueIdentifier(value);
            if (( lastValues.has(id))) {
                removedValues.delete(id);
            }
            else {
                newValues.set(id, value);
                lastValues.set(id, value);
            }
        }
        for (const id of ( removedValues.keys())) {
            lastValues.delete(id);
        }
        if (newValues.size || removedValues.size) {
            handler({ addedValues: [...( newValues.values())], removedValues: [...( removedValues.values())] });
        }
    });
}

export { autorun, autorunDelta, autorunHandleChanges, autorunIterableDelta, autorunOpts, autorunWithStore, autorunWithStoreHandleChanges };
