/**
 * Copyright 2008-2009 DRIVER PROJECT (Bielefeld University)
 * Original author: Marek Imialek <marek.imialek at uni-bielefeld.de>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package eu.dnetlib.common.ws;

import org.apache.log4j.Logger;

import javax.xml.ws.Endpoint;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationContext;

import eu.dnetlib.common.utils.XMLUtils;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.is.sn.rmi.ISSNService;
import eu.dnetlib.enabling.tools.OpaqueResource;
import eu.dnetlib.enabling.tools.StringOpaqueResource;
import eu.dnetlib.enabling.tools.registration.ServiceRegistrator;


/**
 * The Class RegisterServiceJob.
 * 
 * @author <a href="mailto:marek.imialek at uni-bielefeld.de">Marek Imialek</a>
 */
public class RegisterServiceJob implements Job {
	
	protected static final Logger log = Logger.getLogger(RegisterServiceJob.class);
	
	/** The Constant APPLICATION_CONTEXT_KEY. */
	private static final String APPLICATION_CONTEXT_KEY = "applicationContext";
	
	/* (non-Javadoc)
	 * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
	 */
	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException{
		
		String profile = null;
		RegisterServiceJobProperties registerServiceProperties = null;
		
		try {
			ApplicationContext	 appCtx = getApplicationContext(context);	
			registerServiceProperties = 
				(RegisterServiceJobProperties) appCtx.getBean("RegisterServiceProperties");
			String serviceName = registerServiceProperties.getServiceName();
			String serviceHost = 
				registerServiceProperties.getServiceBaseAddress()+"/"+ serviceName;
			boolean blackboardRegistration = 
				registerServiceProperties.getBlackboardRegistration();
			ISLookUpService lookUpService = 
				(ISLookUpService) appCtx.getBean("lookUpService");
			ISSNService snService = 
				(ISSNService) appCtx.getBean("snService");
			
			try {
				
				String xQuery = 
					"collection('/db/DRIVER/ServiceResources')//RESOURCE_PROFILE/HEADER" +
					"[RESOURCE_TYPE[@value='"+serviceName+"ResourceType']]" +
					"[PROTOCOLS/PROTOCOL[@address='"+serviceHost+"']]"+
					"/RESOURCE_IDENTIFIER[@value]";
				
				log.info("Veryfing if service is registered in IS");
				profile = lookUpService.getResourceProfileByQuery(xQuery);
				
			} catch (ISLookUpException e) {
				if (e.getMessage().contains("Profile not found")) {
					log.debug("Service is not existing in IS Registry");
				}
				else {
					String message = "Failed to verify service profile in ISLookUp";
					log.error(message);
					throw (JobExecutionException) 
						new JobExecutionException(message).initCause(e);	
				}
			}	
			
			if (profile == null) {
				log.info("Registering Service in IS");
				ServiceRegistrator serviceRegistrator = 
					(ServiceRegistrator) appCtx.getBean("serviceRegistrator");
				Endpoint endpoint = 
					(Endpoint) appCtx.getBean(serviceName+"EndPointReference");
				
				String profId = serviceRegistrator.registerService(serviceName, endpoint);
				registerServiceProperties.setServiceProfileId(profId);
				
				log.debug("Validating service profile: "+ profId);
				String validprofId = serviceRegistrator.validateProfile(profId);
				log.debug("Service profile validated: " + validprofId);
				
				if (blackboardRegistration) {
					log.debug("Subscribing service to the BLACKBOARD/LAST_REQUEST element " +
							"in order to receive messages for the orchestration protocol");
					final OpaqueResource serviceProfile = 
						new StringOpaqueResource(lookUpService.getResourceProfile(validprofId));
					snService.subscribe(serviceRegistrator.getEprBuilder().getEndpointReference(endpoint),
							"UPDATE/" + serviceProfile.getResourceType() + "/" + validprofId 
							+ "/RESOURCE_PROFILE/BODY/BLACKBOARD/LAST_REQUEST", 0);
					log.debug("Subscribtion successful");	
				}
				
				boolean doSubscribe = false;
				if (registerServiceProperties.isSubscriptionEnabled())
					doSubscribe = true;
				
				if (doSubscribe) {
					log.debug("Subscribing specific topics");
					registerServiceProperties.getSubscriptionObject().setParameter(snService, validprofId, serviceHost);
					registerServiceProperties.getSubscriptionObject().initSubscriptions();
					log.debug("Subscribing specific topics successful");
				}
				
				log.info("Service registration successful.");
			}
			else {
				String message = "This Service is already registered in IS: " + profile;
				log.warn(message);
				registerServiceProperties.setServiceProfileId(XMLUtils.evaluate(profile, "/RESOURCE_IDENTIFIER/@value"));
			}
		} catch (Exception e) {
			String message = "Failed to register service in Information Service";
			log.error(message);
			throw (JobExecutionException)
				new JobExecutionException(message).initCause(e);
		}
		
	}
	
	/**
	 * Gets the application context.
	 * 
	 * @param context
	 *            the context
	 * 
	 * @return the application context
	 * @throws SchedulerException 
	 *	 
	 */
	private ApplicationContext getApplicationContext(JobExecutionContext context )
    	throws JobExecutionException {
		
        ApplicationContext appCtx = null;
        try {
        	appCtx = (ApplicationContext)context
        		.getScheduler().getContext()
        		.get(APPLICATION_CONTEXT_KEY);
        
        	if (appCtx == null) {
        		throw new JobExecutionException(
                    "No application context available in scheduler" +
                    " context for key \"" + APPLICATION_CONTEXT_KEY + "\"");
        	}
        	
        } catch (SchedulerException e) {
        	throw (JobExecutionException) 
				new JobExecutionException(
					"Failed to get service context file.")
				.initCause(e);
        }
        
        return appCtx;
    }
	

}
