"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.DurationIterator = exports.WindowIterator = exports.AtomIterator = exports.FlatAtom = void 0;
const TSU = __importStar(require("@panyam/tsutils"));
const entity_1 = require("./entity");
const core_1 = require("./core");
class FlatAtom extends entity_1.TimedEntity {
    constructor(atom, config = null) {
        super((config = config || {}));
        this.atom = atom;
        this.TYPE = "FlatAtom";
        this.depth = config.depth || 0;
        this.duration = config.duration || atom.duration;
        this.offset = config.offset || TSU.Num.Fraction.ZERO;
        this.isContinuation = "isContinuation" in config ? config.isContinuation : false;
    }
    get endOffset() {
        return this.offset.plus(this.duration);
    }
    debugValue() {
        const out = Object.assign(Object.assign({}, super.debugValue()), { atom: this.atom.debugValue(), duration: this.duration.toString(), offset: this.offset.toString(), depth: this.depth });
        if (this.isContinuation)
            out.isContinuation = true;
        return out;
    }
}
exports.FlatAtom = FlatAtom;
class AtomIterator {
    constructor(...atoms) {
        this.atomQueue = new TSU.Lists.List();
        this.currOffset = TSU.Num.Fraction.ZERO;
        this.peeked = null;
        this.push(...atoms);
    }
    push(...atoms) {
        for (const atom of atoms) {
            this.atomQueue.add([atom, 0, atom.duration]);
        }
        return this;
    }
    next() {
        const out = this.peek();
        this.peeked = null;
        if (out != null) {
            this.currOffset = this.currOffset.plus(out.duration).factorized;
        }
        return out;
    }
    peek() {
        if (this.peeked == null) {
            if (this.hasNext) {
                const [nextAtom, nextDepth, nextDuration] = this.atomQueue.popFront();
                this.peeked = new FlatAtom(nextAtom, {
                    depth: nextDepth,
                    offset: this.currOffset,
                    duration: nextDuration,
                });
            }
        }
        return this.peeked;
    }
    get hasNext() {
        while (this.atomQueue.first != null) {
            const [nextAtom, nextDepth, nextDuration] = this.atomQueue.first.value;
            if (nextAtom.TYPE != core_1.AtomType.GROUP) {
                return true;
            }
            else {
                this.atomQueue.popFront();
                const group = nextAtom;
                for (const child of group.atoms.reversedValues()) {
                    this.atomQueue.pushFront([
                        child,
                        nextDepth + 1,
                        nextDuration.times(child.duration).divby(group.totalChildDuration).factorized,
                    ]);
                }
            }
        }
        return false;
    }
    static getMin(iterators) {
        let currRole = -1;
        let currAtom = null;
        for (let ri = 0; ri < iterators.length; ri++) {
            const flatAtom = iterators[ri].peek();
            if (flatAtom != null) {
                if (currAtom == null || flatAtom.offset.cmp(currAtom.offset) < 0) {
                    currRole = ri;
                    currAtom = flatAtom;
                }
            }
        }
        if (currRole >= 0) {
            iterators[currRole].next();
        }
        return [currRole, currAtom];
    }
}
exports.AtomIterator = AtomIterator;
class WindowIterator {
    constructor(...atoms) {
        this.atomQueue = new TSU.Lists.List();
        this.currOffset = TSU.Num.Fraction.ZERO;
        this.peeked = null;
        this.push(...atoms);
    }
    push(...atoms) {
        for (const atom of atoms) {
            this.atomQueue.add(atom);
        }
        return this;
    }
    next() {
        const out = this.peek();
        this.peeked = null;
        if (out != null) {
            this.currOffset = this.currOffset.plus(out.duration, true);
        }
        return out;
    }
    peek() {
        if (this.peeked == null && this.hasMore) {
            this.peeked = this.atomQueue.popFront();
        }
        return this.peeked;
    }
    get hasMore() {
        return !this.atomQueue.isEmpty;
    }
    get(duration) {
        const out = [];
        let remaining = duration;
        while (remaining.isGTNum(0) && this.hasMore) {
            const next = this.next();
            TSU.assert(next != null, "Next cannot be null here");
            out.push(next);
            const spillOver = next.splitAt(remaining);
            remaining = remaining.minus(next.duration);
            if (spillOver != null) {
                this.atomQueue.pushFront(spillOver);
            }
        }
        return [out, remaining.isZero];
    }
}
exports.WindowIterator = WindowIterator;
class DurationIterator {
    constructor(atomIterator) {
        this.spillOver = null;
        this.atomIterator = atomIterator;
    }
    get hasMore() {
        if (this.spillOver != null) {
            return true;
        }
        return this.atomIterator.hasNext;
    }
    get(duration) {
        const iter = this.atomIterator;
        const out = [];
        let remaining = duration;
        while (remaining.isGTNum(0)) {
            const next = this.spillOver == null ? iter.next() : this.spillOver;
            this.spillOver = null;
            if (next == null) {
                break;
            }
            else {
                out.push(next);
                if (next.duration.cmp(remaining) <= 0) {
                    remaining = remaining.minus(next.duration);
                }
                else {
                    this.spillOver = new FlatAtom(new core_1.Space(next.duration.minus(remaining)));
                    next.duration = remaining;
                    remaining = TSU.Num.Fraction.ZERO;
                }
            }
        }
        return [out, remaining.isZero];
    }
}
exports.DurationIterator = DurationIterator;
//# sourceMappingURL=iterators.js.map