package brs.visitor;

import brs.*;
import rac.*;
import rac.visitor.*;
import java.util.*;

/**
 * This visitor returns an Enumeration that lazily traverses 
 * the tree in a manner prescibed by the type of rac used.
 * The rac is the input parameter to this visitor.
 */
public class BRSLazyEnumerator implements IVisitor {
    public static final BRSLazyEnumerator Singleton = new BRSLazyEnumerator();
    private BRSLazyEnumerator() {}
    
    /**
     * Always returns an Enumeration that has no available elements.
     */
    public Object emptyCase(BiTree host, Object... nu){
        // STUDENT TO COMPLETE
        
        // Returned Enumeration has no elements
        return new Enumeration() {
            public boolean hasMoreElements() {
                return false;
            }
            
            public Object nextElement() {
                throw new NoSuchElementException("Tree is empty!");
            }
        };
    }
    
    /**
     * Returns an Enumeration that has at least 1 available element
     * @param inp The rac to use
     * @return An Enumeration instance
     */
    public Object nonEmptyCase(BiTree host, Object... inp){
        // STUDENT TO COMPLETE
        
        final IRAContainer rac = (IRAContainer) inp[0];
        
        rac.put(host);  // Initial loading of the rac
        
        // Define this these helpers here so that it gets the rac in its closure.
        // These helpers are invariant w.r.t. further traversal thru the tree.
        
        final IVisitor putNonEmpty = new IVisitor() {
            public Object emptyCase(BiTree h, Object... nu){
                return null;
            }
            public Object nonEmptyCase(BiTree h, Object... nu){
                rac.put(h);
                return null;
            }
        };
        
        final IRACVisitor processRAC = new IRACVisitor() {     
            public Object emptyCase(IRAContainer host, Object... inp) {
                throw new NoSuchElementException("No more elements in tree!");
            }
            public Object nonEmptyCase(IRAContainer host, Object... inp){
                BiTree brs =  (BiTree) rac.get();
                
                // We know that only non-empty trees are in the RAC.
                // Load non-empty children into rac
                brs.getRightSubTree().execute(putNonEmpty);
                brs.getLeftSubTree().execute(putNonEmpty);
                return brs.getRootDat();  // return the root data
            }
        };
        
        return new Enumeration() {
            public boolean hasMoreElements() {
                return !(Boolean)rac.execute(IsEmpty.Singleton);
            }
            
            public Object nextElement() {
                // delegate to the RAC        
                return rac.execute(processRAC);
            }
        };
    }
}

