"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_ = void 0;
// ets_tracing: off
const CS = __importStar(require("../../../../Cause"));
const CK = __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 ZipChunks = __importStar(require("./_internal/zipChunks"));
const CombineChunks = __importStar(require("./combineChunks"));
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, CK.empty()), (r) => Tp.tuple(CK.empty(), r));
        const chunkL = O.fold_(maybeO, () => excessL, (upd) => CK.concat_(excessL, upd));
        const chunkR = O.fold_(maybeA1, () => excessR, (upd) => CK.concat_(excessR, upd));
        const { tuple: [emit, newExcess] } = ZipChunks.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, CK.map(left), CK.map(right));
                    return Tp.tuple(CK.concat_(emit, leftover), new End());
                }
            }
        })();
        return Ex.succeed(Tp.tuple(fullEmit, Tp.tuple(status, newExcess)));
    };
    return CombineChunks.combineChunks_(self, that, Tp.tuple(new Running(), E.left(CK.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)), (e) => T.succeed(Ex.failCause(CS.map_(e, O.some)))));
                }
                else {
                    return (T.catchAllCause_(T.zipWithPar(T.unoption(pullR), (a, b) => handleSuccess(a, b, excess))(T.unoption(pullL)), (e) => T.succeed(Ex.failCause(CS.map_(e, O.some)))));
                }
            }
            case LeftDoneTypeId:
                return (T.catchAllCause_(T.map_(T.unoption(pullR), (_) => handleSuccess(O.none, _, excess)), (e) => T.succeed(Ex.failCause(CS.map_(e, O.some)))));
            case RightDoneTypeId:
                return (T.catchAllCause_(T.map_(T.unoption(pullL), (_) => handleSuccess(_, O.none, excess)), (e) => T.succeed(Ex.failCause(CS.map_(e, O.some)))));
            case EndTypeId:
                return T.succeed(Ex.fail(O.none));
        }
    });
}
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=zipAllWithExec.js.map