package playingWithLists;

public class MyLinkedList<Any> extends MySchemeList<Any> implements List<Any>
{
	public MyLinkedList(Any [] x) {
		super(x);
	}
	
	private MySchemeList<Any> findIt(int idx) {
		MySchemeList<Any> current = this;
		while (idx-- != 0) {
			if (current.isNil()) {
				throw new IndexOutOfBoundsException();
			} else {
				current = current.cdr();				
			}
		}
		return current;
	}
	
	private MySchemeList<Any> find(int idx) {
		if (idx < 0) {
			throw new IndexOutOfBoundsException();
		} else {
			return findIt(idx);
		}
	}
	
	public Any get(int idx) {
		MySchemeList<Any> thePlace = find(idx);
		if (thePlace.isNil()) {
			throw new IndexOutOfBoundsException();
		} else {
			return thePlace.car();
		}
	}
	public Any set(int idx, Any newVal) {
		MySchemeList<Any> thePlace = find(idx);
		if (thePlace.isNil()) {
			throw new IndexOutOfBoundsException();
		} else {
			Any oldVal = thePlace.car();	
			thePlace.setCar(newVal);
			return oldVal;
		}
	}
	public void add(int idx, Any x) {
		MySchemeList<Any> thePlace = find(idx);
		if (thePlace.isNil()) {
			thePlace.setNotNil();
			thePlace.setCar(x);
			thePlace.setCdr(new MySchemeList<Any>());
		} else {
			thePlace.setCdr(thePlace.cdr().cons(thePlace.car()));
			thePlace.setCar(x);
		}
	}
	public void remove(int idx) {
		MySchemeList<Any> thePlace = find(idx);
		if (thePlace.isNil()) {
			throw new IndexOutOfBoundsException();
		} else {
			if (thePlace.cdr().isNil()) {
				thePlace.setNil();
			} else {
				thePlace.setCar(thePlace.cdr().car());
				thePlace.setCdr(thePlace.cdr().cdr());
			}
		}
	}
	

    static private class MyLinkedListIterator<Any> implements java.util.Iterator<Any> {
    	private MySchemeList<Any> currentList;
    	private MySchemeList<Any> previousList;
	private boolean okToRemove = false;

    	public MyLinkedListIterator(MyLinkedList<Any> aList) {
    		currentList = aList;
    	}

    	public Any next() {
    		if (currentList.isNil()) {
    			throw new java.util.NoSuchElementException();
    		} else {
    			previousList = currentList;
    			Any theCar = currentList.car();
    			currentList = currentList.cdr();
			okToRemove = true;
    			return theCar;
    		}
    	}
    	public boolean hasNext() {
    		return ! currentList.isNil();
    	}

    	public void remove() {
    		if (previousList == null || !okToRemove) {
		    throw new IllegalStateException();
    		} else {
		    okToRemove = false;
		    if (previousList.cdr().isNil()) {
			previousList.setNil();
		    } else {
			previousList.setCar(previousList.cdr().car());
			previousList.setCdr(previousList.cdr().cdr());
		    }
    		}
    	}
    }
    
    public java.util.Iterator<Any> iterator() {
    	return new MyLinkedListIterator<Any>(this);
    }
 
}
