/*********************************************************************/
/*                                                                   */
/*                     AgentService Framework                        */
/*                       www.agentservice.it                         */
/*                                                                   */
/* Copyright (C) 2007 l.i.d.o. - DIST, University of Genoa, Italy    */
/* 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.                                      */
/*                                                                   */
/*********************************************************************/
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Specialized;

using AgentService.Platform.AMS;

using AgentService.Ontology;
using AgentService.Ontology.Schema;
using AgentService.Ontology.Interfaces;
using AgentService.Ontology.Validation;
using System.Collections.Generic;

namespace AgentService.Ontology.Schema.Abstract
{
	/// <summary>
	/// Converts an ArrayList to an abstract aggregate, using a given ontology.
	/// </summary>
	public class AbsHelper
	{
		/// <summary>
		/// Returns an abstract aggregate of a given ArrayList object.
		/// </summary>
		/// <param name="obj">The ArrayList obj to convert.</param>
		/// <param name="onto">The ontology to use.</param>
		/// <param name="AggregateType">The string that Contains the type of the aggregate.</param>
		/// <returns></returns>
		public static AbsAggregate ExternaliseList(ArrayList obj, Ontology onto, string AggregateType) 
		{
			AbsAggregate ret = new AbsAggregate(AggregateType);
			try 
			{
				for (int i = 0; i < obj.Count; ++i) 
				{
					ret.Add((AbsTerm) (onto.FromObject(obj[i])));
				}
			}
			catch
			{
				throw new ValidationException("Non term object in the aggregate "+AggregateType);
			}
			return ret;
		} 

		/// <summary>
		/// Returns an abstract aggregate of a given stringCollection object, using a given ontoloy.
		/// </summary>
		/// <param name="obj">The stringCollection object to convert in abstract aggregate.</param>
		/// <param name="onto">The ontology to use.</param>
		/// <param name="AggregateType">The string that Contains the type of the aggregate.</param>
		/// <returns></returns>
		public static AbsAggregate ExternaliseStringCollection(List<string> obj, Ontology onto, string AggregateType)
		{
			AbsAggregate ret = new AbsAggregate(AggregateType);
			try 
			{
				for (int i = 0; i < obj.Count; ++i) 
				{
					ret.Add((AbsTerm) (onto.FromObject(obj[i])));
				}
			}
			catch
			{
				throw new ValidationException("Non term object in aggregate "+AggregateType);
			}

			return ret;
		}

		/// <summary>
		/// Returns an abstract aggregate of an AIDCollection object, using a given ontology.
		/// </summary>
		/// <param name="obj">The AIDCollection to convert in abstract aggregate.</param>
		/// <param name="onto">The ontology to use.</param>
		/// <param name="AggregateType">The string that Contains the type of the aggregate.</param>
		/// <returns></returns>
		public static AbsAggregate ExternaliseAIDCollection(AIDCollection obj, Ontology onto, string AggregateType)
		{
			AbsAggregate ret = new AbsAggregate(AggregateType);
			try 
			{
				for (int i = 0; i < obj.Count; ++i) 
				{
					ret.Add((AbsTerm) (onto.FromObject(obj[i])));
				}
			}
			catch
			{
				throw new ValidationException("Non term object in aggregate "+AggregateType);
			}

			return ret;
		}

