"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (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 (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.zipAllWithExec = exports.zipAllWithExec_ = exports.zipAllWith = exports.zipAllWith_ = exports.zipAllRight = exports.zipAllRight_ = exports.zipAllLeft = exports.zipAllLeft_ = exports.zipAll = exports.zipAll_ = void 0;
const tracing_1 = __importStar(require("../../../Tracing"));
const fileName_1 = "(@effect-ts/system): _src/Experimental/Stream/_internal/zipAll.ts";
const CS = __importStar(require("../../../Cause"));
const A = __importStar(require("../../../Collections/Immutable/Chunk"));
const Tp = __importStar(require("../../../Collections/Immutable/Tuple"));
const T = __importStar(require("../../../Effect"));
const E = __importStar(require("../../../Either"));
const Ex = __importStar(require("../../../Exit"));
const Function_1 = require("../../../Function");
const O = __importStar(require("../../../Option"));
const S = __importStar(require("./core"));
const utils_1 = require("./utils");
/**
 * Zips this stream with another point-wise, creating a new stream of pairs of elements
 * from both sides.
 *
 * The defaults `defaultLeft` and `defaultRight` will be used if the streams have different lengths
 * and one of the streams has ended before the other.
 */
function zipAll_(self, that, defaultLeft, defaultRight) {
    return zipAllWith_(self, that, (_) => Tp.tuple(_, defaultRight), (_) => Tp.tuple(defaultLeft, _), (a, b) => Tp.tuple(a, b));
}
exports.zipAll_ = zipAll_;
/**
 * Zips this stream with another point-wise, creating a new stream of pairs of elements
 * from both sides.
 *
 * The defaults `defaultLeft` and `defaultRight` will be used if the streams have different lengths
 * and one of the streams has ended before the other.
 *
 * @ets_data_first zipAll_
 */
function zipAll(that, defaultLeft, defaultRight) {
    return (self) => zipAll_(self, that, defaultLeft, defaultRight);
}
exports.zipAll = zipAll;
/**
 * Zips this stream with another point-wise, and keeps only elements from the other stream.
 *
 * The provided default value will be used if this stream ends before the other one.
 */
function zipAllLeft_(self, that, default_) {
    return zipAllWith_(self, that, Function_1.identity, (_) => default_, (o, _) => o);
}
exports.zipAllLeft_ = zipAllLeft_;
/**
 * Zips this stream with another point-wise, and keeps only elements from the other stream.
 *
 * The provided default value will be used if this stream ends before the other one.
 *
 * @ets_data_first zipAllLeft_
 */
function zipAllLeft(that, default_) {
    return (self) => zipAllLeft_(self, that, default_);
}
exports.zipAllLeft = zipAllLeft;
/**
 * Zips this stream with another point-wise, and keeps only elements from the other stream.
 *
 * The provided default value will be used if this stream ends before the other one.
 */
function zipAllRight_(self, that, default_) {
    return zipAllWith_(self, that, (_) => default_, Function_1.identity, (_, o) => o);
}
exports.zipAllRight_ = zipAllRight_;
/**
 * Zips this stream with another point-wise, and keeps only elements from the other stream.
 *
 * The provided default value will be used if this stream ends before the other one.
 *
 * @ets_data_first zipAllRight_
 */
function zipAllRight(that, default_) {
    return (self) => zipAllRight_(self, that, default_);
}
exports.zipAllRight = zipAllRight;
/**
 * Zips this stream with another point-wise. The provided functions will be used to create elements
 * for the composed stream.
 *
 * The functions `left` and `right` will be used if the streams have different lengths
 * and one of the streams has ended before the other.
 */
function zipAllWith_(self, that, left, right, both) {
    return zipAllWithExec_(self, that, T.parallel, left, right, both);
}
exports.zipAllWith_ = zipAllWith_;
/**
 * Zips this stream with another point-wise. The provided functions will be used to create elements
 * for the composed stream.
 *
 * The functions `left` and `right` will be used if the streams have different lengths
 * and one of the streams has ended before the other.
 *
 * @ets_data_first zipAllWith_
 */
