/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection.iterators;

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

public abstract class RandomAccessIterator<T> implements ListIterator<T> {
    
    private int index;
    
    private int last;

    protected abstract int size();
    
    protected abstract T get(int index);
    
    protected void remove(int index) {
        throw new UnsupportedOperationException();
    }
    
    protected void add(int index, T value) {
        throw new UnsupportedOperationException();
    }
    
    protected void set(int index, T value) {
        throw new UnsupportedOperationException();
    }
    
    public RandomAccessIterator() {
        this(0);
    }
    
    public RandomAccessIterator(int index) {
        this.index = index;
        this.last = -1;
    }

    @Override
    public boolean hasNext() {
        return index < size();
    }

    @Override
    public boolean hasPrevious() {
        return index > 0;
    }

    @Override
    public T next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        return get(last = index++);
    }

    @Override
    public T previous() {
        if (!hasPrevious()) {
            throw new NoSuchElementException();
        }
        return get(last = --index);
    }

    @Override
    public int nextIndex() {
        return index;
    }

    @Override
    public int previousIndex() {
        return index - 1;
    }

    @Override
    public void add(T value) {
        add(index++, value);
    }

    @Override
    public void set(T value) {
        if (last == -1) {
            throw new IllegalStateException();
        }
        set(last, value);
    }

    @Override
    public void remove() {
        if (last == -1) {
            throw new IllegalStateException();
        }
        remove(last);
        // If the last operation was a next(), 
        // we are removing an element *before* us, 
        // and we must decrease pos correspondingly.
        if (last < index) {
            index--;
        }
        last = -1;
    }
    
}
