package at.gv.util.client.moaid;

import java.math.BigInteger;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

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

import org.apache.commons.lang.RandomStringUtils;
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.config.EgovUtilConfiguration;
import at.gv.util.ex.EgovUtilException;
import at.gv.util.wsdl.GetAuthenticationDataService;
import at.gv.util.wsdl.IdentificationPortType;
import at.gv.util.wsdl.MOAFault;
import at.gv.util.xsd.saml.protocol.RequestType;
import at.gv.util.xsd.saml.protocol.ResponseType;

public class MOAIDClient {

	@Resource
  WebServiceContext wsContext;

	private EgovUtilConfiguration config = null;
	Logger log = LoggerFactory.getLogger(MOAIDClient.class);
	
	private IdentificationPortType port = null;
	
	public MOAIDClient() {}
	
	public MOAIDClient(EgovUtilConfiguration config) throws MOAIDClientException, EgovUtilException {
		this.config = config;
		
		URL url = MOAIDClient.class.getResource("/wsdl/MOA-ID-1.x.wsdl");
		GetAuthenticationDataService service = new GetAuthenticationDataService(url, new QName("http://reference.e-government.gv.at/namespace/moa/20020822#", "GetAuthenticationDataService"));
		port = service.getIdentificationPort();
  	
	    // set endpoint address
  		BindingProvider bindingProvider = (BindingProvider) port;
      
    	// 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 (this.config == null) {
      	throw new MOAIDClientException("SSL requires a valid configuration for MOA-ID client.");
      }
      
      log.trace("Using ssl for MOA-ID get authentication data request.");
      SSLContext sslContext = config.getMOAIDsslConfiguration().getSSLContext(false);
      if (sslContext == null) {
		throw new MOAIDClientException("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 );

	}
	
  @SuppressWarnings("unchecked")
  public ResponseType sendGetAuthenticationDataRequest(String getAuthDataServiceURL, String artifact) throws MOAIDClientException {
    
  	// verify that parameters are not null
  	if (getAuthDataServiceURL == null) {
  		throw new NullPointerException("Parameter 'getAuthDataServiceURL' must not be null.");
  	}
  	if (artifact == null) {
  		throw new NullPointerException("Parameter 'artifact' must not be null.");
  	}
  	
  	log.trace("Authentication data service request URL: " + getAuthDataServiceURL);
    try {
    
    	BindingProvider bindingProvider = (BindingProvider) port;
  		Map<String, Object> requestContext = bindingProvider.getRequestContext();
    	requestContext.put(
          BindingProvider.ENDPOINT_ADDRESS_PROPERTY, getAuthDataServiceURL);

      
      // make simple moa-id request
      RequestType request = new RequestType();
      request.setMajorVersion(BigInteger.ONE);
      request.setMinorVersion(BigInteger.ZERO);
      request.setIssueInstant(MiscUtil.getXMLGregorianCalendar(new Date()));
      request.setRequestID(RandomStringUtils.randomAlphanumeric(10));
      
      request.getAssertionArtifact().add(artifact);
      
		return port.getAuthenticationData(request);
      
    } catch (MOAFault e) {
    	throw new MOAIDClientException(e);
    } catch (DatatypeConfigurationException e) {
    	throw new MOAIDClientException(e);
    }
  }
  
}