package net.ranides.assira.collection.iterators;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * Fetch iterator is abstract class for iterators which are able to process data in batches.
 * Just implement "fetch" method which is supposed to return any number of elements at each call.
 * Iterator will execute "fetch" method only when previous elements were consumed.
 * To stop iteration just return empty collection.
 *
 * @param <T> T
 */
public abstract class FetchIterator<T> implements Iterator<T> {

    private Iterator<T> iterator = Collections.emptyIterator();

    private boolean stop;

    /**
     * Fetch method is stateful method which is supposed to return next results in batches of any size.
     * Iterator will execute "fetch" method only when previous elements were consumed.
     * To stop iteration just return empty collection.
     *
     * @return iterable
     */
    public abstract Iterable<T> fetch();

    @Override
    public boolean hasNext() {
        if(stop) {
            return false;
        }
        if(!iterator.hasNext()) {
            iterator = fetch().iterator();
        }
        if(!iterator.hasNext()) {
            stop = true;
            return false;
        }
        return true;
    }

    @Override
    public T next() {
        if(!hasNext()) {
            throw new NoSuchElementException();
        }
        return iterator.next();
    }

}
