/*
 * $Id: PersistenceManager.java,v 1.13 2007/08/16 11:11:01 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: PersistenceManager.java,v $
 * Revision 1.13  2007/08/16 11:11:01  marbobo
 * + Bugfixes
 * + Refactorings
 *
 * Revision 1.12  2004/12/21 15:31:15  koppy
 * Nur eine Log-Nachricht modifiziert
 *
 */
package vkc.db;

import java.sql.Connection;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import vkc.db.helper.DBHelper;
import vkc.exception.DBException;
import vkc.misc.VKCLogManager;

/**
 * This class represents a PersistenceManager for the Converter Server.
 * <p>
 * It is associated with a connection pool.
 * 
 * @created 07.01.2004
 * @author Andreas Koop
 */
public class PersistenceManager {
    private static PersistenceManager instance = new PersistenceManager();

    private Map dbs = new HashMap();

    /**
     * Returns the single instance of the PersistenceManager
     * 
     * @return
     */
    public static PersistenceManager getInstance() {
        return instance;
    }

    /**
     * Initializes the PersistenceManager
     * 
     * @param db
     */
    public synchronized void init(VKCDatabase db) {
        dbs.put(db.getDbUrl().toLowerCase(), new DBWrapper((GenericDBImpl) db));

    }

    public synchronized void addDatabaseByProperties(Properties props) {
        dbs.put(props.getProperty("vkc.db.url").toLowerCase(), new DBWrapper(props));
        VKCLogManager.infoLog(this, "PersistentManager for " + props.getProperty("vkc.db.url") + " added!");
    }

    /**
     * Method generates a new unique id from a specified database table
     * 
     * @param tableName -
     *            name of a database table
     * @param columnName -
     *            name of a column of the table from which the new id will be
     *            created
     * 
     * @return new unique column id
     * 
     * @throws SQLException
     */
    public final synchronized long getNewId(String dbUrl, String tableName, String columnName) throws DBException {
        Connection conn = null;
        DBWrapper db = null;

        try {
            if (dbUrl == null) {
                db = (DBWrapper) dbs.values().iterator().next();
            } else {
                db = (DBWrapper) dbs.get(dbUrl);
            }

            conn = db.openConnection();
            long id = DBHelper.getNewId(conn, db.getDbUrl(), db.getDriverClass(), tableName, columnName).longValue();

            return id;
        } catch (Exception e) {
            throw new DBException(e);
        } finally {
            DBHelper.close(conn);
        }
    }

    /**
     * Shuts down and releases all resources
     * 
     */
    public void shutdown() {
        // TODO ? connections.shutdown();
    }

    /**
     * Returns a connetion from the pool
     * 
     * @return
     * @throws DBException
     */
    public Connection getConnection() throws DBException {
        try {
            Connection conn = ((DBWrapper) dbs.values().iterator().next()).openConnection();

            return conn;
        } catch (Exception e) {
            VKCLogManager.errorLog(this, "", e.getMessage(), e);
            throw new DBException(e);
        }
    }

    /**
     * Returns a connetion from the pool
     * 
     * @return
     * @throws DBException
     */
    public Connection getConnection(String dbUrl) throws DBException {
        if (dbUrl == null) {
            return getConnection();
        }

        try {
            Connection conn = ((DBWrapper) dbs.get(dbUrl)).openConnection();

            return conn;
        } catch (Exception e) {
            VKCLogManager.errorLog(this, "", e.getMessage(), e);
            throw new DBException(e);
        }
    }

    /**
     * Returns all urls of DBs managed by this manager
     * 
     * @return
     */
    public Set getDbUrls() {
        return dbs.keySet();
    }

    private class DBWrapper {
        private DataSource dataSource = null;

        private String dbUrl = null;

        private String driver_class = null;

        public DBWrapper(GenericDBImpl db) {
            this.dbUrl = db.getDbUrl();
            this.driver_class = db.getDriverClass();
            this.dataSource = db.getDataSource();
        }

        public DBWrapper(Properties props) {
            this.dbUrl = props.getProperty("vkc.db.url");
            this.driver_class = props.getProperty("vkc.db.driver_class");
            this.dataSource = GenericDBImpl.buildDataSource(props);
        }

        public Connection openConnection() throws SQLException {
            return dataSource.getConnection();
        }

        public String getDriverClass() {
            return this.driver_class;
        }

        public String getDbUrl() {
            return this.dbUrl;
        }

        public boolean equals(Object obj) {
            if (!(obj instanceof DBWrapper)) {
                return false;
            }

            return (dbUrl + driver_class).equals(((DBWrapper) obj).dbUrl + ((DBWrapper) obj).driver_class);
        }

        public int hashCode() {
            return (dbUrl + driver_class).hashCode();
        }
    }
}