package eu.dnetlib.common.services;

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

import com.google.gson.Gson;

import eu.dnetlib.common.ifaces.BlackboardExecutionCallback;
import eu.dnetlib.enabling.annotations.Blackboard;

public abstract class BlackboardAction<T> {

	private Class<T> messageClass;

	private static final Log log = LogFactory.getLog(BlackboardAction.class);

	abstract protected void doExecute(final T message, final BlackboardExecutionCallback<T> callback) throws Exception;

	@SuppressWarnings("unchecked")
	final public void execute(final Object message, final BlackboardExecutionCallback<Object> callback) {
		if (message == null) {
			log.error("BB message is null");
			throw new RuntimeException("BB message is null");
		}

		T msgObj;
		if (message instanceof String) {
			msgObj = new Gson().fromJson((String) message, messageClass);
		} else if (messageClass.isInstance(message)) {
			msgObj = messageClass.cast(message);
		} else {
			log.error("Invalid bb message class, expected: " + getMessageClass() + ", found: " + message.getClass());
			throw new RuntimeException("Invalid bb message class, expected: " + getMessageClass() + ", found: " + message.getClass());
		}

		try {
			doExecute(msgObj, (BlackboardExecutionCallback<T>) callback);
		} catch (Throwable e) {
			log.error("Blackboard execution failed", e);
			((BlackboardExecutionCallback<T>) callback).fail(msgObj);
		}

	}

	final public String getName() {
		if (messageClass.isAnnotationPresent(Blackboard.class)) {
			return messageClass.getAnnotation(Blackboard.class).action();
		} else {
			throw new RuntimeException("Missing Blackboard annatotion in class: " + messageClass.getSimpleName());
		}
	}

	public Class<T> getMessageClass() {
		return messageClass;
	}

	@Required
	public void setMessageClass(final Class<T> messageClass) {
		this.messageClass = messageClass;
	}

}
