package org.yawlfoundation.yawl.resourcing.codelets;

import java.util.List;
import java.util.ArrayList;
import java.net.URL;
import java.util.HashMap;

import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.yawlfoundation.yawl.elements.data.YParameter;

import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

import org.apache.log4j.Logger;
import org.apache.log4j.Level;

public class OpenERPCodelet extends AbstractCodelet {

	public static XmlRpcClient createXMLRPCClient(String host, int port, String intrface) {
		  XmlRpcClient xmlrpcclnt = new XmlRpcClient();
		  XmlRpcClientConfigImpl xmlrpcConfig = new XmlRpcClientConfigImpl();
//		  xmlrpcConfig.setEnabledForExtensions(true);
		  try {
			  xmlrpcConfig.setServerURL(new URL("http",host,port,"/xmlrpc/" + intrface));
		  } catch (Exception e) {
		        Logger l = Logger.getLogger(OpenERPCodelet.class);
		        l.setLevel(Level.ALL);
			    l.error("Exception while setting server URL: " + e.getMessage());
			    return null;		  
		  }
		  xmlrpcclnt.setConfig(xmlrpcConfig);
		  return xmlrpcclnt;
	}

	public int OpenERPConnect(String url, Integer port, String db, String uname, String pwd)
	{
	  XmlRpcClient client = createXMLRPCClient(url, port, "common");
	  try {
	    //Connect
	    Object id = client.execute("login", new Object[] {db,uname,pwd});
	    if (id instanceof Integer)
	      return (Integer)id;
	    return -1;
	  }
	  catch (Exception e)
	  {
        Logger l = Logger.getLogger(OpenERPCodelet.class);
        l.setLevel(Level.ALL);
	    l.error("Exception while logging in to OpenERP: " + e.getMessage());
	    return -3;
	  }
	}

	public OpenERPCodelet(){
		super();
		setDescription("This codelet accesses an OpenERP system using XML-RPC.<br> " +
                "Inputs: URL (string), Port (integer), Database (string), Username (string), Password (string), Object (string), Method (string), Parameters (ParameterType) <br>" +
                "Outputs: Result (ResultType) - depends on object and method <br>" +
                "The &lt;Parameters&gt; (ParameterType) element must contain method parameters appropriate for the object and method");
	}

