/**
 * WorkflowMessage.java
 * Created Apr 26, 2006
 * Copyright (C) Tandberg Television 2006
 */
package com.tandbergtv.workflow.message;

import java.util.Map;

import com.tandbergtv.workflow.comm.IDestination;
import com.tandbergtv.workflow.comm.ISource;

/**
 * The WorkflowMessage class encapsulates a message that originates from or is
 * addressed to the workflow system.
 * 
 * It carries a payload consisting of a collection of name-value tuples.
 * 
 * @author Sahil Verma
 */
public class WorkflowMessage {

	protected IMessageUID uid;
	
	protected IMessageKey key;

	protected WorkflowPayload payload;

	protected IMessageAttachment attachment;
	
	protected ISource source;
	
	protected IDestination responseDestination;
	
	protected MessageType type;
	
	protected WPCLCommand command;

	/**
	 * Creates a WorkflowMessage with the 'control' MessageType.
	 * 
	 * @param uid
	 *            The Message UID
	 */
	public WorkflowMessage(IMessageUID uid) {
		this(uid, null, MessageType.control);
	}

	/**
	 * Creates a Workflow Message with the 'control' MessageType.
	 * 
	 * @param uid
	 *            The Message UID
	 * @param key
	 *            The Message Correlation Key
	 */
	public WorkflowMessage(IMessageUID uid, IMessageKey key) {
		this(uid, key, MessageType.control);
	}

	/**
	 * Creates a Workflow Message.
	 * 
	 * @param uid
	 *            The Message UID
	 * @param type
	 *            The Message Type
	 */
	public WorkflowMessage(IMessageUID uid, MessageType type) {
		this(uid, null, type);
	}

	/**
	 * Creates a Workflow Message.
	 * 
	 * @param uid
	 *            The Message UID
	 * @param key
	 *            The Message Correlation Key
	 * @param type
	 *            The Message Type
	 */
	public WorkflowMessage(IMessageUID uid, IMessageKey key, MessageType type) {
		this.key = key;
		this.uid = uid;
		this.type = type;
		this.payload = new WorkflowPayload();
	}

	/**
	 * Gets the Message UID
	 * 
	 * @return The Message UID
	 */
	public IMessageUID getMessageUID() {
		return this.uid;
	}

	/**
	 * Sets the Message UID
	 * 
	 * @param uid
	 *            The Message UID
	 */
	public void setMessageUID(IMessageUID uid) {
		this.uid = uid;
	}
	
	/**
	 * Gets the Message Key
	 * 
	 * @return the Message Key.
	 */
	public IMessageKey getKey() {
		return this.key;
	}

	/**
	 * Sets the Message Key
	 * 
	 * @param key
	 *            The Message key.
	 */
	public void setKey(IMessageKey key) {
		this.key = key;
	}

	/**
	 * Gets the Workflow Payload.
	 * 
	 * @return The Message Payload.
	 */
	public WorkflowPayload getPayload() {
		return this.payload;
	}

	/**
	 * Sets the Workflow Payload
	 * 
	 * @param payload
	 *            The Workflow Payload
	 */
	public void setPayload(WorkflowPayload payload) {
		if(payload == null)
			payload = new WorkflowPayload();

		this.payload = payload;
	}
	
	/**
	 * Returns the value of the parameter in the payload
	 * 
	 * @param name The Key in the payload
	 * @return The value associated with the key in the payload.
	 */
	public String getValue(String name) {
		return this.payload.getValue(name);
	}
	
	/**
	 * Convenience method to add a simple key-value pair to the message
	 * @param name
	 * @param value
	 */
	public void putValue(String name, String value) {
		this.payload.putValue(name, value);
	}

	/**
	 * @return Returns the type.
	 */
	public MessageType getType() {
		return this.type;
	}
	
	/**
	 * @param type The type to set.
	 */
	public void setType(MessageType type) {
		this.type = type;
	}
	
	/**
	 * @return The WPCL command
	 */
	public WPCLCommand getCommand() {
		return this.command;
	}
	
	/**
	 * @param command the command to set
	 */
	public void setCommand(WPCLCommand command) {
		this.command = command;
	}

	/**
	 * Gets the Attachment associated with this message
	 * 
	 * @return The Message Attachment
	 */
	public IMessageAttachment getAttachment() {
		return this.attachment;
	}
	
	/**
	 * Adds the specified attachment, overwrites any existing attachment
	 * 
	 * @param attachment The attachment.
	 */
	public void addAttachment(IMessageAttachment attachment) {
		this.attachment = attachment;
	}

	/**
	 * @return Returns the source.
	 */
	public ISource getSource() {
		return this.source;
	}

	/**
	 * @param source
	 */
	public void setSource(ISource source) {
		this.source = source;
	}

	/**
	 * @return Returns the responseDestination.
	 */
	public IDestination getResponseDestination() {
		return responseDestination;
	}

	/**
	 * @param responseDestination The responseDestination to set.
	 */
	public void setResponseDestination(IDestination responseDestination) {
		this.responseDestination = responseDestination;
	}
	
	/**
	 * Matches this message agains the specified parameters
	 * 
	 * @param parameters
	 * @return true if all the specified parameters match the ones' in this message, false if the
	 * set of specified parameters is null or empty (in which case we're most likely matching based
	 * on the request key) 
	 */
	public boolean match(Map<String, Object> parameters) {
		if (parameters == null || parameters.isEmpty())
			return false;
		
		for (String name : parameters.keySet()) {
			Object value = parameters.get(name);
			
			if (!value.equals(getValue(name)))
				return false;
		}
		
		return true;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		StringBuilder buf = new StringBuilder();
		
		buf.append("Message [").append(this.uid).append("], payload=").append(this.payload);
		if (this.attachment != null)
			buf.append(", attachment=").append(this.attachment);
		
		return buf.toString();
	}

	/**
	 * Enumeration of the different types of Message Types that a Workflow Message can be. 
	 */
	public enum MessageType {
		control,
		ack,
		nack,
		notification,
		error
	}
}
