/**
 * 
 */
package jp.ac.osaka_u.ist.sel.similarity.database;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.log4j.Logger;


/**
 * Transaction Manager for FCFinder databases.
 * This class should not make so many instances to avoid memory leaks.
 * 
 * @author ysk-ssk
 *
 */
public class TransactionManager {
	private final Logger _log = Logger.getLogger("TransactionManager");
	private String _dbPath;
	private Connection _conn;
	private int _transactionCount = 0;
	private static final int _TRANSACTION_MAX_COUNT = 10000;

	public TransactionManager(String dbPath) {
		try {
			_dbPath = dbPath;
			getConnection();
		} catch (SQLException e) {
		    _log.error("Failed to access the database.");
		    _log.error(e.getMessage(),e);
		}
	}

	public synchronized void commit() throws SQLException {
		getConnection();
		try {
			_conn.commit();
		} catch (SQLException e) {
		    _log.error("A rollback has occured.");
			_conn.rollback();
			throw e;
		}
	}

	public synchronized void close() throws SQLException {
		getConnection();
		try {
			commit();
		} finally {
		    if (_conn != null) {
	            _conn.close();
		    }
		}
	}

	public synchronized ResultSet executeQuery(PreparedStatement pstmt) throws SQLException {
		// query execution
		ResultSet rset = pstmt.executeQuery();
		return rset;
	}

	public synchronized int executeUpdate(PreparedStatement pstmt) throws SQLException {
		// query execution
		int executed = pstmt.executeUpdate();
		if (_transactionCount++ > _TRANSACTION_MAX_COUNT) {
			_transactionCount = 0;
			commit();
		}
		return executed;
	}

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

	private void getConnection() throws SQLException {
		if (_conn == null || _conn.isClosed()) {
		    File dbFile = new File(_dbPath);
		    if (dbFile.getParentFile() != null && !dbFile.getParentFile().exists()) {
		        throw new RuntimeException("no such directory:\t" + dbFile.getParent());
		    }
			Connection conn =
				DriverManager.getConnection
				("jdbc:derby:" + _dbPath + ";create=true");
			_conn = conn;
			_conn.setAutoCommit(false);
			_conn.setSavepoint();
		}
	}
}
