private static MatchingMethod findBestMethod(List methods, Class typeClass, String name, Class[] argClasses) {
        MatchingMethod mm = null;
        IllegalArgumentException failure = null;
        for (int i = 0, icount = methods.size(); i < icount; i++) {
            Method m = (Method) methods.get(i);

            Class[] mParameterTypes = findParameterTypes(typeClass, m);
            ArgsCompatbilityReport report = areArgsCompatible(argClasses, mParameterTypes, m);
            if (report == null)
                continue;

            String methodName = m.getName();
            int score = report.score;
            if (name.equals(methodName)) {
                // exact match - no additinal score...
            } else if (name.equalsIgnoreCase(methodName)) {
                // minimal penalty..
                score += 200;
            } else if (methodName.toLowerCase().endsWith(name.toLowerCase())) {
                // has a prefix...
                score += 500;
            } else {
                // just in case...
                score += 5000;
            }
            if (mm == null || mm.score > score) {
                mm = new MatchingMethod(m, score, report, mParameterTypes);
                failure = null;
            } else if (mm.score == score) {
                // it happens that we see the same method signature multiple times - for the current class or interfaces ...
                // TODO why are all of them on the list and not only the most specific one?
                // check for same signature
                if (Arrays.equals(mm.mMethod.getParameterTypes(), m.getParameterTypes()) && mm.mMethod.getName().equals(m.getName())) {
                    boolean retsAreEqual = mm.mMethod.getReturnType().equals(m.getReturnType());
                    // it is the same method. we use the most specific one...
                    if (mm.mMethod.getDeclaringClass().isAssignableFrom(m.getDeclaringClass())) {
                        if (!retsAreEqual && !mm.mMethod.getReturnType().isAssignableFrom(m.getReturnType()))
                            System.err.println("Two methods with same method signature but return types conflict? \""+mm.mMethod+"\" and \""+m+"\" please report!");

                        mm = new MatchingMethod(m, score, report, mParameterTypes);
                        failure = null;
                    } else if (!m.getDeclaringClass().isAssignableFrom(mm.mMethod.getDeclaringClass())) {
                        // this should't happen
                        System.err.println("Two methods with same method signature but not providing classes assignable? \""+mm.mMethod+"\" and \""+m+"\" please report!");
                    } else if (!retsAreEqual && !m.getReturnType().isAssignableFrom(mm.mMethod.getReturnType()))
                        System.err.println("Two methods with same method signature but return types conflict? \""+mm.mMethod+"\" and \""+m+"\" please report!");
                } else {
                    // two methods with same score - direct compare to find the better one...
                    // legacy wins over varargs
                    if (isJdk15() && (m.isVarArgs() || mm.mMethod.isVarArgs())) {
                        if (m.isVarArgs() && !mm.mMethod.isVarArgs()) {
                            // keep with current
                        } else if (!m.isVarArgs() && mm.mMethod.isVarArgs()) {
                            // legacy wins...
                            mm = new MatchingMethod(m, score, report, mParameterTypes);
                            failure = null;
                        } else {
                            // both arguments are varargs...
                            System.err.println("Two vararg methods with same score("+score+"): \""+mm.mMethod+"\" and \""+m+"\" please report!");
                        }
                    } else {
                        int scoreCurr = 0;
                        int scoreOther = 0;
                        for (int j=0; j<argClasses.length; j++) {
                            Class argClass = argClasses[j];
                            Class mcClass = mm.mParameterTypes[j];
                            Class moClass = mParameterTypes[j];
                            if (argClass == null) {	// TODO can we avoid this case?
                                // we don't know the class. use the most generic implementation...
                                if (mcClass == moClass) {
                                    // equal args - no winner...
                                } else if (mcClass.isAssignableFrom(moClass)) {
                                    scoreOther += 1000;	// current wins...
                                } else if (moClass.isAssignableFrom(moClass)) {
                                    scoreCurr += 1000;	// other wins...
                                } else {
                                    // both items can't be assigned to each other..
                                    failure = new IllegalArgumentException("Can't decide wich method to use: \""+mm.mMethod+"\" or \""+m+"\"");
                                }
                            } else {
                                // we try to find the more specific implementation
                                if (mcClass == moClass) {
                                    // equal args - no winner...
                                } else if (mcClass == argClass) {
                                    scoreOther += 100;	// current wins...
                                } else if (moClass == argClass) {
                                    scoreCurr += 100;	// other wins...
                                } else {
                                    // both items can't be assigned to each other..
                                    // TODO: if this happens we have to put some weight on the inheritance...
                                    failure = new IllegalArgumentException("Can't decide wich method to use: \""+mm.mMethod+"\" or \""+m+"\"");
                                }
                            }
                        }
                        if (scoreCurr == scoreOther) {
                            if (failure == null)
                                System.err.println("Two methods with same score("+score+"): \""+mm.mMethod+"\" and \""+m+"\" please report!");
                        } else if (scoreCurr > scoreOther) {
                            // other wins...
                            mm = new MatchingMethod(m, score, report, mParameterTypes);
                            failure = null;
                        } // else current one wins...
                    }
                }
            }
        }
        if (failure != null)
            throw failure;
        return mm;
    }