package eu.dnetlib.dummy;

import java.sql.Connection;
import java.sql.Statement;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openrdf.model.Literal;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.springframework.jdbc.core.JdbcTemplate;

import eu.dnetlib.sesame.xapool.XAConnectionSesame;
import eu.dnetlib.sesame.xapool.XADataSourceSesame;

/**
 * DAO implementation which stores a DummyObject in a postgresql database and in a Sesame triple store repository. (It's
 * a merge of DummyDAOSesame and DummyDAO)
 * 
 * @author lexis
 */
public class SesamePostgresDAO implements DummyDAOInterface {
	/**
	 * logger.
	 */
	private static final Log log = LogFactory.getLog(SesamePostgresDAO.class);
	/** Template to access the datasource fora postgresql db. */
	private JdbcTemplate jdbcTemplate;
	/** datasource to get connections to the triplestore. */
	private XADataSourceSesame xaDataSource;

	public JdbcTemplate getJdbcTemplate() {
		return this.jdbcTemplate;
	}

	public void setJdbcTemplate(final JdbcTemplate jdbTemplate1) {
		this.jdbcTemplate = jdbTemplate1;
	}

	public void setXaDataSource(final XADataSourceSesame xaDataSource) {
		this.xaDataSource = xaDataSource;
	}

	public XADataSourceSesame getXaDataSource() {
		return this.xaDataSource;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dummy.DummyDAOInterface#save(eu.dnetlib.dummy.DummyObject, boolean)
	 */
	public void save(final DummyObject obj, final boolean fail) {
		log.debug(this);
		XAConnectionSesame xaCon = null;
		RepositoryConnection con = null;
		try {
			this.jdbcTemplate.execute("INSERT INTO table1 VALUES (" + obj.getTheInt() + ")");
			xaCon = (XAConnectionSesame) this.xaDataSource.getXAConnection();
			con = xaCon.getRepositoryCon();
			this.doSaveInSesame(con, obj, fail);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			try {
				if (xaCon != null)
					xaCon.close();
				if (con != null)
					con.close();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}

	}

	/**
	 * Does the dirty work saving triples to the triplestore using the given RepositoryConnection.
	 * 
	 * @param con
	 *            open connection to a Repository
	 * @param obj
	 *            DummyObject instance to save
	 * @param fail
	 *            true if we want to fail the operation, thus leading to a rollback
	 * @throws RepositoryException
	 *             problems saving triples to the repository through the given connection
	 */
	private void doSaveInSesame(final RepositoryConnection con, final DummyObject obj, final boolean fail) throws RepositoryException {
		URI soggetto = con.getValueFactory().createURI("http://dummy/" + obj.getTheInt());
		URI predicatoInt = con.getValueFactory().createURI("http://dummy/hasInt");
		URI predicatoStr = con.getValueFactory().createURI("http://dummy/hasStr");
		Literal oggettoInt = con.getValueFactory().createLiteral(obj.getTheInt());
		con.add(soggetto, predicatoInt, oggettoInt);
		Literal oggettoStr = con.getValueFactory().createLiteral(obj.getTheString());
		con.add(soggetto, predicatoStr, oggettoStr);
		if (fail) {
			//so we can test if we rollback!
			throw new RuntimeException();
		}
		con.close();
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dummy.DummyDAOInterface#saveUsingConnection(eu.dnetlib.dummy.DummyObject, boolean)
	 */
	@Override
	public void saveUsingConnection(final DummyObject obj, final boolean fail) {
		log.debug(this);
		XAConnectionSesame xaCon = null;
		RepositoryConnection con = null;
		try {
			Connection con1 = this.jdbcTemplate.getDataSource().getConnection();
			log.debug("Connection1 autocommit? " + con1.getAutoCommit());
			Statement st1 = con1.createStatement();
			st1.execute("INSERT INTO table1 VALUES (" + obj.getTheInt() + ")");
			xaCon = (XAConnectionSesame) this.xaDataSource.getXAConnection();
			con = xaCon.getRepositoryCon();
			this.doSaveInSesame(con, obj, fail);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			try {
				if (xaCon != null)
					xaCon.close();
				if (con != null)
					con.close();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dummy.DummyDAOInterface#deleteAllContents()
	 */
	public void deleteAllContents() {
		XAConnectionSesame xaCon = null;
		RepositoryConnection con = null;
		try {
			this.jdbcTemplate.execute("DELETE FROM table1");
			xaCon = (XAConnectionSesame) this.xaDataSource.getXAConnection();
			con = xaCon.getRepositoryCon();
			con.remove(null, null, (Value) null);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			try {
				if (xaCon != null)
					xaCon.close();
				if (con != null)
					con.close();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}

	}

}
