// vi: set ts=3 sw=3:
package org.apache.slide.structure;

import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Stack;

import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.event.VetoException;
import org.apache.slide.security.AccessDeniedException;


/**
 * @author Stefan Lützkendorf
 */
public class StructureIterator 
{
    private Structure structure;
    private SlideToken token;
    private ObjectNode next = null;
    private Stack stack = new Stack();
    
    public StructureIterator(Structure structure, SlideToken token, String uri)
        throws ServiceAccessException, ObjectNotFoundException, VetoException,
        LinkedObjectNotFoundException, AccessDeniedException
    {
        this(structure, token, structure.retrieve(token, uri));
    }
    
    public StructureIterator(Structure structure, SlideToken token, ObjectNode root) 
        throws ServiceAccessException, ObjectNotFoundException, VetoException
    {
        this.structure = structure;
        this.token = token;
        this.next = root;
        
        try {
            stack.push(structure.getChildren(token, root));
        } catch (LinkedObjectNotFoundException e) {
            // can not happen
            e.printStackTrace();
        } 
    }

    public boolean hasNext() 
        throws ServiceAccessException, ObjectNotFoundException, VetoException
    {
        if (this.next != null) {
            return true;
        }
        
        if (this.stack.empty()) {
            return false;
        }
        
        Enumeration e = (Enumeration)this.stack.peek();
        while (e != null && !e.hasMoreElements()) {
            this.stack.pop();
            if (this.stack.empty()) {
                return false;
            }
            e = (Enumeration)this.stack.peek();
        }
        
        try {
            if (e != null) {
                this.next = (ObjectNode)e.nextElement();
                this.stack.push(this.structure.getChildren(this.token, this.next));
                return true;
            }
        } catch (LinkedObjectNotFoundException ex) {
            // can't happen
        }
        
        return false;
    }

    public ObjectNode nextNode()
        throws ServiceAccessException, ObjectNotFoundException, VetoException
    {
        if (hasNext()) {
            ObjectNode node = (ObjectNode)this.next;
            this.next = null;
            return node;
        } else {
            throw new NoSuchElementException();
        }
    }
}
