<?php

// This doc comment block generated by idl/sysdoc.php
/**
 * ( excerpt from http://docs.hhvm.com/manual/en/class.appenditerator.php )
 *
 * An Iterator that iterates over several iterators one after the other.
 *
 */
class AppendIterator extends IteratorIterator implements OuterIterator {
  private $iterators;

  // This doc comment block generated by idl/sysdoc.php
  /**
   * ( excerpt from http://docs.hhvm.com/manual/en/appenditerator.construct.php )
   *
   * Constructs an AppendIterator.
   *
   * @return     mixed   No value is returned.
   */
  function __construct() {
    $this->iterators = new ArrayIterator(array());
  }

  // This doc comment block generated by idl/sysdoc.php
  /**
   * ( excerpt from http://docs.hhvm.com/manual/en/appenditerator.append.php )
   *
   * Appends an iterator.
   *
   * @it         mixed   The iterator to append.
   *
   * @return     mixed   No value is returned.
   */
  function append(\Iterator $it) {
    $it->rewind();
    $this->iterators->append($it);

    // if we will start at $it and $it is empty, advance our position past
    if ($this->iterators->current() === $it && !$it->valid()) {
      $this->iterators->next();
    }
  }

  // This doc comment block generated by idl/sysdoc.php
  /**
   * ( excerpt from
   * http://docs.hhvm.com/manual/en/appenditerator.getarrayiterator.php )
   *
   * This method gets the ArrayIterator that is used to store the iterators
   * added with AppendIterator::append().
   *
   * @return     mixed   Returns an ArrayIterator containing the appended
   *                     iterators.
   */
  function getArrayIterator() {
    return $this->iterators;
  }

  // This doc comment block generated by idl/sysdoc.php
  /**
   * ( excerpt from
   * http://docs.hhvm.com/manual/en/appenditerator.getiteratorindex.php )
   *
   * Gets the index of the current inner iterator.
   *
   * @return     mixed   Returns an integer, which is the zero-based index of
   *                     the current inner iterator.
   */
  function getIteratorIndex() {
    return $this->iterators->key();
  }

  // This doc comment block generated by idl/sysdoc.php
  /**
   * ( excerpt from
   * http://docs.hhvm.com/manual/en/appenditerator.getinneriterator.php )
   *
   * This method returns the current inner iterator.
   *
   * @return     mixed   The current inner iterator, or NULL if there is not
   *                     one.
   */
  function getInnerIterator() {
    return $this->iterators->current();
  }

  // This doc comment block generated by idl/sysdoc.php
  /**
   * ( excerpt from http://docs.hhvm.com/manual/en/appenditerator.rewind.php )
   *
   * Rewind to the first element of the first inner Iterator.
   *
   * @return     mixed   No value is returned.
   */
  function rewind() {
    $this->iterators->rewind();

    /**
     * Advance to the first valid element contained in a child iterator
     */
    while ($this->iterators->valid()) {
      $this->getInnerIterator()->rewind();
      if ($this->getInnerIterator()->valid()) {
        return; /* found a valid element to start on */
      }
      $this->iterators->next();
    }
  }

  // This doc comment block generated by idl/sysdoc.php
  /**
   * ( excerpt from http://docs.hhvm.com/manual/en/appenditerator.valid.php )
   *
   * Checks validity of the current element.
   *
   * @return     mixed   Returns TRUE if the current iteration is valid,
   *                     FALSE otherwise.
   */
  function valid() {
    return $this->iterators->valid() && $this->getInnerIterator()->valid();
  }

  // This doc comment block generated by idl/sysdoc.php
  /**
   * ( excerpt from http://docs.hhvm.com/manual/en/appenditerator.current.php )
   *
   * Gets the current value.
   *
   * @return     mixed   The current value if it is valid or NULL otherwise.
   */
  function current() {
    /* Using $this->valid() would be exactly the same; it would omit
     * the access to a non valid element in the inner iterator. Since
     * the user didn't respect the valid() return value false this
     * must be intended hence we go on. */
    return $this->iterators->valid() ?
      $this->getInnerIterator()->current() : NULL;
  }

  // This doc comment block generated by idl/sysdoc.php
  /**
   * ( excerpt from http://docs.hhvm.com/manual/en/appenditerator.key.php )
   *
   * Get the current key.
   *
   * @return     mixed   The current key if it is valid or NULL otherwise.
   */
  function key() {
    return $this->iterators->valid() ? $this->getInnerIterator()->key() : NULL;
  }

  // This doc comment block generated by idl/sysdoc.php
  /**
   * ( excerpt from http://docs.hhvm.com/manual/en/appenditerator.next.php )
   *
   * Moves to the next element. If this means to another Iterator then it
   * rewinds that Iterator.
   *
   * @return     mixed   No value is returned.
   */
  function next() {
    if (!$this->iterators->valid()){
      return; /* done all */
    }
    $this->getInnerIterator()->next();
    if ($this->getInnerIterator()->valid()) {
      return; /* found valid element in current inner iterator */
    }
    $this->iterators->next();
    while ($this->iterators->valid()) {
      $this->getInnerIterator()->rewind();
      if ($this->getInnerIterator()->valid()) {
        return; /* found element as first elemet in another iterator */
      }
      $this->iterators->next();
    }
  }

  function __call($func, $params) {
    return call_user_func_array(array($this->getInnerIterator(), $func),
                                $params);
  }
}
