package jetbrains.mps.internal.collections.runtime;

/*Generated by MPS */

import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class IterableUtils {
  public IterableUtils() {
  }
  public static <E> void visitAll(Iterable<E> seq, _FunctionTypes._void_P1_E0<? super E> visitor) {
    for (Iterator<E> it = seq.iterator(); it.hasNext();) {
      try {
        visitor.invoke(it.next());
      } catch (StopIteratingException stop) {
        break;
      }
    }
  }
  public static <E> boolean contains(Iterable<E> seq, E e) {
    return IterableUtils.indexOf(seq, e) >= 0;
  }
  public static <E> int indexOf(Iterable<E> seq, E e) {
    int index = 0;
    for (Iterator<E> it = seq.iterator(); it.hasNext(); index++) {
      if (IterableUtils.eq(it.next(), e)) {
        return index;
      }
    }
    return -1;
  }
  public static <E> int lastIndexOf(Iterable<E> seq, E e) {
    int lastIndex = -1;
    int index = 0;
    for (Iterator<E> it = seq.iterator(); it.hasNext(); index++) {
      if (IterableUtils.eq(it.next(), e)) {
        lastIndex = index;
      }
    }
    return lastIndex;
  }
  public static <E> int count(Iterable<E> seq) {
    int count = 0;
    for (Iterator<E> it = seq.iterator(); it.hasNext(); it.next()) {
      count++;
    }
    return count;
  }
  public static <E> boolean isEmpty(Iterable<E> seq) {
    return !(seq.iterator().hasNext());
  }
  public static <E> boolean isNotEmpty(Iterable<E> seq) {
    return seq.iterator().hasNext();
  }
  public static <E> E first(Iterable<E> seq) {
    Iterator<E> it = seq.iterator();
    if (it.hasNext()) {
      return it.next();
    }
    if (Sequence.NULL_WHEN_EMPTY) {
      return null;
    }
    throw new NoSuchElementException("Empty iterator");
  }
  public static <E> E last(Iterable<E> seq) {
    E last = null;
    boolean hasLast = false;
    Iterator<E> it = seq.iterator();
    if (Sequence.NULL_WHEN_EMPTY) {
      if (!(it.hasNext())) {
        return null;
      }
    }
    while (it.hasNext()) {
      last = it.next();
      hasLast = true;
    }
    if (hasLast) {
      return last;
    }
    throw new NoSuchElementException("Empty iterator");
  }
  public static String join(Iterable<? extends String> seq, String delimiter) {
    StringBuilder sb = new StringBuilder();
    String sep = "";
    for (Iterator<? extends String> it = seq.iterator(); it.hasNext();) {
      sb.append(sep).append(it.next());
      sep = delimiter;
    }
    return sb.toString();
  }
  public static <T> T reduceLeft(Iterable<T> seq, _FunctionTypes._return_P2_E0<? extends T, ? super T, ? super T> combinator) {
    Iterator<T> it = seq.iterator();
    if (!(it.hasNext())) {
      if (Sequence.NULL_WHEN_EMPTY) {
        return null;
      }
      throw new NoSuchElementException("Empty iterator");
    }
    T left = it.next();
    while (it.hasNext()) {
      left = combinator.invoke(left, it.next());
    }
    return left;
  }
  public static <T> T reduceRight(Iterable<T> revSeq, _FunctionTypes._return_P2_E0<? extends T, ? super T, ? super T> combinator) {
    Iterator<T> it = revSeq.iterator();
    if (!(it.hasNext())) {
      if (Sequence.NULL_WHEN_EMPTY) {
        return null;
      }
      throw new NoSuchElementException("Empty iterator");
    }
    T right = it.next();
    while (it.hasNext()) {
      right = combinator.invoke(it.next(), right);
    }
    return right;
  }
  public static <T, S> S foldLeft(Iterable<T> seq, S seed, _FunctionTypes._return_P2_E0<? extends S, ? super S, ? super T> combinator) {
    S s = seed;
    for (Iterator<T> it = seq.iterator(); it.hasNext();) {
      s = combinator.invoke(s, it.next());
    }
    return s;
  }
  public static <T, S> S foldRight(Iterable<T> revSeq, S seed, _FunctionTypes._return_P2_E0<? extends S, ? super T, ? super S> combinator) {
    S s = seed;
    for (Iterator<T> it = revSeq.iterator(); it.hasNext();) {
      s = combinator.invoke(it.next(), s);
    }
    return s;
  }
  private static boolean eq(Object a, Object b) {
    return (a == b) || (((a != null) ? a.equals(b) : false));
  }
}