	public Element OpenERPSearch(Element parameters, String url, int port, String db, String uname, String pwd, String object) {
        Logger l = Logger.getLogger(OpenERPCodelet.class);
        l.setLevel(Level.ALL);
        l.info("OpenERPSearch");
        
        Element result = new Element("Result");

		Element searchParams = parameters.getChild("SearchParameters");
		if (searchParams == null)
			return result.addContent(new Element("Error").addContent("Error: No search parameters supplied."));			

		int uid = OpenERPConnect(url, port, db, uname, pwd);
		l.debug("OpenERPConnect returned " + uid);
		if (uid < 0) 
			return result.addContent(new Element("Error").addContent("Error: Could not login to OpenERP"));
		
		XmlRpcClient client = createXMLRPCClient(url, port, "object");
		
		Element criteriaList = searchParams.getChild("CriteriaList");
		List<Element> searchCriteria = criteriaList.getChildren("SearchCriterion");

		Object[] crit = new Object[searchCriteria.size()];
		for (int i = 0; i < searchCriteria.size(); i++) {
			Element searchCriterion = searchCriteria.get(i);
			Object Value;
	
			Value = new String(searchCriterion.getChild("Value").getValue());
			if (searchCriterion.getChild("Type") != null) {
				if (searchCriterion.getChild("Type").getValue().equals("integer"))
					Value = new Integer(searchCriterion.getChild("Value").getValue());
				if (searchCriterion.getChild("Type").getValue().equals("long"))
					Value = new Integer(searchCriterion.getChild("Value").getValue());
				if (searchCriterion.getChild("Type").getValue().equals("float"))
					Value = new Double(searchCriterion.getChild("Value").getValue());
				if (searchCriterion.getChild("Type").getValue().equals("double"))
					Value = new Double(searchCriterion.getChild("Value").getValue());
				if (searchCriterion.getChild("Type").getValue().equals("boolean"))
					Value = new Boolean(searchCriterion.getChild("Value").getValue());
			}

			crit[i] = new Object[] { searchCriterion.getChild("Argument").getValue(), searchCriterion.getChild("Operator").getValue(), Value };
			l.debug("Added criterion ( " + searchCriterion.getChild("Argument").getValue() + " // " + searchCriterion.getChild("Operator").getValue() + " // " + Value + " // " + Value.getClass().getName() + " )");
		}

		Object[] params;
		
		if (searchParams.getChild("Offset") != null) 
			if (searchParams.getChild("Limit") != null) {
				params = new Object[8];
				params[6] = new Integer(searchParams.getChild("Offset").getValue());
				params[7] = new Integer(searchParams.getChild("Limit").getValue());
				l.debug("Offset " + params[6] + " Limit " + params[7]);
			} else {
				params = new Object[7];
				params[6] = new Integer(searchParams.getChild("Offset").getValue());			
				l.debug("Offset " + params[6]);
			}
		else {
			if (searchParams.getChild("Limit") != null) {
				params = new Object[8];
				params[6] = new Integer(0);
				params[7] = new Integer(searchParams.getChild("Limit").getValue());
				l.debug("Offset " + params[6] + " Limit " + params[7]);
			} else {
				params = new Object[6];
				l.debug("No Offset or Limit ");
			}
		}

		params[0] = db;
		params[1] = uid;
		params[2] = pwd;
		params[3] = object;
		params[4] = "search";
		params[5] = crit;

		Object[] ids;

		try {
			ids = (Object[])client.execute("execute", params);
		} catch (Exception e) {
			l.error("Error while executing search: " + e.getMessage());
			return result.addContent(new Element("Error").addContent("Error while executing search: " + e.getMessage()));
		}

		l.debug("Found " + ids.length + " records");
		
		Element searchResults = new Element("SearchResults");
		Element IDlist = new Element("IDList");
		searchResults.addContent(IDlist);
		result.addContent(searchResults);
		
		for (int i=0; i<ids.length; i++) {
			Element id = new Element("ID");
			id.addContent(ids[i].toString());
			IDlist.addContent(id);
			l.debug("Added ID " + ids[i].toString() + " to result");
		}

		return result;
	}
	
	public Element OpenERPCreate(Element parameters, String url, int port, String db, String uname, String pwd, String object) {
        Logger l = Logger.getLogger(OpenERPCodelet.class);
        l.setLevel(Level.ALL);
        l.info("OpenERPCreate");

		Element result = new Element("Result");

		Element createParams = parameters.getChild("CreateParameters");
		if (createParams == null)
			return result.addContent(new Element("Error").addContent("Error: No create parameters supplied."));			

		int uid = OpenERPConnect(url, port, db, uname, pwd);
		l.debug("OpenERPConnect returned " + uid);
		if (uid < 0) 
			return result.addContent(new Element("Error").addContent("Error: Could not login to OpenERP"));
		
		XmlRpcClient client = createXMLRPCClient(url, port, "object");
		
		Element fieldValuePairList = createParams.getChild("FieldValuePairList");
		List<Element> fieldValuePairs = fieldValuePairList.getChildren("FieldValuePair");
		
		HashMap<String, Object> hm = new HashMap<String, Object>();
		for (int i = 0; i < fieldValuePairs.size(); i++) {
			Element fieldValuePair = fieldValuePairs.get(i);

			Object Value;			
			Value = new String(fieldValuePair.getChild("Value").getValue());
			if (fieldValuePair.getChild("Type") != null) {
				if (fieldValuePair.getChild("Type").getValue().equals("integer"))
					Value = new Integer(fieldValuePair.getChild("Value").getValue());
				if (fieldValuePair.getChild("Type").getValue().equals("long"))
					Value = new Integer(fieldValuePair.getChild("Value").getValue());
				if (fieldValuePair.getChild("Type").getValue().equals("float"))
					Value = new Double(fieldValuePair.getChild("Value").getValue());
				if (fieldValuePair.getChild("Type").getValue().equals("double"))
					Value = new Double(fieldValuePair.getChild("Value").getValue());
				if (fieldValuePair.getChild("Type").getValue().equals("boolean"))
					Value = new Boolean(fieldValuePair.getChild("Value").getValue());
			}
		
			hm.put( fieldValuePair.getChild("Field").getValue(), Value );
			l.debug("Added HashMap Entry (" + fieldValuePair.getChild("Field").getValue() + " // " + Value + " // " + Value.getClass().getName() + ")");
		}

		Object[] params = new Object[6];
		
		params[0] = db;
		params[1] = uid;
		params[2] = pwd;
		params[3] = object;
		params[4] = "create";
		params[5] = hm;

		Object id;
		try {
			id = client.execute("execute", params);
		} catch (Exception e) {
			l.error("Error while executing create: " + e.getMessage());
			return result.addContent(new Element("Error").addContent("Error while executing create: " + e.getMessage()));
		}
		
		Element createResults = new Element("CreateResults");
		Element IDelement = new Element("ID");
		IDelement.addContent(id.toString());
		createResults.addContent(IDelement);
		result.addContent(createResults);

		return result;
	}

