// Path: src/main/java/com/timgroup/karg/naming/StringFunctions.java
// public final class StringFunctions {
// 
//     private StringFunctions() { }
// 
//     public static final Function<String, String> TRIM = new Function<String, String>() {
//         @Override
//         public String apply(String arg0) {
//             return arg0.trim();
//         }
//     };
//     
//     public static final Function<String, String> LOWERCASE = new Function<String, String>() {
//         @Override
//         public String apply(String arg0) {
//             return arg0.toLowerCase();
//         }
//     };
//     
//     public static final Function<String, String> LOWERCASE_TRIM = Functions.compose(LOWERCASE, TRIM);
//     
//     public static final Function<String, String> CAPITALISE = new Function<String, String>() {
//         @Override
//         public String apply(String arg0) {
//             switch(arg0.length()) {
//                 case 0: return "";
//                 case 1: return arg0.toUpperCase();
//                 default: return arg0.substring(0, 1).toUpperCase() + arg0.substring(1);
//             }
//         }
//     };
//     
//     public static final Function<String, String> UNCAPITALISE = new Function<String, String>() {
//         @Override
//         public String apply(String arg0) {
//             switch(arg0.length()) {
//                 case 0: return "";
//                 case 1: return arg0.toLowerCase();
//                 default: return arg0.substring(0, 1).toLowerCase() + arg0.substring(1);
//             }
//         }
//     };
//     
//     public static final Predicate<String> EMPTY = new Predicate<String>() {
//         @Override public boolean apply(String arg0) {
//             return arg0.isEmpty();
//         }
//     };
//     
//     public static final Predicate<String> NOT_EMPTY = Predicates.not(EMPTY);
// }


import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.regex.Pattern;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterators;
import com.timgroup.karg.naming.StringFunctions;
import static java.lang.String.format;
    
    public Field findReadableField(String propertyName) {
        return Iterators.find(Iterators.forArray(fields),
                              Predicates.and(isPublic(), fieldNameMatches(propertyName)),
                              null);
    }
    
    public Field findWritableField(String propertyName) {
        return Iterators.find(Iterators.forArray(fields),
                              Predicates.and(isModifiableField(), fieldNameMatches(propertyName)),
                              null);
    }
    
    private Predicate<Member> isPublic() {
        return new Predicate<Member>() {
            @Override public boolean apply(Member member) {
                return Modifier.isPublic(member.getModifiers());
            }
        };
    }
    
    private Predicate<Field> isModifiableField() {
        return new Predicate<Field>() {
            @Override public boolean apply(Field field) {
                return Modifier.isPublic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers());
            }
        };
    }
    
    private Predicate<Method> getterMethodNameMatches(String propertyName) {
// Path: src/main/java/com/timgroup/karg/naming/StringFunctions.java
// public final class StringFunctions {
// 
//     private StringFunctions() { }
// 
//     public static final Function<String, String> TRIM = new Function<String, String>() {
//         @Override
//         public String apply(String arg0) {
//             return arg0.trim();
//         }
//     };
//     
//     public static final Function<String, String> LOWERCASE = new Function<String, String>() {
//         @Override
//         public String apply(String arg0) {
//             return arg0.toLowerCase();
//         }
//     };
//     
//     public static final Function<String, String> LOWERCASE_TRIM = Functions.compose(LOWERCASE, TRIM);
//     
//     public static final Function<String, String> CAPITALISE = new Function<String, String>() {
//         @Override
//         public String apply(String arg0) {
//             switch(arg0.length()) {
//                 case 0: return "";
//                 case 1: return arg0.toUpperCase();
//                 default: return arg0.substring(0, 1).toUpperCase() + arg0.substring(1);
//             }
//         }
//     };
//     
//     public static final Function<String, String> UNCAPITALISE = new Function<String, String>() {
//         @Override
//         public String apply(String arg0) {
//             switch(arg0.length()) {
//                 case 0: return "";
//                 case 1: return arg0.toLowerCase();
//                 default: return arg0.substring(0, 1).toLowerCase() + arg0.substring(1);
//             }
//         }
//     };
//     
//     public static final Predicate<String> EMPTY = new Predicate<String>() {
//         @Override public boolean apply(String arg0) {
//             return arg0.isEmpty();
//         }
//     };
//     
//     public static final Predicate<String> NOT_EMPTY = Predicates.not(EMPTY);
// }


// Path: src/main/java/com/timgroup/karg/reflection/ClassInspector.java
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.regex.Pattern;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterators;
import com.timgroup.karg.naming.StringFunctions;
import static java.lang.String.format;

    
    public Field findReadableField(String propertyName) {
        return Iterators.find(Iterators.forArray(fields),
                              Predicates.and(isPublic(), fieldNameMatches(propertyName)),
                              null);
    }
    
    public Field findWritableField(String propertyName) {
        return Iterators.find(Iterators.forArray(fields),
                              Predicates.and(isModifiableField(), fieldNameMatches(propertyName)),
                              null);
    }
    
    private Predicate<Member> isPublic() {
        return new Predicate<Member>() {
            @Override public boolean apply(Member member) {
                return Modifier.isPublic(member.getModifiers());
            }
        };
    }
    
    private Predicate<Field> isModifiableField() {
        return new Predicate<Field>() {
            @Override public boolean apply(Field field) {
                return Modifier.isPublic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers());
            }
        };
    }
    
    private Predicate<Method> getterMethodNameMatches(String propertyName) {
        String capitalisedPropertyName = StringFunctions.CAPITALISE.apply(propertyName);