/**
 * 
 */
package eu.dnetlib.data.collective.manager;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

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

import eu.dnetlib.common.interfaces.ws.IDriverService;
import eu.dnetlib.common.profile.ResourceDao;
import eu.dnetlib.data.collective.manager.log.LogInfoService;
import eu.dnetlib.data.collective.manager.nh.ActivityListener;
import eu.dnetlib.data.collective.manager.nh.INotificationConsumer;
import eu.dnetlib.data.collective.manager.nh.ServiceActivity;
import eu.dnetlib.data.collective.manager.profile.AbstractInstance;
import eu.dnetlib.data.collective.manager.utils.InstanceRegistry;
import eu.dnetlib.data.collective.manager.utils.ServiceRegistry;
import eu.dnetlib.data.information.DataSourceResolver;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
import eu.dnetlib.enabling.tools.ServiceLocator;
import eu.dnetlib.enabling.tools.blackboard.ActionStatus;

/**
 * Abstract class that manages worker services and their jobs
 * 
 * @author jochen
 * @param <T> type of worker service to manage
 * @param <E> type of instance datastructure
 *
 */
public abstract class WorkerServiceManager<T extends IDriverService, E extends AbstractInstance> implements ActivityListener, IWorkerServiceManager, INotificationConsumer{

	private static final Log log = LogFactory.getLog(WorkerServiceManager.class);
	
	//private String workerServiceResourceType;
	
	private String serviceResourcesXQuery;
	
	@Resource(name = "dataSourceResolver")
	protected DataSourceResolver dataSourceResolver;
	
	@Resource(name = "resourceDao")
	protected ResourceDao resourceDao;
	
	@Resource(name = "serviceRegistry")
	protected ServiceRegistry<T> serviceRegistry;
	
	
	@Resource(name = "instanceRegistry")
	protected InstanceRegistry<E> instanceRegistry;
	
	@Resource(name = "registryLocator")
	protected ServiceLocator<ISRegistryService> registryLocator;
	
	@Resource(name = "lookupLocator")
	protected ServiceLocator<ISLookUpService> lookupLocator;
	
	@Resource(name = "serviceActivityRegistry")
	protected IWorkerServiceActivityProvider serviceActivityRegistry;
	
	protected LogInfoService logInfoService;

	protected IInstanceService uiInstanceService;

	public void init(){
		// initial lookUp for registered worker services
		List<eu.dnetlib.common.profile.Resource> resources = resourceDao.getResources(getServiceResourcesXQuery());
		log.debug("found " + resources.size() + " worker services.");
		for (eu.dnetlib.common.profile.Resource r: resources){			
			serviceRegistry.add(r.getValue("//RESOURCE_IDENTIFIER/@value"), r.getValue("//RESOURCE_URI/@value"));
		}		
	}

	/**
	 * process of ActionStatus.DONE
	 * @param aInstance
	 * @param aParameters
	 * @param aDate the date of the last message
	 */
	protected abstract void done(E aInstance, Map<String, String> aParameters, String aDate);
	
	/**
	 * process of ActionStatus.FAILED
	 * @param aInstance
	 * @param aParameters
	 * @param aDate the date of the last message
	 */
	protected abstract void failed(E aInstance, Map<String, String> aParameters, String aDate);
	
	/**
	 * process of ActionsStatus.ONGOING
	 * @param aInstance
	 * @param aParameters
	 */
	protected abstract void ongoing(E aInstance, Map<String, String> aParameters, String aDate);
	
	@Override
	public abstract void processActivity(ActionStatus status, String date,
			Map<String, String> parameters);
	
	@Required
	public void setServiceRegistry(ServiceRegistry<T> registry){
		this.serviceRegistry = registry;
	}
		
	@Override
	public ServiceRegistry<T> getServiceRegistry() {
		return serviceRegistry;
	}

	public void setResourceDao(ResourceDao resourceDao) {
		this.resourceDao = resourceDao;
	}

	public ResourceDao getResourceDao() {
		return resourceDao;
	}

//	@Required
//	public void setWorkerServiceResourceType(String workerServiceResourceType) {
//		this.workerServiceResourceType = workerServiceResourceType;
//	}
//
//	public String getWorkerServiceResourceType() {
//		return workerServiceResourceType;
//	}

