<?php
namespace Main\CompositePattern;

require_once 'AbstractWorkGroup.php';
require_once 'WorkGroup.php';

/*
 * Using the Standard PHP Library (SPL) class Iterator, SplStack and ArrayIterator
 */

use \Iterator;
use \SplStack;
use \ArrayIterator;

// Recursively iterates through the WorkGroups (composite objects)
// reading all the workers and workgroups associated with
// the array provided in the constructor.
class WorkGroupIterator implements Iterator
{
	// Attributes
	private $_workgroup;
	private $_stack;
	
	// Constructor
	
	public function __construct(array $workgroup)
	{		
		$this->_workgroup = new ArrayIterator($workgroup);;
		$this->rewind();
	}
	
	// Methods for properties
	// Getters and Setters
	
	// Methods
	public function current()
	{
		return $this->CurrentIter()->current();
	}
	
	public function key()
	{
		throw new Exception("Key not available");	
	}
	
	public function next()
	{	
		$group = $this->current()->GetGroup();		// Was it a WorkGroup?
		$this->CurrentIter()->next();				// Move to next item in current iterator
		if(is_null($group) == false)
		{
			// Add the iterator for the WorkGroup to
			// the stack so we can walk through its
			// children next time around.
			// We process this then pop it off so that
			// we can continue processing the original
			// iterator.
			$this->_stack->push($group->NodeIterator);
		}		
	}
	
	public function rewind()
	{
		$this->_stack = new SplStack();

		// Rewind to start of the iterator
		$this->_workgroup->rewind();
		
		// Push this iterator to stack for processing first
		$this->_stack->push($this->_workgroup);  
	}
	
	public function valid()
	{
		if($this->_stack->isEmpty() == false)
		{
			$iter = $this->CurrentIter();
			if($iter->valid())
			{
				return true;
			}
			
			// Done processing this iterator so remove it now!!
			// Continue processing any previous iterator on the stack.		
			$this->_stack->pop();
			return $this->valid();
		}
		return false;
	}
	
	private function CurrentIter()
	{
		// Peek at the front of the stack to
		// read the current iterator we've pushed
		// onto it.
		return $this->_stack->offsetGet(0);
	}
}
?>