/*
 * SimpleArrayList.java
 *
 * Version:
 *    $Id: SimpleArrayList.java,v 1.1 2001/11/28 15:16:51 ptt Exp $
 *
 * Revisions:
 *    $Log: SimpleArrayList.java,v $
 *    Revision 1.1  2001/11/28 15:16:51  ptt
 *    INITIAL COMMIT
 *
 */

import java.util.Iterator;

/**
 * An array based implement of the SimpleList interface.
 *
 * @author Paul Tymann
 */

public class SimpleArrayList implements SimpleList {
    private static final int DEFAULT_CHUNK_SIZE = 50;  // Array sizing

    private final int chunkSize;  // Amount to grow array by
    private Object list[];        // where the elements are stored
    private int count;            // how many elements are in the list

    // Iterator capable of traversing the list

    private class ArrayListIterator implements Iterator {
	private int pos;    // where we are in the list

	/**
	 * Returns true if the iteration has more elements.
	 *
	 * @return true if the iterator has more elements.
	 */

	public boolean hasNext() {
	    return pos < count;
	}

	/**
	 * Returns the next element in the interation.
	 *
	 * @return the next element in the iteration.
	 */

	public Object next() {
	    Object retVal = null;

	    retVal = list[ pos ];
	    pos = pos + 1;

	    return retVal;
	}

	/**
	 * Not supported by this implementation.
	 */

	public void remove() {
	    throw new UnsupportedOperationException();
	}

    } // ArrayListIterator

    /**
     * Create a new SimpleArrayList object.
     */

    public SimpleArrayList() {
	this( DEFAULT_CHUNK_SIZE );
    }

    /**
     * Create a new SimpleArrayList object that grows the array
     * by the specified growth factor.
     *
     * @param growthFactor the amount the array will be increased by.
     */

    public SimpleArrayList( int growthFactor ) {
	chunkSize = growthFactor;

	list = new Object[ growthFactor ];
	count = 0;
    }

    /**
     * Add a new element to the end of the list.
     *
     * @param data the element to add to the list.
     */

    public void add( Object data ) {
	reSize();

	list[ count ] = data;
	count = count + 1;
    }

    /**
     * Inserts the specified element at the specified position in the list.
     * The elements in the list will be shifted to the right to make room
     * for the new element.
     *
     * @param pos position at which element is to be inserted.
     * @param data the element to add to the list.
     *
     * @exception IndexOutOfBoundsException thrown if pos is invalid.
     */

    public void add( int pos, Object data ) throws IndexOutOfBoundsException {

	// Make sure pos is valid

	if ( pos < 0 || pos > size() ) {
	    throw new IndexOutOfBoundsException();
	}

	// Resize the array if necessary

	reSize();

	// Make room for the new element

	for ( int i = size(); i > pos; i-- ) {
	    list[ i ] = list[ i - 1 ];
	}

	// Insert the new element

	list[ pos ] = data;
	count++;
    }

    /**
     * Determine if the specified element is in the list.
     *
     * @param target the element to look for.
     *
     * @returns true if the element is in the list and false otherwise.
     */

    public boolean contains( Object target ) {
        return indexOf( target ) != -1;
    }

    /**
     * Returns the index of the first occurence of the specified element
     * in the list or -1 if the element is not in the list.
     *
     * @param target the element to look for.
     *
     * @returns the index of the specified element or -1 if the element
     *          is not in the list.
     */

    public int indexOf( Object target ) {
        int retVal = 0;
        Object cur = null;

        for ( Iterator i = iterator();
              i.hasNext() && !i.next().equals( target );
              retVal = retVal + 1 );

        if ( retVal == size() ) {
            retVal = -1;
        }

        return retVal;
    }

    /**
     * Returns the element at the specified position in the list.
     *
     * @param pos the position of the element to return.
     *
     * @return the specified element in the list.
     *
     * @exception IndexOutOfBoundsException if pos is invalid.
     */

    public Object get( int pos ) throws IndexOutOfBoundsException {
	if ( pos < 0 || pos >= size() ) {
	    throw new IndexOutOfBoundsException();
	}

	return list[ pos ];
    }

    /**
     * Remove the element at the specified position from the list.
     *
     * @param pos position of the element to remove
     *
     * @exception IndexOutOfBoundsException if pos is invalid.
     */

    public void remove( int pos ) throws IndexOutOfBoundsException {
	Object retVal = null;

	if ( pos < 0 || pos >= size() ) {
	    throw new IndexOutOfBoundsException();
	}

	// Hang on to the element that will be deleted

	retVal = list[ pos ];

	// Move everything up one position in the list

	while ( pos > size() - 1 ) {
	    list[ pos ] = list[ pos + 1 ];
	    pos = pos + 1;
	}

	count--;
    }

    /**
     * Remove the first occurence of the specified element from the
     * list.
     *
     * @param target the element to remove.
     */

    public void remove( Object target ) {
        int pos = indexOf( target );

        if ( pos != -1 ) {
            remove( pos );
        }
    }

    /**
     * Removes all of the elements from this list.
     */

    public void clear() {
	count = 0;
    }

    /**
     * Returns an iterator over the elements in the list.
     *
     * @returns an iterator over the elements in the list.
     */

    public Iterator iterator() {
        return new ArrayListIterator();
    }

    /**
     * Return the number of elements currently in the list.
     *
     * @return the number of elements in the list.
     */

    public int size() {
        return count;
    }

    /**
     * Return true if the list is empty.
     *
     * @return true if the list is empty.
     */

    public boolean isEmpty() {
        return size() == 0;
    }

    /**
     * Determine if another object is equal to this object.  Two lists
     * are equal if the contain the same number of elements in the
     * same order.
     *
     * @param the object to be compared.
     *
     * @return true if the lists are equal and false otherwise.
     */

    public boolean equals( Object o ) {
        boolean retVal = false;
        SimpleList other = null;

        if ( o instanceof SimpleList ) {
            other = (SimpleList)o;

            retVal = size() == other.size();

            for ( Iterator l1 = iterator(), l2 = other.iterator();
                  l1.hasNext() && retVal; ) {

                retVal = retVal && l1.next().equals( l2.next() );
            }
	}

	return retVal;
    }
    /**
     * Return a string representation of this list.
     *
     * @return A string representation of this list.
     */

    public String toString() {
        StringBuffer retVal = new StringBuffer( "[" );
        int len = 0;

        // Assemble the string

        for ( Iterator i = iterator(); i.hasNext(); ) {
            retVal.append( i.next() );
            retVal.append( "," );
        }

        // Get rid of the trailing ','

        if ( ( len = retVal.length() ) != 1 ) {
            retVal.deleteCharAt( retVal.length() - 1 );
        }

        // Close the string and return

        retVal.append( "]" );

        return retVal.toString();
    }

    // Class utility methods

    /**
     * Resize the array used to hold the elements in this list.
     */

    private void reSize() {
	if ( count == list.length ) {
	    Object newList[] = new Object[ list.length + chunkSize ];

	    for ( int i = 0; i < list.length; i++ ) {
		newList[ i ] = list[ i ];
	    }

	    list = newList;
	}
    }

}  // SimpleArrayList

