package eu.dnetlib.enabling.resultset;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Exposes an iterable through our resultset protocol.
 * 
 * <p>
 * The resultset protocol is constructed as if it were random access. Some kind of sources, like an iterable, is not
 * random access. The consumer of such a resultset knows that, and won't try to access the resultset randomly. However,
 * it could ask for some data which is already sent, because of retries caused by network issues.
 * </p>
 * 
 * @author marko
 * 
 */
public class StreamingResultSetListener implements ResultSetListener, ResultSetAware {
	private static final Log log = LogFactory.getLog(StreamingResultSetListener.class); // NOPMD by marko on 11/24/08 5:02 PM

	private ResultSet resultSet;

	private Iterable<String> iterable;
	private Iterator<String> items;
	private int size;

	private int lastFrom = 0;
	private int lastTo = 0;
	private List<String> lastChunk;

	public StreamingResultSetListener(Iterable<String> items, int size) {
		this(items.iterator(), size);
		this.iterable = items;
	}

	public StreamingResultSetListener(Iterator<String> items, int size) {
		super();
		this.items = items;
		this.size = size;
	}

	protected void reset() {
		lastFrom = 0;
		items = iterable.iterator();
	}

	@Override
	public List<String> getResult(int from, int to) {

		log.debug("STREAM: getResult(" + from + ", " + to + ")");

		// handle retry because of network error.
		if (from == lastFrom && to == lastTo)
			return lastChunk;

		if (from != lastTo + 1) {
			if (from == 1 && iterable != null)
				reset();
			else
				throw new IllegalArgumentException("this resultset is not random access, you can only retry last chunk only, asked from " + from + " to "
						+ to + " but lastTo = " + lastTo + ". Size = " + size);
		}

		List<String> chunk = new ArrayList<String>();
		for (int i = from; i <= to; i++)
			chunk.add(items.next());

		if (resultSet != null && !items.hasNext())
			resultSet.close();

		lastFrom = from;
		lastTo = to;
		lastChunk = chunk;

		return chunk;
	}

	@Override
	public int getSize() {
		return size;
	}

	public void setSize(int size) {
		this.size = size;
	}

	public Iterator<String> getItems() {
		return items;
	}

	public void setItems(Iterator<String> items) {
		this.items = items;
	}

	public int getLastFrom() {
		return lastFrom;
	}

	public void setLastFrom(int lastFrom) {
		this.lastFrom = lastFrom;
	}

	public int getLastTo() {
		return lastTo;
	}

	public void setLastTo(int lastTo) {
		this.lastTo = lastTo;
	}

	public List<String> getLastChunk() {
		return lastChunk;
	}

	public void setLastChunk(List<String> lastChunk) {
		this.lastChunk = lastChunk;
	}

	public ResultSet getResultSet() {
		return resultSet;
	}

	@Override
	public void setResultSet(ResultSet resultSet) {
		this.resultSet = resultSet;
	}

}
