package eu.dnetlib.sesame.xapool;

import java.sql.SQLException;
import java.util.Vector;

import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import org.enhydra.jdbc.standard.StandardXAConnection;
import org.enhydra.jdbc.standard.StandardXADataSource;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;

/**
 * Implemented following org.enhydra.jdbc.oracle.OracleXAConnection example.
 * 
 * @author lexis
 */
public class XAConnectionSesame extends StandardXAConnection {

	/** ids of global transaction started. */
	private static Vector<Xid> xids = new Vector<Xid>();

	/** Conenction to a Sesame Repository. */
	//private RepositoryConnection repositoryCon;
	public void setRepositoryCon(final RepositoryConnection repositoryCon) {
		this.con = new ConnectionSesame(repositoryCon);
		this.curCon.con = this.con;
	}

	public RepositoryConnection getRepositoryCon() {
		ConnectionSesame conSes = (ConnectionSesame) this.con;
		return conSes.getRepositoryConnection();
	}

	//	/**
	//	 * Constructor. Creates the first free connection.
	//	 * 
	//	 * @param dataSource
	//	 *            StandardXADataSource instance, guess should be a XADataSourceSesame
	//	 * @param user
	//	 *            username
	//	 * @param password
	//	 *            user's password
	//	 * @throws SQLException
	//	 *             creating connection
	//	 */
	//	public XAConnectionSesame(final StandardXADataSource dataSource, final String user, final String password) throws SQLException {
	//		super(dataSource, user, password);
	//	}

	/**
	 * Constructor.
	 * 
	 * @param dataSource
	 *            StandardXADataSource instance, guess should be a XADataSourceSesame
	 * @param user
	 *            username
	 * @param password
	 *            user's password
	 * @param con
	 *            RepositoryConnection instance
	 * @throws SQLException
	 *             creating connection
	 */
	public XAConnectionSesame(final StandardXADataSource dataSource, final String user, final String password, final RepositoryConnection con)
			throws SQLException {
		super(dataSource, user, password);
		this.setRepositoryCon(con);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.enhydra.jdbc.standard.StandardXAConnection#close()
	 */
	@Override
	public synchronized void close() throws SQLException {

		try {
			RepositoryConnection con = this.getRepositoryCon();
			if (con != null)
				con.close();
			super.close();
		} catch (RepositoryException e) {
			throw new SQLException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.enhydra.jdbc.standard.StandardXAConnection#commit(javax.transaction.xa.Xid, boolean)
	 */
	@Override
	public void commit(final Xid xid, final boolean flag) throws XAException {
		try {
			this.dataSource.log.debug("commit:" + xid.getGlobalTransactionId());
			this.con.commit();
			this.xaDataSource.freeConnection(xid, false);
			xids.remove(xid);
		} catch (SQLException e) {
			this.throwXAException(XAException.XAER_RMERR);
		}

	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.enhydra.jdbc.standard.StandardXAConnection#end(javax.transaction.xa.Xid, int)
	 */
	@Override
	public void end(final Xid xid, final int flags) throws XAException {
		this.dataSource.log.debug("end" + ":" + xid.getFormatId() + ":" + xid.getGlobalTransactionId() + ":" + xid.getBranchQualifier() + ":" + flags);
		super.end(xid, flags);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.enhydra.jdbc.standard.StandardXAConnection#forget(javax.transaction.xa.Xid)
	 */
	@Override
	public void forget(final Xid xid) throws XAException {
		this.dataSource.log.debug("forget" + ":" + xid.getGlobalTransactionId());
		super.forget(xid);
		this.xaDataSource.freeConnection(xid, false);
		xids.remove(xid);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.enhydra.jdbc.standard.StandardXAConnection#prepare(javax.transaction.xa.Xid)
	 */
	@Override
	public int prepare(final Xid xid) throws XAException {
		this.dataSource.log.debug("prepare" + ":" + xid.getGlobalTransactionId());
		int res = super.prepare(xid);
		if (res == XA_RDONLY) {
			this.xaDataSource.freeConnection(xid, false);
			xids.remove(xid);
		}
		return res;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.enhydra.jdbc.standard.StandardXAConnection#rollback(javax.transaction.xa.Xid)
	 */
	@Override
	public void rollback(final Xid xid) throws XAException {
		try {
			this.dataSource.log.debug("rollback" + ":" + xid.getGlobalTransactionId());
			super.rollback(xid);
			//super.rollback(xid);
			this.con.rollback();
			this.xaDataSource.freeConnection(xid, false);
			xids.remove(xid);
		} catch (SQLException e) {
			this.throwXAException(XAException.XAER_RMERR);
		}

	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.enhydra.jdbc.standard.StandardXAConnection#start(javax.transaction.xa.Xid, int)
	 */
	@Override
	public void start(final Xid xid, final int flags) throws XAException {
		try {
			this.dataSource.log.debug("start" + ":" + xid.getFormatId() + ":" + xid.getGlobalTransactionId() + ":" + xid.getBranchQualifier() + ":"
					+ flags);
			this.con.setAutoCommit(false);
			super.doStart(xid, flags);
			xids.add(xid);
			this.curCon = null;
			this.con = null;
		} catch (SQLException e) {
			this.throwXAException(XAException.XAER_RMERR);
		}
		//	        xarsrc = new OracleXAResource(curCon.con);
		//	        OracleXid oXid = getOracleXid(xid);
		//this.xarsrc.start(xid, flags);
		//txctxs.put(xid, xid.getTxContext());
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.enhydra.jdbc.standard.StandardXAConnection#isSameRM(javax.transaction.xa.XAResource)
	 */
	@Override
	public boolean isSameRM(final XAResource res) throws XAException {
		this.dataSource.log.debug("isSameRM returning " + (this == res));
		return this == res;
		//			
		//		if (!(res instanceof XAConnectionSesame)) {
		//			this.dataSource.log.debug("isSameRM returning false");
		//			return false;
		//		}
		//		XAConnectionSesame ores = (XAConnectionSesame) res;
		//		//if (ores.xarsrc.isSameRM(this.xarsrc)) {
		//		if(this.)
		//			this.dataSource.log.debug("isSameRM returning true");
		//			return true;
		//		}
		//		this.dataSource.log.debug("isSameRM returning false");
		//		return false;
	}

	//	/**
	//	 * {@inheritDoc}
	//	 * 
	//	 * @see org.enhydra.jdbc.standard.StandardXAConnection#close()
	//	 */
	//	@Override
	//	public synchronized void close() throws SQLException {
	//		try {
	//			super.close();
	//			this.repositoryCon.close();
	//		} catch (RepositoryException e) {
	//			throw new SQLException(e);
	//		}
	//	}

	/**
	 * Utility method to create and throw a XAEXception with the given code.
	 * 
	 * @param code
	 *            XAException error code
	 * @throws XAException
	 *             always
	 */
	private void throwXAException(final int code) throws XAException {
		XAException e = new XAException();
		e.errorCode = XAException.XAER_RMERR;
		throw e;
	}
}
