<?php

require_once 'common/collection/Collection.php';
require_once 'common/collection/IIterator.php';

/**
 * Class that implements a generic Iterator.
 * 
 * This class provides an Iterator implementation. It could be used both with
 * <em>ArrayList</em> and <em>HashMap</em> objects.
 * It supports remove method, but it's use is discouraged.
 * In it's standard use, you use a <code>while($it->hasMore())</code>, and 
 * inside, you should call <em>next()</em> first, to actually move the internal
 * pointer, before any other method.
 * <br />
 * <strong>Usage example:</strong>
 * <code>
 * // create a HashMap and populate it
 * $jL = new HashMap();
 * $jL->set('name', 'John Winston Lennon');
 * $jL->set('born', 1940);
 * // traverse all data (note that next() must be called before key()!
 * $it = $jL->getIterator();
 * while ($it->hasMore()) {
 *     $it->next();
 *     echo $it->key . ": " . $it->current() . "<br />";
 * }
 * 
 * // create an ArrayList and populate it
 * $beatles = new ArrayList();
 * $beatles->add('John Lennon');
 * $beatles->add('Paul McCartney');
 * $beatles->add('Ringo Starr');
 * $beatles->add('George Harrison');
 * // traverse all data
 * $it = $beatles->getIterator();
 * echo '<ul>';
 * while ($it->hasMore()) {
 *     echo '<li>' . $it->next() . '</li>';
 * }
 * echo '</ul>';
 * </code>
 * 
 * @implements ICollection, IIterator, IIterable
 * @author  $Author: pruna $
 * @package common/collection
 * @version $Revision: 1.1 $
 * @created 18-Dic-2003
 * @modified $Date: 2005/12/06 02:56:45 $
 */
class BaseIterator extends Collection implements IIterator {
    
    /**
     * Internal holder for current element's index.
     * This is the core and only index to move (internal pointer).
     * 
     * @var      int
     * @access   private
     */
    private $index = null;
    
    /**
     * Internal holder for current element's key.
     * Created only to simplify access to this info.
     * 
     * @var      mixed
     * @access   private
     * @see      index, key()
     */
    private $key = null;
    
    /**
     * Internal holder array's keys.
     * It supports any kind of keys (both int and strings).
     * 
     * @var      array
     * @access   private
     */
    private $keys = array();
    
    /**
     * Internal holder for current element's value.
     * Created only to simplify access to this info.
     * 
     * @var      mixed
     * @access   private
     * @see      index, current()
     */
    private $value = null;
    
    /**
     * Creates an Iterator with the specified values.
     *
     * @access   public
     * @param    ICollection    $collection    Initial elements
     */
    public function __construct($collection = null) {
        parent::__construct($collection);
        $this->keys = array_keys($this->toArray());
        $this->rewind();
    }
    
    /**
     * Return an IIterator from any object.
     * It's used as BaseIterator::castCollection()
     * Normaly, second parameter isn't used.
     * 
     * @access  public
     * @param   mixed     $mixed          Element to cast to IIterator
     * @param   mixed     $typeToCast     ICollection or string to cast to.
     * @return  IIterator
     */
    public function castCollection($mixed = null, $typeToCast = 'BaseIterator') {
        if (ObjectInspector::isA($mixed, 'IIterator')) {
            return $mixed;
        } elseif (ObjectInspector::isA($mixed, 'IIterable')) {
            return $mixed->getIterator();
        } elseif (is_array($mixed)) {
            return new BaseIterator($mixed);
        } else {
            return Collection::castCollection($mixed, $typeToCast);
        }
    }
    
    /**
     * Retrieve current item value.
     * 
     * @access   public
     * @return   mixed (by reference)
     */
    public function current() {
        return $this->value;
    }
    
    /**
     * Check if has more elements when forward traversing the list.
     *
     * @access    public
     * @return    boolean
     */
    public function hasMore() {
        return (($this->index() !== null) && ($this->index() < $this->size()));
    }
    
    /**
     * Return the current item number (index).
     * 
     * @access   public
     * @return   mixed
     */
    public function index() {
        return (($this->index === null) ? null : $this->index + 1);
    }
    
    /**
     * Return the current key.
     * 
     * @access   public
     * @return   mixed
     */
    public function key() {
        return $this->key;
    }
    
    /**
     * Get the next element in the list.
     *
     * @access    public
     * @return    mixed
     */
    public function next() {
        if ($this->hasMore()) {
            $this->key = $this->keys[++$this->index];
            $this->value = $this->elements[$this->key];
        }
        return $this->value;
    }
    
    /**
     * Removes current element data.
     *
     * @access    private
     */
    private function resetInternalValues() {
        $this->key = null;
        $this->value = null;
    }
    
    /**
     * Reverse iterator's content.
     *
     * @access    public
     */
    public function reverse() {
        $this->elements = array_reverse($this->elements);
        $this->keys = array_reverse($this->keys);
        $this->rewind();
    }
    
    /**
     * Resets iterator.
     *
     * @access    public
     */
    public function rewind() {
        $this->resetInternalValues();
        if (sizeof($this->elements)) {
            $this->index = -1;
        } else {
            $this->index = null;
        }
    }
    
    /**
     * Check if has more elements when forward traversing the list.
     * This method is an alias for <em>hasMore()</em>.
     *
     * @access    public
     * @return    boolean
     */
    public function valid() {
        return $this->hasMore();
    }
    
}

?>