"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
class StreamImpl {
  constructor(startFn, nextFn) {
    this.startFn = startFn;
    this.nextFn = nextFn;
  }
  iterator() {
    const iterator = {
      state: this.startFn(),
      next: () => this.nextFn(iterator.state),
      [Symbol.iterator]: () => iterator
    };
    return iterator;
  }
  [Symbol.iterator]() {
    return this.iterator();
  }
  isEmpty() {
    const iterator = this.iterator();
    return Boolean(iterator.next().done);
  }
  count() {
    const iterator = this.iterator();
    let count = 0;
    let next = iterator.next();
    while (!next.done) {
      count++;
      next = iterator.next();
    }
    return count;
  }
  toArray() {
    const result = [];
    const iterator = this.iterator();
    let next;
    do {
      next = iterator.next();
      if (next.value !== void 0) {
        result.push(next.value);
      }
    } while (!next.done);
    return result;
  }
  toSet() {
    return new Set(this);
  }
  toMap(keyFn, valueFn) {
    const entryStream = this.map((element) => [
      keyFn ? keyFn(element) : element,
      valueFn ? valueFn(element) : element
    ]);
    return new Map(entryStream);
  }
  toString() {
    return this.join();
  }
  concat(other) {
    return new StreamImpl(() => ({ first: this.startFn(), firstDone: false, iterator: other[Symbol.iterator]() }), (state) => {
      let result;
      if (!state.firstDone) {
        do {
          result = this.nextFn(state.first);
          if (!result.done) {
            return result;
          }
        } while (!result.done);
        state.firstDone = true;
      }
      do {
        result = state.iterator.next();
        if (!result.done) {
          return result;
        }
      } while (!result.done);
      return DONE_RESULT;
    });
  }
  join(separator = ",") {
    const iterator = this.iterator();
    let value = "";
    let result;
    let addSeparator = false;
    do {
      result = iterator.next();
      if (!result.done) {
        if (addSeparator) {
          value += separator;
        }
        value += toString(result.value);
      }
      addSeparator = true;
    } while (!result.done);
    return value;
  }
  indexOf(searchElement, fromIndex = 0) {
    const iterator = this.iterator();
    let index = 0;
    let next = iterator.next();
    while (!next.done) {
      if (index >= fromIndex && next.value === searchElement) {
        return index;
      }
      next = iterator.next();
      index++;
    }
    return -1;
  }
  every(predicate) {
    const iterator = this.iterator();
    let next = iterator.next();
    while (!next.done) {
      if (!predicate(next.value)) {
        return false;
      }
      next = iterator.next();
    }
    return true;
  }
  some(predicate) {
    const iterator = this.iterator();
    let next = iterator.next();
    while (!next.done) {
      if (predicate(next.value)) {
        return true;
      }
      next = iterator.next();
    }
    return false;
  }
  forEach(callbackfn) {
    const iterator = this.iterator();
    let index = 0;
    let next = iterator.next();
    while (!next.done) {
      callbackfn(next.value, index);
      next = iterator.next();
      index++;
    }
  }
  map(callbackfn) {
    return new StreamImpl(this.startFn, (state) => {
      const { done, value } = this.nextFn(state);
      if (done) {
        return DONE_RESULT;
      } else {
        return { done: false, value: callbackfn(value) };
      }
    });
  }
  filter(predicate) {
    return new StreamImpl(this.startFn, (state) => {
      let result;
      do {
        result = this.nextFn(state);
        if (!result.done && predicate(result.value)) {
          return result;
        }
      } while (!result.done);
      return DONE_RESULT;
    });
  }
  nonNullable() {
    return this.filter((e) => e !== void 0 && e !== null);
  }
  reduce(callbackfn, initialValue) {
    const iterator = this.iterator();
    let previousValue = initialValue;
    let next = iterator.next();
    while (!next.done) {
      if (previousValue === void 0) {
        previousValue = next.value;
      } else {
        previousValue = callbackfn(previousValue, next.value);
      }
      next = iterator.next();
    }
    return previousValue;
  }
  reduceRight(callbackfn, initialValue) {
    return this.recursiveReduce(this.iterator(), callbackfn, initialValue);
  }
  recursiveReduce(iterator, callbackfn, initialValue) {
    const next = iterator.next();
    if (next.done) {
      return initialValue;
    }
    const previousValue = this.recursiveReduce(iterator, callbackfn, initialValue);
    if (previousValue === void 0) {
      return next.value;
    }
    return callbackfn(previousValue, next.value);
  }
  find(predicate) {
    const iterator = this.iterator();
    let next = iterator.next();
    while (!next.done) {
      if (predicate(next.value)) {
        return next.value;
      }
      next = iterator.next();
    }
    return void 0;
  }
  findIndex(predicate) {
    const iterator = this.iterator();
    let index = 0;
    let next = iterator.next();
    while (!next.done) {
      if (predicate(next.value)) {
        return index;
      }
      next = iterator.next();
      index++;
    }
    return -1;
  }
  includes(searchElement) {
    const iterator = this.iterator();
    let next = iterator.next();
    while (!next.done) {
      if (next.value === searchElement) {
        return true;
      }
      next = iterator.next();
    }
    return false;
  }
  flatMap(callbackfn) {
    return new StreamImpl(() => ({ this: this.startFn() }), (state) => {
      do {
        if (state.iterator) {
          const next = state.iterator.next();
          if (next.done) {
            state.iterator = void 0;
          } else {
            return next;
          }
        }
        const { done, value } = this.nextFn(state.this);
        if (!done) {
          const mapped = callbackfn(value);
          if (isIterable(mapped)) {
            state.iterator = mapped[Symbol.iterator]();
          } else {
            return { done: false, value: mapped };
          }
        }
      } while (state.iterator);
      return DONE_RESULT;
    });
  }
  flat(depth) {
    if (depth === void 0) {
      depth = 1;
    }
    if (depth <= 0) {
      return this;
    }
    const stream2 = depth > 1 ? this.flat(depth - 1) : this;
    return new StreamImpl(() => ({ this: stream2.startFn() }), (state) => {
      do {
        if (state.iterator) {
          const next = state.iterator.next();
          if (next.done) {
            state.iterator = void 0;
          } else {
            return next;
          }
        }
        const { done, value } = stream2.nextFn(state.this);
        if (!done) {
          if (isIterable(value)) {
            state.iterator = value[Symbol.iterator]();
          } else {
            return { done: false, value };
          }
        }
      } while (state.iterator);
      return DONE_RESULT;
    });
  }
  head() {
    const iterator = this.iterator();
    const result = iterator.next();
    if (result.done) {
      return void 0;
    }
    return result.value;
  }
  tail(skipCount = 1) {
    return new StreamImpl(() => {
      const state = this.startFn();
      for (let i = 0; i < skipCount; i++) {
        const next = this.nextFn(state);
        if (next.done) {
          return state;
        }
      }
      return state;
    }, this.nextFn);
  }
  limit(maxSize) {
    return new StreamImpl(() => ({ size: 0, state: this.startFn() }), (state) => {
      state.size++;
      if (state.size > maxSize) {
        return DONE_RESULT;
      }
      return this.nextFn(state.state);
    });
  }
  distinct(by) {
    return new StreamImpl(() => ({ set: /* @__PURE__ */ new Set(), internalState: this.startFn() }), (state) => {
      let result;
      do {
        result = this.nextFn(state.internalState);
        if (!result.done) {
          const value = by ? by(result.value) : result.value;
          if (!state.set.has(value)) {
            state.set.add(value);
            return result;
          }
        }
      } while (!result.done);
      return DONE_RESULT;
    });
  }
  exclude(other, key) {
    const otherKeySet = /* @__PURE__ */ new Set();
    for (const item of other) {
      const value = key ? key(item) : item;
      otherKeySet.add(value);
    }
    return this.filter((e) => {
      const ownKey = key ? key(e) : e;
      return !otherKeySet.has(ownKey);
    });
  }
}
function toString(item) {
  if (typeof item === "string") {
    return item;
  }
  if (typeof item === "undefined") {
    return "undefined";
  }
  if (typeof item.toString === "function") {
    return item.toString();
  }
  return Object.prototype.toString.call(item);
}
function isIterable(obj) {
  return !!obj && typeof obj[Symbol.iterator] === "function";
}
const EMPTY_STREAM = new StreamImpl(() => void 0, () => DONE_RESULT);
const DONE_RESULT = Object.freeze({ done: true, value: void 0 });
function stream(...collections) {
  if (collections.length === 1) {
    const collection = collections[0];
    if (collection instanceof StreamImpl) {
      return collection;
    }
    if (isIterable(collection)) {
      return new StreamImpl(() => collection[Symbol.iterator](), (iterator) => iterator.next());
    }
    if (typeof collection.length === "number") {
      return new StreamImpl(() => ({ index: 0 }), (state) => {
        if (state.index < collection.length) {
          return { done: false, value: collection[state.index++] };
        } else {
          return DONE_RESULT;
        }
      });
    }
  }
  if (collections.length > 1) {
    return new StreamImpl(() => ({ collIndex: 0, arrIndex: 0 }), (state) => {
      do {
        if (state.iterator) {
          const next = state.iterator.next();
          if (!next.done) {
            return next;
          }
          state.iterator = void 0;
        }
        if (state.array) {
          if (state.arrIndex < state.array.length) {
            return { done: false, value: state.array[state.arrIndex++] };
          }
          state.array = void 0;
          state.arrIndex = 0;
        }
        if (state.collIndex < collections.length) {
          const collection = collections[state.collIndex++];
          if (isIterable(collection)) {
            state.iterator = collection[Symbol.iterator]();
          } else if (collection && typeof collection.length === "number") {
            state.array = collection;
          }
        }
      } while (state.iterator || state.array || state.collIndex < collections.length);
      return DONE_RESULT;
    });
  }
  return EMPTY_STREAM;
}
class TreeStreamImpl extends StreamImpl {
  constructor(root, children, options) {
    super(() => ({
      iterators: (options === null || options === void 0 ? void 0 : options.includeRoot) ? [[root][Symbol.iterator]()] : [children(root)[Symbol.iterator]()],
      pruned: false
    }), (state) => {
      if (state.pruned) {
        state.iterators.pop();
        state.pruned = false;
      }
      while (state.iterators.length > 0) {
        const iterator = state.iterators[state.iterators.length - 1];
        const next = iterator.next();
        if (next.done) {
          state.iterators.pop();
        } else {
          state.iterators.push(children(next.value)[Symbol.iterator]());
          return next;
        }
      }
      return DONE_RESULT;
    });
  }
  iterator() {
    const iterator = {
      state: this.startFn(),
      next: () => this.nextFn(iterator.state),
      prune: () => {
        iterator.state.pruned = true;
      },
      [Symbol.iterator]: () => iterator
    };
    return iterator;
  }
}
exports.Reduction = void 0;
(function(Reduction) {
  function sum(stream2) {
    return stream2.reduce((a, b) => a + b, 0);
  }
  Reduction.sum = sum;
  function product(stream2) {
    return stream2.reduce((a, b) => a * b, 0);
  }
  Reduction.product = product;
  function min(stream2) {
    return stream2.reduce((a, b) => Math.min(a, b));
  }
  Reduction.min = min;
  function max(stream2) {
    return stream2.reduce((a, b) => Math.max(a, b));
  }
  Reduction.max = max;
})(exports.Reduction || (exports.Reduction = {}));
exports.DONE_RESULT = DONE_RESULT;
exports.EMPTY_STREAM = EMPTY_STREAM;
exports.StreamImpl = StreamImpl;
exports.TreeStreamImpl = TreeStreamImpl;
exports.stream = stream;
//# sourceMappingURL=lib-utils-stream.cjs.map
