/**
 * An implementation of Scheme-like lists that uses arrays.
 *
 * @author Samuel A. Rebelsky
 * @author Yvonne Palm
 * @author "Better Late Than Never" Leach
 */
public class ArrayBasedSchemeList
  implements SchemeList
{
  // +-----------+-----------------------------------------------
  // | Constants |
  // +-----------+

  // +--------+--------------------------------------------------
  // | Fields |
  // +--------+

  /** 
   * The contents of the list.
   */
  Object[] contents;

  /**
   * The cdr of this list.
   */
  ArrayBasedSchemeList myCdr;

  // +--------------+--------------------------------------------
  // | Constructors |
  // +--------------+

  /**
   * Build an empty list.
   */
  public ArrayBasedSchemeList()
  {
    this.contents = new Object[0];
  } // ArrayBasedSchemeList()

  // +------------------+----------------------------------------
  // | Exported Methods |
  // +------------------+

  /** 
   * Determine if this list is empty.
   */
  public boolean isEmpty()
  {
    return (0 == this.contents.length);
  } // isEmpty()

  /**
   * Create a new list by adding something to the front of this list.
   */
  public SchemeList addToFront(Object val)
  {
    ArrayBasedSchemeList newList = new ArrayBasedSchemeList();
    newList.contents = new Object[this.contents.length + 1];
    newList.contents[0] = val;
    for (int i = 0; i < this.contents.length; i++) {
      newList.contents[i+1] = this.contents[i];
    }
    newList.myCdr = this;
    return newList;
  } // addToFront(Object)
  
  /**
   * Get the initial element of the list.
   */
  public Object car()
    throws EmptyListException
  {
    if (this.isEmpty())
      throw new EmptyListException();
    return this.contents[0];
  } // car()

  /**
   * Get a list that contains all but the first element.
   */
  public SchemeList cdr()
    throws EmptyListException
  {
    return this.myCdr;
/*
    if (this.isEmpty())
      throw new EmptyListException();
    ArrayBasedSchemeList newList = new ArrayBasedSchemeList();
    newList.contents = new Object[this.contents.length - 1];
    for (int i = 1; i < this.contents.length; i++) {
      newList.contents[i-1] = this.contents[i];
    }
    return newList;
 */
  } // cdr()

  /**
   * Convert this list to a string (often for printing).
   */
  public String toString() 
  {
    if (this.isEmpty()) { return "()"; }
    String result = "(" + this.contents[0];
    for (int i = 1; i < this.contents.length; i++) {
      result = result + " " + this.contents[i];
    }
    result = result + ")";
    return result;
  } // toString()
} // interface ArrayBasedSchemeList
