package com.eactive.eai.adapter.socket2.filter.ssl;

import com.eactive.eai.adapter.socket2.config.SocketAdapterContext;
import com.eactive.eai.adapter.socket2.config.SocketLoggerManager;
import com.eactive.eai.common.util.Logger;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.Security;


public class SSLContextFactory {
	/**
	 * Protocol to use.
	 */
	private static final String PROTOCOL = "TLS";
	private static final String KEY_MANAGER_FACTORY_ALGORITHM;

	static {
		String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
		if (algorithm == null) {
			algorithm = "SunX509";
		}

		KEY_MANAGER_FACTORY_ALGORITHM = algorithm;
	}

	/**
	 * Bougus Server certificate keystore file name.
	 */
//	private String sslCertStore = "bogus.cert";

	// NOTE: The keystore was generated using keytool:
	// keytool -genkey -alias bogus -keysize 512 -validity 3650
	// -keyalg RSA -dname "CN=bogus.com, OU=XX CA,
	// O=Bogus Inc, L=Stockholm, S=Stockholm, C=SE"
	// -keypass boguspw -storepass boguspw -keystore bogus.cert

	/**
	 * Bougus keystore password.
	 */
//	private String sslPassword = "boguspw";

	private static SSLContext serverSslContext = null;
	private static SSLContext clientSslContext = null;

	/**
	 * Get SSLContext singleton.
	 * 
	 * @return SSLContext
	 * @throws GeneralSecurityException
	 * 
	 */
	public static SSLContext createSSLContext(SocketAdapterContext context) throws GeneralSecurityException, IOException {
		boolean isServer = context.isServer() ? true : false;

		Logger logger = SocketLoggerManager.getInstance().getLogger(context.getAdapterName());
		if (context.getTraceLevel() >= context.TRACE_LEVEL_DEBUG) {
			logger.debug(context.getAdapterName() + " | create SSLContext - "  + (isServer ? "SERVER" : "CLIENT"));
		}
		
		SSLContext sslContext = null;
		if (isServer) {
			if (serverSslContext == null) {
				synchronized (SSLContextFactory.class) {
					if (serverSslContext == null) {
						try {
							serverSslContext = createServerSSLContext(context);
						} catch (Exception ioe) {
							throw new GeneralSecurityException("Can't create Server SSLContext:" + ioe);
						}
					}
				}
			}
			sslContext = serverSslContext;
		} else {
			if (clientSslContext == null) {
				synchronized (SSLContextFactory.class) {
					if (clientSslContext == null) {
						clientSslContext = createClientSSLContext(context);
					}
				}
			}
			sslContext = clientSslContext;
		}
		return sslContext;
	}

	
	private static SSLContext createServerSSLContext(SocketAdapterContext context) throws GeneralSecurityException,	IOException {
		// Create keystore
		KeyStore ks = KeyStore.getInstance("JKS");
		InputStream in = null;
		try {
			in = SSLContextFactory.class.getResourceAsStream(context.getSslCertStore());
			if (in == null) {
				throw new GeneralSecurityException("ssl cert store does not exist - " + context.getSslCertStore());
			}
			ks.load(in, context.getSslCertPassword().toCharArray());
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException ignored) {
				}
			}
		}

		// Set up key manager factory to use our key store
		KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
		kmf.init(ks, context.getSslCertPassword().toCharArray());

		// Initialize the SSLContext to work with our key managers.
		SSLContext sslContext = SSLContext.getInstance(PROTOCOL);
		sslContext.init(kmf.getKeyManagers(), TrustManagerFactory.X509_MANAGERS, null);

		return sslContext;
	}

	
	private static SSLContext createClientSSLContext(SocketAdapterContext context) throws GeneralSecurityException {
		SSLContext sslContext = SSLContext.getInstance(PROTOCOL);
		sslContext.init(null, TrustManagerFactory.X509_MANAGERS, null);
		//SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket();
		//sslSocket.startHandshake();
		return sslContext;
	}
}
