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

import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.teiid.core.util.PropertiesUtils;
import org.teiid.jdbc.BaseDataSource;
import org.teiid.jdbc.ConnectionImpl;
import org.teiid.jdbc.EmbeddedProfile;
import org.teiid.jdbc.JDBCPlugin;
import org.teiid.jdbc.JDBCURL;
import org.teiid.jdbc.JDBCURL.ConnectionType;
import org.teiid.jdbc.TeiidDriver;
import org.teiid.jdbc.TeiidSQLException;
import org.teiid.net.TeiidURL;

/**
 * @author klebeck
 *
 */
public class Driver extends TeiidDriver {

	static Logger logger = Logger.getLogger("com.datavirtuality.dv.jdbc"); //$NON-NLS-1$
	static final String DRIVER_NAME = "DataVirtuality JDBC Driver"; //$NON-NLS-1$


	private static Driver INSTANCE = new Driver();

	static {
		try {
			DriverManager.registerDriver(INSTANCE);
		} catch (SQLException e) {
			// Logging
			String logMsg = JDBCPlugin.Util.getString(
					"MMDriver.Err_registering", e.getMessage()); //$NON-NLS-1$
			logger.log(Level.SEVERE, logMsg);
		}
	}

	public static Driver getInstance() {
		return INSTANCE;
	}


	@Override
	public ConnectionImpl connect(String url, Properties info) throws SQLException {
		ConnectionType conn = DataVirtualityJDBCURL.acceptsUrl(url);
		if (conn == null) {
			return null;
		}
		if (info == null) {
			// create a properties obj if it is null
			info = new Properties();
		} else {
			// don't modify the original
			info = PropertiesUtils.clone(info);
		}
		parseURL(url, info);

		// Auto-initialize FIPS mode if properties request it
		org.teiid.jdbc.FipsManager.initializeFipsMode(info);

		ConnectionImpl myConnection = null;

		try {
			if (conn == ConnectionType.Embedded) {
				if (getEmbeddedProfile() == null) {
					try {
						getClass().getClassLoader().loadClass(
								"org.jboss.modules.Module"); //$NON-NLS-1$
					} catch (ClassNotFoundException e) {
						throw new TeiidSQLException(
								JDBCPlugin.Util.gs("module_load_failed")); //$NON-NLS-1$
					}
					setEmbeddedProfile(new EmbeddedProfile());
				}
				myConnection = getEmbeddedProfile().connect(url, info);
			} else {
				myConnection = getSocketProfile().connect(url, info);
			}
		} catch (TeiidSQLException e) {
			logger.log(Level.SEVERE, "Could not create connection", e); //$NON-NLS-1$
			throw TeiidSQLException.create(e, e.getMessage());
		}

		// logging
		String logMsg = JDBCPlugin.Util
				.getString("JDBCDriver.Connection_sucess"); //$NON-NLS-1$
		logger.fine(logMsg);

		return myConnection;
	}

	@Override
	public boolean acceptsURL(String url) throws SQLException {
		return DataVirtualityJDBCURL.acceptsUrl(url) != null;
	}

	@Override
	public String getDriverName() {
		return DRIVER_NAME;
	}

	protected static void parseURL(String url, Properties info)
			throws SQLException {
		if (url == null) {
			String msg = JDBCPlugin.Util.getString("MMDriver.urlFormat"); //$NON-NLS-1$
			throw new TeiidSQLException(msg);
		}
		try {
			JDBCURL jdbcURL = new DataVirtualityJDBCURL(url);
			info.setProperty(BaseDataSource.VDB_NAME, jdbcURL.getVDBName());
			if (jdbcURL.getConnectionURL() != null) {
				info.setProperty(TeiidURL.CONNECTION.SERVER_URL,
						jdbcURL.getConnectionURL());
			}
			Properties optionalParams = jdbcURL.getProperties();
			JDBCURL.normalizeProperties(info);
			Enumeration keys = optionalParams.keys();
			while (keys.hasMoreElements()) {
				String propName = (String) keys.nextElement();
				// Don't let the URL properties override the passed-in
				// Properties object.
				if (!info.containsKey(propName)) {
					info.setProperty(propName,
							optionalParams.getProperty(propName));
				}
			}
			// add the property only if it is new because they could have
			// already been specified either through url or otherwise.
			if (!info.containsKey(BaseDataSource.VDB_VERSION)
					&& jdbcURL.getVDBVersion() != null) {
				info.setProperty(BaseDataSource.VDB_VERSION,
						jdbcURL.getVDBVersion());
			}
			if (!info.containsKey(BaseDataSource.APP_NAME)) {
				info.setProperty(BaseDataSource.APP_NAME,
						BaseDataSource.DEFAULT_APP_NAME);
			}

		} catch (IllegalArgumentException iae) {
			throw new TeiidSQLException(
					JDBCPlugin.Util.getString("MMDriver.urlFormat")); //$NON-NLS-1$
		}
	}

}
