/*
 *
 * Copyright (C)  5-sept-2003 Jean-Yves Beaujean, Dieter ?????
 * 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 2 of the License, or (at your option)
 * any later version.
 * 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.
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,  59
 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * 
 * Thanks to Dieter, for the dynamic class loader
 */
package jxtray.connection;


import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.Vector;
import java.sql.DriverManager;

import jxtray.Jxtray;


public class JxtConnection 
{
	private JxtConnectionParam jxtConnectionParam;
	private Connection connection;
	private Statement  statement;
	private boolean visible = false;
	private String driverName;
	private boolean _DEBUG_ = false;
	private static ClassLoader driverClassLoader; //**** DS add
	
	/** Constructor */
	public JxtConnection(JxtConnectionParam param, String driverName)
	{
			this.jxtConnectionParam = param;
			this.driverName = driverName;
	}
	
	public void setDebug(boolean debug)
	{
		_DEBUG_ = debug;
	}
	
	/** Close connection */
	public void close()throws SQLException
	{
			statement.close();
			connection.close();
			jxtConnectionParam.setConnected(false);
			visible = false;
	}
	
	 
	public boolean isVisible() { return visible; }
	public void setVisible(boolean visible) { this.visible = visible; }

	/** Establish connection with the server 
	 * @throws MalformedURLException
	 * @throws ClassNotFoundException
	 * @throws IllegalAccessException
	 * @throws InstantiationException*/ 
	public void connect() throws SQLException, MalformedURLException, InstantiationException, IllegalAccessException, ClassNotFoundException
	{
			DriverInfo drv = (DriverInfo) Jxtray.getDriverCache().get(driverName);
			double t = System.currentTimeMillis();
			double t2 = System.currentTimeMillis();
		
        if ( drv.getPathfile().trim().length() > 0 		 ) 
        {
					System.out.println("Dynamic load : "+ drv.getPathfile().trim() );
					//**** DS begin
					if (driverClassLoader == null) 
					{
						
						URL	driver = new URL("file:" + drv.getPathfile().trim());
						URL[] drivers = new URL[1];
						drivers[0] = driver;
						driverClassLoader = new URLClassLoader(drivers, getClass().getClassLoader());
					}
					Driver driver = (Driver) Class.forName(drv.getClassname(), true, driverClassLoader).newInstance();
					java.util.Properties p = new java.util.Properties();
					p.put("user",jxtConnectionParam.getLogin());
					p.put("password",jxtConnectionParam.getPassword());
					connection = driver.connect(jxtConnectionParam.getJdbcurl(),p);
					//**** DS end
			}
			else
			{
				Class.forName(drv.getClassname());
				System.out.println("Classic load ");
				connection = DriverManager.getConnection(jxtConnectionParam.getJdbcurl(),jxtConnectionParam.getLogin(),jxtConnectionParam.getPassword());
			}
			
			double diff2 = System.currentTimeMillis()-t;
			if ( _DEBUG_)
				System.out.println("--> Class.forName() :  "+ getName() +" : time : " + (diff2/1000) );
			 
			statement = connection.createStatement();
			jxtConnectionParam.setConnected(true);
			visible = true;
			double diff = System.currentTimeMillis()-t;
			if ( _DEBUG_)
				System.out.println("--> connect() :  "+ getName() +" : time : " + (diff/1000) ); 
	}
	
	/** Execute the function executeQuery from Statement class */ 
	public ResultSet select(String query)throws SQLException
	{
		return statement.executeQuery(query);
	}
	
	/** Execute the function executeUpdate from Statement class */
	public void update(String query) throws SQLException
	{
		statement.executeUpdate(query);
	}
	
	/** Return true if connection is active
	 *  @return boolean  
	 * */
	public boolean isConnected()
	{
		return jxtConnectionParam.isConnected();
	}
	/**
	 * @return java.sql.Connection
	 */
	public Connection getConnection()
	{
		return connection;
	}

	/**
	 * Initialize Connection object
	 * @param connection
	 */
	public void setConnection(Connection connection) {
		this.connection = connection;
	}
	
	/** Memory Managnement */
	public void finalize() 
	{
			try
			{
				close();
				visible = false;
				connection = null;
				statement = null;

			}
			catch ( Exception e )
			{
					
			}
	}

	/**
	 * @return JxtConnectionParam
	 */
	public JxtConnectionParam getJxtConnectionParam()
	{
		return jxtConnectionParam;
	}

	/**
	 * @param jxtConnectionParam
	 */
	public void setJxtConnectionParam(JxtConnectionParam jxtConnectionParam) 
	{
		this.jxtConnectionParam = jxtConnectionParam;
	}

	
	/** Return the connection name
	 *  @return String 
	 * */
	public String getName() 
	{
			return jxtConnectionParam.getName();
	}

	/**
	 * @return String
	 */
	public String getDriverName() 
	{
		return driverName;
	}

	/**
	 * @param driverName
	 * 
	 */
	public void setDriverName(String driverName) 
	{
		this.driverName = driverName;
	}
	