	public Element OpenERPWrite(Element parameters, String url, int port, String db, String uname, String pwd, String object) {
        Logger l = Logger.getLogger(OpenERPCodelet.class);
        l.setLevel(Level.ALL);
        l.info("OpenERPWrite");

		Element result = new Element("Result");

		Element writeParams = parameters.getChild("WriteParameters");
		if (writeParams == null)
			return result.addContent(new Element("Error").addContent("Error: No write parameters supplied."));			

		int uid = OpenERPConnect(url, port, db, uname, pwd);
		l.debug("OpenERPConnect returned " + uid);
		if (uid < 0) 
			return result.addContent(new Element("Error").addContent("Error: Could not login to OpenERP"));
		
		XmlRpcClient client = createXMLRPCClient(url, port, "object");
		
		Element fieldValuePairList = writeParams.getChild("FieldValuePairList");
		List<Element> fieldValuePairs = fieldValuePairList.getChildren("FieldValuePair");
		HashMap<String, Object> hm = new HashMap<String, Object>();
		for (int i = 0; i < fieldValuePairs.size(); i++) {
			Element fieldValuePair = fieldValuePairs.get(i);

			Object Value;			
			Value = new String(fieldValuePair.getChild("Value").getValue());
			if (fieldValuePair.getChild("Type") != null) {
				if (fieldValuePair.getChild("Type").getValue().equals("integer"))
					Value = new Integer(fieldValuePair.getChild("Value").getValue());
				if (fieldValuePair.getChild("Type").getValue().equals("long"))
					Value = new Integer(fieldValuePair.getChild("Value").getValue());
				if (fieldValuePair.getChild("Type").getValue().equals("float"))
					Value = new Double(fieldValuePair.getChild("Value").getValue());
				if (fieldValuePair.getChild("Type").getValue().equals("double"))
					Value = new Double(fieldValuePair.getChild("Value").getValue());
				if (fieldValuePair.getChild("Type").getValue().equals("boolean"))
					Value = new Boolean(fieldValuePair.getChild("Value").getValue());
			}

			hm.put(fieldValuePair.getChild("Field").getValue(), Value );
			l.debug("Added HashMap Entry (" + fieldValuePair.getChild("Field").getValue() + " // " + Value + " // " + Value.getClass().getName() + ")");
		}
		
		Element idListElement = writeParams.getChild("IDList");
		List<Element> idsElement = idListElement.getChildren("ID");		
		Integer[] ids = new Integer[idsElement.size()];
		for (int i = 0; i < idsElement.size(); i++) {
			Element idElement = idsElement.get(i);
			ids[i] = new Integer(idElement.getValue());
			l.debug("Added ID entry (" + ids[i] + ")");
		}

		Object[] params = new Object[7];
		
		params[0] = db;
		params[1] = uid;
		params[2] = pwd;
		params[3] = object;
		params[4] = "write";
		params[5] = ids;
		params[6] = hm;

		try {
			client.execute("execute", params);
		} catch (Exception e) {
			l.error("Error while executing write: " + e.getMessage());
			return result.addContent(new Element("Error").addContent("Error while executing write: " + e.getMessage()));
		}

        result.addContent(new Element("WriteResults").addContent("true"));
		return result;
	}
	
	
	public Element OpenERPRead(Element parameters, String url, int port, String db, String uname, String pwd, String object) {
        Logger l = Logger.getLogger(OpenERPCodelet.class);
        l.setLevel(Level.ALL);
        l.info("OpenERPRead");

		Element result = new Element("Result");

		Element readParams = parameters.getChild("ReadParameters");
		if (readParams == null)
			return result.addContent(new Element("Error").addContent("Error: No read parameters supplied."));			

		int uid = OpenERPConnect(url, port, db, uname, pwd);
		l.debug("OpenERPConnect returned " + uid);
		if (uid < 0) 
			return result.addContent(new Element("Error").addContent("Error: Could not login to OpenERP"));
		
		XmlRpcClient client = createXMLRPCClient(url, port, "object");

		Object[] params;
		
		Element idListElement = readParams.getChild("IDList");
		List<Element> idsElement = idListElement.getChildren("ID");		
		Object[] ids = new Object[idsElement.size()];
		for (int i = 0; i < idsElement.size(); i++) {
			Element idElement = idsElement.get(i);
			ids[i] = new Integer(idElement.getValue());
			l.debug("Added ID entry (" + ids[i] + ")");
		}

		Object[] fields = null;
		Element fieldListElement = readParams.getChild("FieldList");
		if (fieldListElement != null) {
			params = new Object[7];
			List<Element> fieldsElement = fieldListElement.getChildren("Field");
			fields = new Object[fieldsElement.size()];
			for (int i = 0; i < fieldsElement.size(); i++) {
				Element fieldElement = fieldsElement.get(i);
				fields[i] = fieldElement.getValue();
				l.debug("Added fields entry (" + fields[i] + ")");
			}
			params[6] = fields;
		} else {
			params = new Object[6];
			l.debug("No fields specified");
		}
			
		params[0] = db;
		params[1] = uid;
		params[2] = pwd;
		params[3] = object;
		params[4] = "read";
		params[5] = ids;

		Object[] info;
		
		try {
			info = (Object[])client.execute("execute", params);
		} catch (Exception e) {
			l.error("Error while executing read: " + e.getMessage());
			return result.addContent(new Element("Error").addContent("Error while executing read: " + e.getMessage()));
		}
		
		Element readResults = new Element("ReadResults");
		result.addContent(readResults);
		l.debug("Read " + info.length + " records");

		for (int i=0; i<info.length; i++) {
			Element fieldValuePairList = new Element("FieldValuePairList");
			readResults.addContent(fieldValuePairList);
			HashMap<Object, Object> hm = (HashMap<Object, Object>)info[i];
			Object[] keyvalues = hm.keySet().toArray();
			for (int j=0; j<keyvalues.length; j++) {
				Element fieldValuePair = new Element("FieldValuePair");
				fieldValuePairList.addContent(fieldValuePair);
				fieldValuePair.addContent(new Element("Field").addContent((String)keyvalues[j]));
				try {
				if (!hm.get(keyvalues[j]).getClass().isArray()) {
					fieldValuePair.addContent(new Element("Value").addContent(hm.get(keyvalues[j]).toString()));
				
					if (hm.get(keyvalues[j]).getClass().getName().equals("java.lang.String")) 
						fieldValuePair.addContent(new Element("Type").addContent("string"));
					if (hm.get(keyvalues[j]).getClass().getName().equals("java.lang.Integer")) 
						fieldValuePair.addContent(new Element("Type").addContent("integer"));
					if (hm.get(keyvalues[j]).getClass().getName().equals("java.lang.Long")) 
						fieldValuePair.addContent(new Element("Type").addContent("long"));
					if (hm.get(keyvalues[j]).getClass().getName().equals("java.lang.Float")) 
						fieldValuePair.addContent(new Element("Type").addContent("float"));
					if (hm.get(keyvalues[j]).getClass().getName().equals("java.lang.Double")) 
						fieldValuePair.addContent(new Element("Type").addContent("double"));
					if (hm.get(keyvalues[j]).getClass().getName().equals("java.lang.Boolean")) 
						fieldValuePair.addContent(new Element("Type").addContent("boolean"));

					l.debug("Added FieldValuePair with Field (" + (String)keyvalues[j] + ") and Value (" + hm.get(keyvalues[j]).toString() + ") of Type (" + hm.get(keyvalues[j]).getClass().getName() + " )");
				} else {
					Object [] arr = (Object[])hm.get(keyvalues[j]);
					if (arr.length == 0) {
						// Assume that arrays of length 0 are empty one2many lists, signal this by adding a -1 value since values are required, leave it to the caller to react appropriately
						fieldValuePair.addContent(new Element("Value").addContent("-1"));
						// We do not need to set tye Type here, as the test on "allIntegers" for the general length array will be true
						// fieldValuePair.addContent(new Element("Type").addContent("one2many"));
						l.debug("Added FieldValuePair with Field (" + (String)keyvalues[j] + ") and Value (0) of Type (one2many )");						
					}
					if (arr.length == 2) { 
						if (arr[0].getClass().getName().equals("java.lang.Integer") && arr[1].getClass().getName().equals("java.lang.String")) {
							fieldValuePair.addContent(new Element("Value").addContent(arr[0].toString()));
							fieldValuePair.addContent(new Element("Value").addContent(arr[1].toString()));
							fieldValuePair.addContent(new Element("Type").addContent("many2one"));
							l.debug("Added FieldValuePair with Field (" + (String)keyvalues[j] + ") and Value (" + arr[0].toString() + ", " + arr[1].toString() + ") of Type (many2one )");
						} else if (arr[0].getClass().getName().equals("java.lang.Integer") && arr[1].getClass().getName().equals("java.lang.Integer")) {
							fieldValuePair.addContent(new Element("Value").addContent(arr[0].toString()));
							fieldValuePair.addContent(new Element("Value").addContent(arr[1].toString()));
							fieldValuePair.addContent(new Element("Type").addContent("one2many"));
							l.debug("Added FieldValuePair with Field (" + (String)keyvalues[j] + ") and Value (" + arr[0].toString() + ", " + arr[1].toString() + ") of Type (one2many )");
						} else {
							l.error("Found unknown array of length " + arr.length);
							for (int k=0; k<arr.length; k++) {
								l.error("  " + arr[k].toString() + " (" + arr[k].getClass().getName() + ")");
							}
						}
					} else if (allIntegers(arr)) {
						for (int k=0; k<arr.length; k++)
							fieldValuePair.addContent(new Element("Value").addContent(arr[k].toString()));
						fieldValuePair.addContent(new Element("Type").addContent("one2many"));
						l.debug("Added FieldValuePair with Field (" + (String)keyvalues[j] + ") and Value (" + arr[0].toString() + ", ...) of Type (one2many )");
					} else {
						l.error("Found unknown array of length " + arr.length);
						for (int k=0; k<arr.length; k++) {
							l.error("  " + arr[k].toString() + " (" + arr[k].getClass().getName() + ")");
						}						
					}
				}
				} catch (Exception e) {
					l.error("Exception! Message: " + e.getMessage().toString());
				}
			}
		}
		return result;
	}
	