		/// <summary>
		/// Returns an abstract concept for a given AID.
		/// </summary>
		/// <param name="obj">The AID object to convert.</param>
		/// <returns></returns>
		public static AbsConcept ExternaliseAID(AID obj) 
		{
			try
			{
				AbsConcept aid = new AbsConcept(BasicOntology.aid);

				aid.SetAttribute(BasicOntology.aid_name, obj.Name);
				AbsAggregate addresses = new AbsAggregate(BasicOntology.string_collection);
				foreach(string s in obj.Addresses)
				{
					string addr = (string) s;
					addresses.Add(AbsPrimitive.Wrap(addr));
				}
				aid.SetAttribute(BasicOntology.aid_addresses, addresses);

				AbsAggregate resolvers = new AbsAggregate(BasicOntology.sequence);
				foreach(object s in obj.Resolvers)
				{
			
				
					AID res = (AID) s;
					resolvers.Add(ExternaliseAID(res));
				
				}
				aid.SetAttribute(BasicOntology.aid_resolvers, resolvers);
				return aid;
			}
			catch(Exception e)
			{
				throw new ValidationException("An error occurs during the externalisation of an AID: "+e.ToString());
			}

		}

    
		/// <summary>
		/// Returns an abstract content element list of content element list, using a given ontology. 
		/// </summary>
		/// <param name="obj">The content element list to convert.</param>
		/// <param name="onto">The ontology to use.</param></param>
		/// <returns></returns>
		public static AbsContentElementList ExternaliseContentElementList(ContentElementList obj, Ontology onto)
		{
			AbsContentElementList ret = new AbsContentElementList();

			try 
			{
				for (int i = 0; i < obj.Size(); i++) 
				{
					ret.Add((AbsContentElement) (onto.FromObject(obj.GetElement(i))));
				}
			}
			catch
			{
				throw new ValidationException("Non contentElement object in contentElement list");
			}

			return ret;
		} 

 
		/// <summary>
		/// Returns an abstract agent action of an ACLMessageBody, using a given ontology.
		/// </summary>
		/// <param name="obj">The ACLMessageBody to convert.</param>
		/// <param name="onto">The ontology to use.</param>
		/// <returns></returns>
		public static AbsAgentAction ExternaliseACLMessageBody(ACLMessageBody obj, Ontology onto)
		{
			try 
			{
				AbsAgentAction absMsg =  new AbsAgentAction(ACLMessageBody.GetPerfomativeString(System.Convert.ToInt32(obj.Performative,10)));
				absMsg.SetAttribute(BasicOntology.aclmsg_sender, obj.Sender);
				absMsg.SetAttribute(BasicOntology.aclmsg_reply_to, obj.Reply_to);
				absMsg.SetAttribute(BasicOntology.aclmsg_receivers, obj.Receivers);
				absMsg.SetAttribute(BasicOntology.aclmsg_language, obj.Language);
				absMsg.SetAttribute(BasicOntology.aclmsg_ontology, obj.Ontology);
				absMsg.SetAttribute(BasicOntology.aclmsg_protocol, obj.Protocol);
				absMsg.SetAttribute(BasicOntology.aclmsg_in_reply_to, obj.In_reply_to);
				absMsg.SetAttribute(BasicOntology.aclmsg_reply_with, obj.Reply_with);
				absMsg.SetAttribute(BasicOntology.aclmsg_conversation_id, obj.Conversation_id);
				absMsg.SetAttribute(BasicOntology.aclmsg_reply_by, obj.Reply_by);
				absMsg.SetAttribute(BasicOntology.aclmsg_content, obj.Content.ToString());
				absMsg.SetAttribute(BasicOntology.aclmsg_encoding, obj.Encoding);
  			
				return absMsg;
			}
			catch 
			{
				throw new ValidationException("An error occurs externalising ACLMessage");
			}
		}

            
        /*
		public static ArrayList internaliseList(AbsAggregate aggregate, Ontology.Ontology onto)
		{
			try
			{
				ArrayList ret = new ArrayList();

				for (int i = 0; i < aggregate.Size(); i++) 
				{
					Object element = onto.toObject(aggregate.GetElement(i));
					Ontology.Ontology.CheckIsTerm(element);
					ret.Add(element);
				}

				return ret;
			}
			catch(Exception e)
			{
				throw new OntologyException(e.ToString());
			}
		} */


		/*
		public static OntoAID internaliseAID(AbsConcept aid) 
		{
			OntoAID ret = new OntoAID(aid.GetString(BasicOntology.aid_name));

			try 
			{
				//ret.Name=aid.GetString(BasicOntology.aid_name);

				AbsAggregate addresses = (AbsAggregate) aid.GetAbsObject(BasicOntology.aid_addresses);
				if (addresses != null) 
				{
					for (int i = 0; i < addresses.Size(); ++i) 
					{
						string addr = ((AbsPrimitive) addresses.GetElement(i)).GetString();
						ret.Addresses.Add(addr);
					}
				}
		
				AbsAggregate resolvers = (AbsAggregate) aid.GetAbsObject(BasicOntology.aid_resolvers);
				if (resolvers != null) 
				{
					for (int i = 0; i < resolvers.Size(); ++i) 
					{
						OntoAID res = internaliseAID((AbsConcept) resolvers.GetElement(i));
						ret.AddResolvers(res);
					}
				}
				return ret;
			}
			catch 
			{
				throw new OntologyException(aid+" is not a valid AID");
			}
		} */