	public Properties getProperties() throws SQLException
	{
		
		Properties _p = new Properties();
		DatabaseMetaData dmtd = connection.getMetaData();
		_p.put("Catalog separator",dmtd.getCatalogSeparator());
		_p.put("Catalog Term",dmtd.getCatalogTerm());
		_p.put("Database product name",dmtd.getDatabaseProductName());
		_p.put("Product version",dmtd.getDatabaseProductVersion());
		_p.put("Transaction isolation",""+dmtd.getDefaultTransactionIsolation());
		_p.put("Driver name",dmtd.getDriverName());
		_p.put("Driver version",dmtd.getDriverVersion());
		_p.put("Extra name character",dmtd.getExtraNameCharacters());
		_p.put("Identifier quote string",dmtd.getIdentifierQuoteString());
		_p.put("Max binary literal length",""+dmtd.getMaxBinaryLiteralLength());
		_p.put("Max catalog name lengh",""+dmtd.getMaxCatalogNameLength());
		_p.put("Max char literal lengh",""+dmtd.getMaxCharLiteralLength());
		_p.put("Max column name length",""+dmtd.getMaxColumnNameLength());
		_p.put("Max columns in group by",""+dmtd.getMaxColumnsInGroupBy());
		_p.put("Max columns in index",""+dmtd.getMaxColumnsInIndex());
		_p.put("Max columns in order by",""+dmtd.getMaxColumnsInOrderBy());
		_p.put("Max columns in select",""+dmtd.getMaxColumnsInSelect());
		_p.put("Max columns in table",""+dmtd.getMaxColumnsInTable());
		_p.put("Max connections",""+dmtd.getMaxConnections());
		_p.put("Max cursor name length",""+dmtd.getMaxCursorNameLength());
		_p.put("Max indexLength",""+dmtd.getMaxIndexLength());
		_p.put("Max procedure name length",""+dmtd.getMaxProcedureNameLength());
		_p.put("Max row size length",""+dmtd.getMaxRowSize());
		_p.put("Max schema name length",""+dmtd.getMaxSchemaNameLength());
		_p.put("Max statement length",""+dmtd.getMaxStatementLength());
		_p.put("Max statements",""+dmtd.getMaxStatements());
		_p.put("Max table name length",""+dmtd.getMaxTableNameLength());
		_p.put("Max table in select",""+dmtd.getMaxTablesInSelect());
		_p.put("Max user name length",""+dmtd.getMaxUserNameLength());
		_p.put("Numeric functions",""+dmtd.getNumericFunctions());
		_p.put("Procedure term",dmtd.getProcedureTerm());
		_p.put("Schema term",dmtd.getSchemaTerm());
		_p.put("Search string espace",dmtd.getSearchStringEscape());
		_p.put("SQL Keywords",dmtd.getSQLKeywords());
		_p.put("String functions",dmtd.getStringFunctions());
		_p.put("System functions",dmtd.getSystemFunctions());
		_p.put("Time-Date functions",dmtd.getTimeDateFunctions());
		_p.put("Url",dmtd.getURL());
		_p.put("UserName",dmtd.getUserName());
		_p.put("Supports Catalogs in data manipulation ?",""+ dmtd.supportsCatalogsInDataManipulation() );
		_p.put("Supports Catalogs in index definitions ?",""+dmtd.supportsCatalogsInIndexDefinitions() );
		_p.put("Supports Catalogs in table definitions ?" ,""+ dmtd.supportsCatalogsInTableDefinitions() );		
		_p.put("Supports Schemas in data manipulation ?",""+dmtd.supportsSchemasInDataManipulation() );
		_p.put("Supports Schemas in index definitions ?" ,""+ dmtd.supportsSchemasInIndexDefinitions() );
		_p.put("Supports Schemas in table definitions ?",""+ dmtd.supportsSchemasInTableDefinitions() );
		_p.put("Supports Group by ?",""+ dmtd.supportsGroupBy() );
		_p.put("Supports Select for update ?",""+ dmtd.supportsSelectForUpdate() );
		_p.put("Supports Stored procedures ?", ""+dmtd.supportsStoredProcedures() );
		_p.put("Supports Transactions ?",""+ dmtd.supportsTransactions() );
		_p.put("Supports Union ?",""+ dmtd.supportsUnion() );
		
		return _p;
	}	
	
	public String[] getCatalogs() throws Exception
	{

		double t = System.currentTimeMillis();
		Vector vCatalog = new Vector();  
		if ( connection.getMetaData().supportsCatalogsInDataManipulation())
		{
			ResultSet res = connection.getMetaData().getCatalogs();
			while ( res.next() )
				vCatalog.add(res.getString(1));
		}
		
		String catalog[] = new String[vCatalog.size()];
		vCatalog.copyInto(catalog);
		double diff = System.currentTimeMillis()-t;
		if ( _DEBUG_)
			System.out.println("--> getCatalogs() :  "+ getName() +" : time : " + (diff/1000) );
		return catalog;
	}
	
	
	public String[] getSchemas() throws Exception
	{

		double t = System.currentTimeMillis();
		Vector vSchema = new Vector();  
		if ( connection.getMetaData().supportsSchemasInDataManipulation())
		{
			ResultSet res =  connection.getMetaData().getSchemas();
			while ( res.next() ) 
				vSchema.add(res.getString(1));
		}
					
		String schema[] = new String[vSchema.size()];
		vSchema.copyInto(schema);
		double diff = System.currentTimeMillis()-t;
		if ( _DEBUG_)
			System.out.println("--> getSchema() :  "+ getName() +" : time : " + (diff/1000) );		
		return schema;
	}
	
	public DatabaseMetaData getMetaData() throws Exception 
	{
		return connection.getMetaData();
	}
	
	public Vector getTables(String catalog, String schema) throws Exception 
	{
			DatabaseMetaData dmtd = connection.getMetaData();

			double t = System.currentTimeMillis();
			Vector vTable = new Vector();  

			ResultSet res;
			res = dmtd.getTables(catalog,schema,"%",null);
			while ( res.next() )
			{
				vTable.add(res.getString(3));
			}					

			double diff = System.currentTimeMillis()-t;
			if ( _DEBUG_)
				System.out.println("--> getTables() :  "+ getName() +" : time : " + (diff/1000) );		
			return vTable;
		
	}

}
