/*****************************************************************
 JADE - Java Agent DEvelopment Framework is a framework to develop 
 multi-agent systems in compliance with the FIPA specifications.
 Copyright (C) 2000 CSELT S.p.A. 
 
 GNU Lesser General Public License
 
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation, 
 version 2.1 of the License. 
 
 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the
 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA  02111-1307, USA.
 *****************************************************************/

package jade.lang.acl;

import java.io.Writer;
import java.io.IOException;
import java.util.Date;
import jade.util.leap.Serializable;

import jade.util.leap.Iterator;
import jade.util.leap.List;
import jade.util.leap.LinkedList;
import jade.util.leap.ArrayList;

import jade.core.AID;
import jade.core.CaseInsensitiveString;
import jade.core.messaging.TopicManagementHelper;
import jade.core.messaging.TopicUtility;

/**
 A pattern for matching incoming ACL messages. This class allows to
 build complex slot patterns to select ACL messages. These patterns
 can then be used in <code>receive()</code> operations.
 
 This class provide one method for each attribute of an ACLMessage, 
 that can be combined using the logic operators to create more complex 
 patterns.
 A user can also create an application-specific pattern. 
 In this case he has to implement the MatchExpression interface,
 writing the application specific <code>match()</code> method. 
 Then an instance of that class can be used as parameter of the MessageTemplate
 constructor to define the application specific MessageTemaplate.
 
 
 @see jade.core.Agent#receive(MessageTemplate mt)
 
 @author Giovanni Rimassa - Universita' di Parma
 @author Tiziana Trucco - Telecom Italia Lab S.p.A.
 @version $Date: 2008-10-09 14:07:18 +0200 (gio, 09 ott 2008) $ $Revision: 6052 $
 
 */
public class MessageTemplate implements Serializable {
	
	// Names of the various fields of an ACL messages.
	private static final int CONVERSATION_ID = 0;
	private static final int ENCODING = 1;
	private static final int IN_REPLY_TO = 2;
	private static final int LANGUAGE = 3;
	private static final int ONTOLOGY = 4;
	private static final int PROTOCOL = 5;
	private static final int REPLY_BY = 6;    
	private static final int REPLY_WITH = 7;
	private static final int RECEIVER = 9;
	private static final int REPLY_TO = 10;
	private static final int PERFORMATIVE = 11;
	private static final int CONTENT = 12;
	private static final int SENDER = 13;
	private static final int REPLY_BY_DATE = 14;
	
	/**
	 This interface must be overriden in order to define an application 
	 specific MessageTemplate.
	 In particular in the method <code> match()</code> the programmer
	 should realize the necessary checks on the ACLMessage in order 
	 to return <b>true</b> if the message match with the application 
	 specific requirements <b>false</b> otherwise.
	 */
	public static interface MatchExpression extends Serializable{
		/**
		 Check whether a given ACL message matches this
		 template. Concrete implementations of this interface will
		 have this method called to accept or refuse an ACL message.
		 @param msg The ACL message to match against this message
		 template.
		 @return A compliant implementation will return
		 <code>true</code> if the parameter ACL message matches the
		 template, and <code>false</code> otherwise.
		 */
		boolean match(ACLMessage msg);
	}
	
	private static class AndExpression implements MatchExpression {
		
		private MatchExpression op1;
		private MatchExpression op2;
		
		public AndExpression(MatchExpression e1, MatchExpression e2) {
			op1 = e1;
			op2 = e2;
		}
		
		public boolean match(ACLMessage msg) {
			return op1.match(msg) && op2.match(msg);
		}
		
		public String toString(){
			return "("+op1.toString()+  " AND " + op2.toString()+")";
		}
		
	} // End of AndExpression class
	
	private static class OrExpression implements MatchExpression{
		
		private MatchExpression op1;
		private MatchExpression op2;
		
		public OrExpression(MatchExpression e1, MatchExpression e2) {
			op1 = e1;
			op2 = e2;
		}
		
		public boolean match(ACLMessage msg) {
			return op1.match(msg) || op2.match(msg);
		}
		//only for debug
		public String toString(){
			return "("+op1.toString()+  " OR " + op2.toString()+")";
		}
		
	} // End of OrExpression class
	
	private static class NotExpression implements MatchExpression{
		private MatchExpression op;
		
		public NotExpression(MatchExpression e) {
			op = e;
		}
		
		public boolean match(ACLMessage msg) {
			return ! op.match(msg);
		}
		//only for debug
		public String toString(){
			return  "(NOT " + op.toString()+")";
		}
	} // End of NotExpression class
	
	private static class Literal implements MatchExpression{
		