function zipAllWith(that, left, right, both) {
    return (self) => zipAllWith_(self, that, left, right, both);
}
exports.zipAllWith = zipAllWith;
const StatusTypeId = Symbol();
const RunningTypeId = Symbol();
class Running {
    constructor() {
        this._statusTypeId = StatusTypeId;
        this._typeId = RunningTypeId;
    }
}
const LeftDoneTypeId = Symbol();
class LeftDone {
    constructor() {
        this._statusTypeId = StatusTypeId;
        this._typeId = LeftDoneTypeId;
    }
}
const RightDoneTypeId = Symbol();
class RightDone {
    constructor() {
        this._statusTypeId = StatusTypeId;
        this._typeId = RightDoneTypeId;
    }
}
const EndTypeId = Symbol();
class End {
    constructor() {
        this._statusTypeId = StatusTypeId;
        this._typeId = EndTypeId;
    }
}
/**
 * Zips this stream with another point-wise. The provided functions will be used to create elements
 * for the composed stream.
 *
 * The functions `left` and `right` will be used if the streams have different lengths
 * and one of the streams has ended before the other.
 *
 * The execution strategy `exec` will be used to determine whether to pull
 * from the streams sequentially or in parallel.
 */
function zipAllWithExec_(self, that, exec, left, right, both) {
    const handleSuccess = (maybeO, maybeA1, excess) => {
        const { tuple: [excessL, excessR] } = E.fold_(excess, (l) => Tp.tuple(l, A.empty()), (r) => Tp.tuple(A.empty(), r));
        const chunkL = O.fold_(maybeO, () => excessL, (upd) => A.concat_(excessL, upd));
        const chunkR = O.fold_(maybeA1, () => excessR, (upd) => A.concat_(excessR, upd));
        const { tuple: [emit, newExcess] } = (0, utils_1.zipChunks_)(chunkL, chunkR, both);
        const { tuple: [fullEmit, status] } = (() => {
            if (O.isSome(maybeO)) {
                if (O.isSome(maybeA1)) {
                    return Tp.tuple(emit, new Running());
                }
                else {
                    return Tp.tuple(emit, new RightDone());
                }
            }
            else {
                if (O.isSome(maybeA1)) {
                    return Tp.tuple(emit, new LeftDone());
                }
                else {
                    const leftover = E.fold_(newExcess, A.map(left), A.map(right));
                    return Tp.tuple(A.concat_(emit, leftover), new End());
                }
            }
        })();
        return Ex.succeed(Tp.tuple(fullEmit, Tp.tuple(status, newExcess)));
    };
    return S.combineChunks_(self, that, Tp.tuple(new Running(), E.left(A.empty())), ({ tuple: [status, excess] }, pullL, pullR) => {
        switch (status._typeId) {
            case RunningTypeId: {
                if (exec._tag === "Sequential") {
                    return (T.catchAllCause_(T.zipWith_(T.unoption(pullL), T.unoption(pullR), (a, b) => handleSuccess(a, b, excess), fileName_1 + ":264:24"), (e) => T.succeed(Ex.failCause(CS.map_(e, O.some)), fileName_1 + ":265:47"), fileName_1 + ":265:30"));
                }
                else {
                    return (T.catchAllCause_(T.zipWithPar(T.unoption(pullR), (a, b) => handleSuccess(a, b, excess), fileName_1 + ":271:27")(T.unoption(pullL)), (e) => T.succeed(Ex.failCause(CS.map_(e, O.some)), fileName_1 + ":272:47"), fileName_1 + ":272:30"));
                }
            }
            case LeftDoneTypeId:
                return (T.catchAllCause_(T.map_(T.unoption(pullR), (_) => handleSuccess(O.none, _, excess), fileName_1 + ":280:18"), (e) => T.succeed(Ex.failCause(CS.map_(e, O.some)), fileName_1 + ":281:45"), fileName_1 + ":281:28"));
            case RightDoneTypeId:
                return (T.catchAllCause_(T.map_(T.unoption(pullL), (_) => handleSuccess(_, O.none, excess), fileName_1 + ":287:18"), (e) => T.succeed(Ex.failCause(CS.map_(e, O.some)), fileName_1 + ":288:45"), fileName_1 + ":288:28"));
            case EndTypeId:
                return T.succeed(Ex.fail(O.none), fileName_1 + ":291:27");
        }
    });
}
exports.zipAllWithExec_ = zipAllWithExec_;
/**
 * Zips this stream with another point-wise. The provided functions will be used to create elements
 * for the composed stream.
 *
 * The functions `left` and `right` will be used if the streams have different lengths
 * and one of the streams has ended before the other.
 *
 * The execution strategy `exec` will be used to determine whether to pull
 * from the streams sequentially or in parallel.
 *
 * @ets_data_first zipAllWithExec_
 */
function zipAllWithExec(that, exec, left, right, both) {
    return (self) => zipAllWithExec_(self, that, exec, left, right, both);
}
exports.zipAllWithExec = zipAllWithExec;
//# sourceMappingURL=zipAll.js.map