package eu.dnetlib.enabling.blackboard;

import java.util.Date;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.common.collect.Maps;
import com.google.gson.Gson;

import eu.dnetlib.common.ifaces.BlackboardExecutionCallback;
import eu.dnetlib.common.services.BlackboardAction;
import eu.dnetlib.rmi.objects.is.BlackboardActionStatus;
import eu.dnetlib.rmi.objects.is.BlackboardMessageContainer;
import eu.dnetlib.rmi.objects.is.Operation;
import eu.dnetlib.rmi.objects.is.Subscription;
import eu.dnetlib.rmi.soap.InformationService;
import eu.dnetlib.rmi.soap.exceptions.InformationServiceException;

public class BlackboardRegistry {

	@Resource
	private InformationService informationService;

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

	private Map<String, BlackboardAction<?>> actions = Maps.newHashMap();

	public void registerAction(final String managerId, final String serviceId, final BlackboardAction<?> action) throws InformationServiceException {
		final Map<String, Object> cond = Maps.newHashMap();
		cond.put("service", serviceId);
		cond.put("action", action.getName());
		final String subscrId = informationService.addSubscription(new Subscription(null, managerId, Operation.INSERT, "blackboard", cond));
		actions.put(subscrId, action);

		log.debug("BB Subscription " + subscrId + " -> " + action.getClass());
	}

	public void activateAction(final String subscrId, final BlackboardMessageContainer bbMessage) {

		final BlackboardAction<?> action = actions.get(subscrId);
		if (action == null) {
			throw new RuntimeException("No action has been registered for subscription " + subscrId);
		} else {
			try {
				updateBlackboard(BlackboardActionStatus.ONGOING, bbMessage);

				action.execute(bbMessage.getJsonMessage(), new BlackboardExecutionCallback<Object>() {

					@Override
					public void success(final Object input) {
						bbMessage.setJsonMessage(new Gson().toJson(input));
						updateBlackboard(BlackboardActionStatus.DONE, bbMessage);
						log.debug("MESSAGE: " + input);
					}

					@Override
					public void ongoing(final Object input) {
						bbMessage.setJsonMessage(new Gson().toJson(input));
						updateBlackboard(BlackboardActionStatus.ONGOING, bbMessage);
						log.debug("MESSAGE: " + input);
					}

					@Override
					public void fail(final Object input) {
						bbMessage.setJsonMessage(new Gson().toJson(input));
						updateBlackboard(BlackboardActionStatus.FAILED, bbMessage);
						log.debug("MESSAGE: " + input);
					}
				});
			} catch (Throwable e) {
				bbMessage.setJsonMessage(new Gson().toJson(e));
				updateBlackboard(BlackboardActionStatus.FAILED, bbMessage);
			}
		}
	}

	private void updateBlackboard(final BlackboardActionStatus status, final BlackboardMessageContainer bbMessage) {
		try {
			bbMessage.setStatus(status);
			bbMessage.setDate(new Date());
			informationService.updateBlackBoardMessage(bbMessage);
		} catch (InformationServiceException e) {
			log.error("Error updating blackboard message: " + bbMessage);
		}
	}

	public boolean requiresBlackboardAction(final String subscrId) {
		return actions.containsKey(subscrId);
	}

}