		Object matchValue;
		int perfValue;
		int slotName;
		
		//Literal for all the string value to match: language, ontology,encoding...
		Literal(String matchValue, int slotName) {
			this.matchValue = matchValue;
			this.slotName = slotName;
		}
		
		//Literal for the sender value
		Literal(AID matchValue){
			this.matchValue = matchValue;
			this.slotName = SENDER;
		}
		//Literal for the receiver and replyTo slot.
		Literal(AID[] matchValue, int slotName){
			this.matchValue = matchValue;
			this.slotName = slotName;
		}
		
		//Literal for the performative slot
		Literal(int matchValue){
			this.perfValue = matchValue;
			this.slotName = PERFORMATIVE;
		}
		//literal for the reply_by_date slot.
		Literal(Date matchValue){
			this.matchValue=matchValue;
			this.slotName = REPLY_BY_DATE;
		}
		public boolean match(ACLMessage msg) {
			switch(slotName){
			
			case CONVERSATION_ID:
				return CaseInsensitiveString.equalsIgnoreCase((String)matchValue,msg.getConversationId());
			case REPLY_WITH:
				return CaseInsensitiveString.equalsIgnoreCase((String)matchValue,msg.getReplyWith());
			case PERFORMATIVE:
				return (perfValue == msg.getPerformative());
			case LANGUAGE:
				return CaseInsensitiveString.equalsIgnoreCase((String)matchValue,msg.getLanguage());
			case ONTOLOGY:
				return CaseInsensitiveString.equalsIgnoreCase((String)matchValue,msg.getOntology());
			case PROTOCOL:
				return CaseInsensitiveString.equalsIgnoreCase((String)matchValue,msg.getProtocol());
			case ENCODING:
				return CaseInsensitiveString.equalsIgnoreCase((String)matchValue,msg.getEncoding());
			case IN_REPLY_TO:
				return CaseInsensitiveString.equalsIgnoreCase((String)matchValue,msg.getInReplyTo());
				//  case(REPLY_BY):
				// return CaseInsensitiveString.equalsIgnoreCase((String)matchValue,msg.getReplyBy());
			case REPLY_BY_DATE:
				return ((Date)matchValue).equals(msg.getReplyByDate());
			case RECEIVER:
				if(matchValue != null){
					AID[] receivers = (AID[])matchValue;
					for(int i =0; i<receivers.length; i++){
						AID recToMatch = receivers[i];
						Iterator rec = msg.getAllReceiver();
						boolean found = false;
						while(rec.hasNext()){
							if(recToMatch.equals((AID)rec.next())){
								found = true;
								break; //out of the inner loop
							}
						}//end while
						if (found == false)
							return false;
					}//end for
					return true;
				}else
					return false;
				
			case REPLY_TO:
				if(matchValue != null){
					AID[] receivers = (AID[])matchValue;
					for(int i =0; i<receivers.length; i++){
						AID recToMatch = receivers[i];
						Iterator rec = msg.getAllReplyTo();
						boolean found = false;
						while(rec.hasNext()){
							if(recToMatch.equals((AID)rec.next())){
								found = true;
								break; //out of the inner loop
							}
						}//end while
						if (found == false)
							return false;
					}//end for
					return true;
				}else
					return false;
			case CONTENT://FIXME: verificare il caso in cui il contenuto e'in byte.
				return CaseInsensitiveString.equalsIgnoreCase((String)matchValue,msg.getContent());
			case SENDER:
				if(matchValue != null)
					return ((AID)matchValue).equals(msg.getSender());
				else
					return false;
				
			default:return false;
			}
		}
		
