package org.maachang.dao.dbms.pool;

import java.io.IOException;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Properties;

/**
 * Connection実体. <BR>
 * <BR>
 * Connection実体を表すオブジェクト.<BR>
 * このオブジェクトはjava6用で対応しています.
 * 
 * @version 2007/10/18
 * @author masahito suzuki
 * @since MaachangDao 1.00
 */
class ConnectionImple implements Connection {

    /**
     * プールコネクション.
     */
    private PoolConnection connect = null;

    /**
     * 同期オブジェクト.
     */
    private Object sync = null;

    /**
     * コンストラクタ.
     */
    private ConnectionImple() {

    }

    /**
     * コンストラクタ. <BR>
     * <BR>
     * プールコネクションを設定して生成します. <BR>
     * 
     * @param conn
     *            対象のプールオブジェクトを設定します.
     * @exception IllegalArgumentException
     *                入力例外.
     * @exception IOException
     *                アクセス例外.
     */
    public ConnectionImple(PoolConnection conn)
            throws IllegalArgumentException, IOException {
        if (conn == null || conn.isUse() == true) {
            throw new IllegalArgumentException("引数は不正です");
        }

        if (conn.isCuttingConnection() == false) {
            if (conn.getCheckSQL() == null) {
                throw new IOException("指定コネクションは接続が確立していません");
            } else {
                throw new IOException("指定コネクションは接続が確立していないか、チェック用SQL["
                        + conn.getCheckSQL() + "]が不正なので利用できません");
            }
        }

        this.connect = conn;
        sync = conn.getSync();
    }

    /**
     * ファイナライズ処理定義. <BR>
     * <BR>
     * ファイナライズ処理定義. <BR>
     * 
     * @exception Exception
     *                例外処理が返されます.
     */
    protected final void finalize() throws Exception {
        try {
            this.close();
        } catch (Exception e) {
        }

        this.connect = null;
        sync = null;
    }

    // /////////////////////////
    // 以下Wapperオブジェクト.
    // /////////////////////////

