package at.gv.util.client.ersb;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.Handler;

import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.gv.util.LaxHostNameVerifier;
import at.gv.util.LoggingHandler;
import at.gv.util.MiscUtil;
import at.gv.util.client.szr.SZRSOAPHandler;
import at.gv.util.config.EgovUtilConfiguration;
import at.gv.util.ex.EgovUtilException;
import at.gv.util.wsdl.ersb.ErsbService;
import at.gv.util.wsdl.ersb.ErsbServiceService;
import at.gv.util.xsd.ersb.ErsbRequest;
import at.gv.util.xsd.ersb.ErsbResponse;
import at.gv.util.xsd.szr.pvp.PvpTokenType;

public class ERsBClient {

	@Resource
  WebServiceContext wsContext;

	private EgovUtilConfiguration config = null;
	Logger log = LoggerFactory.getLogger(ERsBClient.class);
	
	public ERsBClient() {}
	
	public ERsBClient(EgovUtilConfiguration config) {
		if (config == null) {
			throw new NullPointerException("Parameter config must not be null.");
		}
		this.config = config;
		
		
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public ErsbResponse sendERsBRequest(ErsbRequest mir, String ersbServiceURL) throws EgovUtilException {
		MiscUtil.assertNotNull(mir, "mir");
		MiscUtil.assertNotNull(ersbServiceURL, "ersbServiceURL");
		
		URL url = ERsBClient.class.getResource("/wsdl/ERsB/1.1/ErsbService.wsdl");
		ErsbServiceService service = new ErsbServiceService(url, new QName("http://statistik.at/namespace/ersb/1#", "ErsbServiceService"));
		ErsbService port = service.getErsbServiceSoap11();
		
		log.debug("ERsB connection URL: " + ersbServiceURL);
		BindingProvider bindingProvider = (BindingProvider) port;
		Map<String, Object> requestContext = bindingProvider.getRequestContext();
		requestContext.put(
				BindingProvider.ENDPOINT_ADDRESS_PROPERTY, ersbServiceURL);
				
		List<Handler> handlerList = bindingProvider.getBinding().getHandlerChain();
		if (handlerList == null) {
			handlerList = new ArrayList();
		}

		log.trace("Adding WS-Security Header handler.");
		PvpTokenType pvpToken = config.getERsBPVPToken();
		SZRSOAPHandler szrSOAPHandler = new SZRSOAPHandler();
		szrSOAPHandler.configure(pvpToken);
		handlerList.add(szrSOAPHandler);
		
		log.trace("Adding JAX-WS request/response trace handler.");
		LoggingHandler loggingHandler = new LoggingHandler();
		handlerList.add(loggingHandler);
						
		bindingProvider.getBinding().setHandlerChain(handlerList);
    
		// check for ssl
		if (ersbServiceURL.toLowerCase().startsWith("https")) {
			log.trace("Using ssl for MISSTORK client request.");
			SSLContext sslContext = config.getERsBsslConfiguration().getSSLContext(false);
			if (sslContext == null) {
				throw new EgovUtilException("SSL context from configuration is empty. Please configure an SSL context in the configuration first.");
			}
			
			Client client = ClientProxy.getClient(port);
			HTTPConduit http = (HTTPConduit) client.getConduit();
			HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
			 
			httpClientPolicy.setConnectionTimeout(36000);
			httpClientPolicy.setAllowChunking(false);
			httpClientPolicy.setReceiveTimeout(32000);
			 
			http.setClient(httpClientPolicy);
			
			TLSClientParameters tlsParams = new TLSClientParameters();			
			tlsParams.setSSLSocketFactory(sslContext.getSocketFactory());
						
			// check for lax hostname
			if (this.config.getERsBsslConfiguration().useLaxHostNameVerifier()) {
				log.trace("LaxHostnameVerifier enabled. This setting is not recommended to use.");
				tlsParams.setHostnameVerifier(new LaxHostNameVerifier());
			}
			
			http.setTlsClientParameters(tlsParams );
		}
		
		return port.ersb(mir);
	}
  
}