package list;

import java.util.ListIterator;
import java.util.NoSuchElementException;

public class ListIteratorImpl<E> implements ListIterator<E> {

    private AbstractLinkedList<E> list;
    private int currentElement;
    private int indexOfFirstElement;
    private int lastReturnedIndex = -1;
    
    
    public ListIteratorImpl(AbstractLinkedList<E> myList, int indexOfFirstElement) {
        this.list = myList;
        this.indexOfFirstElement = indexOfFirstElement;
        this.currentElement = indexOfFirstElement;
    }
    
    public boolean hasNext() {
        return this.currentElement < this.list.size();
    }

    public E next() {
        if (! hasNext()) {
            throw new NoSuchElementException();
        }
        E result = this.list.get(this.currentElement);
        this.lastReturnedIndex = this.currentElement;
        this.currentElement++;
        return result;
    }

    public int nextIndex() {
        return currentElement;
    }

    public boolean hasPrevious() {
        return currentElement > indexOfFirstElement;
    }

    public E previous() {
        if (! hasPrevious()) {
            throw new NoSuchElementException();
        }
        this.currentElement--;
        E result = this.list.get(this.currentElement);
        this.lastReturnedIndex = this.currentElement;
        return result;
    }

    public int previousIndex() {
        return currentElement-1;
    }

    public void remove() {
        ensureLastReturnedIndex();
        this.list.remove(this.lastReturnedIndex);
        this.currentElement = this.lastReturnedIndex;
        this.lastReturnedIndex = -1;
    }

    public void add(E element) {
        this.list.add(this.currentElement, element);
        this.currentElement++;
        this.lastReturnedIndex = -1;
    }

    public void set(E o) {
        ensureLastReturnedIndex();
        this.list.set(this.lastReturnedIndex, o);
    }

    //------------------------- Helper methods
    
    private void ensureLastReturnedIndex() {
        if (this.lastReturnedIndex < 0) {
            throw new IllegalStateException("No element has been returned, yet or remove() or add() have just been invoked");
        }
    }
}
