/**
 * Copyright © 2012-2017 by Data Virtuality GmbH
 */
package com.datavirtuality.dv.jdbc;

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

import org.teiid.jdbc.JDBCURL;
import org.teiid.jdbc.TeiidDataSource;
import org.teiid.jdbc.TeiidSQLException;
import org.teiid.net.TeiidURL;

/**
 * @author klebeck
 * 
 */
public class DataSource extends TeiidDataSource {

	// to pass any additional parameter (for OAuth2, OpenID, SAML, etc.)
	private Map<String, String> additionalParameters;

	private static final long serialVersionUID = -4198237025438371483L;
	private static final String MASKED_PASSWORD = "*****";

	@Override
	public Connection getConnection(String userName, String password)
			throws java.sql.SQLException {
		final Driver driver = new Driver();

		validateProperties(userName, password);
		final Properties props = buildProperties(userName, password);

		// check if this is embedded connection
		if (isEmbedded()) {
			String url = new JDBCURL(getDatabaseName(), null, props).getJDBCURL();
			return driver.connect(url, props);
		}

		return driver.connect(buildURL().getJDBCURL(), null);
	}

	@Override
	protected Properties buildProperties(String userName, String password) {
		Properties props = super.buildProperties(userName, password);
		if (isEmbedded()) {
			props.setProperty(TeiidURL.CONNECTION.PASSTHROUGH_AUTHENTICATION,
					Boolean.toString(this.getPassthroughAuthentication()));

			if (getJaasName() != null) {
				props.setProperty(TeiidURL.CONNECTION.JAAS_NAME, getJaasName());
			}
			if (getKerberosServicePrincipleName() != null) {
				props.setProperty(
						TeiidURL.CONNECTION.KERBEROS_SERVICE_PRINCIPLE_NAME,
						getKerberosServicePrincipleName());
			}
		}

		if (additionalParameters != null) {
			for (Map.Entry<String, String> entry : additionalParameters.entrySet()) {
				props.setProperty(entry.getKey(), entry.getValue());
			}
		}

		return props;
	}

	@Override
	protected String buildServerURL() throws TeiidSQLException {
		return isEmbedded() ? null : super.buildServerURL();
	}

	@Override
	protected void validateProperties(String userName, String password) throws SQLException {
		if (isEmbedded())
			super.validateBaseProperties(userName, password);
		else
			super.validateProperties(userName, password);
	}

	@Override
	protected JDBCURL buildURL() throws TeiidSQLException {
		return buildDataVirtualityJDBC(getPassword());
	}

	/**
	 * returns the connection properties with the masked password 
	 */
	@Override
	public String toString() {
		try {
			// get the URL with the masked password
			return buildDataVirtualityJDBC(MASKED_PASSWORD).getJDBCURL();
		} catch (TeiidSQLException e) {
			return e.getMessage();
		}
	}
	
	/**
	 * When true, this connection uses the passed in security domain to do the
	 * authentication.
	 * 
	 * @return
	 */
	@Override
	public boolean isPassthroughAuthentication() {
		return super.isPassthroughAuthentication();
	}

	/**
	 * Same as "isPassthroughAuthentication". Required by the reflection login
	 * in connection pools to identify the type
	 * 
	 * @return
	 */
	@Override
	public boolean getPassthroughAuthentication() {
		return isPassthroughAuthentication();
	}

	/**
	 * When set to true, the connection uses the passed in security domain to do
	 * the authentication.
	 * 
	 * @since 7.1
	 * @return
	 */
	@Override
	public void setPassthroughAuthentication(
			final boolean passthroughAuthentication) {
		super.setPassthroughAuthentication(passthroughAuthentication);
	}

	private boolean isEmbedded() {
		return getServerName() == null;
	}

	private JDBCURL buildDataVirtualityJDBC(String password) throws TeiidSQLException {
		return new DataVirtualityJDBCURL(
				this.getDatabaseName(),
				buildServerURL(),
				buildProperties(getUser(), password)
		);
	}

	public Map<String, String> getAdditionalParameters() {
		if (additionalParameters == null) {
			additionalParameters = new HashMap<>();
		}
		return additionalParameters;
	}
}
