package eu.dnetlib.data.utility.objectpackaging;

import java.io.StringReader;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;

import javax.xml.ws.wsaddressing.W3CEndpointReference;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;

import eu.dnetlib.data.utility.objectpackaging.rmi.ObjectPackagingException;

class ObjectQueue {
	/**
	 * 
	 */
	private static final long serialVersionUID = -8679627487574601486L;
	
	/**
	 * logger. 
	 */
	private static final Log log = LogFactory.getLog(ObjectQueue.class); // NOPMD by marko on 11/24/08 5:02 PM
	
	private int totalItems = 0;
	private int givenItems = 0;

	protected Queue<String> theQueue;

	private String xpath_ID;
	
	private ObjectProvider provider;
	
	private ObjectProviderFactory objectProviderFactory; 
	
	protected ObjectQueue(W3CEndpointReference epr, String xpath_ID, ObjectProviderFactory objectProviderFactory) throws ObjectPackagingException {
		this.provider = objectProviderFactory.createObjectProvider(epr);
		this.xpath_ID = xpath_ID;
		this.theQueue = new PriorityQueue<String>();
		this.objectProviderFactory = objectProviderFactory;
		callDataProvider();
	}
		
	private void callDataProvider() throws ObjectPackagingException {
		if (provider == null) throw new ObjectPackagingException("Problem with DataProvider: provider is null");
		try {
			totalItems = provider.getSize();
		} catch (Exception e) {
			throw new ObjectPackagingException("Problem with DataProvider: " + e.getMessage()); 
		}
		
	}

	public boolean isEmpty() {
		if (givenItems == totalItems) return true;
		return false;
	}

	public String fetchNextElement() {
		if (theQueue.isEmpty() && (givenItems < totalItems)) {
			retrieveMoreElements();
		}
		String response = theQueue.poll();
		if (response != null) givenItems += 1;
		return response;
	}
	
	public String watchNextElementId() throws ObjectPackagingException {
		if (theQueue.isEmpty() && (givenItems < totalItems)) {
			retrieveMoreElements();
		}
		String elem = theQueue.peek();
		if (elem == null) return null;
		
		try {
			return calculateID(elem);
		} catch (DocumentException e) {
			// TODO ??????
			return null;
		}
	}

	private String calculateID(String s) throws DocumentException, ObjectPackagingException {
		SAXReader reader = new SAXReader();
		Document doc = reader.read(new StringReader(s));
		String res = doc.valueOf(xpath_ID);
		if ((res == null)||(res.length() == 0)) {
			throw new ObjectPackagingException("xpath " + xpath_ID + " has returned an empty identifier");
		}
		return res;
	}

	private void retrieveMoreElements() {
		int from = givenItems + 1;
		int to   = from       + ObjectPackagesCollection.DEFAULTPAGESIZE - 1;
		if (to > totalItems) to = totalItems;
		
		try {
			List<String> res = provider.getElements(from, to);
			theQueue.addAll(res);
		} catch (ObjectPackagingException e) {
			log.fatal(e);
		}
	}

	protected int getGivenItems() {
		return givenItems;
	}

	public int getTotalItems() {
		return totalItems;
	}

	public List<String> obtainOldItems(int from, int to) throws ObjectPackagingException {
		return provider.getElements(from, to);
	}

	public ObjectProviderFactory getObjectProviderFactory() {
		return objectProviderFactory;
	}

	public void setObjectProviderFactory(ObjectProviderFactory objectProviderFactory) {
		this.objectProviderFactory = objectProviderFactory;
	}
	
}
