<?php
/**
 * This set of classes implements a Flyweight pattern
 * (http://en.wikipedia.org/wiki/Flyweight_pattern). Refactor/rename
 * some based on this fact?
 *
 * @package Horde_RDO
 */

/**
 * @package Horde_RDO
 */
interface Horde_RDO_Decorating_Iterator_Lens {

    /**
     */
    public function decorate($target);

}

/**
 * @package Horde_RDO
 */
class Horde_RDO_Lens implements Horde_RDO_Decorating_Iterator_Lens, IteratorAggregate {

    /**
     */
    protected $target;

    /**
     */
    public function decorate($target)
    {
        $this->target = $target;
        return $this;
    }

    /**
     * Implement the IteratorAggregate pattern. When a single RDO
     * object is iterated over, we return an iterator that loops over
     * each property of the object.
     *
     * @return ArrayIterator The Iterator instance.
     */
    public function getIterator()
    {
        return new Horde_RDO_Iterator($this);
    }

    /**
     */
    public function __get($key)
    {
        return $this->target->$key;
    }

    /**
     */
    public function __set($key, $value)
    {
        $this->target->$key = $value;
        return $this;
    }

    /**
     */
    public function __call($func, $params)
    {
        return call_user_func_array(array($this->target, $func), $params);
    }

}

/**
 */
class Horde_RDO_Decorating_Iterator implements OuterIterator {

    /**
     * The Iterator to decorate.
     * @var Iterator
     */
    private $_i;

    /**
     * The Decorator that will observe each element of the iterator.
     * @var Horde_RDO_Decorating_Iterator_Lens
     */
    protected $_d;

    /**
     * Constructs a decorator around an iterator using a single
     * Horde_RDO_Decorating_Iterator_Lens object, which decorates the current()
     * element of the iterator. The decorator is like a lens,
     * decotrating one element at a time, instead of having a
     * decorator for every element in the list.
     *
     * @param Iterator $i The iterator to decorate.
     */
    public function __construct(Iterator $i, $d = null)
    {
        $this->_i = $i;
        if ($d !== null) {
            $this->setLens($d);
        }
    }

    /**
     * Set or change the Lens modifying the inner iterator. Sets the
     * current object of the lens automatically and returns the lens.
     */
    public function setLens(Horde_RDO_Decorating_Iterator_Lens $d)
    {
        $this->_d = $d;
        return $this->current();
    }

    /**
     * Rewind the inner iterator.
     */
    function rewind()
    {
        $this->_i->rewind();
    }

    /**
     * Move to next element.
     *
     * @return void
     */
    function next()
    {
        $this->_i->next();
    }

    /**
     * @return Whether more elements are available.
     */
    function valid()
    {
        return $this->_i->valid();
    }

    /**
     * @return The current key.
     */
    function key()
    {
        return $this->_i->key();
    }

    /**
     * @return The current value.
     */
    function current()
    {
        return $this->_d->decorate($this->_i->current());
    }

    /**
     * @return Iterator The inner iterator.
     */
    function getInnerIterator()
    {
        return $this->_i;
    }

    /**
     * Aggregate the inner iterator.
     *
     * @param func    Name of method to invoke.
     * @param params  Array of parameters to pass to method.
     */
    function __call($func, $params)
    {
        return call_user_func_array(array($this->_i, $func), $params);
    }

}