/* JFox, the OpenSource J2EE Application Server
 *
 * Distributable under GNU LGPL license by gun.org
 * more details please visit http://www.huihoo.org/jfox
 */

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) {

    }
}

