package rac;

import listFW.*;
import listFW.factory.*;
import lrs.*;

/**
 * Implements a factory for restricted access containers.  These
 * restricted access containers are implemented using an LRStruct to
 * hold the data objects.
 */
public abstract class ALRSRACFactory implements IRACFactory {
    /**
     * Implements a general-purpose restricted access container using
     * an LRStruct.  How? 
     *
     * The next item to remove is always at the front of the list of
     * contained objects.  This is invariant!
     *
     * Insertion is, however, delegated to a strategy routine; and
     * this strategy is provided to the container.  This strategy
     * varies to implement the desired kind of container, e.g., queue
     * vs. stack.
     *
     * This inner class is protected so that classes derived from its
     * factory can reuse it to create other kinds of restricted access
     * container. 
     */
    protected class LRSRAContainer implements IRAContainer {
        private IAlgo _insertStrategy;
        private LRStruct _lrs;
        
        public LRSRAContainer(IAlgo strategy) {
            _insertStrategy = strategy;
            _lrs = new LRStruct();
        }
        
        /**
         * Empty the container.
         */
        public void clear() {
            _lrs = new LRStruct();
        }
        
        /**
         * Return TRUE if the container is full; otherwise, return
         * FALSE. 
         *
         * This implementation can hold an arbitrary number of
         * objects.  Thus, always return false.
         */
        public boolean isFull() {
            return false;
        }
        
        /**
         * Return an immutable list of all elements in the container.
         */
        public IList elements(final IListFactory fact) {
            return (IList)_lrs.execute(new IAlgo() {               
                public Object emptyCase(LRStruct host, Object... input) {
                    return fact.makeEmptyList();
                }
                
                public Object nonEmptyCase(LRStruct host, Object... input) {
                    return fact.makeNEList(host.getFirst(),
                                           (IList)host.getRest().execute(this, input));
                }
            });
        }
        
        /**
         * Remove the next item from the container and return it.
         */
        public Object get() {
            return _lrs.removeFront();
        }
        
        /**
         * Add an item to the container.
         */
        public void put(Object input) {
            _lrs.execute(_insertStrategy, input);
        }
        
        /**
         * Return the next element in this IRAContainer withour removing it.
         * @throw an Exception if this IRAContainer is empty.
         */
        public Object peek() {
            return _lrs.getFirst();
        }
        
        /**
         * Extensibility hook to accept a visitor algorithm.
         * @param v  The visitor to execute
         * @param inp An arbitrary input parameter for the visitor
         * @return The return value of the calculation performed by the visitor.
         */
        public Object execute(final IRACVisitor v, final Object... inp) { 
            return _lrs.execute(new IAlgo() {
                public Object emptyCase(LRStruct host, Object... nu) {
                    return v.emptyCase(LRSRAContainer.this, inp);
                }
                public Object nonEmptyCase(LRStruct host, Object... nu) {
                    return v.nonEmptyCase(LRSRAContainer.this, inp);          
                }
            });
        }
        
    }    
}

