package eu.dnetlib.enabling.nodeManager;

import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

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

import eu.dnetlib.common.services.AbstractBaseService;
import eu.dnetlib.common.services.BlackboardAction;
import eu.dnetlib.common.services.ServiceNameResolver;
import eu.dnetlib.common.services.locators.DnetServiceLocator;
import eu.dnetlib.enabling.blackboard.BlackboardRegistry;
import eu.dnetlib.rmi.objects.is.DnetService;
import eu.dnetlib.rmi.soap.InformationService;
import eu.dnetlib.rmi.soap.exceptions.InformationServiceException;

public class NodeServicesRegistrator {

	@Resource
	private InformationService informationService;

	@Resource
	private List<AbstractBaseService> services;

	@Resource
	private DnetServiceLocator serviceLocator;

	@Resource
	private BlackboardRegistry blackboardRegistry;

	private boolean allDone = false;
	private static final Log log = LogFactory.getLog(NodeServicesRegistrator.class);

	public void register() throws Exception {
		synchronized (this) {
			if (!allDone) {
				registerServices();
				addBlackboardSubscriptions();
				log.info("*** Services and subscriptions have been registered ***");
				allDone = true;
			}
		}
	}

	private void addBlackboardSubscriptions() throws InformationServiceException {
		final String managerId = findNodeManagerService().getServiceId();

		informationService.deleteAllServiceSubscriptions(managerId);

		log.info("Old subscriptions deleted for nodeManager: " + managerId);

		for (AbstractBaseService service : services) {
			if (StringUtils.isNotBlank(service.getServiceId())) {
				for (BlackboardAction<?> action : service.getBlackboardActions()) {
					blackboardRegistry.registerAction(managerId, service.getServiceId(), action);
				}
			}
		}
		log.info("New subscriptions created for nodeManager: " + managerId);
	}

	private void registerServices() {
		try {
			for (AbstractBaseService service : services) {
				final String addr = service.getProtocols().get(service.getMainProtocol());
				if (StringUtils.isNotBlank(addr)) {
					final String id = informationService.registerService(asDnetService(service));
					service.setServiceId(id);
					log.info("Service " + id + " registered/updated");
				} else {
					log.error("MainProtocol (" + service.getMainProtocol() + ") is missing, service: " + service.getClass());
				}
			}
		} catch (Throwable e) {
			log.warn("Service registration failed: " + e.getMessage());
			log.debug(e);
		}
	}

	private DnetService asDnetService(final AbstractBaseService s) {
		final DnetService srv = new DnetService();
		srv.setName(ServiceNameResolver.resolveServiceName(s.getClass()));
		srv.setDate(new Date());
		srv.setValid(true);
		srv.setProtocols(s.getProtocols());
		srv.setProperties(s.getProperties());
		return srv;
	}

	private NodeManagerServiceImpl findNodeManagerService() {
		for (AbstractBaseService s : services) {
			if (s instanceof NodeManagerServiceImpl) { return (NodeManagerServiceImpl) s; }
		}
		throw new RuntimeException("NodeManager service not found");
	}
}