	private boolean allIntegers(Object[] arr) {
		boolean b = true;
		for (int i=0; i<arr.length; i++) {
			b = b && arr[i].getClass().getName().equals("java.lang.Integer");
		}
		return b;
	}
	
	public Element OpenERPAction(Element parameters, String url, int port, String db, String uname, String pwd, String object) {
        Logger l = Logger.getLogger(OpenERPCodelet.class);
        l.setLevel(Level.ALL);
        l.info("OpenERPAction");

		Element result = new Element("Result");

		Element readParams = parameters.getChild("ActionParameters");
		if (readParams == null)
			return result.addContent(new Element("Error").addContent("Error: No action parameters supplied."));			

		int uid = OpenERPConnect(url, port, db, uname, pwd);
		l.debug("OpenERPConnect returned " + uid);
		if (uid < 0) 
			return result.addContent(new Element("Error").addContent("Error: Could not login to OpenERP"));
		
		XmlRpcClient client = createXMLRPCClient(url, port, "object");

		Object[] params = new Object[6];
		
		Integer id = new Integer(readParams.getChild("ID").getValue());
		l.debug("Added id entry (" + id + ")");
		String action = new String(readParams.getChild("Action").getValue());
		l.debug("Added action entry (" + action + ")");

		params[0] = db;
		params[1] = uid;
		params[2] = pwd;
		params[3] = object;
		params[4] = action;
		params[5] = id;

		Object info;
		
		try {
			info = client.execute("exec_workflow", params);
		} catch (Exception e) {
			l.error("Error while executing action: " + e.getMessage());
			return result.addContent(new Element("Error").addContent("Error while executing action: " + e.getMessage()));
		}
		l.debug("Action returned " + info + " of type " + info.getClass().getName().toString());

		Element actionResults = new Element("ActionResults");
		result.addContent(actionResults);
		actionResults.addContent(info.toString());
		
		return result;
	}
	
	
	
