package org.hildan.livedoc.core.builders.doc;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.hildan.livedoc.core.annotations.types.ApiTypeProperty;
import org.hildan.livedoc.core.model.doc.types.ApiPropertyDoc;
import org.hildan.livedoc.core.model.doc.types.ApiTypeDoc;
import org.hildan.livedoc.core.model.doc.version.ApiVersionDoc;
import org.hildan.livedoc.core.model.types.LivedocType;
import org.hildan.livedoc.core.scanners.properties.Property;
import org.hildan.livedoc.core.scanners.types.references.TypeReferenceProvider;
import org.hildan.livedoc.core.util.BeanUtils;
import org.hildan.livedoc.core.util.HibernateValidationProcessor;

public class ApiPropertyDocReader {

    public static ApiPropertyDoc read(Property property, ApiTypeDoc parentDoc,
            TypeReferenceProvider typeReferenceProvider) {
        ApiPropertyDoc apiPropertyDoc = new ApiPropertyDoc();
        apiPropertyDoc.setName(property.getName());
        apiPropertyDoc.setType(getLivedocType(property, typeReferenceProvider));
        // FIXME maybe DefaultDocAnnotationScanner.UNDEFINED.toUpperCase() when not set
        apiPropertyDoc.setRequired(String.valueOf(property.isRequired()));
        apiPropertyDoc.setOrder(property.getOrder());

        String[] allowedvalues = getAllowedValues(property);
        apiPropertyDoc.setAllowedValues(allowedvalues);

        Field field = property.getField();
        if (field != null) {
            overrideFromMember(apiPropertyDoc, field);
        }
        Method getter = property.getGetter();
        if (getter != null) {
            overrideFromMember(apiPropertyDoc, getter);
        }

        apiPropertyDoc.setSupportedVersions(getVersionDoc(property, parentDoc));
        return apiPropertyDoc;
    }

    private static void overrideFromMember(ApiPropertyDoc apiPropertyDoc, AnnotatedElement annotatedElement) {
        ApiTypeProperty annotation = annotatedElement.getAnnotation(ApiTypeProperty.class);
        if (annotation != null) {
            overrideFromAnnotation(apiPropertyDoc, annotation);
        }
        HibernateValidationProcessor.addConstraintMessages(annotatedElement, apiPropertyDoc);
    }

    private static void overrideFromAnnotation(ApiPropertyDoc apiPropertyDoc, ApiTypeProperty annotation) {
        apiPropertyDoc.setName(BeanUtils.maybeOverridden(annotation.name(), apiPropertyDoc.getName()));
        apiPropertyDoc.setDescription(annotation.description());

        String[] allowedValues = BeanUtils.maybeOverridden(annotation.allowedValues(), apiPropertyDoc.getAllowedValues());
        apiPropertyDoc.setAllowedValues(allowedValues);

        // FIXME maybe DefaultDocAnnotationScanner.UNDEFINED.toUpperCase() when not set
        boolean isRequired = Boolean.valueOf(apiPropertyDoc.getRequired());
        apiPropertyDoc.setRequired(String.valueOf(annotation.required() || isRequired));
        apiPropertyDoc.setOrder(BeanUtils.maybeOverridden(annotation.order(), apiPropertyDoc.getOrder(), Integer.MAX_VALUE));

        if (!annotation.format().isEmpty()) {
            apiPropertyDoc.addFormat(annotation.format());
        }
    }

    private static String[] getAllowedValues(Property property) {
        if (property.getType().isEnum()) {
            Object[] enumConstants = property.getType().getEnumConstants();
            return BeanUtils.enumConstantsToStringArray(enumConstants);
        }
        return null;
    }

    private static LivedocType getLivedocType(Property property, TypeReferenceProvider typeReferenceProvider) {
        return typeReferenceProvider.getReference(property.getGenericType());
    }

    private static ApiVersionDoc getVersionDoc(Property property, ApiTypeDoc parentDoc) {
        ApiVersionDoc versionDoc = parentDoc.getSupportedVersions();
        Field field = property.getField();
        if (field != null) {
            versionDoc = ApiVersionDocReader.read(field, versionDoc);
        }
        Method getter = property.getGetter();
        if (getter != null) {
            versionDoc = ApiVersionDocReader.read(getter, versionDoc);
        }
        return versionDoc;
    }
}

@@ -910,28 +910,17 @@
 ertyDoc 
-apiPropertyD
+d
 oc = new
@@ -942,36 +942,25 @@
 ();%0A        
-apiPropertyD
+d
 oc.setName(p
@@ -983,36 +983,25 @@
 ));%0A        
-apiPropertyD
+d
 oc.setType(g
@@ -1141,36 +1141,25 @@
 set%0A        
-apiPropertyD
+d
 oc.setRequir
@@ -1205,36 +1205,25 @@
 ));%0A        
-apiPropertyD
+d
 oc.setOrder(
@@ -1310,36 +1310,25 @@
 y);%0A        
-apiPropertyD
+d
 oc.setAllowe
@@ -1451,36 +1451,25 @@
 eFromMember(
-apiPropertyD
+d
 oc, field);%0A
@@ -1585,28 +1585,17 @@
 mMember(
-apiPropertyD
+d
 oc, gett
@@ -1614,36 +1614,25 @@
  %7D%0A%0A        
-apiPropertyD
+d
 oc.setSuppor
@@ -1695,28 +1695,17 @@
  return 
-apiPropertyD
+d
 oc;%0A    
@@ -1761,36 +1761,25 @@
 PropertyDoc 
-apiPropertyD
+d
 oc, Annotate
@@ -1968,28 +1968,17 @@
 otation(
-apiPropertyD
+d
 oc, anno
@@ -2073,28 +2073,17 @@
 lement, 
-apiPropertyD
+d
 oc);%0A   
@@ -2148,28 +2148,17 @@
 ertyDoc 
-apiPropertyD
+d
 oc, ApiT
@@ -2187,36 +2187,25 @@
 ) %7B%0A        
-apiPropertyD
+d
 oc.setName(B
@@ -2244,36 +2244,25 @@
 ion.name(), 
-apiPropertyD
+d
 oc.getName()
@@ -2269,36 +2269,25 @@
 ));%0A        
-apiPropertyD
+d
 oc.setDescri
@@ -2403,36 +2403,25 @@
 edValues(), 
-apiPropertyD
+d
 oc.getAllowe
@@ -2436,36 +2436,25 @@
 ));%0A        
-apiPropertyD
+d
 oc.setAllowe
@@ -2611,28 +2611,17 @@
 valueOf(
-apiPropertyD
+d
 oc.getRe
@@ -2635,36 +2635,25 @@
 ));%0A        
-apiPropertyD
+d
 oc.setRequir
@@ -2709,24 +2709,25 @@
 ired));%0A
+%0A
         
 apiPrope
@@ -2722,32 +2722,24 @@
     
-apiPropertyDoc.setO
+Integer o
 rder
-(
+ = 
 Bean
@@ -2780,28 +2780,17 @@
 rder(), 
-apiPropertyD
+d
 oc.getOr
@@ -2814,16 +2814,44 @@
 X_VALUE)
+;%0A        doc.setOrder(order
 );%0A%0A    
@@ -2908,20 +2908,9 @@
     
-apiPropertyD
+d
 oc.a

Fix checkstyle warning