"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.clone = void 0;
const Stream_1 = require("../../stream/Stream");
const symbols_1 = require("../symbols");
const Arbitrary_1 = require("./definition/Arbitrary");
const Shrinkable_1 = require("./definition/Shrinkable");
class CloneArbitrary extends Arbitrary_1.Arbitrary {
    constructor(arb, numValues) {
        super();
        this.arb = arb;
        this.numValues = numValues;
    }
    generate(mrng) {
        const items = [];
        if (this.numValues <= 0) {
            return this.wrapper(items);
        }
        for (let idx = 0; idx !== this.numValues - 1; ++idx) {
            items.push(this.arb.generate(mrng.clone()));
        }
        items.push(this.arb.generate(mrng));
        return this.wrapper(items);
    }
    static makeItCloneable(vs, shrinkables) {
        vs[symbols_1.cloneMethod] = () => {
            const cloned = [];
            for (let idx = 0; idx !== shrinkables.length; ++idx) {
                cloned.push(shrinkables[idx].value);
            }
            this.makeItCloneable(cloned, shrinkables);
            return cloned;
        };
        return vs;
    }
    wrapper(items) {
        let cloneable = false;
        const vs = [];
        for (let idx = 0; idx !== items.length; ++idx) {
            const s = items[idx];
            cloneable = cloneable || s.hasToBeCloned;
            vs.push(s.value);
        }
        if (cloneable) {
            CloneArbitrary.makeItCloneable(vs, items);
        }
        return new Shrinkable_1.Shrinkable(vs, () => Stream_1.stream(this.shrinkImpl(items)).map((v) => this.wrapper(v)));
    }
    *shrinkImpl(items) {
        if (items.length === 0) {
            return;
        }
        const its = items.map((s) => s.shrink()[Symbol.iterator]());
        let cur = its.map((it) => it.next());
        while (!cur[0].done) {
            yield cur.map((c) => c.value);
            cur = its.map((it) => it.next());
        }
    }
}
function clone(arb, numValues) {
    return new CloneArbitrary(arb, numValues);
}
exports.clone = clone;
