/*
 * Created on Jul 31, 2006
 * 
 * (C) Copyright TANDBERG Television Ltd.
 */

package com.tandbergtv.workflow.webservice.filesubsystem.messagehandler;

import java.util.Map;

/**
 * Factory to generate the Handler given the appropriate Message UID
 * 
 * @author Vijay Silva
 */
public class MessageHandlerFactory
{
	private static MessageHandlerFactory instance = null;

	private Map<String, MessageConfiguration> configurationMap = null;

	/**
	 * Singleton accessor method
	 * 
	 * @return The Singleton instance
	 * 
	 * @throws MessageHandlerConfigurationException
	 *             Error parsing the Message Handler configuration
	 */
	public synchronized static MessageHandlerFactory getInstance()
			throws MessageHandlerConfigurationException
	{
		if (instance == null)
			instance = new MessageHandlerFactory();

		return instance;
	}

	/*
	 * Default Constructor
	 */
	private MessageHandlerFactory() throws MessageHandlerConfigurationException
	{
		// Need to parse the XML and load the map
		configurationMap = MessageHandlerConfigReader.readConfiguration();
	}

	/**
	 * Method to get the Message Handler configured for a Message UID
	 * 
	 * @param messageUID
	 *            The Message UID
	 * 
	 * @return The Message Handler configured for the UID
	 * 
	 * @throws MessageHandlerConfigurationException
	 *             Exception thrown when the Message UID is not configured or the configured class
	 *             does not exist or is not a Message Handler.
	 */
	public MessageHandler getMessageHandler(String messageUID)
			throws MessageHandlerConfigurationException
	{
		if (messageUID != null)
			messageUID = messageUID.trim();

		MessageConfiguration config = this.configurationMap.get(messageUID);
		String className = (config != null) ? config.getHandlerClassName() : null;
		if (className == null)
		{
			String msg = "The Message UID: " + messageUID
					+ " does not have a Message Handler configured for it.";
			throw new MessageHandlerConfigurationException(msg);
		}

		// Try and instantiate the configured class
		return loadMessageHandler(className);
	}

	/**
	 * This method checks whether the specified message UID requires asynchronous handling
	 * 
	 * @param messageUID
	 *            The Message UID to check
	 * 
	 * @return true if the message requires asynchronous handling, false otherwise.
	 * 
	 * @throws MessageHandlerConfigurationException
	 *             No configuration is present for the specified UID.
	 */
	public boolean isMessageAsynchronous(String messageUID) throws MessageHandlerConfigurationException
	{
		if (messageUID != null)
			messageUID = messageUID.trim();

		MessageConfiguration config = this.configurationMap.get(messageUID);

		if (config == null)
		{
			String msg = "The Message UID: " + messageUID
					+ " is not configured and cannot be handled.";
			throw new MessageHandlerConfigurationException(msg);
		}

		return (!config.isSynchronous());
	}

	/**
	 * Get the Response UID for the specified Message UID. Returns null if the message is
	 * synchronous.
	 * 
	 * @param messageUID
	 *            The Message UID
	 * 
	 * @return The Response UID for the input UID.
	 * 
	 * @throws MessageHandlerConfigurationException
	 *             Exception if the input UID is not configured.
	 */
	public String getResponseUID(String messageUID) throws MessageHandlerConfigurationException
	{
		if (messageUID != null)
			messageUID = messageUID.trim();

		MessageConfiguration config = this.configurationMap.get(messageUID);

		if (config == null)
		{
			String msg = "The Message UID: " + messageUID
					+ " is not configured and cannot be handled.";
			throw new MessageHandlerConfigurationException(msg);
		}

		return config.getResponseUID();
	}

	/*
	 * Method to load the Message Handler given the class name
	 */
	private MessageHandler loadMessageHandler(String className)
			throws MessageHandlerConfigurationException
	{
		Object handlerClass = null;

		try
		{
			Class<?> refClass = Class.forName(className);
			handlerClass = refClass.newInstance();
		}
		catch (Exception ex)
		{
			String msg = "Failed to create instance of Message Handler class: " + className;
			throw new MessageHandlerConfigurationException(msg, ex);
		}

		if (!(handlerClass instanceof MessageHandler))
		{
			String msg = "The configured Message Handler class: " + className
					+ " does not implement: " + MessageHandler.class.getName();
			throw new MessageHandlerConfigurationException(msg);
		}

		return (MessageHandler) handlerClass;
	}
}
