/*
 * Copyright 2002-2006,2009 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.opensymphony.xwork2.validator;

import com.opensymphony.xwork2.validator.annotations.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <code>AnnotationValidationConfigurationBuilder</code>
 *
 * @author Rainer Hermanns
 * @author jepjep
 * @version $Id$
 */
public class AnnotationValidationConfigurationBuilder {

    private static final Pattern SETTER_PATTERN = Pattern.compile("set([A-Z][A-Za-z0-9]*)$");
    private static final Pattern GETTER_PATTERN = Pattern.compile("(get|is|has)([A-Z][A-Za-z0-9]*)$");

    private ValidatorFactory validatorFactory;

    public AnnotationValidationConfigurationBuilder(ValidatorFactory fac) {
        this.validatorFactory = fac;
    }

    private List<ValidatorConfig> processAnnotations(Object o) {

        List<ValidatorConfig> result = new ArrayList<ValidatorConfig>();

        String fieldName = null;
        String methodName = null;

        Annotation[] annotations = null;

        if (o instanceof Class) {
            Class clazz = (Class) o;
            annotations = clazz.getAnnotations();
        }

        if (o instanceof Method) {
            Method method = (Method) o;
            fieldName = resolvePropertyName(method);
            methodName = method.getName();

            annotations = method.getAnnotations();
        }

        if (annotations != null) {
            for (Annotation a : annotations) {

                // Process collection of custom validations
                if (a instanceof Validations) {
                    processValidationAnnotation(a, fieldName, methodName, result);

                }

                // Process single custom validator
                if (a instanceof Validation) {
                    Validation v = (Validation) a;
                    if ( v.validations() != null ) {
                        for ( Validations val: v.validations()) {
                            processValidationAnnotation(val , fieldName, methodName, result);
                        }
                    }

                }
                // Process single custom validator
                else if (a instanceof ExpressionValidator) {
                    ExpressionValidator v = (ExpressionValidator) a;
                    ValidatorConfig temp = processExpressionValidatorAnnotation(v, fieldName, methodName);
                    if (temp != null) {
                        result.add(temp);
                    }

                }
                // Process single custom validator
                else if (a instanceof CustomValidator) {
                    CustomValidator v = (CustomValidator) a;
                    ValidatorConfig temp = processCustomValidatorAnnotation(v, fieldName, methodName);
                    if (temp != null) {
                        result.add(temp);
                    }

                }

                // Process ConversionErrorFieldValidator
                else if ( a instanceof ConversionErrorFieldValidator) {
                    ConversionErrorFieldValidator v = (ConversionErrorFieldValidator) a;
                    ValidatorConfig temp = processConversionErrorFieldValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process DateRangeFieldValidator
                else if ( a instanceof DateRangeFieldValidator) {
                    DateRangeFieldValidator v = (DateRangeFieldValidator) a;
                    ValidatorConfig temp = processDateRangeFieldValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process EmailValidator
                else if ( a instanceof EmailValidator) {
                    EmailValidator v = (EmailValidator) a;
                    ValidatorConfig temp = processEmailValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process FieldExpressionValidator
                else if ( a instanceof FieldExpressionValidator) {
                    FieldExpressionValidator v = (FieldExpressionValidator) a;
                    ValidatorConfig temp = processFieldExpressionValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process IntRangeFieldValidator
                else if ( a instanceof IntRangeFieldValidator) {
                    IntRangeFieldValidator v = (IntRangeFieldValidator) a;
                    ValidatorConfig temp = processIntRangeFieldValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process DoubleRangeFieldValidator
                else if ( a instanceof DoubleRangeFieldValidator) {
                    DoubleRangeFieldValidator v = (DoubleRangeFieldValidator) a;
                    ValidatorConfig temp = processDoubleRangeFieldValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process RequiredFieldValidator
                else if ( a instanceof RequiredFieldValidator) {
                    RequiredFieldValidator v = (RequiredFieldValidator) a;
                    ValidatorConfig temp = processRequiredFieldValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process RequiredStringValidator
                else if ( a instanceof RequiredStringValidator) {
                    RequiredStringValidator v = (RequiredStringValidator) a;
                    ValidatorConfig temp = processRequiredStringValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process StringLengthFieldValidator
                else if ( a instanceof StringLengthFieldValidator) {
                    StringLengthFieldValidator v = (StringLengthFieldValidator) a;
                    ValidatorConfig temp = processStringLengthFieldValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }
                }
                // Process UrlValidator
                else if ( a instanceof UrlValidator) {
                    UrlValidator v = (UrlValidator) a;
                    ValidatorConfig temp = processUrlValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process ConditionalVisitorFieldValidator
                else if ( a instanceof ConditionalVisitorFieldValidator) {
                    ConditionalVisitorFieldValidator v = (ConditionalVisitorFieldValidator) a;
                    ValidatorConfig temp = processConditionalVisitorFieldValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process VisitorFieldValidator
                else if ( a instanceof VisitorFieldValidator) {
                    VisitorFieldValidator v = (VisitorFieldValidator) a;
                    ValidatorConfig temp = processVisitorFieldValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
                // Process RegexFieldValidator
                else if ( a instanceof RegexFieldValidator) {
                    RegexFieldValidator v = (RegexFieldValidator) a;
                    ValidatorConfig temp = processRegexFieldValidatorAnnotation(v, fieldName, methodName);
                    if ( temp != null) {
                        result.add(temp);
                    }

                }
            }
        }
        return result;
    }

    private void processValidationAnnotation(Annotation a, String fieldName, String methodName, List<ValidatorConfig> result) {
        Validations validations = (Validations) a;
        CustomValidator[] cv = validations.customValidators();
        if ( cv != null ) {
            for (CustomValidator v : cv) {
                ValidatorConfig temp = processCustomValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        ExpressionValidator[] ev = validations.expressions();
        if ( ev != null ) {
            for (ExpressionValidator v : ev) {
                ValidatorConfig temp = processExpressionValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        ConversionErrorFieldValidator[] cef = validations.conversionErrorFields();
        if ( cef != null ) {
            for (ConversionErrorFieldValidator v : cef) {
                ValidatorConfig temp = processConversionErrorFieldValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        DateRangeFieldValidator[] drfv = validations.dateRangeFields();
        if ( drfv != null ) {
            for (DateRangeFieldValidator v : drfv) {
                ValidatorConfig temp = processDateRangeFieldValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        EmailValidator[] emv = validations.emails();
        if ( emv != null ) {
            for (EmailValidator v : emv) {
                ValidatorConfig temp = processEmailValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        FieldExpressionValidator[] fev = validations.fieldExpressions();
        if ( fev != null ) {
            for (FieldExpressionValidator v : fev) {
                ValidatorConfig temp = processFieldExpressionValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        IntRangeFieldValidator[] irfv = validations.intRangeFields();
        if ( irfv != null ) {
            for (IntRangeFieldValidator v : irfv) {
                ValidatorConfig temp = processIntRangeFieldValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        RegexFieldValidator[] rfv = validations.regexFields();
        if ( rfv != null ) {
            for (RegexFieldValidator v : rfv) {
                ValidatorConfig temp = processRegexFieldValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        RequiredFieldValidator[] rv = validations.requiredFields();
        if ( rv != null ) {
            for (RequiredFieldValidator v : rv) {
                ValidatorConfig temp = processRequiredFieldValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        RequiredStringValidator[] rsv = validations.requiredStrings();
        if ( rsv != null ) {
            for (RequiredStringValidator v : rsv) {
                ValidatorConfig temp = processRequiredStringValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        StringLengthFieldValidator[] slfv = validations.stringLengthFields();
        if ( slfv != null ) {
            for (StringLengthFieldValidator v : slfv) {
                ValidatorConfig temp = processStringLengthFieldValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        UrlValidator[] uv = validations.urls();
        if ( uv != null ) {
            for (UrlValidator v : uv) {
                ValidatorConfig temp = processUrlValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        ConditionalVisitorFieldValidator[] cvfv = validations.conditionalVisitorFields();
        if ( cvfv != null ) {
            for (ConditionalVisitorFieldValidator v : cvfv) {
                ValidatorConfig temp = processConditionalVisitorFieldValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
        VisitorFieldValidator[] vfv = validations.visitorFields();
        if ( vfv != null ) {
            for (VisitorFieldValidator v : vfv) {
                ValidatorConfig temp = processVisitorFieldValidatorAnnotation(v, fieldName, methodName);
                if (temp != null) {
                    result.add(temp);
                }
            }
        }
    }

    private ValidatorConfig processExpressionValidatorAnnotation(ExpressionValidator v, String fieldName, String methodName) {
        String validatorType = "expression";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        }

        params.put("expression", v.expression());

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();

    }

    private ValidatorConfig processCustomValidatorAnnotation(CustomValidator v, String fieldName, String methodName) {

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }


        String validatorType = v.type();

        validatorFactory.lookupRegisteredValidatorType(validatorType);

        Annotation[] recursedAnnotations = v.parameters();

        if ( recursedAnnotations != null ) {
            for (Annotation a2 : recursedAnnotations) {

                if (a2 instanceof ValidationParameter) {

                    ValidationParameter parameter = (ValidationParameter) a2;
                    String parameterName = parameter.name();
                    String parameterValue = parameter.value();
                    params.put(parameterName, parameterValue);
                }

            }
        }

        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processRegexFieldValidatorAnnotation(RegexFieldValidator v, String fieldName, String methodName) {
        String validatorType = "regex";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        params.put("expression", v.expression());

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processConditionalVisitorFieldValidatorAnnotation(ConditionalVisitorFieldValidator v, String fieldName, String methodName) {
        String validatorType = "conditionalvisitor";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        params.put("expression", v.expression());
        params.put("context", v.context());
        params.put("appendPrefix", String.valueOf(v.appendPrefix()));

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }



    private ValidatorConfig processVisitorFieldValidatorAnnotation(VisitorFieldValidator v, String fieldName, String methodName) {

        String validatorType = "visitor";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        params.put("context", v.context());
        params.put("appendPrefix", String.valueOf(v.appendPrefix()));

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processUrlValidatorAnnotation(UrlValidator v, String fieldName, String methodName) {
        String validatorType = "url";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processStringLengthFieldValidatorAnnotation(StringLengthFieldValidator v, String fieldName, String methodName) {
        String validatorType = "stringlength";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        if ( v.maxLength() != null && v.maxLength().length() > 0) {
            params.put("maxLength", v.maxLength());
        }
        if ( v.minLength() != null && v.minLength().length() > 0) {
            params.put("minLength", v.minLength());
        }
        params.put("trim", String.valueOf(v.trim()));

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private Date parseDateString(String value) {

        SimpleDateFormat d1 = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, Locale.getDefault());
        SimpleDateFormat d2 = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, Locale.getDefault());
        SimpleDateFormat d3 = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault());
        SimpleDateFormat[] dfs = {d1, d2, d3};
        DateFormat df = null;
        for (SimpleDateFormat df1 : dfs) {
            try {
                Date check = df1.parse(value);
                df = df1;
                if (check != null) {
                    return check;
                }
            }
            catch (ParseException ignore) {
            }
        }
        return null;

    }

    private ValidatorConfig processRequiredStringValidatorAnnotation(RequiredStringValidator v, String fieldName, String methodName) {
        String validatorType = "requiredstring";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        params.put("trim", String.valueOf(v.trim()));

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processRequiredFieldValidatorAnnotation(RequiredFieldValidator v, String fieldName, String methodName) {
        String validatorType = "required";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processIntRangeFieldValidatorAnnotation(IntRangeFieldValidator v, String fieldName, String methodName) {
        String validatorType = "int";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        if ( v.min() != null && v.min().length() > 0) {
            params.put("min", v.min());
        }
        if ( v.max() != null && v.max().length() > 0) {
            params.put("max", v.max());
        }

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processDoubleRangeFieldValidatorAnnotation(DoubleRangeFieldValidator v, String fieldName, String methodName) {
        String validatorType = "double";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        if ( v.minInclusive() != null && v.minInclusive().length() > 0) {
            params.put("minInclusive", v.minInclusive());
        }
        if ( v.maxInclusive() != null && v.maxInclusive().length() > 0) {
            params.put("maxInclusive", v.maxInclusive());
        }

        if ( v.minExclusive() != null && v.minExclusive().length() > 0) {
            params.put("minExclusive", v.minExclusive());
        }
        if ( v.maxExclusive() != null && v.maxExclusive().length() > 0) {
            params.put("maxExclusive", v.maxExclusive());
        }

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processFieldExpressionValidatorAnnotation(FieldExpressionValidator v, String fieldName, String methodName) {
        String validatorType = "fieldexpression";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        params.put("expression", v.expression());

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processEmailValidatorAnnotation(EmailValidator v, String fieldName, String methodName) {
        String validatorType = "email";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processDateRangeFieldValidatorAnnotation(DateRangeFieldValidator v, String fieldName, String methodName) {
        String validatorType = "date";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }
        if ( v.min() != null && v.min().length() > 0) {
             final Date minDate = parseDateString(v.min());
             params.put("min", String.valueOf(minDate == null ? v.min() : minDate));
        }
        if ( v.max() != null && v.max().length() > 0) {
             final Date maxDate = parseDateString(v.max());
             params.put("max", String.valueOf(maxDate == null ? v.max() : maxDate));
        }

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    private ValidatorConfig processConversionErrorFieldValidatorAnnotation(ConversionErrorFieldValidator v, String fieldName, String methodName) {
        String validatorType = "conversion";

        Map<String, String> params = new HashMap<String, String>();

        if (fieldName != null) {
            params.put("fieldName", fieldName);
        } else if (v.fieldName() != null && v.fieldName().length() > 0 ) {
            params.put("fieldName", v.fieldName());
        }

        validatorFactory.lookupRegisteredValidatorType(validatorType);
        return new ValidatorConfig.Builder(validatorType)
            .addParams(params)
            .addParam("methodName", methodName)
            .shortCircuit(v.shortCircuit())
            .defaultMessage(v.message())
            .messageKey(v.key())
            .build();
    }

    public List<ValidatorConfig> buildAnnotationClassValidatorConfigs(Class aClass) {

        List<ValidatorConfig> result = new ArrayList<ValidatorConfig>();

        List<ValidatorConfig> temp = processAnnotations(aClass);
        if (temp != null) {
            result.addAll(temp);
        }

        Method[] methods = aClass.getDeclaredMethods();

        if ( methods != null ) {
            for (Method method : methods) {
                temp = processAnnotations(method);
                if (temp != null) {
                    result.addAll(temp);
                }
            }
        }

        return result;

    }

    /**
     * Returns the property name for a method.
     * This method is independant from property fields.
     *
     * @param method The method to get the property name for.
     * @return the property name for given method; null if non could be resolved.
     */
    public String resolvePropertyName(Method method) {

        Matcher matcher = SETTER_PATTERN.matcher(method.getName());
        if (matcher.matches() && method.getParameterTypes().length == 1) {
            String raw = matcher.group(1);
            return raw.substring(0, 1).toLowerCase() + raw.substring(1);
        }

        matcher = GETTER_PATTERN.matcher(method.getName());
        if (matcher.matches() && method.getParameterTypes().length == 0) {
            String raw = matcher.group(2);
            return raw.substring(0, 1).toLowerCase() + raw.substring(1);
        }

        return null;
    }

}