	public Element OpenERPDelete(Element parameters, String url, int port, String db, String uname, String pwd, String object) {
        Logger l = Logger.getLogger(OpenERPCodelet.class);
        l.setLevel(Level.ALL);
        l.info("OpenERPDelete");

		Element result = new Element("Result");

		Element deleteParams = parameters.getChild("DeleteParameters");
		if (deleteParams == null)
			return result.addContent(new Element("Error").addContent("Error: No delete parameters supplied."));			

		int uid = OpenERPConnect(url, port, db, uname, pwd);
		l.debug("OpenERPConnect returned " + uid);
		if (uid < 0) 
			return result.addContent(new Element("Error").addContent("Error: Could not login to OpenERP"));
		
		XmlRpcClient client = createXMLRPCClient(url, port, "object");

		Object[] params;
		
		Element idListElement = deleteParams.getChild("IDList");
		List<Element> idsElement = idListElement.getChildren("ID");		
		Integer[] ids = new Integer[idsElement.size()];
		for (int i = 0; i < idsElement.size(); i++) {
			Element idElement = idsElement.get(i);
			ids[i] = new Integer(idElement.getValue().toString());
			l.debug("Put into ids: " + ids[i]);
		}

		params = new Object[6];
		params[0] = db;
		params[1] = uid;
		params[2] = pwd;
		params[3] = object;
		params[4] = "unlink";
		params[5] = ids;

		try {
			client.execute("execute", params);
		} catch (Exception e) {
			l.error("Error while executing delete: " + e.getMessage());
			return result.addContent(new Element("Error").addContent("Error while executing delete: " + e.getMessage()));
		}

        result.addContent(new Element("DeleteResults").addContent("true"));
        return result;
	}
	
