/**
 * <p>
 * Copyright © 2009-2010, Res Interactive, LLC
 * </p>
 * <p>
 * Based upon public domain sample code provided by Authorize.net
 * </p>
 * <p>
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 * </p>
 * <p>
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 * </p>
 * <p>
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * </p>
 * 
 * @author theys
 */

package org.starhope.appius.test;

import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * WRITEME: Document this type. theys Jan 4, 2010
 * 
 * @author <a href="mailto:theys@resinteractive.com">Tim Heys</a>
 * 
 */
public class ConnectionDebug implements Connection {

	/**
	 * 
	 */
	private static int connectionCounter = 0;

	/**
	 * 
	 */
	private static int openConnectionCounter = 0;

	/**
	 * 
	 */
	private static HashMap <Integer, String> openConnections = new HashMap <Integer, String> ();

	/**
	 * 
	 * <pre>
	 * theys Jan 4, 2010
	 * </pre>
	 * 
	 * TO dumpOpenConnections WRITEME...
	 * 
	 */
	public static void dumpOpenConnections () {
		if (ConnectionDebug.openConnections.isEmpty ()) {
			System.out
					.println ("*******************************************************************************\n\n");
			System.out.println (" NO OPEN CONNECTIONS");
			System.out
					.println ("\n\n*******************************************************************************");
			return;
		}
		System.out
				.println ("*******************************************************************************\n\n"
						+ " OPEN CONNECTIONS:");
		for (final String value : ConnectionDebug.openConnections
				.values ()) {
			System.out.println ("Open Connection From: " + value);
		}
		System.out
				.println ("\n\n*******************************************************************************");
	}

	/**
	 * 
	 */
	String caller;

	/**
	 * 
	 */
	private final Connection realConnection;

	/**
	 * 
	 */
	private final int serial;

	/**
	 * 
	 * <pre>
	 * theys Jan 4, 2010
	 * </pre>
	 * 
	 * A ConnectionDebug WRITEME...
	 * 
	 * @param con
	 */
	public ConnectionDebug (final Connection con) {
		ConnectionDebug.openConnectionCounter++ ;
		serial = ConnectionDebug.connectionCounter++ ;
		caller = getCallerFromTrace ();
		ConnectionDebug.openConnections.put (serial, caller);
		realConnection = con;
	}

	/**
	 * @see java.sql.Connection#clearWarnings()
	 */
	public void clearWarnings () throws SQLException {
		realConnection.clearWarnings ();
	}

	/**
	 * @see java.sql.Connection#close()
	 */
	public void close () throws SQLException {
		ConnectionDebug.openConnectionCounter-- ;
		ConnectionDebug.openConnections.remove (serial);
		realConnection.close ();
	}

	/**
	 * @see java.sql.Connection#commit()
	 */
	public void commit () throws SQLException {
		realConnection.commit ();
	}

	/**
	 * @see java.sql.Connection#createArrayOf(java.lang.String,
	 *      java.lang.Object[])
	 */
	public Array createArrayOf (final String typeName,
			final Object [] elements) throws SQLException {
		return realConnection.createArrayOf (typeName, elements);
	}

	/**
	 * @see java.sql.Connection#createBlob()
	 */
	public Blob createBlob () throws SQLException {
		return realConnection.createBlob ();
	}

	/**
	 * @see java.sql.Connection#createClob()
	 */
	public Clob createClob () throws SQLException {
		return realConnection.createClob ();
	}

	/**
	 * @see java.sql.Connection#createNClob()
	 */
	public NClob createNClob () throws SQLException {
		return realConnection.createNClob ();
	}

	/**
	 * @see java.sql.Connection#createSQLXML()
	 */
	public SQLXML createSQLXML () throws SQLException {
		return realConnection.createSQLXML ();
	}

	/**
	 * @see java.sql.Connection#createStatement()
	 */
	public Statement createStatement () throws SQLException {
		return realConnection.createStatement ();

	}

	/**
	 * @see java.sql.Connection#createStatement(int, int)
	 */
	public Statement createStatement (final int resultSetType,
			final int resultSetConcurrency) throws SQLException {
		return realConnection.createStatement (resultSetType,
				resultSetConcurrency);
	}

	/**
	 * @see java.sql.Connection#createStatement(int, int, int)
	 */
	public Statement createStatement (final int resultSetType,
			final int resultSetConcurrency,
			final int resultSetHoldability) throws SQLException {
		return realConnection.createStatement ();
	}

