/*
 *    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.fidmapper;

import org.geotools.data.jdbc.JDBCDataStoreConfig;
import org.geotools.data.jdbc.fidmapper.DefaultFIDMapperFactory;
import org.geotools.data.jdbc.fidmapper.FIDMapper;
import org.geotools.data.postgis.PostgisSQLBuilder;
import org.geotools.filter.SQLEncoderPostgis;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;


/**
 * Postgis specific FIDMapperFactory that uses the {@link org.geotools.data.postgis.fidmapper.OIDFidMapper OIDFidMapper}
 * to map tables with no primary keys or tables that have weird primary keys that cannot be mapped
 * in other ways.
 *
 * @author Andrea Aime
 *
 * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/plugin/postgis/src/main/java/org/geotools/data/postgis/fidmapper/PostgisFIDMapperFactory.java $
 */
public class PostgisFIDMapperFactory extends DefaultFIDMapperFactory {
    JDBCDataStoreConfig config;

    public PostgisFIDMapperFactory(JDBCDataStoreConfig config) {
        this.config = config;
        //setReturningTypedFIDMapper( false );
    }

    protected FIDMapper buildNoPKMapper(String schema, String tableName,
        Connection connection) {
        //oid's supported before version 7
        if (getDatabaseMajorVersion(connection) <= 7) {
            return new OIDFidMapper();
        }

        //table could also have been created with OID flag on
        PostgisSQLBuilder sqlb = new PostgisSQLBuilder(new SQLEncoderPostgis(),
                config);
        String sql = "SELECT " + sqlb.encodeColumnName("oid") + " FROM "
            + sqlb.encodeTableName(tableName) + " LIMIT 1";
        Statement st = null;

        try {
            st = connection.createStatement();
            st.execute(sql);

            //if we get here oid is supported
            return new OIDFidMapper();
        } catch (SQLException e) {
            //ignore, fall back to parent
        } finally {
            try {
                st.close();
            } catch (SQLException ignore) {
            }
        }

        return super.buildNoPKMapper(schema, tableName, connection);
    }

    /**
     * Retrieves Postgresql database major version number. This is used to see
     * if OID are there or not.
     *
     * @param connection
     */
    private int getDatabaseMajorVersion(Connection connection) {
        int major;

        try {
            major = connection.getMetaData().getDatabaseMajorVersion();
        } catch (SQLException e) {
            LOGGER.log(Level.WARNING,
                "Failed to retrieve Postgres "
                + "database version number, assuming 7. Error is: "
                + e.getMessage(), e);
            major = 7;
        }

        return major;
    }

    protected FIDMapper buildLastResortFidMapper(String schema,
        String tableName, Connection connection, ColumnInfo[] colInfos) {
        if (getDatabaseMajorVersion(connection) > 7) {
            throw new IllegalArgumentException(
                "Tables for postgis 8+ must have a primary key defined");
        }

        return new OIDFidMapper();
    }

    protected FIDMapper buildSingleColumnFidMapper(String schema,
        String tableName, Connection connection, ColumnInfo ci) {
        if (ci.isAutoIncrement()) {
            return new PostGISAutoIncrementFIDMapper(schema, tableName,
                ci.getColName(), ci.getDataType());
        }

        return super.buildSingleColumnFidMapper(schema, tableName, connection,
            ci);
    }

    /**
     *  see@DefaultFIDMapperFactory in main module (jdbc)
     *   This version pre-double quotes the column name and table name and passes it to the superclass's version.
     */
    protected boolean isAutoIncrement(String catalog, String schema,
        String tableName, Connection conn, ResultSet tableInfo,
        String columnName, int dataType) throws SQLException {
        String schemaName = null;

        if (schema != null) {
            schemaName = "\"" + schema + "\"";
        }

        return super.isAutoIncrement(catalog, schemaName,
            "\"" + tableName + "\"", conn, tableInfo, "\"" + columnName + "\"",
            dataType);
    }

    //
    //    /**
    //     * @see org.geotools.data.jdbc.fidmapper.DefaultFIDMapperFactory#getMapper(org.geotools.feature.FeatureType)
    //     */
    //    public FIDMapper getMapper( FeatureType featureType ) {
    //        return new TypedFIDMapper(new OIDFidMapper(), featureType.getTypeName());
    //    }
    //    
    //    /**
    //     * @see org.geotools.data.jdbc.fidmapper.DefaultFIDMapperFactory#getMapper(java.lang.String, java.lang.String, java.lang.String, java.sql.Connection)
    //     */
    //    public FIDMapper getMapper( String catalog, String schema, String tableName,
    //            Connection connection ) throws IOException {
    //        return new TypedFIDMapper(new OIDFidMapper(), tableName);
    //    }
}
