package org.icij.extract.mysql;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.io.FilenameUtils;
import org.icij.task.Options;
import org.icij.task.annotation.Option;

import java.nio.file.Path;
import java.security.KeyStore;
import java.util.Locale;

@Option(name = "mysqlUser", description = "The MySQL database user to authenticate as.", parameter = "username")
@Option(name = "mysqlPassword", description = "The MySQL user password.", parameter = "password")
@Option(name = "mysqlHostname", description = "The MySQL server hostname.", parameter = "hostname")
@Option(name = "mysqlDatabase", description = "The MySQL database to user.", parameter = "database")
@Option(name = "mysqlPort", description = "The MySQL server port number.", parameter = "port")
@Option(name = "mysqlSSL", description = "Explicitly disable or require SSL, which the client will try and use by " +
		"default but not require.")
@Option(name = "mysqlCACertificate", description = "A trust store containing a CA certificate, used to verify the " +
		"MySQL server's certificate.", parameter = "path")
@Option(name = "mysqlCACertificatePassword", description = "The password for the CA certificate trust store.",
		parameter = "password")
public class DataSourceFactory {

	private String user = null;
	private String password = null;
	private String serverName = null;
	private String databaseName = null;
	private int port = 0;
	private boolean useSSL = true;
	private boolean requireSSL = false;
	private Path caCertificate = null;
	private String caPassword = null;
	private int maximumPoolSize = 0;

	public DataSourceFactory(final Options<String> options) {
		withOptions(options);
	}

	public DataSourceFactory withOptions(final Options<String> options) {
		options.get("mysqlUser").value().ifPresent(this::withUser);
		options.get("mysqlPassword").value().ifPresent(this::withPassword);
		options.get("mysqlHostname").value().ifPresent(this::withServerName);
		options.get("mysqlDatabase").value().ifPresent(this::withDatabaseName);
		options.get("mysqlPort").parse().asInteger().ifPresent(this::withPort);
		options.get("mysqlSSL").parse().asBoolean().ifPresent(this::withSSL);
		options.get("mysqlCACertificate").parse().asPath().ifPresent(this::withCACertificate);
		options.get("mysqlCACertificatePassword").value().ifPresent(this::withCACertificatePassword);
		return this;
	}

	public DataSourceFactory withUser(final String user) {
		this.user = user;
		return this;
	}

	public DataSourceFactory withPassword(final String password) {
		this.password = password;
		return this;
	}

	public DataSourceFactory withServerName(final String serverName) {
		this.serverName = serverName;
		return this;
	}

	public DataSourceFactory withDatabaseName(final String databaseName) {
		this.databaseName = databaseName;
		return this;
	}

	public DataSourceFactory withPort(final int port) {
		this.port = port;
		return this;
	}

	public DataSourceFactory withSSL(final boolean useSSL) {
		this.useSSL = useSSL;
		if (useSSL) {
			requireSSL = true;
		}

		return this;
	}

	public DataSourceFactory withCACertificate(final Path path) {
		this.caCertificate = path;
		return this;
	}

	public DataSourceFactory withCACertificatePassword(final String password) {
		this.caPassword = password;
		return this;
	}

	public DataSourceFactory withMaximumPoolSize(final int maximumPoolSize) {
		this.maximumPoolSize = maximumPoolSize;
		return this;
	}

	public HikariDataSource create(final String poolName) {
		final HikariConfig config = new HikariConfig();

		config.setJdbcUrl("jdbc:mysql://" + (null == serverName ? "localhost" : serverName) + ":" +
				(port > 0 ? port : 3306) + "/" + (null	== databaseName ? "extract" : databaseName));
		config.setUsername(null == user ? "extract" : user);
		config.setPassword(password);
		config.setPoolName(poolName);

		if (maximumPoolSize > 0) {
			config.setMaximumPoolSize(maximumPoolSize);
		}

		config.addDataSourceProperty("cachePrepStmts", true);
		config.addDataSourceProperty("prepStmtCacheSize", 250);
		config.addDataSourceProperty("prepStmtCacheSqlLimit", 2048);
		config.addDataSourceProperty("autoCommit", true);
		config.addDataSourceProperty("useSSL", useSSL);
		config.addDataSourceProperty("requireSSL", requireSSL);

		if (null != caCertificate) {
			String keyStoreType = FilenameUtils.getExtension(caCertificate.getFileName().toString()
					.toUpperCase(Locale.ROOT));

			if (keyStoreType.isEmpty()) {
				keyStoreType = KeyStore.getDefaultType();
			} else if (keyStoreType.equals("P12")) {
				keyStoreType = "PKCS12";
			}

			config.addDataSourceProperty("verifyServerCertificate", true);
			config.addDataSourceProperty("trustCertificateKeyStoreType", keyStoreType);
			config.addDataSourceProperty("trustCertificateKeyStoreUrl", "file://" + caCertificate.toString());

			if (null != caPassword) {
				config.addDataSourceProperty("trustCertificateKeyStorePassword", caPassword);
			} else if (keyStoreType.equals("JKS")) {
				config.addDataSourceProperty("trustCertificateKeyStorePassword", "changeit");
			}
		}

		return new HikariDataSource(config);
	}
}

@@ -1483,27 +1483,28 @@
 an useSSL = 
-tru
+fals
 e;%0A%09private 

Set useSSL to false by default