    public Statement createStatement() throws SQLException {
        return this.connect.getConnection().createStatement();
        // throw new SQLException( "This method is not permitted." ) ;
    }

    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return this.connect.getConnection().prepareStatement(sql);
    }

    public CallableStatement prepareCall(String sql) throws SQLException {
        return this.connect.getConnection().prepareCall(sql);
    }

    public String nativeSQL(String sql) throws SQLException {
        return this.connect.getConnection().nativeSQL(sql);
    }

    public void setAutoCommit(boolean autoCommit) throws SQLException {
        this.connect.getConnection().setAutoCommit(autoCommit);
    }

    public boolean getAutoCommit() throws SQLException {
        return this.connect.getConnection().getAutoCommit();
    }

    public void commit() throws SQLException {
        try {
            synchronized (sync) {
                this.connect.getConnection().commit();
                this.connect.commitRollbackON();
            }
        } catch (SQLException se) {
            throw se;
        } catch (Exception e) {
            throw new SQLException(e.getMessage());
        }
    }

    public void rollback() throws SQLException {
        try {
            synchronized (sync) {
                this.connect.getConnection().rollback();
                this.connect.commitRollbackON();
            }
        } catch (SQLException se) {
            throw se;
        } catch (Exception e) {
            throw new SQLException(e.getMessage());
        }
    }

    public void close() throws SQLException {
        this.connect.close();
    }

    public boolean isClosed() throws SQLException {
        return this.connect.isCuttingConnection();
    }

    // ======================================================================
    // Advanced features:

    public DatabaseMetaData getMetaData() throws SQLException {
        return this.connect.getConnection().getMetaData();
    }

    public void setReadOnly(boolean readOnly) throws SQLException {
        this.connect.getConnection().setReadOnly(readOnly);
    }

    public boolean isReadOnly() throws SQLException {
        return this.connect.getConnection().isReadOnly();
    }

    public void setCatalog(String catalog) throws SQLException {
        this.connect.getConnection().setCatalog(catalog);
    }

    public String getCatalog() throws SQLException {
        return this.connect.getConnection().getCatalog();
    }

    public void setTransactionIsolation(int level) throws SQLException {
        this.connect.getConnection().setTransactionIsolation(level);
    }

    public int getTransactionIsolation() throws SQLException {
        return this.connect.getConnection().getTransactionIsolation();
    }

    public SQLWarning getWarnings() throws SQLException {
        return this.connect.getConnection().getWarnings();
    }

    public void clearWarnings() throws SQLException {
        this.connect.getConnection().clearWarnings();
    }

    // --------------------------JDBC 2.0-----------------------------

    public Statement createStatement(int resultSetType, int resultSetConcurrency)
            throws SQLException {
        return this.connect.getConnection().createStatement(resultSetType,
                resultSetConcurrency);
        // throw new SQLException( "This method is not permitted." ) ;
    }

    public PreparedStatement prepareStatement(String sql, int resultSetType,
            int resultSetConcurrency) throws SQLException {
        return this.connect.getConnection().prepareStatement(sql,
                resultSetType, resultSetConcurrency);
    }

    public CallableStatement prepareCall(String sql, int resultSetType,
            int resultSetConcurrency) throws SQLException {
        return this.connect.getConnection().prepareCall(sql, resultSetType,
                resultSetConcurrency);
    }

    public java.util.Map<String, Class<?>> getTypeMap() throws SQLException {
        return this.connect.getConnection().getTypeMap();
    }

    public void setTypeMap(java.util.Map<String, Class<?>> map)
            throws SQLException {
        this.connect.getConnection().setTypeMap(map);
    }

    // --------------------------JDBC 3.0-----------------------------

    public void setHoldability(int holdability) throws SQLException {
        this.connect.getConnection().setHoldability(holdability);
    }

    public int getHoldability() throws SQLException {
        return this.connect.getConnection().getHoldability();
    }

    public Savepoint setSavepoint() throws SQLException {
        return this.connect.getConnection().setSavepoint();
    }

    public Savepoint setSavepoint(String name) throws SQLException {
        return this.connect.getConnection().setSavepoint(name);
    }

    public void rollback(Savepoint savepoint) throws SQLException {
        try {
            synchronized (sync) {
                this.connect.getConnection().rollback(savepoint);
                this.connect.commitRollbackON();
            }
        } catch (SQLException se) {
            throw se;
        } catch (Exception e) {
            throw new SQLException(e.getMessage());
        }
    }

    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
        this.connect.getConnection().releaseSavepoint(savepoint);
    }

    public Statement createStatement(int resultSetType,
            int resultSetConcurrency, int resultSetHoldability)
            throws SQLException {
        return this.connect.getConnection().createStatement(resultSetType,
                resultSetConcurrency, resultSetHoldability);
        // throw new SQLException( "This method is not permitted." ) ;
    }

    public PreparedStatement prepareStatement(String sql, int resultSetType,
            int resultSetConcurrency, int resultSetHoldability)
            throws SQLException {
        return this.connect.getConnection().prepareStatement(sql,
                resultSetType, resultSetConcurrency, resultSetHoldability);
    }

    public CallableStatement prepareCall(String sql, int resultSetType,
            int resultSetConcurrency, int resultSetHoldability)
            throws SQLException {
        return this.connect.getConnection().prepareCall(sql, resultSetType,
                resultSetConcurrency, resultSetHoldability);
    }

    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
            throws SQLException {
        return this.connect.getConnection().prepareStatement(sql,
                autoGeneratedKeys);
    }

    public PreparedStatement prepareStatement(String sql, int columnIndexes[])
            throws SQLException {
        return this.connect.getConnection()
                .prepareStatement(sql, columnIndexes);
    }

    public PreparedStatement prepareStatement(String sql, String columnNames[])
            throws SQLException {
        return this.connect.getConnection().prepareStatement(sql, columnNames);
    }

    public Clob createClob() throws SQLException {
        return this.connect.getConnection().createClob();
    }

    public Blob createBlob() throws SQLException {
        return this.connect.getConnection().createBlob();
    }

    public NClob createNClob() throws SQLException {
        return this.connect.getConnection().createNClob();
    }

    public SQLXML createSQLXML() throws SQLException {
        return this.connect.getConnection().createSQLXML();
    }

    public boolean isValid(int timeout) throws SQLException {
        return this.connect.getConnection().isValid(timeout);
    }

    public void setClientInfo(String name, String value)
            throws SQLClientInfoException {
        Connection conn = null;
        try {
            conn = this.connect.getConnection();
        } catch (SQLException se) {
            return;
        }
        conn.setClientInfo(name, value);
    }

    public void setClientInfo(Properties properties)
            throws SQLClientInfoException {
        Connection conn = null;
        try {
            conn = this.connect.getConnection();
        } catch (SQLException se) {
            return;
        }
        conn.setClientInfo(properties);
    }

    public String getClientInfo(String name) throws SQLException {
        return this.connect.getConnection().getClientInfo(name);
    }

    public Properties getClientInfo() throws SQLException {
        return this.connect.getConnection().getClientInfo();
    }

    public Array createArrayOf(String typeName, Object[] elements)
            throws SQLException {
        return this.connect.getConnection().createArrayOf(typeName, elements);
    }

    public Struct createStruct(String typeName, Object[] attributes)
            throws SQLException {
        return this.connect.getConnection().createStruct(typeName, attributes);
    }

    // Wrapper.java
    public <T> T unwrap(java.lang.Class<T> iface) throws java.sql.SQLException {
        return this.connect.getConnection().unwrap(iface);
    }

    public boolean isWrapperFor(java.lang.Class<?> iface)
            throws java.sql.SQLException {
        return this.connect.getConnection().isWrapperFor(iface);
    }

}
