/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.camel.util.jsse;

import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;

import org.apache.camel.CamelContext;
import org.apache.camel.TestSupport;
import org.apache.camel.component.properties.PropertiesComponent;
import org.apache.camel.impl.DefaultCamelContext;

public abstract class AbstractJsseParametersTest extends TestSupport {

    protected CamelContext createPropertiesPlaceholderAwareContext() throws Exception {
        Properties supplementalProperties = new Properties();

        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        SecureRandom sr = null;
        try {
            sr = SecureRandom.getInstance("SHA1PRNG");
        } catch (NoSuchAlgorithmException e) {
            // Ignore
        }

        SSLContext sslc = SSLContext.getInstance("TLS");
        sslc.init(null, null, null);
        SSLSocket socket = (SSLSocket) sslc.getSocketFactory().createSocket();

        supplementalProperties.setProperty("keyStoreParameters.type", KeyStore.getDefaultType());
        supplementalProperties.setProperty("keyStoreParameters.provider", ks.getProvider().getName());

        supplementalProperties.setProperty("keyManagersParameters.algorithm", KeyManagerFactory.getDefaultAlgorithm());
        supplementalProperties.setProperty("keyManagersParameters.provider", kmf.getProvider().getName());

        supplementalProperties.setProperty("trustManagersParameters.algorithm", TrustManagerFactory.getDefaultAlgorithm());
        supplementalProperties.setProperty("trustManagersParameters.provider", tmf.getProvider().getName());

        if (sr != null) {
            supplementalProperties.setProperty("secureRandomParameters.algorithm", "SHA1PRNG");
            supplementalProperties.setProperty("secureRandomParameters.provider", sr.getProvider().getName());
        }

        supplementalProperties.setProperty("sslContextParameters.provider", sslc.getProvider().getName());
        supplementalProperties.setProperty("cipherSuite.0", socket.getSupportedCipherSuites()[0]);

        // Have to skip this guy because he doesn't work with TLS as the SSLContext protocol
        String ssp = "";
        for (String protocol : socket.getSupportedProtocols()) {
            if (!"SSLv2Hello".equals(protocol)) {
                ssp = protocol;
                break;
            }
        }
        supplementalProperties.setProperty("secureSocketProtocol.0", ssp);


        return this.createPropertiesPlaceholderAwareContext(supplementalProperties);
    }

    protected CamelContext createPropertiesPlaceholderAwareContext(Properties supplementalProperties) throws IOException {
        Properties properties = new Properties(supplementalProperties);
        properties.load(AbstractJsseParametersTest.class.getResourceAsStream("test.properties"));

        if (supplementalProperties != null) {
            Properties mergedProps = new Properties();

            Set<String> keys = new HashSet<>();
            keys.addAll(properties.stringPropertyNames());
            keys.addAll(supplementalProperties.stringPropertyNames());

            for (String key : keys) {
                mergedProps.setProperty(key, properties.getProperty(key));
            }

            properties = mergedProps;
        }

        properties.store(new FileOutputStream("target/jsse-test.properties"),
                "Generated by " + AbstractJsseParametersTest.class.getName());

        PropertiesComponent pc = new PropertiesComponent();
        pc.setLocation("file:./target/jsse-test.properties");

        CamelContext context = new DefaultCamelContext();
        context.addComponent("properties", pc);

        return context;
    }

}
