import * as tracing_1 from "../../../Tracing";
const fileName_1 = "(@effect-ts/system): _src/Experimental/Stream/_internal/zipAll.ts";
import * as CS from "../../../Cause";
import * as A from "../../../Collections/Immutable/Chunk";
import * as Tp from "../../../Collections/Immutable/Tuple";
import * as T from "../../../Effect";
import * as E from "../../../Either";
import * as Ex from "../../../Exit";
import { identity, pipe } from "../../../Function";
import * as O from "../../../Option";
import * as S from "./core";
import { zipChunks_ } from "./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.
 */

export function zipAll_(self, that, defaultLeft, defaultRight) {
  return zipAllWith_(self, that, _ => Tp.tuple(_, defaultRight), _ => Tp.tuple(defaultLeft, _), (a, b) => Tp.tuple(a, b));
}
/**
 * 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_
 */

export function zipAll(that, defaultLeft, defaultRight) {
  return self => zipAll_(self, that, defaultLeft, defaultRight);
}
/**
 * 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.
 */

export function zipAllLeft_(self, that, default_) {
  return zipAllWith_(self, that, identity, _ => default_, (o, _) => o);
}
/**
 * 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_
 */

export function zipAllLeft(that, default_) {
  return self => zipAllLeft_(self, that, default_);
}
/**
 * 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.
 */

export function zipAllRight_(self, that, default_) {
  return zipAllWith_(self, that, _ => default_, identity, (_, o) => o);
}
/**
 * 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_
 */

export function zipAllRight(that, default_) {
  return self => zipAllRight_(self, that, default_);
}
/**
 * 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.
 */

export function zipAllWith_(self, that, left, right, both) {
  return zipAllWithExec_(self, that, T.parallel, left, right, both);
}
/**
 * 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_
 */

export function zipAllWith(that, left, right, both) {
  return self => zipAllWith_(self, that, left, right, both);
}
const StatusTypeId = /*#__PURE__*/Symbol();
const RunningTypeId = /*#__PURE__*/Symbol();

class Running {
  constructor() {
    this._statusTypeId = StatusTypeId;
    this._typeId = RunningTypeId;
  }

}

const LeftDoneTypeId = /*#__PURE__*/Symbol();

class LeftDone {
  constructor() {
    this._statusTypeId = StatusTypeId;
    this._typeId = LeftDoneTypeId;
  }

}

const RightDoneTypeId = /*#__PURE__*/Symbol();

class RightDone {
  constructor() {
    this._statusTypeId = StatusTypeId;
    this._typeId = RightDoneTypeId;
  }

}

const EndTypeId = /*#__PURE__*/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.
 */


export 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]
    } = 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");
    }
  });
}
/**
 * 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_
 */

export function zipAllWithExec(that, exec, left, right, both) {
  return self => zipAllWithExec_(self, that, exec, left, right, both);
}
//# sourceMappingURL=zipAll.js.map