package eu.dnetlib.clients.utils.ws;

import java.util.HashMap;
import java.util.Map;

import javax.xml.ws.wsaddressing.W3CEndpointReference;

import eu.dnetlib.api.DriverService;
import eu.dnetlib.domain.EPR;
import eu.dnetlib.utils.EPRUtils;
import eu.dnetlib.utils.resolver.EndpointResolver;
import eu.dnetlib.utils.resolver.ServiceClientFactory;

/**
 * This is an implementation of EndpointResolver. It assumes that the EPRs given
 * are W3CEPRs. This implementation assumes that all service interfaces are part
 * of the DriverService hierarchy, but makes no assumption for the web service
 * interfaces.
 * 
 * This implementation is created for dnet1.1, where there is no common API for
 * all partners and the only transport layer is SOAP based for all services.
 * 
 * Jaxws endpoints in the general case are not thread-safe, however in our case
 * we can consider them as such (see 
 * <a href="http://cxf.apache.org/faq.html#FAQ-AreJAXWSclientproxiesthreadsafe%253F">
 * here</a> for more info).
 * 
 * @author <a href="mailto:antleb@di.uoa.gr">Antonis Lempesis</a>
 * 
 */
public class CompatibilityEndpointResolver implements EndpointResolver {
	private eu.dnetlib.enabling.tools.ServiceResolver serviceResolver = null;
	private CompatibilityTransportConfiguration config = null;
	private Map<Class<?>, ServiceClientFactory<?>> clientFactoryMap = null;

	private Map<String, DriverService> serviceCache = new HashMap<String, DriverService>();
	
	public <T extends DriverService> T getService(Class<T> clazz, EPR epr) {
		String address = epr.getAddress();
		@SuppressWarnings("unchecked") T service = (T) this.serviceCache.get(address);
		
		if (service == null) {
			W3CEndpointReference w3cEpr = EPRUtils.createW3CEPR(epr);
			Class<?> endpointClass = this.getEndpointClass(clazz);
			Object endpoint = serviceResolver.getService(endpointClass, w3cEpr);
	
			 service = createServiceClient(clazz, endpoint);
			 
			 serviceCache.put(address, service);
		}
		
		return service;
	}

	private <T extends DriverService> Class<?> getEndpointClass(
			Class<T> serviceClass) {
		return config.getEndpointClass(serviceClass);
	}

	@SuppressWarnings("unchecked")
	private <T extends DriverService> T createServiceClient(Class<T> clazz,
			Object endpoint) {
		ServiceClientFactory<T> clientFactory = (ServiceClientFactory<T>) clientFactoryMap
				.get(clazz);

		T client = clientFactory.newClient(endpoint);

		return client;
	}

	public eu.dnetlib.enabling.tools.ServiceResolver getServiceResolver() {
		return serviceResolver;
	}

	public void setServiceResolver(
			eu.dnetlib.enabling.tools.ServiceResolver serviceResolver) {
		this.serviceResolver = serviceResolver;
	}

	public CompatibilityTransportConfiguration getConfig() {
		return config;
	}

	public void setConfig(CompatibilityTransportConfiguration config) {
		this.config = config;
	}

	public Map<Class<?>, ServiceClientFactory<?>> getClientFactoryMap() {
		return clientFactoryMap;
	}

	public void setClientFactoryMap(
			Map<Class<?>, ServiceClientFactory<?>> clientFactoryMap) {
		this.clientFactoryMap = clientFactoryMap;
	}
}