/*
 * Created on Jul 31, 2006
 * 
 * (C) Copyright TANDBERG Television Ltd.
 */

package com.tandbergtv.workflow.webservice.filesubsystem;

import java.util.Iterator;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;

import org.apache.axis.MessageContext;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import com.tandbergtv.workflow.message.WorkflowMessage;
import com.tandbergtv.workflow.message.util.MarshalException;
import com.tandbergtv.workflow.message.util.Unmarshaller;

/**
 * Class that helps parse the incoming SOAP requests.
 * 
 * @author Vijay Silva
 */
public final class RequestHandler
{
	private static final String WORKFLOW_MESSAGE_ELEMENT = "WFSMessage";

	private static RequestHandler instance = null;

	private DocumentBuilder docBuilder = null;

	/**
	 * Singleton Accessor Method.
	 * 
	 * @return The Singleton Instance.
	 * @throws ParserConfigurationException
	 */
	public synchronized static RequestHandler getInstance() throws ParserConfigurationException
	{
		if (instance == null)
			instance = new RequestHandler();

		return instance;
	}

	/*
	 * Internal Constructor to instantiate the singleton instance.
	 */
	private RequestHandler() throws ParserConfigurationException
	{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setNamespaceAware(true);

		this.docBuilder = factory.newDocumentBuilder();
	}

	/**
	 * Method to Parse the incoming SOAP Envelope and read the Workflow Message contained in the
	 * request.
	 * 
	 * @param request
	 *            The SOAP Envelope request
	 * 
	 * @return The Workflow Message contained in the request
	 * 
	 * @throws OperationException
	 *             Error parsing the request object.
	 */
	public WorkflowMessage parseRequest(SOAPEnvelope request) throws OperationException
	{
		try
		{
			/* extract soap request from the envelope */
			SOAPMessage soapMessage = MessageContext.getCurrentContext().getMessage();
			SOAPBody body = soapMessage.getSOAPBody();

			/* get Workflow Message Element - assuming there is only one */
			Element workflowMessageElement = null;
			Iterator iterator = body.getChildElements();
			while (iterator.hasNext())
			{
				Element element = (Element) iterator.next();
				if (element.getNodeName().equals(WORKFLOW_MESSAGE_ELEMENT))
				{ // found the match
					workflowMessageElement = element;
					break;
				}
			}

			/* Failed to find the Workflow Message Element */
			if (workflowMessageElement == null)
			{ // Invalid request
				String error = "Failed to find the Workflow Message in the SOAP request,"
						+ " unable to process request.";
				throw new OperationException(error);
			}

			Document workflowMessageDocument = docBuilder.newDocument();
			Node messageNode = workflowMessageDocument.importNode(workflowMessageElement, true);
			workflowMessageDocument.appendChild(messageNode);

			WorkflowMessage message = Unmarshaller.unmarshal(workflowMessageDocument);

			return message;
		}
		catch (SOAPException se)
		{
			String msg = "Failed to read the SOAP Envelope for the File Subsystem request.";
			throw new OperationException(msg, se);
		}
		catch (DOMException de)
		{
			String msg = "Failed to import the Workflow Message element into a new XML Document.";
			throw new OperationException(msg, de);
		}
		catch (MarshalException me)
		{
			String msg = "Failed to unmarshal the Workflow Message element in the File Subsystem request.";
			throw new OperationException(msg, me);
		}
		catch (Exception ex)
		{
			String msg = "Unexpected error when parsing the SOAP Envelope containing the File Subsystem request.";
			throw new OperationException(msg, ex);
		}
	}
}
