/* JFox, the OpenSource J2EE Application Server
 *
 * Copyright (C) 2002 huihoo.com
 * Distributable under GNU LGPL license
 * See the GNU Lesser General Public License for more details.
 */

package org.jfox.ejb.meta;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Node;

/**
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class MethodDescriptor extends Descriptor implements Comparable {

  private String ejbName;
  private String intf;
  private String name;
  private String paramTypeNames[];

  public MethodDescriptor() {

  }

  public void processXML(Node node) throws EJBDescriptionException {
    super.processXML(node);
    setEjbName(XmlUtil.getChildNodeValueOf(node, "ejb-name"));
    setIntf(XmlUtil.getChildNodeValueOf(node, "method-intf"));
    setName(XmlUtil.getChildNodeValueOf(node, "method-name"));
    List params = new ArrayList();
    for (Node paramNode = node.getFirstChild(); paramNode != null; paramNode = paramNode.getNextSibling()) {
      if (paramNode.getNodeType() == Node.ELEMENT_NODE && "method-param".equals(paramNode.getNodeName()))
        params.add(XmlUtil.getValueOf(paramNode));
    }
    setParamTypeNames((String[]) params.toArray(new String[0]));
  }

  public String getEjbName() {
    return ejbName;
  }

  public void setEjbName(String ejbName) {
    this.ejbName = ejbName;
  }

  public String getIntf() {
    return intf;
  }

  public void setIntf(String intf) {
    this.intf = intf;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String[] getParamTypeNames() {
    return paramTypeNames;
  }

  public void setParamTypeNames(String[] paramTypeNames) {
    this.paramTypeNames = paramTypeNames;
  }

  public String getPrettyParameterString() {
    if (paramTypeNames == null)
      return "";
    String readableString = "(";
    for (int i = 0; i < paramTypeNames.length; i++) {
      if (i > 0) readableString = readableString + ", ";
      readableString = readableString + paramTypeNames[i];
    }

    readableString = readableString + ")";
    return readableString;
  }

  public boolean isDefault() {
    return name == null || name.equals("*");
  }

  public String toString() {
    return getName() + getPrettyParameterString();
  }

  public int hashCode() {
    return getName().hashCode() ^ getPrettyParameterString().hashCode();
  }

  public boolean match(Method method) {
    if (isDefault())
      return true;
    if (!name.equals(method.getName()))
      return false;
    if (paramTypeNames == null)
      return true;
    Class _params[] = method.getParameterTypes();
    if (_params.length != paramTypeNames.length)
      return false;
    for (int i = 0; i < _params.length; i++) {
      String paramType = getTypeName(_params[i]);
      if (!paramType.equals(paramTypeNames[i]))
        return false;
    }
    return true;
  }

  private static final String getTypeName(Class clz) {
    String typeName = "";
    for (; clz.isArray(); clz = clz.getComponentType())
      typeName = typeName + "[]";

    return clz.getName() + typeName;
  }

  public int compareTo(Object methodDesc) {
    if(!(methodDesc instanceof MethodDescriptor)){ return 1;}
    String _intf = ((MethodDescriptor)methodDesc).getIntf();
    String _name = ((MethodDescriptor)methodDesc).getName();
    String[] _paramTypeNames = ((MethodDescriptor)methodDesc).getParamTypeNames();
    if (!intf.equals(_intf))
      return intf.compareTo(_intf);
    if (name.equals("*"))
      return _name.equals("*") ? 0 : 1;
    if (_name.equals("*"))
      return -1;
    if (!name.equals(_name))
      return name.compareTo(_name);
    if (paramTypeNames == null)
      return _paramTypeNames != null ? 1 : 0;
    if (_paramTypeNames == null)
      return -1;
    if (paramTypeNames.length != _paramTypeNames.length)
      return paramTypeNames.length - _paramTypeNames.length;
    for (int i = 0; i < paramTypeNames.length; i++)
      if (!paramTypeNames[i].equals(_paramTypeNames[i]))
        return paramTypeNames[i].compareTo(_paramTypeNames[i]);

    return 0;
  }

  public boolean equals(Object obj) {
    if (obj != null && (obj instanceof MethodDescriptor))
      return compareTo((MethodDescriptor) obj) == 0;
    else
      return false;
  }
  public static void main(String[] args) {

  }
}