/**
 * Represents an abstract Scheme-like list, an  immutable linear recursive
 * structure of data. Has abstract methods to provide its internal data and
 * structure to the client. Since an AList has an internal structure that is
 * isomorphic to itself, it's best to implement it using the composite pattern.
 */
public abstract class AList {

    /**
     * Computes the minimum of this AList, assuming it contains Integer objects.
     * Uses helpGetMin.
     * @return behavior relegated to concrete subclasses.
     */
    public abstract int getMin();

    /**
    * Computes the minimum of the preceding list and this AList using the
    * accumulated minimum.
    * @param accMin the smallest int containing in the list preceding this AList.
    * @return behavior relegated to concrete subclasses.
    */
    protected abstract int helpGetMin(int accMin);
   /**
    * If this AList is empty, returns the empty list, else returns an AList
    * consisting of the even-indexed elements of this AList, with 0 being the
    * index of the first element of a non-empty list.  Uses helpEveryOther().
    * @return behavior relegated to concrete subclasses.
    */
    public abstract AList everyOther();

    /**
    * Accepts as input the first element of the enclosing list and builds an
    * AList consisting of every other element of the enclosing list.
    * @param first the first element of the enclosing list.
    * @return behavior relegated to concrete subclasses.
    */
    protected abstract AList helpEveryOther(Object first);
    /**
     * Computes the length of this AList.  Uses helpGetLen.
     * @return int >= 0.
     */
    public abstract int getLen();

    /**
     * Uses the accumulated length of the preceding list to help compute the
     * length of the preceding list.
     * @param acc the accumlated length of the preceding list.
     * @return behavior relegated to concrete subclasses.
     */
    protected abstract int helpGetLen(int acc);

    // Other methods elided ...
}

public class EmptyList extends AList {
    public final static EmptyList Singleton = new EmptyList();
    private EmptyList() {
    }
public class NEList extends AList {
    private Object _first;
    private AList _rest;

    /**
     *  Thows an IllegalArgument exception
     *  @return does not return

     */
    public int getMin() {
        throw new IIlegalArgumentException("Empty has min!");
    }

    /**
     * Asks _rest for help to compute the min, passing it
     *
the int value of _first as the accumulated min.
     * @return the minimum int contained in this NEList.
     */
    public int getMin() {
        return _rest.helpGetMin(((Integer)_first).intValue());
    }
  /**
 * Returns the accum
ulated minimum, since this is the end of the list.
 * @param accMin the smallest int containing in the list preceding this NEList.
 * @return accMin.
 */
  protected int helpGetMin(int
accMin) {
        return
accMin;
 
   }

  /**
 * Computes the smaller of the accumulated min parameter
 *
and the value of _first, and passes the result down to the
 *
tail for help to compute the min.
 * @param accMin the smallest int containing in the list preceding this NEList.
 * @return the minimum int contained in the preceding list and this NEList.
 */
  protected int helpGetMin(int accMin) {
      return _rest.helpGetMin(Math.min(((Integer)_first).intValue(), accMin));
 }
   
/**
* The empty list contains all even-indexed elements of the empty list!
* @return this
*/

public AList everyOther() {
  return this;
}
/**
* Passes _first to _rest, asking it for help to collect every other
* elements and builds the resulting list.
* @return an AList consisting of every other elements of this AList.
*/

public AList everyOther() {
  return _rest.helpEveryOther(_first);
}
/**
* The enclosing list has an empty tail. This means the enclosing list has
* only one element.
* @param first the first element of the enclosing list.
* @return a NEList with fist as its only element.
*/

protected AList helpEveryOther(Object first) {
   return new NEList( first, this);
}
/**
* "Cons" the parameter first the the list consisting of every other
* elements of _rest.
* @param first the first element of the enclosing list.
* @return an AList consisting of every other elements of the enclosing list.
*/

protected AList helpEveryOther(Object first) {
   return new NEList(first, _rest.everyOther());
}
   
/**
 * Computes the length of this EmptyList.
 * @return 0.
 */
  public int getLen() {
     
  return 0;
  }
 /**
 * Asks the tail for help to compute the length, passing
 * 
it an accumulated length of 1, and returns the result.
 
*/
  public int getLen() {
        return _rest.helpGetLen(1);
 }
   /**
     * Returns the accumulated length, since this is the end of the list.
     * @param acc the length of the list preceding this EmptyList.
     * @return acc.
     */
    protected int helpGetLen(int acc) {
        return acc;
    }
}
  /**
  * Adds 1 to the accumulated length, passes it down to the
  *
tail for help to compute the length, and returns the result.
 
* @param acc the length of the list preceding this NEList.
  * @return int > acc.
  */
 
  protected int helpGetLen(int acc) {
        return _rest.helpGetLen(acc + 1);
   
}
}