		//#MIDP_EXCLUDE_BEGIN
		//only for debug purpose.
		public String toString(){
			
			switch(slotName){
			
			case CONVERSATION_ID:
				return  "(ConversationId: " + (String)matchValue + ")";
			case ENCODING:
				return  "( Encoding: " +(String)matchValue + " )";
			case IN_REPLY_TO:
				return  "( InReplyTo: " + (String)matchValue + " )";
			case LANGUAGE:
				return  "( Language: " + (String)matchValue +  " )";
			case ONTOLOGY:
				return  "( Ontology: " + (String)matchValue + " )";
			case PROTOCOL:
				return  "( Protocol: " + (String)matchValue+  " )";
				// case(REPLY_BY):
				// return CaseInsensitiveString.equalsIgnoreCase((String)matchValue,msg.getReplyBy());
			case REPLY_BY_DATE:
				return  "( ReplyByDate: "+ (Date)matchValue + " )";
			case REPLY_WITH:
				return  "( ReplyWith: " + (String)matchValue + " )"; 
			case RECEIVER: 
				if(matchValue != null){
					AID[] receivers = (AID[])matchValue;
					String output =  "( Receivers: "; 
					for(int i =0; i<receivers.length; i++){
						AID recToMatch = receivers[i];
						output += recToMatch.toString();
					}
					return output +  ")" ;}
				else
					return  "(Receivers: null)"; 
			case REPLY_TO: //FIXME: da finire.
				if(matchValue != null){
					AID[] receivers = (AID[])matchValue;
					String output =  "( ReplyTo: "; 
					for(int i =0; i<receivers.length; i++){
						AID recToMatch = receivers[i];
						output += recToMatch.toString();
					}
					return output + " )" ;
				}else
					return  "(ReplyTo: null)" ;
			case PERFORMATIVE:
				return  "( Perfomative: " + ACLMessage.getPerformative(perfValue) + " )" ;
			case CONTENT:
				return  "( Content: " + (String)matchValue + ")";
			case SENDER:
				if(matchValue != null)
					return  "( Sender AID: " +  ((AID)matchValue).toString()+ ")" ;
				else
					return  "(Sender AID: null)" ;
				
			default:return  "No slot. This casa should never occur !!!" ;
			}
			
		}
		//#MIDP_EXCLUDE_END
	} // End of Literal class
	
	private static class MatchAllLiteral implements MatchExpression{
		//use this literal for a MessageTemplate who matches all ACLMessages
		MatchAllLiteral(){
		}
		
		public boolean match(ACLMessage msg){
			return true;
		}
		
		public String toString(){
			return  "Match ALL Template";     
		}
	}//end class MatchAllLiteral
	
	private static class CustomMsgLiteral implements MatchExpression{
		
		//use this literal for a messageTemplate matching the values of a given ACLMessage.
		ACLMessage messageToMatch;
		boolean matchPerformative;
		
		CustomMsgLiteral(ACLMessage msg,boolean matchPerformative){
			messageToMatch = msg;
			this.matchPerformative = matchPerformative;
		}

	    private static boolean compareByteArrays(byte[] a, byte[] a2) {
	        if (a==a2)
	            return true;
	        if (a==null || a2==null)
	            return false;

	        int length = a.length;
	        if (a2.length != length)
	            return false;

	        for (int i=0; i<length; i++)
	            if (a[i] != a2[i])
	                return false;

	        return true;
	    }

		public boolean match(ACLMessage msg){
			
			if(matchPerformative && (messageToMatch.getPerformative() != msg.getPerformative()))
				return false; 
			if(messageToMatch.hasByteSequenceContent()) {
				// we cannot use Array.equals() here because it is not available in MIDP 
				if (!compareByteArrays(messageToMatch.getByteSequenceContent(), msg.getByteSequenceContent()))
					return false;
				else if(!match(messageToMatch.getContent(),msg.getContent()))
					return false;
			}
			if(!match(messageToMatch.getConversationId(),msg.getConversationId()))
				return false;
			if(!match(messageToMatch.getEncoding(),msg.getEncoding()))
				return false;
			if(!match(messageToMatch.getInReplyTo(),msg.getInReplyTo()))
				return false;
			if(!match(messageToMatch.getLanguage(),msg.getLanguage()))
				return false;
			if(!match(messageToMatch.getOntology(),msg.getOntology()))
				return false;
			if(!match(messageToMatch.getProtocol(),msg.getProtocol()))
				return false;
			if(!match(messageToMatch.getReplyWith(),msg.getReplyWith()))
				return false;
			if(!match(messageToMatch.getReplyByDate(),msg.getReplyByDate()))
				return false;
			//receiver
			Iterator it1 = messageToMatch.getAllReceiver();
			while(it1.hasNext()){
				boolean found = false;
				AID rec = (AID)it1.next();
				Iterator it2 = msg.getAllReceiver();
				while(it2.hasNext()){
					if(rec.equals((AID)it2.next())){
						found = true;
						break;
					}    
				}//end while
				if(found == false)
					return false; //when a receiver of the template is not into the receivers of the ACLMessage.
			}//end while
			
			//replyTo
			Iterator it3 = messageToMatch.getAllReceiver();
			while(it3.hasNext()){
				boolean found = false;
				AID rec = (AID)it3.next();
				Iterator it2 = msg.getAllReceiver();
				while(it2.hasNext()){
					if(rec.equals((AID)it2.next())){
						found = true;
						break;
					}    
				}//end while
				if(found == false)
					return false; //when a receiver of the template is not into the receivers of the ACLMessage.
			}//end while
			
			//sender
			if((messageToMatch.getSender() != null) &&!(messageToMatch.getSender().equals(msg.getSender())))
				return false;
			
			return true;
		}
		