	@Override
	public Element execute(Element inData, List<YParameter> inParams,
			List<YParameter> outParams) throws CodeletExecutionException {
		// set the inputs passed in the base class
        setInputs(inData, inParams, outParams);
        
        Logger l = Logger.getLogger(OpenERPCodelet.class);
        l.setLevel(Level.ALL);

        String url = (String)getParameterValue("URL");
        Integer port = new Integer((String)getParameterValue("Port"));
        String db = (String)getParameterValue("Database");
        String uname = (String)getParameterValue("Username");
        String pwd = (String)getParameterValue("Password");
        String object = (String)getParameterValue("Object");
        String method = (String)getParameterValue("Method");
        
        l.info("OpenERPCodelet.execute called with URL " + url + ", Port " + port + ", Db " + db + ", Uname : " + uname + ", Object: " + object + ", Method : " + method);
        XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
        l.debug("OpenERPCodelet.execute inData :\n" + outputter.outputString(inData));

        Element outData;

        Element parameters = inData.getChild("Parameters");
        if (parameters == null)
        	outData = new Element("Result").addContent(new Element("Error").addContent("Error: No Parameters found in input document."));
        else {
	        	if (method.toLowerCase().equals("search"))
		        	outData = OpenERPSearch(parameters, url, port, db, uname, pwd, object.toLowerCase());
	        	else
	        		if (method.toLowerCase().equals("write"))
			        	outData = OpenERPWrite(parameters, url, port, db, uname, pwd, object.toLowerCase());
	        		else 
	        			if (method.toLowerCase().equals("read"))
	    		        	outData = OpenERPRead(parameters, url, port, db, uname, pwd, object.toLowerCase());
	        			else
	        				if (method.toLowerCase().equals("delete"))
	        		        	outData = OpenERPDelete(parameters, url, port, db, uname, pwd, object.toLowerCase());
	        				else
	        					if (method.toLowerCase().equals("create"))
	        			        	outData = OpenERPCreate(parameters, url, port, db, uname, pwd, object.toLowerCase());
	        					else
	        						if (method.toLowerCase().equals("action"))
	        							outData = OpenERPAction(parameters, url, port, db, uname, pwd, object.toLowerCase());
	        						else
	        							outData = new Element("Result").addContent(new Element("Error").addContent("Error: Method '"+method+"' on Object '"+object+"' not implemented."));
        }
        
        Element outElement = new Element("codelet_output");
        outElement.addContent(outData);

        l.debug("OpenERPCodelet.execute outElement: \n" + outputter.outputString(outElement));

        return outElement;
	}
	
