"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.windowTime = void 0;
const Subject_js_1 = require("../Subject.js");
const async_js_1 = require("../scheduler/async.js");
const Observable_js_1 = require("../Observable.js");
const arrRemove_js_1 = require("../util/arrRemove.js");
const args_js_1 = require("../util/args.js");
const executeSchedule_js_1 = require("../util/executeSchedule.js");
function windowTime(windowTimeSpan, ...otherArgs) {
    const scheduler = (0, args_js_1.popScheduler)(otherArgs) ?? async_js_1.asyncScheduler;
    const windowCreationInterval = otherArgs[0] ?? null;
    const maxWindowSize = otherArgs[1] || Infinity;
    return (source) => new Observable_js_1.Observable((destination) => {
        let windowRecords = [];
        let restartOnClose = false;
        const closeWindow = (record) => {
            const { window, subs } = record;
            window.complete();
            subs.unsubscribe();
            (0, arrRemove_js_1.arrRemove)(windowRecords, record);
            restartOnClose && startWindow();
        };
        const startWindow = () => {
            if (windowRecords) {
                const subs = new Observable_js_1.Subscription();
                destination.add(subs);
                const window = new Subject_js_1.Subject();
                const record = {
                    window,
                    subs,
                    seen: 0,
                };
                windowRecords.push(record);
                destination.next(window.asObservable());
                (0, executeSchedule_js_1.executeSchedule)(subs, scheduler, () => closeWindow(record), windowTimeSpan);
            }
        };
        if (windowCreationInterval !== null && windowCreationInterval >= 0) {
            (0, executeSchedule_js_1.executeSchedule)(destination, scheduler, startWindow, windowCreationInterval, true);
        }
        else {
            restartOnClose = true;
        }
        startWindow();
        const loop = (cb) => windowRecords.slice().forEach(cb);
        const terminate = (cb) => {
            loop(({ window }) => cb(window));
            cb(destination);
            destination.unsubscribe();
        };
        source.subscribe((0, Observable_js_1.operate)({
            destination,
            next: (value) => {
                loop((record) => {
                    record.window.next(value);
                    maxWindowSize <= ++record.seen && closeWindow(record);
                });
            },
            error: (err) => terminate((consumer) => consumer.error(err)),
            complete: () => terminate((consumer) => consumer.complete()),
        }));
        return () => {
            windowRecords = null;
        };
    });
}
exports.windowTime = windowTime;