<?php
/**
 * Implementation of bidirectional iterator over the simple
 * array
 *
 * @package Library
 * @author Miroslav Kubelik (koubel@volny.cz)
 * @copyright Copyright (c) 2007-2009 Miroslav Kubelik
 * @license http://opensource.org/licenses/gpl-license.php GNU GPL
 */
/**
 * Bidirectional iterator over the simple array with a seeking
 *
 * Support for the backward iteration via {@link previous()}. Seek to the
 * current element is through the values equivalency.
 *
 * @package Library
 * @author Miroslav Kubelik (koubel@volny.cz)
 * @copyright Copyright (c) 2007-2009 Miroslav Kubelik
 * @license http://opensource.org/licenses/gpl-license.php GNU GPL
 */
class BidirSimpleArrIterator implements SeekableIterator {

    /** internal array, the source of an iteration
     * @var array
     */
    protected $innerArray;

    /**
     * constructor
     * set the inner array
     */
    public function __construct($arr) {
        $this->innerArray = $arr;
    }

    /**
     * rewind iterator
     */
    public function rewind() {
        reset($this->innerArray);
    }

    /**
     * return current iterator value
     * @return mixed current value from $innerArray
     */
    public function current() {
        return current($this->innerArray);
    }

    /**
     * move to previous element
     */
    public function previous() {
        prev($this->innerArray);
    }

    /**
     * move to next element
     */
    public function next() {
        next($this->innerArray);
    }

    /**
     * get current key value
     * @return mixed current $innerArray key
     */
    public function key() {
        return key($this->innerArray);
    }

    /**
     * Check if a current iterator element is valid
     * @return bool
     */
    public function valid() {
        return $this->current() !== false ? true : false;
    }

    /**
     * Seek to the defined element
     *
     * Seek to the element in inner array, the element must be equivalent with
     * $seekVar parametr. Elements in the inner array and the parameter must implement interface
     * {@link IComparableEqual} for an equivalency check.
     */
    public function seek($seekVar) {
        //echo "seeking to $seekVar->Name<br>";
        if (!$seekVar instanceof IComparableEqual) throw new Exception("Seeked variable must implement IComparableEqual");
        $this->rewind();
        while ($this->valid()) {
            $val = $this->current();
            //echo "testing $val->Name<br>\n";
            if (!$val instanceof IComparableEqual) {
                throw new Exception("inner array values must implement IComparableEqual");
            }
            //value found
            if ($val->isEqual($seekVar)) {
                //echo "$val->Name found<br>\n";
                return;
            }
            $this->next();
        }
    }

    /**
     * seek to the end of an inner array
     */
    public function seekToEnd() {
        end($this->innerArray);
    }
}
