package eu.dnetlib.enabling.database;

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

import com.google.gson.Gson;
import eu.dnetlib.enabling.database.utils.DatabaseUtils;
import eu.dnetlib.enabling.resultset.factory.ResultSetFactory;
import eu.dnetlib.enabling.tools.blackboard.AbstractBlackboardNotificationHandler;
import eu.dnetlib.enabling.tools.blackboard.BlackboardJob;
import eu.dnetlib.enabling.tools.blackboard.BlackboardServerHandler;
import eu.dnetlib.enabling.tools.blackboard.NotificationHandler;
import eu.dnetlib.rmi.common.ResultSet;
import eu.dnetlib.rmi.data.DatabaseException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;

public class DatabaseBlackBoardNotificationHandler extends AbstractBlackboardNotificationHandler<BlackboardServerHandler> implements NotificationHandler {

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

	private DatabaseServiceCore core;

	private ExecutorService threadPool = Executors.newCachedThreadPool();

	@Autowired
	private ResultSetFactory resultSetFactory;

	@Autowired
	private DatabaseUtils databaseUtils;

	@Override
	protected void processJob(final BlackboardJob job) {
		threadPool.execute(new Runnable() {

			@Override
			public void run() {
				try {
					processJobInternal(job);
				} catch (final Throwable e) {
					log.error(e.getMessage(), e);
					getBlackboardHandler().failed(job, e);
				}
			}
		});
	}

	@SuppressWarnings("unchecked")
	private void processJobInternal(final BlackboardJob job) throws DatabaseException {
		String action = job.getAction();

		log.info("processing database job: " + action);

		if (action.equals("IMPORT")) {
			String db = job.getParameters().get("db");
			String rsJson = job.getParameters().get("epr");
			String xslt = decodeBase64(job.getParameters().get("xslt"));
			String xsltParamsString = decodeBase64(job.getParameters().get("xsltParams"));

			Map<String, String> xsltParams = null;
			if ((xsltParamsString != null) && !xsltParamsString.isEmpty()) {
				xsltParams = (new Gson()).fromJson(xsltParamsString, Map.class);
			}

			if (StringUtils.isBlank(rsJson)) {
				throw new IllegalArgumentException("Some needed params are null or empty.");
			}

			ResultSet<?> rs = ResultSet.fromJson(rsJson);

			ResultSet<String> mappedRs = null;
			if ((xslt == null) || xslt.isEmpty()) {
				mappedRs = (ResultSet<String>) rs;
			} else if ((xsltParams == null) || xsltParams.isEmpty()) {

				mappedRs = resultSetFactory.xsltMap(rs, xslt);
			} else {
				mappedRs = resultSetFactory.xsltMap(rs, xslt, xsltParams);

			}

			core.importFromResultset(db, mappedRs);
			getBlackboardHandler().done(job);
			log.info("IMPORT job set to DONE");
		} else if (action.equals("EXEC")) {
			String db = job.getParameters().get("db");
			String sql = job.getParameters().get("sql");

			if ((db == null) || db.isEmpty() || (sql == null) || sql.isEmpty())
				throw new IllegalArgumentException("Some needed params are null or empty.");

			log.info("EXECUTING SCRIPT: " + sql + " on " + db);
			databaseUtils.executeSql(db, sql);
			getBlackboardHandler().done(job);
			log.info("SCRIPT COMPLETED");
		} else {
			throw new IllegalArgumentException("unsupported message action: " + action);
		}
	}

	private String decodeBase64(final String s) {
		if ((s != null) && Base64.isBase64(s.getBytes())) return new String(Base64.decodeBase64(s.getBytes()));
		return s;
	}

	public DatabaseServiceCore getCore() {
		return core;
	}

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

	public ExecutorService getThreadPool() {
		return threadPool;
	}

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

}
