<?php

/**
 * @author Bastiaan Welmers <haasje@welmers.net>
 *
 * cache layer to an iterator
 * @see Cache
 * @see Iterator
 */
class Cache_Iterator implements Iterator, Countable
{
	/**
	 * Cache object to be spawned by current()
	 * @var string
	 */
	protected $_class = 'Cache';
	
	/**
	 * holds Iterator object that needs to be cached
	 * @var Iterator
	 */
	private $object;
	
	/**
	 * The instance of Zend_Cache
	 * @var Zend_Cache
	 */
	private $cacheInstance;
	
	/**
	 * The cache data
	 * @var array
	 */
	private $cache;
	
	/**
	 * the Cache ID of the cache data in Zend_Cache
	 * @var string
	 */
	private $cacheId;
	
	/**
	 * construct cache object.
	 * @param Iterator Object that needs to be cached
	 */
	public function __construct(Iterator $object)
	{
		
		$this->object = $object;
		$this->cacheInstance = Zend_Registry::get('cache');
		$this->cacheId = get_class($object) . md5(serialize($object));
		$this->cache = $this->cacheInstance->load($this->cacheId);
		if (!is_array($this->cache))
			$this->cache = array();
	}
	
	/**
	 * Rewinds object.
	 * Passed directly.
	 */
	public function rewind()
	{
		$this->object->rewind();
	}
	
	/**
	 * Get current value, and cache it if it is an object
	 * @return mixed value
	 */
	public function current()
	{
		// get value
		$object = $this->object->current();
		if (is_object($object))
			// create cache layer object of object,
			// pass our cache data array to it so it can save 
			// its data there
			$object = new $this->_class($object, $this->cache[$this->key()]);
		
		return $object;
	}
	
	/**
	 * Get key of current value
	 * Passed directly.
	 * @return int key
	 */
	public function key()
	{
		return $this->object->key();
	}
	
	/**
	 * Move to next value.
	 * Passed directly.
	 */
	public function next()
	{
		$this->object->next();
	}
	
	/**
	 * Is current object still valid?
	 * Passed directly.
	 * @return boolean valid or not
	 */
	public function valid()
	{
		return $this->object->valid();
	}
	
	/**
	 * For countable iterators, count the values
	 * Passed directly.
	 * @see Countable
	 * @return int amount of values
	 */
	public function count()
	{
		if ($this->object instanceof Countable)
			return $this->object->count();
		else
			throw new Cache_Exception('Object of class ' . get_class($object) . ' does not implement Countable');
	}
	
	/**
	 * Destructor which saves the cache data at the end of object life time 
	 */
	public function __destruct()
	{
		$this->cacheInstance->save($this->cache, $this->cacheId);
	}
	
}