package eu.dnetlib.enabling.database;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.xml.ws.wsaddressing.W3CEndpointReference;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;

import eu.dnetlib.enabling.database.rmi.DatabaseException;
import eu.dnetlib.enabling.database.rmi.DatabaseService;
import eu.dnetlib.enabling.resultset.XSLTMappedResultSetFactory;
import eu.dnetlib.enabling.tools.AbstractBaseService;

public class DatabaseServiceImpl extends AbstractBaseService implements DatabaseService {

	private static final Log log = LogFactory.getLog(DatabaseServiceImpl.class); // NOPMD by marko on 11/24/08 5:02 PM

	private DatabaseServiceCore core;

	private XSLTMappedResultSetFactory xsltResultsetFactory;
	
	private DatabaseBlackBoardNotificationHandler blackBoardNotificationHandler; 

	private ExecutorService threadPool = Executors.newCachedThreadPool();

	@Override
	public W3CEndpointReference dumpTable(final String db, final String table) {
		return core.generateResultSet(db, table, null);
	}

	@Override
	public W3CEndpointReference dumpTableAndLogs(final String db, final String table, final Date from, final Date until) {
		return core.generateResultSet(db, table, from, until);
	}

	@Override
	public void notify(final String subscriptionId, final String topic, final String isId, final String message) {
		log.info("Received notification " + subscriptionId + ", TOPIC: " + topic);
		
		if (topic.contains("BLACKBOARD")) {
			blackBoardNotificationHandler.notified(subscriptionId, topic, isId, message);
			return;
		}
	}

	@Override
	public boolean importFromEPR(final String db, final W3CEndpointReference epr, final String xslt) {

		final W3CEndpointReference mappedEpr = (xslt == null || xslt.isEmpty()) ?
				xsltResultsetFactory.createMappedResultSet(epr, xslt) : epr;
		
		
		threadPool.execute(new Runnable() {
			@Override
			public void run() {
				try {
					core.importFromResultset(db, mappedEpr);
				} catch (final Exception e) {
					log.error("Error in thread when importing from epr", e);
				}
			}
		});

		return true;
	}

	@Required
	public void setCore(final DatabaseServiceCore core) {
		this.core = core;
	}

	@Override
	public W3CEndpointReference searchSQL(final String db, final String sql) {
		return core.generateResultSet(db, sql);
	}
	
	@Override
	public W3CEndpointReference alternativeSearchSQL(String db, String sql, String sqlForSize) {
		return core.generateResultsetWithSize(db, sql, sqlForSize);
	}
	
	@Override
	public boolean updateSQL(final String db, final String sql) {
		try {
			core.getDbUtils().executeSql(db, sql);
			return true;
		} catch (DatabaseException e) {
			log.error("error updating db: " + db + " sql: " + sql, e);
			return false;
		}
	}	

	@Override
	public W3CEndpointReference xsltSearchSQL(final String db, final String sql, final String xslt) {
		try {
			return xsltResultsetFactory.createMappedResultSet(searchSQL(db, sql), xslt);
		} catch (Exception e) {
			throw new RuntimeException("Error returning a transformed resultSet", e);
		}
	}

	@Override
	public W3CEndpointReference alternativeXsltSearchSQL(String db, String sql, String sqlForSize, String xslt) {
		try {
			return xsltResultsetFactory.createMappedResultSet(alternativeSearchSQL(db, sql, sqlForSize), xslt);
		} catch (Exception e) {
			throw new RuntimeException("Error returning a transformed resultSet", e);
		}
	}
	
	
	@Override
	public boolean contains(final String db, final String table, final String column, final String value) {
		return core.getDbUtils().contains(db, table, column, value);
	}	

	public XSLTMappedResultSetFactory getXsltResultsetFactory() {
		return xsltResultsetFactory;
	}

	@Required
	public void setXsltResultsetFactory(final XSLTMappedResultSetFactory xsltResultsetFactory) {
		this.xsltResultsetFactory = xsltResultsetFactory;
	}

	public ExecutorService getThreadPool() {
		return threadPool;
	}

	public void setThreadPool(ExecutorService threadPool) {
		this.threadPool = threadPool;
	}

	public DatabaseBlackBoardNotificationHandler getBlackBoardNotificationHandler() {
		return blackBoardNotificationHandler;
	}

	@Required
	public void setBlackBoardNotificationHandler(DatabaseBlackBoardNotificationHandler blackBoardNotificationHandler) {
		this.blackBoardNotificationHandler = blackBoardNotificationHandler;
	}

}
