package eu.dnetlib.enabling.resultset;

import java.util.List;

import javax.annotation.Resource;
import javax.xml.ws.Endpoint;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

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

import eu.dnetlib.common.rmi.UnimplementedException;
import eu.dnetlib.enabling.resultset.push.PushResultSet;
import eu.dnetlib.enabling.resultset.push.PushResultSetFactory;
import eu.dnetlib.enabling.resultset.rmi.ResultSetException;
import eu.dnetlib.enabling.resultset.rmi.ResultSetService;
import eu.dnetlib.enabling.tools.AbstractBaseService;
import eu.dnetlib.soap.EndpointReferenceBuilder;

/**
 * This component dispatches the service method calls to stateful datastructure instances and to the singleton core.
 *
 * @author marko
 *
 */
public class ResultSetServiceImpl extends AbstractBaseService implements ResultSetService {
	/**
	 * Maps resultset identifiers to resultsets and manages expiration etc.
	 */
	private ResultSetRegistry resultsetRegistry;

	/**
	 * push resultset factory.
	 */
	private PushResultSetFactory pushFactory;

	/**
	 * Service endpoint.
	 */
	private Endpoint endpoint;

	/**
	 * injected epr builder.
	 */
	@Resource(name = "jaxwsEndpointReferenceBuilder")
	private EndpointReferenceBuilder<Endpoint> eprBuilder;

	/**
	 * custom resultset properties.
	 */
	private ResultSetPropertyDao customPropertyDao;

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.resultset.rmi.ResultSetService#closeRS(java.lang.String)
	 */
	public void closeRS(final String rsId) {
		// TODO Auto-generated method stub

	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.resultset.rmi.ResultSetService#createPullRS(java.lang.String, java.lang.String, int,
	 *      int, java.lang.String, java.lang.Integer, java.lang.Integer)
	 */
	public W3CEndpointReference createPullRS(
			final String providerAddress,
			final String bdId,
			final int initialPageSize,
			final int expiryTime,
			final String styleSheet,
			final Integer keepAliveTime,
			final Integer total) {
		throw new UnimplementedException();
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.resultset.rmi.ResultSetService#createPullRSEPR(javax.xml.ws.wsaddressing.W3CEndpointReference,
	 *      java.lang.String, int, int, java.lang.String, java.lang.Integer, java.lang.Integer)
	 */
	public W3CEndpointReference createPullRSEPR(
			final W3CEndpointReference dataProviderEPR,
			final String bdId,
			final int initialPageSize,
			final int expiryTime,
			final String styleSheet,
			final Integer keepAliveTime,
			final Integer total) {
		throw new UnimplementedException();
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.resultset.rmi.ResultSetService#getNumberOfElements(java.lang.String)
	 */
	public int getNumberOfElements(final String rsId) throws ResultSetException {
		final ResultSet resultSet = getResultSetById(rsId); // NOPMD
		return resultSet.getNumberOfResults();
	}

	/**
	 * {@inheritDoc}
	 * @see eu.dnetlib.enabling.resultset.rmi.ResultSetService#getResult(java.lang.String, int, int, java.lang.String)
	 */
	public List<String> getResult(final String rsId, final int fromPosition, final int toPosition, final String requestMode) throws ResultSetException {
		final ResultSet resultSet = getResultSetById(rsId); // NOPMD
		return resultSet.getResults(fromPosition, toPosition);
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.resultset.rmi.ResultSetService#createPushRS(int, int)
	 */
	public W3CEndpointReference createPushRS(final int expiryTime, final int keepAliveTime) throws ResultSetException {
		return pushFactory.createPushResultSet(expiryTime);
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.resultset.rmi.ResultSetService#getProperty(java.lang.String, java.lang.String)
	 */
	public String getProperty(final String rsId, final String name) throws ResultSetException {
		final ResultSet resultSet = getResultSetById(rsId); // NOPMD

		if ("rsId".equals(name))
			return resultSet.getIdentifier();
		else if ("total".equals(name))
			return Integer.toString(resultSet.getNumberOfResults());
		// ...

		return customPropertyDao.getProperties(resultSet).get(name);
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.resultset.rmi.ResultSetService#getRSStatus(java.lang.String)
	 */
	public String getRSStatus(final String rsId) throws ResultSetException {
		final ResultSet resultSet = getResultSetById(rsId); // NOPMD
		if (resultSet.isOpen())
			return "open";
		return "closed";
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.enabling.resultset.rmi.ResultSetService#populateRS(java.lang.String, java.util.List)
	 */
	public String populateRS(final String rsId, final List<String> elements) throws ResultSetException {
		final ResultSet resultSet = getResultSetById(rsId); // NOPMD
		if (resultSet instanceof PushResultSet)
			((PushResultSet) resultSet).addElements(elements);
		else
			throw new ResultSetException("ResultSet '" + rsId + "' is not a push resultset");

		return "1";
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see eu.dnetlib.common.rmi.BaseService#start()
	 */
	public void start() {
		// TODO Auto-generated method stub

	}

	/**
	 * obtain the resultset object for a given id.
	 *
	 * @param rsId
	 *            resultset id
	 * @return resultset object, never null
	 * @throws ResultSetException
	 *             thrown when the id doesn't exist;
	 */
	private ResultSet getResultSetById(final String rsId) throws ResultSetException {
		final ResultSet resultSet = resultsetRegistry.getResultSetById(rsId); // NOPMD
		if (resultSet == null)
			throw new ResultSetException("resultset with id '" + rsId + "' doesn't exist");
		return resultSet;
	}

	public ResultSetRegistry getResultsetRegistry() {
		return resultsetRegistry;
	}

	@Required
	public void setResultsetRegistry(final ResultSetRegistry resultsetRegistry) {
		this.resultsetRegistry = resultsetRegistry;
	}

	public EndpointReferenceBuilder<Endpoint> getEprBuilder() {
		return eprBuilder;
	}

	public void setEprBuilder(final EndpointReferenceBuilder<Endpoint> eprBuilder) {
		this.eprBuilder = eprBuilder;
	}

	public Endpoint getEndpoint() {
		return endpoint;
	}

	@Required
	public void setEndpoint(final Endpoint endpoint) {
		this.endpoint = endpoint;
	}

	public PushResultSetFactory getPushFactory() {
		return pushFactory;
	}

	@Required
	public void setPushFactory(final PushResultSetFactory pushFactory) {
		this.pushFactory = pushFactory;
	}

	public ResultSetPropertyDao getCustomPropertyDao() {
		return customPropertyDao;
	}

	public void setCustomPropertyDao(final ResultSetPropertyDao customPropertyDao) {
		this.customPropertyDao = customPropertyDao;
	}

}
