"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.chunkN = exports.chunkN_ = void 0
// tracing: off
const C = __importStar(require("../../Cause"))
const A = __importStar(require("../../Collections/Immutable/Chunk"))
const Function_1 = require("../../Function")
const O = __importStar(require("../../Option"))
const T = __importStar(require("../_internal/effect"))
const M = __importStar(require("../_internal/managed"))
const Ref = __importStar(require("../_internal/ref"))
const Pull = __importStar(require("../Pull"))
const definitions_1 = require("./definitions")
const halt_1 = require("./halt")
class State {
  constructor(buffer, done) {
    this.buffer = buffer
    this.done = done
  }
}
function emitOrAccumulate(buffer, done, ref, pull, n) {
  if (A.size(buffer) < n) {
    if (done) {
      if (A.isEmpty(buffer)) {
        return Pull.end
      } else {
        return T.zipRight_(ref.set(new State(A.empty(), true)), Pull.emitChunk(buffer))
      }
    } else {
      return T.foldM_(
        pull,
        O.fold(() => emitOrAccumulate(buffer, true, ref, pull, n), Pull.fail),
        (ch) => emitOrAccumulate(A.concat_(buffer, ch), false, ref, pull, n)
      )
    }
  } else {
    const {
      tuple: [chunk, leftover]
    } = A.splitAt_(buffer, n)
    return T.zipRight_(ref.set(new State(leftover, done)), Pull.emitChunk(chunk))
  }
}
/**
 * Re-chunks the elements of the stream into chunks of
 * `n` elements each.
 * The last chunk might contain less than `n` elements
 */
function chunkN_(self, n) {
  if (n < 1) {
    return (0, halt_1.halt)(
      C.die(new C.IllegalArgumentException("chunkN: n must be at least 1"))
    )
  } else {
    return new definitions_1.Stream(
      M.map_(
        M.let_(
          M.bind_(
            M.bind_(M.do, "ref", () =>
              T.toManaged(Ref.makeRef(new State(A.empty(), false)))
            ),
            "p",
            () => self.proc
          ),
          "pull",
          ({ p, ref }) =>
            T.chain_(ref.get, (s) => emitOrAccumulate(s.buffer, s.done, ref, p, n))
        ),
        ({ pull }) => pull
      )
    )
  }
}
exports.chunkN_ = chunkN_
/**
 * Re-chunks the elements of the stream into chunks of
 * `n` elements each.
 * The last chunk might contain less than `n` elements
 */
function chunkN(n) {
  return (self) => chunkN_(self, n)
}
exports.chunkN = chunkN
//# sourceMappingURL=chunkN.js.map
