/**
 * RuleSetInvoker.java
 * Created May 28, 2009
 * Copyright (c) Tandberg Television 2009
 */
package com.tandbergtv.watchpoint.pmm.job.callback;

import static com.tandbergtv.watchpoint.pmm.job.util.JobScheduleInfoConstants.JOB_IS_ASSOCIATED_WITH_TITLES;
import static com.tandbergtv.watchpoint.pmm.job.util.JobScheduleInfoConstants.JOB_NAME;
import static com.tandbergtv.watchpoint.pmm.job.util.JobScheduleInfoConstants.JOB_PARAMETERS;
import static com.tandbergtv.watchpoint.pmm.job.util.JobScheduleInfoConstants.RULESET_ID;
import static com.tandbergtv.watchpoint.pmm.job.util.JobScheduleInfoConstants.TITLES;
import static javax.jms.Session.AUTO_ACKNOWLEDGE;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.Context;
import javax.naming.InitialContext;

import org.apache.log4j.Logger;

import com.tandbergtv.watchpoint.pmm.entities.JobParameter;
import com.tandbergtv.watchpoint.pmm.entities.Title;

/**
 * Invokes a rule set, with parameters if available
 * 
 * @author Sahil Verma
 */
public class RuleSetInvoker extends AbstractJobCallback {
	
	private static final String QUEUE_NAME = "queue/EventQueue";
	
	private static final Logger logger = Logger.getLogger(RuleSetInvoker.class);

	/**
	 * @param next
	 */
	public RuleSetInvoker(IJobCallback next) {
		super(next);
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.job.callback.IJobCallback#executeJob(java.util.Map, java.util.Date)
	 */
	@Override
	public void executeJob(Map<String, Object> data, Date date) {
		String id = getRuleSetId(data);
		List<Long> titles = getTitles(data);

		boolean isAssociatedWithTitles = ((Boolean) data
				.get(JOB_IS_ASSOCIATED_WITH_TITLES)).booleanValue();
		// Do not invoke the ruleset if this job is associated with titles
		// and there were no titles in the map.
		if (titles.isEmpty() && isAssociatedWithTitles) {
			super.executeJob(data, date);
			return;
		}
		
		if (id != null) {
			QueueSession session = null;
			QueueSender sender = null;
			QueueConnection connection = null;
			
			try {
				logger.debug("Calling rule engine");
				
				Context context = new InitialContext();
				QueueConnectionFactory queueFactory = (QueueConnectionFactory) context.lookup("ConnectionFactory");
				
				connection = queueFactory.createQueueConnection();
				session = connection.createQueueSession(false, AUTO_ACKNOWLEDGE);
				
				Queue queue = (Queue) context.lookup(QUEUE_NAME);
				
				sender = session.createSender(queue);
				
				Message message = session.createObjectMessage();
				
				message.setStringProperty("ruleSetId", id);
				
				/* If we send an empty list of title ids, the rule engine doesn't bother 
				 * searching for titles */
				if (!titles.isEmpty())
					message.setObjectProperty("titleIds", titles.toString());
		        
		        sender.send(queue, message);
			} catch (Exception e) {
				logger.warn("Problem during job " + data.get(JOB_NAME) + " execution", e);
			} finally {
				try {
					connection.close();
				} catch (JMSException e1) {
					logger.warn("Problems cleaning up after sending message", e1);
				}
			}
		}
		
		super.executeJob(data, date);
	}
	
	@SuppressWarnings("unchecked")
	private String getRuleSetId(Map<String, Object> data) {
		Collection<JobParameter> parameters = (Collection<JobParameter>) data.get(JOB_PARAMETERS);
		
		for (JobParameter parameter : parameters) {
			if (parameter.getName().equals(RULESET_ID)) {
				logger.debug("Found ruleset " + parameter.getValue());
				return parameter.getValue();
			}
		}
		
		return null;
	}
	
	@SuppressWarnings("unchecked")
	private List<Long> getTitles(Map<String, Object> data) {
		List<Long> titles = new ArrayList<Long>();
		
		if (data.containsKey(TITLES)) {
			for (Title title : (Collection<Title>) data.get(TITLES))
				titles.add(title.getId());
		}
		
		return titles;
	}
}
