/*
 * Copyright (C) 2005 NTT DATA Corporation
 * 
 */
package org.postgresforest.vm.jdbc;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.Map;
import java.util.Properties;

import org.postgresforest.core.ProtocolConnection;
import org.postgresforest.jdbc3.AbstractJdbc3Connection;
import org.postgresforest.vm.LogUtil;
import org.postgresforest.vm.core.QueryExecutorImpl;
import org.postgresforest.vm.gsc.GscData;
import org.postgresforest.vm.gsc.GscMetaData;

/**
 * PostgresForest用Connection基底クラス.
 * GSCクラスをメンバにもつ。
 * GSCをメンバ変数に持つ。
 * Forest用の処理とオリジナルの処理の切り分けを行う。
 * 実行されるSQLの順序を管理する（キューイング）。 
 * @since 2.0
 */
public class ForestConnection extends AbstractJdbc3Connection implements Connection{




	protected QueryExecutorImpl m_queryExecuter;

	public ForestConnection(String host, int port, String user, String database, Properties info, String url) throws SQLException {
		super(host, port, user, database, info, url);
		m_queryExecuter = (QueryExecutorImpl)getQueryExecutor(); 
	}

    public java.sql.DatabaseMetaData getMetaData() throws SQLException
    {
        if (metadata == null)
            metadata = new ForestDatabaseMetaData(this);
        return metadata;
    }

	/**
	 * GSCメタデータ取得.
	 */
	public GscMetaData getGscMetaData() {
	    return	new GscMetaData( m_queryExecuter.getGsc() );
	}

	public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        ForestStatement s = new ForestStatement(this, resultSetType, resultSetConcurrency, resultSetHoldability);
        s.setPrepareThreshold(getPrepareThreshold());
        return s;

	}

	public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
		// TODO 自動生成されたメソッド・スタブ
		return null;
	}

	public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
		ForestPreparedStatement s = new ForestPreparedStatement(this, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
        s.setPrepareThreshold(getPrepareThreshold());
        return s;
	}

    public void setTypeMap(Map map) throws SQLException
    {
        setTypeMapImpl(map);
    }


	public void commit() throws SQLException {

		//実行中のクエリーが無くなるまで待機
		m_queryExecuter.waitFree();
		
		//ProtocolConnectionはConnectionのprivate変数のため
		//QueryExecuterからトランザクション状態を設定する
		m_queryExecuter.setTransactionState(ProtocolConnection.TRANSACTION_OPEN);		

		//エラーが発生した場合DB間の同期が取れなくなるので
		//エラーが発生したサーバーを切り離すために更新非同期モードに設定
		boolean orgSync = getUpdateSyncMode();
		setUpdateSyncMode(false);
		try {
			super.commit();
		} finally {
			//実行中のクエリーが無くなるまで待機
			m_queryExecuter.waitFree();
			//更新同期モードを元に戻す
			setUpdateSyncMode(orgSync);
		}
		m_queryExecuter.setTransactionState(ProtocolConnection.TRANSACTION_IDLE);
	}


	/**
	 * 
	 */
	public void setMetaDataAccess() {
		m_queryExecuter.addMetaDataAccess();
		
	}
	
	/**
	 * 
	 */
	public void clearMetaDataAccess() {
		m_queryExecuter.removeMetaDataAccess();

	}

	/** 
	 * オートコミット設定.
	 * グローバルシステムカタログで保持しているすべてのコネクションに設定するとともに
	 * 更新同期モードを設定
	 * @param autoCommit　オートコミット
	 * @param syncronize　更新同期モード true:同期 false 非同期
	 * @since 3.0 
	 */
	public void setAutoCommit(boolean autoCommit, boolean syncronize) throws SQLException {

		setUpdateSyncMode(syncronize);

		setAutoCommit(autoCommit);
		

	}



	/**
	 * @return 更新同期モード true:同期 false 非同期
	 * @since 3.0
	 */
	public boolean getUpdateSyncMode() {
		return m_queryExecuter.isUpdateSyncMode();
	}

	/**
	 * @param syncronize　更新同期モード true:同期 false 非同期
	 * @since 3.0
	 */
	public void setUpdateSyncMode(boolean b) {
		m_queryExecuter.setUpdateSyncMode(b);
	}	
	
	
	
	/// JDBC標準API(JBossのEJBコンテナから使用される)
	/**
	 * トランザクション分離レベルの取得
	 * 単一サーバに割り振る
	 * @since 3.0
	 * @see org.postgresforest.jdbc1.AbstractJdbc1Connection#getTransactionIsolation()
	 */
	public int getTransactionIsolation() throws SQLException {
		
		try {
			setMetaDataAccess();
			return super.getTransactionIsolation();
		} finally {
			clearMetaDataAccess();
		}
		
		
	}

	public void setAutoCommit(boolean autoCommit) throws SQLException {
		m_queryExecuter.setAutocommit(autoCommit);
		super.setAutoCommit(autoCommit);
	}

	public void rollback() throws SQLException {
		//実行中のクエリーが無くなるまで待機
		m_queryExecuter.waitFree();
		
		//ProtocolConnectionはConnectionのprivate変数のため
		//QueryExecuterからトランザクション状態を設定する
		m_queryExecuter.setTransactionState(ProtocolConnection.TRANSACTION_OPEN);		

		//エラーが発生した場合DB間の同期が取れなくなるので
		//エラーが発生したサーバーを切り離すために更新非同期モードに設定
		boolean orgSync = getUpdateSyncMode();
		setUpdateSyncMode(false);
		try {
			super.rollback();
		} finally {
			//実行中のクエリーが無くなるまで待機
			m_queryExecuter.waitFree();
			//更新同期モードを元に戻す
			setUpdateSyncMode(orgSync);
		}

		m_queryExecuter.setTransactionState(ProtocolConnection.TRANSACTION_IDLE);
	}
	

	public void setTransactionIsolation(int level) throws SQLException {
		//実行中のクエリーが無くなるまで待機
		m_queryExecuter.waitFree();
		
		//ProtocolConnectionはConnectionのprivate変数のため
		//QueryExecuterからトランザクション状態を設定する
		m_queryExecuter.setTransactionState(ProtocolConnection.TRANSACTION_IDLE);		

		//エラーが発生した場合DB間の同期が取れなくなるので
		//エラーが発生したサーバーを切り離すために更新非同期モードに設定
		boolean orgSync = getUpdateSyncMode();
		setUpdateSyncMode(false);
		try {
			super.setTransactionIsolation(level);
		} finally {
			//実行中のクエリーが無くなるまで待機
			m_queryExecuter.waitFree();
			//更新同期モードを元に戻す
			setUpdateSyncMode(orgSync);
		}

		
	}


	
	

}
