package eu.dnetlib.enabling.resultset;

import java.util.Iterator;
import java.util.LinkedList;

/**
 * a LinkedList populated by a given iterable, which provides a fetch window of elements
 *
 * @author claudio
 *
 * @param <T>
 *            The FetchList type
 */
public class FetchList<T> extends LinkedList<T> {

	/**
	 *
	 */
	private static final long serialVersionUID = 7135272008563693321L;

	/**
	 * represents the number of elements ready to be pulled out of the list
	 */
	private int fetchSize;

	/**
	 * represents the number of elements already consumed by a poll call
	 */
	private int consumedElements;

	/**
	 * the given itarable used to populate the list
	 */
	private Iterator<T> iter;

	/**
	 * @param iter
	 * @param fetchSize
	 */
	public FetchList(final Iterator<T> iter, final int fetchSize) {
		super();
		this.consumedElements = 0;
		this.fetchSize = fetchSize;
		this.iter = iter;
	}

	/**
	 * used to fill the list
	 */
	public synchronized void fill() {
		for (int i = 0; i < fetchSize; i++) {
			if (!iter.hasNext()) {
				break;
			}
			this.add(iter.next());
		}
	}

	/**
	 * return the first element and makes the list to be filled in case its size is zero
	 */
	@Override
	public T poll() {
		if (this.isEmpty()) {
			fill();
		}

		if (this.size() > 0) {
			consumedElements++;
			return super.poll();
		}
		return null;
	}

	/**
	 * @return the number of elements already consumed by a "poll"
	 */
	public int getConsumedElements() {
		return consumedElements;
	}

	/**
	 * @return the actual number of elements of the list
	 */
	public int getTotalElements() {
		return consumedElements + this.size();
	}

	/**
	 * to provide an actual size, fills the list if there are elements to fill it
	 */
	@Override
	public int size() {
		if (this.isEmpty() && iter.hasNext()) {
			fill();
		}
		return super.size();
	}

	@Override
	public boolean isEmpty() {
		return super.size() == 0;
	}

}
