package eu.dnetlib.enabling.resultset;

import java.util.List;

import javax.xml.ws.wsaddressing.W3CEndpointReference;

import org.springframework.beans.factory.annotation.Required;

import eu.dnetlib.enabling.resultset.rmi.ResultSetException;
import eu.dnetlib.enabling.resultset.rmi.ResultSetService;
import eu.dnetlib.enabling.tools.ServiceResolver;
import eu.dnetlib.miscutils.collections.MappedCollection;
import eu.dnetlib.miscutils.functional.UnaryFunction;

/**
 * A resultset filter. Applies a transformation for every resultset record.
 * 
 * @author marko
 * 
 */
public class MappedResultSet implements ResultSetListener, ResultSetAware {

	/**
	 * input resultset.
	 */
	private ResultSetService resultSetService;

	/**
	 * input resultset id.
	 */
	private String rsId;

	/**
	 * mapper function.
	 */
	private UnaryFunction<String, String> mapper;

	/**
	 * service resolver.
	 */
	private ServiceResolver serviceResolver;

	private ResultSet resultSet;

	/**
	 * Create a new mapped resultset.
	 * 
	 * @param epr
	 *            input resultset epr
	 * @param mapper
	 *            mapper function
	 * @param serviceResolver
	 *            service resolver
	 */
	public MappedResultSet(final W3CEndpointReference epr, final UnaryFunction<String, String> mapper, final ServiceResolver serviceResolver) {
		super();

		this.resultSetService = serviceResolver.getService(ResultSetService.class, epr);
		this.rsId = serviceResolver.getResourceIdentifier(epr);

		this.mapper = mapper;

		this.serviceResolver = serviceResolver;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.resultset.ResultSetListener#getResult(int, int)
	 */
	@Override
	public List<String> getResult(final int fromPosition, final int toPosition) {
		return MappedCollection.listMap(getResultFromSource(fromPosition, toPosition), mapper);

	}

	protected List<String> getResultFromSource(final int fromPosition, final int toPosition) {
		try {
			List<String> res = resultSetService.getResult(rsId, fromPosition, toPosition, "waiting");
			checkStatus();
			return res;
		} catch (final ResultSetException e) {
			throw new IllegalStateException(e);
		}
	}

	private void checkStatus() throws ResultSetException {
		if (getResultSet().isOpen() && resultSetService.getRSStatus(rsId).equals("closed")) {
			getResultSet().close();
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.resultset.ResultSetListener#getSize()
	 */
	@Override
	public int getSize() {
		try {
			int numberOfElements = resultSetService.getNumberOfElements(rsId);
			checkStatus();		
			return numberOfElements;
		} catch (final ResultSetException e) {
			throw new IllegalStateException(e);
		}
	}

	public ResultSetService getResultSetService() {
		return resultSetService;
	}

	public void setResultSetService(final ResultSetService resultSetService) {
		this.resultSetService = resultSetService;
	}

	public UnaryFunction<String, String> getMapper() {
		return mapper;
	}

	public void setMapper(final UnaryFunction<String, String> mapper) {
		this.mapper = mapper;
	}

	public ServiceResolver getServiceResolver() {
		return serviceResolver;
	}

	@Required
	public void setServiceResolver(final ServiceResolver serviceResolver) {
		this.serviceResolver = serviceResolver;
	}

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

	public ResultSet getResultSet() {
		return resultSet;
	}

	public String getRsId() {
		return rsId;
	}

	public void setRsId(String rsId) {
		this.rsId = rsId;
	}

}
