/*
 *    GeoTools - OpenSource mapping toolkit
 *    http://geotools.org
 *    (C) 2002-2006, GeoTools Project Managment Committee (PMC)
 * 
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 */
package org.geotools.data.postgis;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;

import javax.sql.DataSource;

import org.geotools.data.jdbc.ConnectionPool;
import org.geotools.data.jdbc.ConnectionPoolManager;
import org.geotools.data.jdbc.datasource.DataSourceFinder;
import org.geotools.data.jdbc.datasource.DataSourceUtil;

/**
 * Shell for JDBC transactions of all types. This creates connections for the
 * postgis datasource to make its  transactions.  To create a
 * PostgisDataSource, create a  PostgisConnectionFactory, then call
 * getConnection(), and pass that connection to the PostgisDataSource
 * constructor.
 *
 * @author Rob Hranac, Vision for New York
 * @author Chris Holmes, TOPP
 * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/plugin/postgis/src/main/java/org/geotools/data/postgis/PostgisConnectionFactory.java $
 * @version $Id: PostgisConnectionFactory.java 27862 2007-11-12 19:51:19Z desruisseaux $
 * @deprecated Use {@link DataSource}, {@link DataSourceUtil} and {@link DataSourceFinder} instead
 *  *
 * @task REVISIT: connection pooling, implementing java.sql.Datasource.  I
 *       removed the implementing because that class should be provided by the
 *       vendor, not a hack on top of DriverManager.  The only problem is that
 *       we can't use the postgres one directly, because it doesn't allow you
 *       to set the charset, which some of our users need.
 */
public class PostgisConnectionFactory {
    /** Standard logging instance */
    private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger(
            "org.geotools.defaultcore");

    /** Creates PostGIS-specific JDBC driver class. */
    private static final String DRIVER_CLASS = "org.postgresql.Driver";

    /** Creates PostGIS-specific JDBC driver path. */
    private static final String DRIVER_PATH = "jdbc:postgresql";

    /** The full path used to connect to the database */
    private String connPath;

       /** The host to connect to */
    private String host;

   /** The database to connect to.*/
    private String dbName;

   /** The port to connect on.*/
    private int port = -1;

    /** The user to connect with */
    private String user = "test";

    /** The password of the user */
    private String password = "test";
    
    /** Map that contains Connection Pool Data Sources */
    private static Map dataSources = new HashMap();

    /**
     * Constructor with all internal database driver classes, driver paths and
     * database types.
     *
     * @param host The name or ip address of the computer where the postgis
     *        database is installed.
     * @param port The port to connect on; 5432 is generally the postgres
     *        default.
     * @param dbName The name of the pgsql database that holds the tables of
     *        the feature types that will be used by PostgisDataSource.
     */
    public PostgisConnectionFactory(String host, String port, String dbName) {
	this.host = host;
	this.dbName = dbName;
	if (port != null) {
	    try {
		this.port = Integer.parseInt(port);
	    } catch (NumberFormatException nfe) {
		throw new IllegalArgumentException("could not parse port " + 
						   "to an int value");
	    }
	}
	connPath = DRIVER_PATH + "://" + host + ":" + port + "/"
            + dbName;
    }

     /**
     * Constructor with all internal database driver classes, driver paths and
     * database types.
     *
     * @param host The name or ip address of the computer where the postgis
     *        database is installed.
     * @param port The port to connect on; 5432 is generally the postgres
     *        default.
     * @param dbName The name of the pgsql database that holds the tables of
     *        the feature types that will be used by PostgisDataSource.
     */
    public PostgisConnectionFactory(String host, int port, String dbName) {
	connPath = DRIVER_PATH + "://" + host + ":" + port + "/"
            + dbName;
	this.host = host;
	this.dbName = dbName;
	this.port = port;
    }