		private boolean match(String template, String actualValue){
			if(template == null)
				return true;
			else
				return CaseInsensitiveString.equalsIgnoreCase(template,actualValue);
		}
		
		private boolean match(Date template,Date actualValue){
			if(template == null)
				return true;
			else
				return template.equals(actualValue);
		}
		
		//only for debug purpose.
		public String toString(){
			String output = (matchPerformative ?  "match the performative "  : "no match on performative "   );
			return (output + messageToMatch.toString());
		}
		
	}//end class CustomMsgLiteral
	
	private static class MatchTopic implements MatchExpression {
		private String topicName;
		private boolean isTemplate;
		private boolean matchAll = false;
		
		MatchTopic(AID topic) {
			String tmp = topic.getLocalName();
			if (tmp.equals(TopicManagementHelper.TOPIC_TEMPLATE_WILDCARD)) {
				matchAll = true;
			}
			else {
				if (tmp.endsWith("."+TopicManagementHelper.TOPIC_TEMPLATE_WILDCARD)) {
					topicName = tmp.substring(0, tmp.length()-2);
					isTemplate = true;
				}
				else {
					topicName = tmp;
					isTemplate = false;
				}
			}
		}
		
		public boolean match(ACLMessage msg) {
			Iterator it = msg.getAllReceiver();
			while (it.hasNext()) {
				AID receiver = (AID) it.next();
				if (TopicUtility.isTopic(receiver)) {
					if (matchAll) {
						return true;
					}
					else {
						String name = receiver.getLocalName();
						if (name.equals(topicName)) {
							return true;
						}
						else if (isTemplate && name.startsWith(topicName+'.')) {
							return true;
						}
					}
				}
			}
			return false;
		}
		
		public String toString() {
			String name = (matchAll ? TopicManagementHelper.TOPIC_TEMPLATE_WILDCARD : (isTemplate ? topicName+'.'+TopicManagementHelper.TOPIC_TEMPLATE_WILDCARD : topicName));
			return "( Topic: "+name+" )";
		}
	}
	/**
	 @serial
	 */
	private MatchExpression toMatch;
	
	/** Public constructor to use when the user needs to define 
	 an application specific pattern.	 
	 */
	
