"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OnNewFanOut = exports.MapFanOut = exports.MicrotaskBufferFanOut = exports.MergeFanOut = void 0;
const fanout_1 = require("thingies/lib/fanout");
/**
 * Merges multiple fanouts into a single fanout. The merged fanout emits the
 * same data as the source fanouts.
 */
class MergeFanOut extends fanout_1.FanOut {
    constructor(fanouts) {
        super();
        this.fanouts = fanouts;
        this.unsubs = [];
    }
    listen(listener) {
        if (!this.listeners.size)
            this.unsubs = this.fanouts.map((fanout) => fanout.listen((data) => this.emit(data)));
        const unsub = super.listen(listener);
        return () => {
            unsub();
            if (!this.listeners.size) {
                for (const unsub of this.unsubs)
                    unsub();
                this.unsubs = [];
            }
        };
    }
}
exports.MergeFanOut = MergeFanOut;
/**
 * Buffers data from a fanout and emits the buffered data once per microtask.
 */
class MicrotaskBufferFanOut extends fanout_1.FanOut {
    constructor(source) {
        super();
        this.source = source;
        this.buffer = [];
        this.unsub = undefined;
    }
    listen(listener) {
        if (!this.unsub) {
            this.unsub = this.source.listen((data) => {
                const buffer = this.buffer;
                if (!buffer.length) {
                    queueMicrotask(() => {
                        this.emit(buffer);
                        this.buffer = [];
                    });
                }
                buffer.push(data);
            });
        }
        const unsub = super.listen(listener);
        return () => {
            unsub();
            if (!this.listeners.size)
                this.clear();
        };
    }
    clear() {
        this.listeners.clear();
        this.buffer = [];
        this.unsub?.();
        this.unsub = undefined;
    }
}
exports.MicrotaskBufferFanOut = MicrotaskBufferFanOut;
/**
 * Maps the data from a fanout using a mapper function.
 */
class MapFanOut extends fanout_1.FanOut {
    constructor(source, mapper) {
        super();
        this.source = source;
        this.mapper = mapper;
        this.unsub = undefined;
    }
    listen(listener) {
        if (!this.unsub)
            this.unsub = this.source.listen((data) => this.emit(this.mapper(data)));
        const unsub = super.listen(listener);
        return () => {
            unsub();
            if (!this.listeners.size)
                this.clear();
        };
    }
    clear() {
        this.listeners.clear();
        this.unsub?.();
        this.unsub = undefined;
    }
}
exports.MapFanOut = MapFanOut;
/**
 * Emits only when the source fanout emits a new value. The first value is
 * emitted immediately.
 */
class OnNewFanOut extends fanout_1.FanOut {
    constructor(source, last = undefined) {
        super();
        this.source = source;
        this.last = last;
        this.unsub = undefined;
    }
    listen(listener) {
        if (!this.unsub) {
            this.unsub = this.source.listen((data) => {
                if (this.last !== data)
                    this.emit((this.last = data));
            });
        }
        const unsub = super.listen(listener);
        return () => {
            unsub();
            if (!this.listeners.size)
                this.clear();
        };
    }
    clear() {
        this.listeners.clear();
        this.last = undefined;
        this.unsub?.();
        this.unsub = undefined;
    }
}
exports.OnNewFanOut = OnNewFanOut;
//# sourceMappingURL=fanout.js.map