/FileExtraction/Java_unseen/dlitz_resin/modules/quercus/src/com/caucho/quercus/lib/spl/AbstractIteratorImpl.java
package com.caucho.quercus.lib.spl;

import com.caucho.quercus.env.Env;
import com.caucho.quercus.env.ObjectValue;
import com.caucho.quercus.env.QuercusClass;
import com.caucho.quercus.env.Value;
import com.caucho.quercus.function.AbstractFunction;
import com.caucho.util.L10N;

import java.util.Iterator;

public abstract class AbstractIteratorImpl<T> implements Iterator<T> {
    private static final L10N L = new L10N(AbstractIteratorImpl.class);

    protected final Env _env;
    protected final ObjectValue _obj;
    protected final QuercusClass _qClass;

    private final AbstractFunction _nextFun;
    private final AbstractFunction _currentFun;
    private final AbstractFunction _keyFun;
    private final AbstractFunction _rewindFun;
    private final AbstractFunction _validFun;
    private boolean _needNext;

    public AbstractIteratorImpl(Env env, 
                                ObjectValue obj)
    {
      _env = env;
      _qClass = obj.getQuercusClass();
      _obj = obj;

      if (!obj.isA("iterator"))
        throw new IllegalStateException(L.l("'{0}' is an invalid iterator",
          obj));
      _currentFun = _qClass.getFunction(env.createString("current"));
      _keyFun = _qClass.getFunction(env.createString("key"));
      _nextFun = _qClass.getFunction(env.createString("next"));
      _rewindFun = _qClass.getFunction(env.createString("rewind"));
      _validFun = _qClass.getFunction(env.createString("valid"));

      _rewindFun.callMethod(_env, _qClass, _obj);

      _needNext = false;
    }

    public boolean hasNext()
    {
      if (_needNext)
        _nextFun.callMethod(_env, _qClass, _obj);

      _needNext = true;

      return _validFun.callMethod(_env, _qClass, _obj).toBoolean();
    }

    public T next()
    {
      return getCurrent();
    }

    abstract protected T getCurrent();

    protected Value getCurrentKey()
    {
      return _keyFun.callMethod(_env, _qClass, _obj);
    }

    protected Value getCurrentValue()
    {
      return _currentFun.callMethod(_env, _qClass, _obj);
    }

    public void remove()
    {
      throw new UnsupportedOperationException();
    }
}