key0-96/
key0-96/doc/key/
key0-96/doc/key/credits/
key0-96/doc/key/developers/
key0-96/doc/key/developers/resources/
key0-96/setup/caves/
key0-96/setup/help/
key0-96/setup/ruins/
key0-96/src/
key0-96/src/commands/
key0-96/src/events/
key0-96/src/hack/
key0-96/src/sql/
key0-96/src/swing/
key0-96/src/talker/forest/
key0-96/src/talker/objects/
key0-96/src/terminals/
/*
**  $Id$
**
**  Class History
**
**  Date        Name         Description
**  ---------|------------|-----------------------------------------------
**  15Nov98     subtle       created
**
*/

package key.util;

import java.util.Enumeration;
import java.util.EmptyStackException;
import java.util.Stack;

/**
  *  This is a special type of enumerator filter that will
  *  unroll other enumerations that are encountered as
  *  elements.
  *
  *  For instance, using this on a Vector enumerator,
  *  where the vector contains Enumerations, would
  *  cause a loop through all of each of those enumerations
  *  in turn.
  *
  *  At the moment, only a shallow unroll is done - to
  *  unroll deeply, each of the sub enumerations should
  *  also be wrapped in this class.
 */
public final class RecursiveEnumeration implements Enumeration
{
	Enumeration e;
	Enumeration recurse;
	Object next;
	boolean goDeep;
	Stack st = null;
	Observer teo = null;
	
	/**
	  * @param enum the enumeration to walk through
	  * @param deep recurse deeply through the tree (more than just one level?)
	  * @param o a callback that can be notified as we step into different
	  *          enumerations (may be null)
	 */
	public RecursiveEnumeration( Enumeration enum, boolean deep, Observer o )
	{
		e = enum;
		goDeep = deep;
		teo = o;
		
		scanNext();
	}
	
	public boolean hasMoreElements()
	{
		return( next != null );
	}
	
	private void scanNext()
	{
		if( recurse != null && recurse.hasMoreElements() )
		{
			next = recurse.nextElement();
				
			if( goDeep && next instanceof Enumeration )
			{
				if( st == null )
					st = new Stack();
				
				st.push( recurse );
				recurse = (Enumeration) next;
				if( teo != null )
					teo.notify( recurse, st.size() );
				scanNext();
			}
		}
		else
		{
			if( st != null )
			{
				if( !st.empty() )
				{
					recurse = (Enumeration) st.pop();
					scanNext();
					return;
				}
				else
					st = null;
			}
			
			if( e.hasMoreElements() )
			{
				next = e.nextElement();
				
				if( next instanceof Enumeration )
				{
					recurse = (Enumeration) next;
					if( teo != null )
						teo.notify( recurse, (st != null) ? st.size() : 0 );
					scanNext();
				}
				else
					recurse = null;
			}
			else
				next = null;
		}
	}
	
	public Object nextElement()
	{
		if( next != null )
		{
			Object n = next;
			scanNext();
			return( n );
		}
		else
			throw new java.util.NoSuchElementException();
	}
	
	public static interface Observer
	{
		/**
		  * @param steppingInto the enumeration we're about to
		  *        walk through
		  * @param depth the depth that this enumeration is at.  top
		  *        level enumerations are at depth 0.
		 */
		public void notify( Enumeration steppingInto, int depth );
	}
}