	public void setInstanceRegistry(InstanceRegistry<E> instanceRegistry) {
		this.instanceRegistry = instanceRegistry;
	}

	public InstanceRegistry<E> getInstanceRegistry() {
		return instanceRegistry;
	}
	
	public ServiceLocator<ISRegistryService> getRegistryLocator() {
		return this.registryLocator;
	}

	public void setRegistryLocator(ServiceLocator<ISRegistryService> registryLocator) {
		this.registryLocator = registryLocator;
	}
	
//	protected String getXquery_serviceResources(){
//		return "collection('/db/DRIVER/ServiceResources')//RESOURCE_PROFILE[.//RESOURCE_TYPE/@value = '" 
//		+ workerServiceResourceType + "']";
//	}

	public DataSourceResolver getDataSourceResolver() {
		return dataSourceResolver;
	}

	public void setDataSourceResolver(DataSourceResolver dataSourceResolver) {
		this.dataSourceResolver = dataSourceResolver;
	}
	
	protected Date parseDate(String aDate){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
		try {
			return sdf.parse(aDate);
		} catch (ParseException e) {
			log.error(e);
		}
		return null;
	}

	@Override
	public boolean addResource(eu.dnetlib.common.profile.Resource aResource) {
		return this.serviceRegistry.add(aResource.getValue("//RESOURCE_IDENTIFIER/@value"), aResource.getValue("//RESOURCE_URI/@value"));
	}

	@Override
	public boolean removeResource(eu.dnetlib.common.profile.Resource aResource) {
		return this.serviceRegistry.remove(aResource.getValue("//RESOURCE_IDENTIFIER/@value"));
	}

	@Override
	public boolean updateResource(eu.dnetlib.common.profile.Resource aResource) {
		return false;
	}

	/**
	 * updates the instance resource profile by the ISRegistryService and notifies the UI component to update using the serviceActivity
	 * @param aInstance
	 * @param aServiceActivity
	 * @throws ISRegistryException
	 */
	public void updateAll(E aInstance, ServiceActivity aServiceActivity) throws ISRegistryException{
		this.uiInstanceService.update(aServiceActivity);		
		this.registryLocator.getService().updateProfile(aInstance.getResourceId(), aInstance.getResource().getResource().asXML(), aInstance.getResourceType());
	}

	/**
	 * @return the logInfoService
	 */
	public LogInfoService getLogInfoService() {
		return logInfoService;
	}


	/**
	 * @param logInfoService the logInfoService to set
	 */
	public void setLogInfoService(LogInfoService logInfoService) {
		this.logInfoService = logInfoService;
	}

	/**
	 * @param uiInstanceService the uiInstanceService to set
	 */
	public void setUiInstanceService(IInstanceService uiInstanceService) {
		this.uiInstanceService = uiInstanceService;
	}

	/**
	 * @return the uiInstanceService
	 */
	public IInstanceService getUiInstanceService() {
		return uiInstanceService;
	}

	/**
	 * @return the lookupLocator
	 */
	public ServiceLocator<ISLookUpService> getLookupLocator() {
		return lookupLocator;
	}

	/**
	 * @param lookupLocator the lookupLocator to set
	 */
	public void setLookupLocator(ServiceLocator<ISLookUpService> lookupLocator) {
		this.lookupLocator = lookupLocator;
	}

	/**
	 * @return the serviceActivityRegistry
	 */
	public IWorkerServiceActivityProvider getServiceActivityRegistry() {
		return serviceActivityRegistry;
	}

	/**
	 * @param serviceActivityRegistry the serviceActivityRegistry to set
	 */
	public void setServiceActivityRegistry(
			IWorkerServiceActivityProvider serviceActivityRegistry) {
		this.serviceActivityRegistry = serviceActivityRegistry;
	}

	/**
	 * @return the serviceResourcesXQuery
	 */
	public String getServiceResourcesXQuery() {
		return serviceResourcesXQuery;
	}

	/**
	 * @param serviceResourcesXQuery the serviceResourcesXQuery to set
	 */
	@Required
	public void setServiceResourcesXQuery(String serviceResourcesXQuery) {
		this.serviceResourcesXQuery = serviceResourcesXQuery;
	}


}
