package jetbrains.mps.baseLanguage.closures.runtime;

/*Generated by MPS */

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * * @author fyodor
 */
public abstract class YieldingIterator<T> implements Iterator<T> {
  private T yielded;
  private State state = State.UNKNOWN;
  private DelayedException delayedEx;
  public YieldingIterator() {
  }
  @Override
  public boolean hasNext() {
    if (state == State.UNKNOWN) {
      try {
        this.state = ((this.moveToNext() ? State.HAS_NEXT : State.AT_END));
      } catch (DelayedException ex) {
        this.state = State.AT_END;
        throw ex;
      }
    }
    if (delayedEx != null) {
      DelayedException tmp = this.delayedEx;
      this.delayedEx = null;
      throw tmp;
    }
    return state == State.HAS_NEXT;
  }
  @Override
  public T next() {
    switch (state) {
      case AT_END:
        throw new NoSuchElementException();
      case UNKNOWN:
        try {
          if (!(this.moveToNext())) {
            this.state = State.AT_END;
            throw new NoSuchElementException();
          }
        } catch (DelayedException ex) {
          this.delayedEx = ex;
          this.state = State.AT_END;
          throw new NoSuchElementException();
        }
      case HAS_NEXT:
        T res = this.yielded;
        this.yielded = null;
        this.state = State.UNKNOWN;
        return res;
      default:
        throw new IllegalStateException();
    }
  }
  @Override
  public void remove() {
    throw new UnsupportedOperationException();
  }
  protected abstract boolean moveToNext();
  protected void yield(T t) {
    this.yielded = t;
  }
  private enum State {
    HAS_NEXT(),
    AT_END(),
    UNKNOWN();

    private State() {
    }
  }
}