	/**
	 * @see java.sql.Connection#createStruct(java.lang.String,
	 *      java.lang.Object[])
	 */
	public Struct createStruct (final String typeName,
			final Object [] attributes) throws SQLException {
		return realConnection.createStruct (typeName, attributes);
	}

	/**
	 * @see java.sql.Connection#getAutoCommit()
	 */
	public boolean getAutoCommit () throws SQLException {
		return realConnection.getAutoCommit ();

	}

	/**
	 * 
	 * <pre>
	 * theys Jan 4, 2010
	 * </pre>
	 * 
	 * TO getCallerFromTrace WRITEME...
	 * 
	 * @return
	 */
	private String getCallerFromTrace () {
		StackTraceElement [] stack = null;
		try {
			throw new Exception ();
		} catch (final Exception e) {
			stack = e.getStackTrace ();
		}
		if (null == stack) return null;

		final String trace = "\n*******************************\n  "
				+ stack [3].toString () + "\n  "
				+ stack [4].toString () + "\n  "
				+ stack [5].toString () + "\n  "
				+ stack [6].toString ()
				+ "\n*******************************\n";
		return trace;
	}

	/**
	 * @see java.sql.Connection#getCatalog()
	 */
	public String getCatalog () throws SQLException {
		return realConnection.getCatalog ();

	}

	/**
	 * @see java.sql.Connection#getClientInfo()
	 */
	public Properties getClientInfo () throws SQLException {
		return realConnection.getClientInfo ();

	}

	/**
	 * @see java.sql.Connection#getClientInfo(java.lang.String)
	 */
	public String getClientInfo (final String name) throws SQLException {
		return realConnection.getClientInfo (name);
	}

	/**
	 * @see java.sql.Connection#getHoldability()
	 */
	public int getHoldability () throws SQLException {
		return realConnection.getHoldability ();

	}

	/**
	 * @see java.sql.Connection#getMetaData()
	 */
	public DatabaseMetaData getMetaData () throws SQLException {
		return realConnection.getMetaData ();
	}

	/**
	 * @see java.sql.Connection#getTransactionIsolation()
	 */
	public int getTransactionIsolation () throws SQLException {
		return realConnection.getTransactionIsolation ();
	}

	/**
	 * @see java.sql.Connection#getTypeMap()
	 */
	public Map <String, Class <?>> getTypeMap () throws SQLException {
		return realConnection.getTypeMap ();
	}

	/**
	 * @see java.sql.Connection#getWarnings()
	 */
	public SQLWarning getWarnings () throws SQLException {
		return realConnection.getWarnings ();
	}

	/**
	 * @see java.sql.Connection#isClosed()
	 */
	public boolean isClosed () throws SQLException {
		return realConnection.isClosed ();
	}

	/**
	 * @see java.sql.Connection#isReadOnly()
	 */
	public boolean isReadOnly () throws SQLException {
		return realConnection.isReadOnly ();
	}

	/**
	 * @see java.sql.Connection#isValid(int)
	 */
	public boolean isValid (final int timeout) throws SQLException {
		return realConnection.isValid (timeout);
	}

	/**
	 * @see java.sql.Wrapper#isWrapperFor(java.lang.Class)
	 */
	public boolean isWrapperFor (final Class <?> iface)
		throws SQLException {
		return realConnection.isWrapperFor (iface);
	}

	/**
	 * @see java.sql.Connection#nativeSQL(java.lang.String)
	 */
	public String nativeSQL (final String sql) throws SQLException {
		return realConnection.nativeSQL (sql);
	}

	/**
	 * @see java.sql.Connection#prepareCall(java.lang.String)
	 */
	public CallableStatement prepareCall (final String sql)
		throws SQLException {
		return realConnection.prepareCall (sql);

	}

	/**
	 * @see java.sql.Connection#prepareCall(java.lang.String, int, int)
	 */
	public CallableStatement prepareCall (final String sql,
			final int resultSetType, final int resultSetConcurrency)
		throws SQLException {
		return realConnection.prepareCall (sql, resultSetType,
				resultSetConcurrency);
	}

	/**
	 * @see java.sql.Connection#prepareCall(java.lang.String, int, int,
	 *      int)
	 */
	public CallableStatement prepareCall (final String sql,
			final int resultSetType, final int resultSetConcurrency,
			final int resultSetHoldability) throws SQLException {
		return realConnection.prepareCall (sql, resultSetType,
				resultSetConcurrency, resultSetHoldability);
	}

	/**
	 * @see java.sql.Connection#prepareStatement(java.lang.String)
	 */
	public PreparedStatement prepareStatement (final String sql)
		throws SQLException {
		return realConnection.prepareStatement (sql);
	}