        /*
		public static ContentElementList internaliseContentElementList(AbsContentElementList l, Ontology.Ontology onto) 
		{
			ContentElementList ret = new ContentElementList();

			try 
			{
				for (int i = 0; i < l.Size(); i++) 
				{
					ContentElement element = (ContentElement) onto.toObject(l.GetElement(i));
					ret.Add(element);
				}
			}
			catch
			{
				throw new OntologyException("Non content element object in contentElement list");
			}

			return ret;
		} */

 
		/*public static OntoACLMessage internaliseACLMessage(AbsAgentAction absMsg, Ontology.Ontology onto) 
		{
			OntoACLMessage ret = new OntoACLMessage(ACLMessageBody.GetPerformativeInteger(absMsg.GetTypeName()));

			try 
			{
				ret.setSender((AID) onto.toObject(absMsg.GetAbsObject(BasicOntology.aclmsg_sender))); 
				ret.clearReceivers();
				ArrayList l = (ArrayList) onto.toObject(absMsg.GetAbsObject(BasicOntology.aclmsg_receivers));
  			
				foreach(object o in l)
				{
					ret.addReceiver((AID) o);
				}

				ret.Reply_to=null;
				AID s = (AID) onto.toObject(absMsg.GetAbsObject(BasicOntology.aclmsg_reply_to));
  		
				ret.addReplyTo((AID) s);
	  		
				ret.Language=absMsg.GetString(BasicOntology.aclmsg_language); 
				ret.Ontology=absMsg.GetString(BasicOntology.aclmsg_ontology); 
				ret.Protocol=absMsg.GetString(BasicOntology.aclmsg_protocol); 
				//ret.Reply_to=new AID((BasicOntology.aclmsg_in_reply_to,true); 
				ret.Reply_with=absMsg.GetString(BasicOntology.aclmsg_reply_with); 
				ret.Conversation_id=absMsg.GetString(BasicOntology.aclmsg_conversation_id); 
				ret.Reply_by=absMsg.GetLong(System.conBasicOntology.aclmsg_reply_by); 
				string c = absMsg.GetString(BasicOntology.aclmsg_content);
  			
				ret.setContent(c);
  			
				ret.Encoding=absMsg.GetString(BasicOntology.aclmsg_encoding); 
  			
				return ret;
			}
			catch 
			{
				throw  new OntologyException("Error internalising OntoACLMessage");
			}
		}*/
  	

		/// <summary>
		/// Sets an attribute, performing type checks.
		/// </summary>
		/// <param name="abs">The abstract descriptor of witch the attribute is setted. </param>
		/// <param name="attrName">The name of the attribute</param>
		/// <param name="attrValue">The new value of the attribute.</param></param>
		public static void SetAttribute(AbsObject abs, string attrName, AbsObject attrValue) 
		{ 
			try
			{
				if (abs is AbsAgentAction) 
				{
					if (attrValue is AbsTerm) 
					{
						((AbsAgentAction) abs).SetAttribute(attrName, (AbsTerm) attrValue);
						return;
					}
					if (attrValue is AbsPredicate) 
					{
						((AbsAgentAction) abs).SetAttribute(attrName, (AbsPredicate) attrValue);
						return;
					}
				}
				if (abs is AbsConcept) 
				{
					if (attrValue is AbsTerm) 
					{
						((AbsConcept) abs).SetAttribute(attrName, (AbsTerm) attrValue);
						return;
					}
				}
				else if (abs is AbsPredicate) 
				{
					((AbsPredicate) abs).SetAttribute(attrName, attrValue);
					return;
				}
				else if (abs is AbsIRE) 
				{
					if (attrValue is AbsVariable && System.String.Equals(attrName.ToLower(), IRESchema.variable.ToLower())) 
					{
						((AbsIRE) abs).SetVariable((AbsVariable) attrValue);
						return;
					}
					else if (attrValue is AbsPredicate && System.String.Equals(attrName.ToLower(), IRESchema.proposition.ToLower())) 
					{
						((AbsIRE) abs).SetProposition((AbsPredicate) attrValue);
						return;
					}
				}
				else if (abs is AbsVariable) 
				{
					if (attrValue is AbsPrimitive && System.String.Equals(attrName.ToLower(), VariableSchema.name.ToLower())) 
					{
						((AbsVariable) abs).SetName(((AbsPrimitive) attrValue).GetString());
						return;
					}
					else if (attrValue is AbsPrimitive && System.String.Equals(attrName.ToLower(), VariableSchema.value_type.ToLower())) 
					{
						((AbsVariable) abs).SetType(((AbsPrimitive) attrValue).GetString());
						return;
					}
				}
									
				throw new OntologyException("!Type incompatibility: attribute "+attrName+" of "+abs+" is of type "+attrValue.GetType().ToString());
			}
			catch(Exception e)
			{
				throw new ValidationException(e.ToString());
			}
		}
	}
}
