"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
// tracing: off
const C = __importStar(require("../../Cause"))
const A = __importStar(require("../../Collections/Immutable/Chunk"))
const Tp = __importStar(require("../../Collections/Immutable/Tuple"))
const E = __importStar(require("../../Either"))
const Ex = __importStar(require("../../Exit"))
const Function_1 = require("../../Function")
const O = __importStar(require("../../Option"))
const T = __importStar(require("../_internal/effect"))
const utils_1 = require("../_internal/utils")
const combineChunks_1 = require("./combineChunks")
/**
 * 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) {
  class Running {
    constructor() {
      this._tag = "Running"
    }
  }
  class LeftDone {
    constructor() {
      this._tag = "LeftDone"
    }
  }
  class RightDone {
    constructor() {
      this._tag = "RightDone"
    }
  }
  class End {
    constructor() {
      this._tag = "End"
    }
  }
  const handleSuccess = (maybeO, maybeO2, excess) => {
    const [excessL, excessR] = E.fold_(
      excess,
      (l) => [l, A.empty()],
      (r) => [A.empty(), r]
    )
    const chunkL = O.fold_(
      maybeO,
      () => excessL,
      (upd) => A.concat_(excessL, upd)
    )
    const chunkR = O.fold_(
      maybeO2,
      () => excessR,
      (upd) => A.concat_(excessR, upd)
    )
    const [emit, newExcess] = (0, utils_1.zipChunks_)(chunkL, chunkR, both)
    const [fullEmit, status] = ((oDefined, o2Defined) => {
      if (oDefined && o2Defined) {
        return [emit, new Running()]
      }
      if (!oDefined && !o2Defined) {
        const leftover = E.fold_(newExcess, A.map(left), A.map(right))
        return [A.concat_(emit, leftover), new End()]
      }
      if (!oDefined && o2Defined) {
        return [emit, new LeftDone()]
      }
      return [emit, new RightDone()]
    })(O.isSome(maybeO), O.isSome(maybeO2))
    return Ex.succeed(Tp.tuple(fullEmit, Tp.tuple(status, newExcess)))
  }
  return (0, combineChunks_1.combineChunks_)(
    self,
    that,
    Tp.tuple(new Running(), E.left(A.empty)),
    ({ tuple: [state, excess] }, pullL, pullR) => {
      switch (state._tag) {
        case "Running": {
          if (exec._tag === "Sequential") {
            return T.catchAllCause_(
              T.zipWith_(T.optional(pullL), T.optional(pullR), (a, b) =>
                handleSuccess(a, b, excess)
              ),
              (e) => T.succeed(Ex.halt(C.map_(e, O.some)))
            )
          } else {
            return T.catchAllCause_(
              T.zipWithPar(T.optional(pullR), (a, b) => handleSuccess(a, b, excess))(
                T.optional(pullL)
              ),
              (e) => T.succeed(Ex.halt(C.map_(e, O.some)))
            )
          }
        }
        case "LeftDone": {
          return T.catchAllCause_(
            T.map_(T.optional(pullR), (_) => handleSuccess(O.none, _, excess)),
            (e) => T.succeed(Ex.halt(C.map_(e, O.some)))
          )
        }
        case "RightDone": {
          return T.catchAllCause_(
            T.map_(T.optional(pullL), (_) => handleSuccess(_, O.none, excess)),
            (e) => T.succeed(Ex.halt(C.map_(e, O.some)))
          )
        }
        case "End": {
          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.
 */
function zipAllWithExec(that, exec, left, right, both) {
  return (self) => zipAllWithExec_(self, that, exec, left, right, both)
}
exports.zipAllWithExec = zipAllWithExec
//# sourceMappingURL=zipAllWithExec.js.map