    /**
     * Constructor with all internal database driver classes, driver paths and
     * database types.
     *
     * @param connPath The driver class; should be passed from the
     *        database-specific subclass.
     */
    //public PostgisConnectionFactory(String connPath) {
    //  connPath = DRIVER_PATH + "://" + connPath;
    //}

    /**
     * Creates a database connection method to initialize a given database for
     * feature extraction.
     *
     * @param user the name of the user connect to connect to the pgsql db.
     * @param password the password for the user.
     */
    public void setLogin(String user, String password) {
        this.user = user;
        this.password = password;
    }

    

    /**
     * Creates a database connection method to initialize a given database for
     * feature extraction using the set username and password.
     *
     * @return the sql Connection object to the database.
     *
     * @throws SQLException if the postgres driver could not be found
     */
    public Connection getConnection() throws SQLException {
        return getConnection(user, password);
    }

    /**
     * Creates a database connection method to initialize a given database for
     * feature extraction with the user and password params.
     *
     * @param user the name of the user connect to connect to the pgsql db.
     * @param password the password for the user.
     *
     * @return the sql Connection object to the database.
     *
     * @throws SQLException if the postgis sql driver could not be found
     */
    public Connection getConnection(String user, String password)
        throws SQLException {
        Properties props = new Properties();
        props.put("user", user);
        props.put("password", password);

        return getConnection(props);
    }

      public ConnectionPool getConnectionPool(String user, String pass)
        throws SQLException {
        org.postgresql.jdbc2.optional.ConnectionPool poolDataSource = null;
	String dbUrl = connPath;
        String poolKey = dbUrl + user + pass;
	LOGGER.fine("looking up pool key " + poolKey);
	Object poolDS = dataSources.get(poolKey);
	poolDataSource = (org.postgresql.jdbc2.optional.ConnectionPool)poolDS;
	LOGGER.fine("pool is " + poolDataSource);
        if (poolDataSource == null) {
	    poolDataSource = new org.postgresql.jdbc2.optional.ConnectionPool();
	    //source.setDataSourceName("Geotools Postgis");
	    poolDataSource.setServerName(host);
	    poolDataSource.setDatabaseName(dbName);
	    poolDataSource.setPortNumber(port);
	    poolDataSource.setUser(user);
	    poolDataSource.setPassword(pass);
	    //source.setMaxConnections(10);
	    //the source looks like this defaults to false, but we have
	    //assumed true (as that's how it was before pooling)
	    poolDataSource.setDefaultAutoCommit(true);
        dataSources.put(poolKey, poolDataSource);
            
        }

        ConnectionPoolManager manager = ConnectionPoolManager.getInstance();
        ConnectionPool connectionPool = manager.getConnectionPool(poolDataSource);
        
        return connectionPool;
    }

    public ConnectionPool getConnectionPool() throws SQLException {
        return getConnectionPool(user, password);
    }
    public void free(ConnectionPool connectionPool){
        if (connectionPool == null) return;
    	if(!connectionPool.isClosed() ){
            connectionPool.close();
        }        
        ConnectionPoolManager.getInstance().free( connectionPool );
    }
    /**
     * Creates a database connection method to initialize a given database for
     * feature extraction with the given Properties.
     *
     * @param props Should contain at a minimum the user and password.
     *        Additional properties, such as charSet, can also be added.
     *
     * @return the sql Connection object to the database.
     *
     * @throws SQLException if the postgis sql driver could not be found
     */
    public Connection getConnection(Properties props) throws SQLException {
        // makes a new feature type bean to deal with incoming
        Connection dbConnection = null;

        // Instantiate the driver classes
        try {
            Class.forName(DRIVER_CLASS);
            LOGGER.finest("getting connection at " + connPath + "with props: "
                + props);
            dbConnection = DriverManager.getConnection(connPath, props);
        } catch (ClassNotFoundException cnfe) {
            throw new SQLException("Postgis driver was not found.");
        }

        return dbConnection;
    }
}