    public List<YParameter> getRequiredParams() { 
    
    	List<YParameter> params = new ArrayList<YParameter>();
    	
        YParameter param = new YParameter(null, YParameter._INPUT_PARAM_TYPE);
        param.setDataTypeAndName("string", "URL", XSD_NAMESPACE);
        param.setDocumentation("The hostname of the URL of the OpenERP system");
        params.add(param);

        param = new YParameter(null, YParameter._INPUT_PARAM_TYPE);
        param.setDataTypeAndName("int", "Port", XSD_NAMESPACE);
        param.setDocumentation("The port on which the OpenERP system listens for XML-RPC calls (usually 8069)");
        params.add(param);

        param = new YParameter(null, YParameter._INPUT_PARAM_TYPE);
        param.setDataTypeAndName("string", "Database", XSD_NAMESPACE);
        param.setDocumentation("The name of the OpenERP to access");
        params.add(param);
        
        param = new YParameter(null, YParameter._INPUT_PARAM_TYPE);
        param.setDataTypeAndName("string", "Username", XSD_NAMESPACE);
        param.setDocumentation("The username for the OpenERP login");
        params.add(param);
        
        param = new YParameter(null, YParameter._INPUT_PARAM_TYPE);
        param.setDataTypeAndName("string", "Password", XSD_NAMESPACE);
        param.setDocumentation("The password for the OpenERP login");
        params.add(param);
        
        param = new YParameter(null, YParameter._INPUT_PARAM_TYPE);
        param.setDataTypeAndName("string", "Object", XSD_NAMESPACE);
        param.setDocumentation("The name of the OpenERP object to access");
        params.add(param);
        
        param = new YParameter(null, YParameter._INPUT_PARAM_TYPE);
        param.setDataTypeAndName("string", "Method", XSD_NAMESPACE);
        param.setDocumentation("The name of the OpenERP method to execute (either read, search, write, create, delete)");
        params.add(param);
        
        param = new YParameter(null, YParameter._INPUT_PARAM_TYPE);
        param.setDataTypeAndName("ParameterType", "Parameters", XSD_NAMESPACE);
        param.setDocumentation("The parameters for the method as a complex data type (see XSD definitions)");
        params.add(param);

        param = new YParameter(null, YParameter._OUTPUT_PARAM_TYPE);
        param.setDataTypeAndName("ResultType", "Result", XSD_NAMESPACE);
        param.setDocumentation("The result of the operation as a complex data type (see XSD definitions)");
        params.add(param);
        return params;
    }
	
	
}
