package at.gv.util.client.mzs;

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.config.EgovUtilConfiguration;
import at.gv.util.ex.EgovUtilException;
import at.gv.util.wsdl.mzs.App2Mzs;
import at.gv.util.wsdl.mzs.App2MzsPortType;
import at.gv.util.xsd.mzs.DeliveryRequestType;
import at.gv.util.xsd.mzs.DeliveryResponseType;

public class MOAZSClient {

	@Resource
  WebServiceContext wsContext;

	private EgovUtilConfiguration config = null;
	Logger log = LoggerFactory.getLogger(MOAZSClient.class);
	
	public MOAZSClient() {}
	
	public MOAZSClient(EgovUtilConfiguration config) {
		if (config == null) {
			throw new NullPointerException("Parameter config must not be null.");
		}
		this.config = config;
	}
	
  @SuppressWarnings({ "unchecked", "rawtypes" })
  public DeliveryResponseType sendMOAZSRequest(DeliveryRequestType request, String serviceURL) throws MOAZSClientException {
    
  	// verify that parameters are not null
  	if (request == null) {
  		throw new NullPointerException("Parameter 'request' must not be null.");
  	}
  	
  	if (serviceURL == null) {
  		throw new NullPointerException("Parameter 'serviceURL' must not be null.");
  	}
  	
		URL url = MOAZSClient.class.getResource("/wsdl/mzs/app2mzs.wsdl");
		App2Mzs service = new App2Mzs(url, new QName("http://reference.e-government.gv.at/namespace/app2mzs.wsdl", "app2mzs"));
		App2MzsPortType port = service.getApp2MzsPort();
  	
  	log.trace("MOA-ZS request URL: " + serviceURL);
    try {
    
	    // set endpoint address
  		BindingProvider bindingProvider = (BindingProvider) port;
  		Map<String, Object> requestContext = bindingProvider.getRequestContext();
    	requestContext.put(
          BindingProvider.ENDPOINT_ADDRESS_PROPERTY, serviceURL);
      
    	// add trace log
    	log.trace("Adding JAX-WS request/response trace handler.");
    	List<Handler> handlerList = bindingProvider.getBinding().getHandlerChain();
    	if (handlerList == null) {
	      handlerList = new ArrayList();
      }
	    LoggingHandler loggingHandler = new LoggingHandler();
	    handlerList.add(loggingHandler);
	    bindingProvider.getBinding().setHandlerChain(handlerList);

      // initialize ssl
      if (serviceURL.toLowerCase().startsWith("https")) {
      	log.trace("Using ssl for MOA-ZS get authentication data request.");
      	SSLContext sslContext = config.getMOAZSsslConfiguration().getSSLContext(false);
      	if (sslContext == null) {
					throw new MOAZSClientException("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.getMOAIDsslConfiguration().useLaxHostNameVerifier()) {
			log.trace("LaxHostnameVerifier enabled. This setting is not recommended to use.");
			tlsParams.setHostnameVerifier(new LaxHostNameVerifier());
		}
		
		http.setTlsClientParameters(tlsParams );
      }
      
      // make simple moa-id request
            
			return port.app2Mzs(request);
      
    } catch (EgovUtilException e) {
    	throw new MOAZSClientException(e);
    }
  }
  
}