	public MessageTemplate(MatchExpression e) {
		toMatch = e;
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message.
	 @return A new <code>MessageTemplate</code> matching any given
	 value.
	 */
	
	public static MessageTemplate MatchAll() {
		return new MessageTemplate(new MatchAllLiteral());
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:sender</code> slot.
	 @param value The value the message slot will be matched against.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchSender(AID value) {
		return new MessageTemplate(new Literal(value));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:receiver</code> slot.
	 @param values An array of Agent IDs against which the
	 value of the message slot will be matched.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchReceiver(AID[] values) {
		return new MessageTemplate(new Literal(values,RECEIVER));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message about a given topic.
	 @param topic An AID representing the topic to be matched
	 @return A new <code>MessageTemplate</code> matching messages about the given topic
	 */
	public static MessageTemplate MatchTopic(AID topic) {
		return new MessageTemplate(new MatchTopic(topic));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:content</code> slot.
	 @param value The value the message slot will be matched against.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchContent(String value) {
		return new MessageTemplate(new Literal(value,CONTENT));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:reply-with</code> slot.
	 @param value The value the message slot will be matched against.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchReplyWith(String value) {
		return new MessageTemplate(new Literal(value, REPLY_WITH));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:in-reply-to</code> slot.
	 @param value The value the message slot will be matched against.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchInReplyTo(String value) {
		return new MessageTemplate(new Literal(value,IN_REPLY_TO));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:reply-to</code> slot.
	 @param values An array of Agent IDs against which the
	 value of the message slot will be matched.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchReplyTo(AID[] values) {
		return new MessageTemplate(new Literal(values,REPLY_TO));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:language</code> slot.
	 @param value The value the message slot will be matched against.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchLanguage(String value) {
		return new MessageTemplate(new Literal(value,LANGUAGE));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:encoding</code> slot.
	 @param value The value the message slot will be matched against.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchEncoding(String value) {
		return new MessageTemplate(new Literal(value,ENCODING));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:ontology</code> slot.
	 @param value The value the message slot will be matched against.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchOntology(String value) {
		return new MessageTemplate(new Literal(value,ONTOLOGY));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:reply-by</code> slot.
	 @param value The <code>Date</code> the message slot will be matched against.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 **/
	public static MessageTemplate MatchReplyByDate(Date value){
		return new MessageTemplate(new Literal(value));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:protocol</code> slot.
	 @param value The value the message slot will be matched against.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchProtocol(String value) {
		return new MessageTemplate(new Literal(value, PROTOCOL));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given <code>:conversation-id</code> slot.
	 @param value The value the message slot will be matched against.
	 @return A new <code>MessageTemplate</code> matching the given
	 value.
	 */
	public static MessageTemplate MatchConversationId(String value) {
		return new MessageTemplate(new Literal(value,CONVERSATION_ID));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches any message with a given performative.
	 @param value The value the message slot will be matched against.
	 @return A new <code>MessageTenplate</code>matching the given
	 value.
	 */
	public static MessageTemplate MatchPerformative(int value){
		return new MessageTemplate(new Literal(value));
	}
	
	/**
	 This <em>Factory Method</em> returns a message template that
	 matches ACL messages against a given one, passed as
	 parameter. The following algorithm is used:
	 When the given <code>ACLMessage</code> has a non
	 <code>null</code> slot, subsequent messages must have the same
	 slot value in that slot to have a match.
	 When the given <code>ACLMessage</code> has a <code>null</code>
	 slot, subsequent messages can have any value for that slot and
	 still match the template.
	 In short, a <code>null</code> value for a slot means <em>don't
	 care</em>.
	 @param msg The <code>ACLMessage</code> used to build a custom
	 message template.
	 @param matchPerformative a <code>bool</code> value. When
	 <code>true</code>, the performative of the <code>msg</code> will
	 be considered as a part of the template (i.e. the message
	 template will match only ACL messages with the same performativa
	 as <code>msg</code>).
	 When <false>, the performative of <code>msg</code> is ignored and
	 the resulting message template will not consider it when matching
	 messages.
	 @return A new <code>MessageTemplate</code>, matching the given
	 message according to the above algorithm.
	 */
	public static MessageTemplate MatchCustom(ACLMessage msg, boolean matchPerformative) {
		ACLMessage message = (ACLMessage)msg.clone();
		return new MessageTemplate(new CustomMsgLiteral(message, matchPerformative));
	}
	
	/**
	 Logical <b>and</b> between two <code>MessageTemplate</code>
	 objects. This method creates a new message template that is
	 matched by those ACL messages matching <b><em>both</b></em>
	 message templates given as operands.
	 @param op1 The first <em>and</em> operand.
	 @param op2 The second <em>and</em> operand.
	 @return A new <code>MessageTemplate</code> object.
	 @see jade.lang.acl.MessageTemplate#or(MessageTemplate op1, MessageTemplate op2)
	 */
	public static MessageTemplate and(MessageTemplate op1, MessageTemplate op2) {
		AndExpression e = new AndExpression(op1.toMatch, op2.toMatch);
		MessageTemplate result = new MessageTemplate(e);
		return result;
	}
	
	/**
	 Logical <b>or</b> between two <code>MessageTemplate</code>
	 objects. This method creates a new message template that is
	 matched by those ACL messages matching <b><em>any</b></em> of the
	 two message templates given as operands.
	 @param op1 The first <em>or</em> operand.
	 @param op2 The second <em>or</em> operand.
	 @return A new <code>MessageTemplate</code> object.
	 @see jade.lang.acl.MessageTemplate#and(MessageTemplate op1, MessageTemplate op2)
	 */
	public static MessageTemplate or(MessageTemplate op1, MessageTemplate op2) {
		OrExpression e = new OrExpression(op1.toMatch, op2.toMatch);
		MessageTemplate result = new MessageTemplate(e);
		return result;
	}
	
	/**
	 Logical <b>not</b> of a <code>MessageTemplate</code> object. This
	 method creates a new message template that is matched by those
	 ACL messages <b><em>not</em></b> matching the message template
	 given as operand.
	 @param op The <em>not</em> operand.
	 @return A new <code>MessageTemplate</code> object.
	 */
	public static MessageTemplate not(MessageTemplate op) {
		NotExpression e = new NotExpression(op.toMatch);
		MessageTemplate result = new MessageTemplate(e);
		return result;
	}
	
	/**
	 Matches an ACL message against this <code>MessageTemplate</code>
	 object.
	 @param msg The <code>ACLMessage</code> to check for matching.
	 @return <code>true</code> if the ACL message matches this
	 template, <code>false</code> otherwise.
	 */
	public boolean match(ACLMessage msg) {
		return toMatch.match(msg);
	}
	
	/**
	 Retrieve a string representation of this message template.
	 @return A string describing the syntactic structure of this
	 message template.
	 */
	public String toString(){
		return toMatch.toString();
	}
}
