package org.micord.config;

import com.atomikos.jdbc.AtomikosDataSourceBean;
import org.micord.models.requests.SqlConnectionParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @author Maksim Tereshin
 */
public class DatabaseConnection {

	private static final Logger logger = LoggerFactory.getLogger(DatabaseConnection.class);

	private static final Map<String, DataSource> dataSources = new HashMap<>();

	public static Connection getConnection(SqlConnectionParams params) throws SQLException {
		logger.debug("Get connection for params: {}", params);
		long startExecTime = System.currentTimeMillis();
		try {
			Class.forName(params.getJdbcDriverClassName());
		} catch (ClassNotFoundException e) {
			throw new SQLException("Unable to load the JDBC driver class", e);
		}

		long endExecTime = System.currentTimeMillis();
		logger.debug("Time to load JDBC driver class: {} ms", endExecTime - startExecTime);

		return getXaDataSource(params).getConnection();
	}

	public static DataSource getXaDataSource(SqlConnectionParams params) {
		logger.debug("Getting XA data source for params: {}", params);
		long startExecTime = System.currentTimeMillis();
		String database = params.getJdbcDatabase();

		if (!dataSources.containsKey(database)) {
			AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
			xaDataSource.setUniqueResourceName(database);
			xaDataSource.setXaDataSourceClassName(params.getJdbcXaDataSourceClassName());
			xaDataSource.setPoolSize(Integer.parseInt(params.getJdbcXaDataSourcePoolSize()));

			if (params.getJdbcXaDataSourceBorrowConnectionTimeout() != null) {
				xaDataSource.setBorrowConnectionTimeout(Integer.parseInt(params.getJdbcXaDataSourceBorrowConnectionTimeout()));
			}

			Properties xaProperties = loadDatabaseProperties(params);
			xaDataSource.setXaProperties(xaProperties);

			dataSources.put(database, xaDataSource);
		}

		long endExecTime = System.currentTimeMillis();
		logger.debug("Time to get XA data source: {} ms", endExecTime - startExecTime);

		return dataSources.get(database);
	}

	private static Properties loadDatabaseProperties(SqlConnectionParams params) {
		Properties xaProperties = new Properties();
		try {
			xaProperties.setProperty("user", params.getJdbcUsername());
			xaProperties.setProperty("password", params.getJdbcPassword());
			xaProperties.setProperty("serverName", params.getJdbcHost());
			xaProperties.setProperty("portNumber", String.valueOf(params.getJdbcPort()));
			xaProperties.setProperty("databaseName", params.getJdbcDatabase());

		} catch (Exception e) {
			throw new RuntimeException("Failed to load database properties", e);
		}
		return xaProperties;
	}

}