	/**
	 * @see java.sql.Connection#prepareStatement(java.lang.String, int)
	 */
	public PreparedStatement prepareStatement (final String sql,
			final int autoGeneratedKeys) throws SQLException {
		return realConnection.prepareStatement (sql, autoGeneratedKeys);
	}

	/**
	 * @see java.sql.Connection#prepareStatement(java.lang.String, int,
	 *      int)
	 */
	public PreparedStatement prepareStatement (final String sql,
			final int resultSetType, final int resultSetConcurrency)
		throws SQLException {
		return realConnection.prepareStatement (sql, resultSetType,
				resultSetConcurrency);
	}

	/**
	 * @see java.sql.Connection#prepareStatement(java.lang.String, int,
	 *      int, int)
	 */
	public PreparedStatement prepareStatement (final String sql,
			final int resultSetType, final int resultSetConcurrency,
			final int resultSetHoldability) throws SQLException {
		return realConnection.prepareStatement (sql, resultSetType,
				resultSetConcurrency, resultSetHoldability);
	}

	/**
	 * @see java.sql.Connection#prepareStatement(java.lang.String,
	 *      int[])
	 */
	public PreparedStatement prepareStatement (final String sql,
			final int [] columnIndexes) throws SQLException {
		return realConnection.prepareStatement (sql, columnIndexes);
	}

	/**
	 * @see java.sql.Connection#prepareStatement(java.lang.String,
	 *      java.lang.String[])
	 */
	public PreparedStatement prepareStatement (final String sql,
			final String [] columnNames) throws SQLException {
		return realConnection.prepareStatement (sql, columnNames);
	}

	/**
	 * @see java.sql.Connection#releaseSavepoint(java.sql.Savepoint)
	 */
	public void releaseSavepoint (final Savepoint savepoint)
		throws SQLException {
		realConnection.releaseSavepoint (savepoint);
	}

	/**
	 * @see java.sql.Connection#rollback()
	 */
	public void rollback () throws SQLException {
		realConnection.rollback ();
	}

	/**
	 * @see java.sql.Connection#rollback(java.sql.Savepoint)
	 */
	public void rollback (final Savepoint savepoint)
		throws SQLException {
		realConnection.rollback ();
	}

	/**
	 * @see java.sql.Connection#setAutoCommit(boolean)
	 */
	public void setAutoCommit (final boolean autoCommit)
		throws SQLException {
		realConnection.setAutoCommit (autoCommit);
	}

	/**
	 * @see java.sql.Connection#setCatalog(java.lang.String)
	 */
	public void setCatalog (final String catalog) throws SQLException {
		realConnection.setCatalog (catalog);
	}

	/**
	 * @see java.sql.Connection#setClientInfo(java.util.Properties)
	 */
	public void setClientInfo (final Properties properties)
		throws SQLClientInfoException {
		realConnection.setClientInfo (properties);
	}

	/**
	 * @see java.sql.Connection#setClientInfo(java.lang.String,
	 *      java.lang.String)
	 */
	public void setClientInfo (final String name, final String value)
		throws SQLClientInfoException {
		realConnection.setClientInfo (name, value);
	}

	/**
	 * @see java.sql.Connection#setHoldability(int)
	 */
	public void setHoldability (final int holdability)
		throws SQLException {
		realConnection.setHoldability (holdability);
	}

	/**
	 * @see java.sql.Connection#setReadOnly(boolean)
	 */
	public void setReadOnly (final boolean readOnly)
		throws SQLException {
		realConnection.setReadOnly (readOnly);
	}

	/**
	 * @see java.sql.Connection#setSavepoint()
	 */
	public Savepoint setSavepoint () throws SQLException {
		return realConnection.setSavepoint ();
	}

	/**
	 * @see java.sql.Connection#setSavepoint(java.lang.String)
	 */
	public Savepoint setSavepoint (final String name)
		throws SQLException {
		return realConnection.setSavepoint (name);
	}

	/**
	 * @see java.sql.Connection#setTransactionIsolation(int)
	 */
	public void setTransactionIsolation (final int level)
		throws SQLException {
		realConnection.setTransactionIsolation (level);
	}

	/**
	 * @see java.sql.Connection#setTypeMap(java.util.Map)
	 */
	public void setTypeMap (final Map <String, Class <?>> map)
		throws SQLException {
		realConnection.setTypeMap (map);
	}

	/**
	 * @see java.sql.Wrapper#unwrap(java.lang.Class)
	 */
	public <T> T unwrap (final Class <T> iface) throws SQLException {
		return realConnection.unwrap (iface);
	}
}
