/* 
 * a stack of strings implemented using an array
 * @author	Biagioni, Edoardo
 * @assignment	lecture 7
 * @date	February 4, 2008
 */

import java.util.EmptyStackException;

public class IntArrayStack implements IntStackInterface {
    /* fields to store the stack elements and the location of the
     * top of the stack.
     * the values are in array locations 0..top if top >= 0
     * for an empty array, top is -1
     */
    private int top;
    private int[] array;

    /* no-arguments default constructor creates an empty stack */
    public IntArrayStack() {
	top = -1;		// empty stack
	array = new int[10];	// always have room for at least 10 items
    }

    /* @return	whether the stack is empty */
    public boolean empty() {
	return (top == -1);
    }
       
    /* @param	int to push onto the stack */
    public void push(int value) {
	/* make sure there is room in the array */
	if (array.length == top + 1) {
	    int[] newArray = new int[array.length * 2];
	    System.arraycopy(array, 0, newArray, 0, array.length);
	    array = newArray;
	} // else, there already is room for one new element
	top++;
	array[top] = value;
    }

    /* @return	the top int on the stack */
    public int pop() throws EmptyStackException {
	if (empty()) {
	    throw new EmptyStackException();
	}
	int result = array[top];
	top--;
	return result;
    }

    /* different implementation of pop, does exactly the same.
     * @return	the top int on the stack
     */
    public int pop2() throws EmptyStackException {
	try {
	    return array[top--];
	} catch(java.lang.ArrayIndexOutOfBoundsException error) {
	    top = -1;		// just to be sure
	    throw new EmptyStackException();
	}
    }

    /* convert the stack to a printable string
     * @return	a string representing the stack
     */
    public String toString() {
	if (empty()) {
	    return "Empty Stack";
	} else {
	    return recursiveToString(0);
	}
    }

    /* recursive method to print a non-empty stack
     * @param	the starting index in the array
     * @return	a string representing the stack
     */
    private String recursiveToString(int startPos) {
	if (startPos > top) {
	    return "";
	}
	String separator = "";
	if (startPos > 0) {
	    separator = " :: ";
	}
	return separator + array[startPos] + recursiveToString(startPos + 1);
    }

    // simple test
    public static void main(String[] args) {
	IntStackInterface s = new IntArrayStack();

	System.out.println("before pushing anything, " + s);
	s.push(55);
	s.push(99);
	System.out.println("after pushing 55 and 99, " + s);
	System.out.println("pop returns " + s.pop());
	System.out.println("after popping, " + s);
	// push 100 values
	for (int i = 0; i < 100; i++) {
	    s.push(i);
	}
	// now pop them and make sure the same values are returned
	// in LIFO order
	for (int i = 99; i >= 0; i--) {
	    int returned = s.pop();
	    if (returned != i) {
		System.out.println("error: pop returns " + returned +
				   ", expected " + i);
	    }
	}
	s.push(77);
	s.push(44);
	s.push(25);
	System.out.println("after pushing 77, 44, 25, " + s);
	System.out.println("pop returns " + s.pop());
	System.out.println("pop returns " + s.pop());
	System.out.println("pop returns " + s.pop());
	System.out.println("pop returns " + s.pop());
	System.out.println("after popping, " + s);
    }
}