/*
 * TypeMap.java
 * 
 * (C) 28.02.2005 Markus Schaber, Logi-Track ag, CH 8001 Zuerich
 * 
 * $Id: $
 */
package org.postgresql.types;

import org.postgresql.PGConnection;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

public class TypeMap {
    protected HashMap byType = new HashMap();
    protected HashMap byClass = new HashMap();
    protected ArrayList drivers = new ArrayList();

    /**
     * Search the driver for a given SQL type
     * 
     * @returns the driver, null if none is found
     */
    public TypeDriver getDriverForType(String type) {
        return (TypeDriver) byType.get(type);
    }

    /**
     * Search the driver for a given java object
     * 
     * @returns the driver, null if none is found
     */
    public TypeDriver getDriverForObject(Object obj) {
        Class klass = obj.getClass();
        return getDriverForClass(klass);
    }

    /**
     * Search the driver for a given java class
     * 
     * @returns the driver, null if none is found
     */
    private TypeDriver getDriverForClass(Class klass) {
        TypeDriver d = (TypeDriver) byClass.get(klass);
        if (d == null) {
            for (int i = 0; i < drivers.size(); i++) {
                TypeDriver drv = (TypeDriver) drivers.get(i);
                if (drv.supports(klass)) {
                    d = drv;
                    break;
                }
            }
            if (d != null) { // cache the search result
                byClass.put(klass, d);
            }
        }
        return d;
    }

    /** Register a new driver */
    public void addDriver(TypeDriver drv) {
        Class[] classes = drv.getSupportedClasses();
        for (int i = 0; i < classes.length; i++) {
            byClass.put(classes[i], drv);
        }
        String[] types = drv.getSupportedTypes();
        for (int i = 0; i < types.length; i++) {
            byType.put(types[i], drv);
        }
        drivers.add(drv);
    }

    /**
     * Clones the TypeDriver for a new connection.
     * 
     * This is e. G. used by the driver to get connection specific instances
     * from the default TypeDriver, and by Connection.setCatalog() to re-init
     * the typemap on a database change.
     * 
     * This method may do read-only queries on the database, as it calls
     * TypeDriver.forConnection() for each known driver.
     * 
     * XXX: Should we only use java.sql.Connection here?
     * 
     * @returns the TypeDriver instance
     */
    public TypeMap forConnection(PGConnection conn) throws SQLException {
        TypeMap result = new TypeMap();
        for (int i = 0; i < drivers.size(); i++) {
            TypeDriver drv = (TypeDriver) drivers.get(i);
            TypeDriver newdrv = drv.forConnection(conn);
            result.addDriver(newdrv);
        }
        return result;
    }
}
