package info.izumin.android.droidux.processor.util;

import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.AnnotationValueVisitor;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleAnnotationValueVisitor6;

import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
import static com.google.auto.common.MoreElements.getAnnotationMirror;

/**
 * Created by izumin on 11/2/15.
 */
public final class AnnotationUtils {
    public static final String TAG = AnnotationUtils.class.getSimpleName();

    private AnnotationUtils() {
        throw new AssertionError("constructor of the utility class should not be called");
    }

    public static List<ExecutableElement> findMethodsByAnnotation(Element element, Class<? extends Annotation> clazz) {
        List<ExecutableElement> list = new ArrayList<>();
        for (Element el : element.getEnclosedElements()) {
            Annotation annotation = el.getAnnotation(clazz);
            if (annotation != null) {
                list.add((ExecutableElement) el);
            }
        }
        return list;
    }

    public static TypeMirror getTypeFromAnnotation(Element element, Class<? extends Annotation> annotationType, String argName) {
        AnnotationMirror am = getAnnotationMirror(element, annotationType).get();
        AnnotationValue av = getAnnotationValue(am, argName);
        return TO_TYPE.visit(av);
    }

    public static List<TypeMirror> getTypesFromAnnotation(Element element, Class<? extends Annotation> annotationType, String argName) {
        AnnotationMirror am = getAnnotationMirror(element, annotationType).get();
        AnnotationValue av = getAnnotationValue(am, argName);
        return TO_LIST_OF_TYPE.visit(av);
    }

    private static final AnnotationValueVisitor<ImmutableList<TypeMirror>, Void> TO_LIST_OF_TYPE = new SimpleAnnotationValueVisitor6<ImmutableList<TypeMirror>, Void>() {
        @Override
        public ImmutableList<TypeMirror> visitArray(List<? extends AnnotationValue> vals, Void aVoid) {
            return FluentIterable.from(vals).transform(new Function<AnnotationValue, TypeMirror>() {
                @Override
                public TypeMirror apply(AnnotationValue input) {
                    return TO_TYPE.visit(input);
                }
            }).toList();
        }
    };

    private static final AnnotationValueVisitor<TypeMirror, Void> TO_TYPE = new SimpleAnnotationValueVisitor6<TypeMirror, Void>() {
        @Override
        public TypeMirror visitType(TypeMirror t, Void aVoid) {
            return t;
        }
    };
}
@@ -82,24 +82,65 @@
 e.Function;%0A
+import com.google.common.base.Predicate;%0A
 import com.g
@@ -269,36 +269,8 @@
 on;%0A
-import java.util.ArrayList;%0A
 impo
@@ -1144,32 +1144,38 @@
 Element element,
+ final
  Class%3C? extends
@@ -1208,155 +1208,241 @@
     
-List%3CExecutableElement%3E list = new ArrayList%3C%3E();%0A        for (Element el : element.getEnclosedElements()) %7B%0A            Annotation annotation = el
+return FluentIterable.from(element.getEnclosedElements())%0A                .filter(new Predicate%3CElement%3E() %7B%0A                    @Override%0A                    public boolean apply(Element input) %7B%0A                        return input
 .get
@@ -1458,16 +1458,24 @@
 n(clazz)
+ != null
 ;%0A      
@@ -1484,59 +1484,238 @@
     
-if (annotation != null) %7B%0A                list.add(
+        %7D%0A                %7D)%0A                .transform(new Function%3CElement, ExecutableElement%3E() %7B%0A                    @Override%0A                    public ExecutableElement apply(Element input) %7B%0A                        return 
 (Exe
@@ -1734,13 +1734,22 @@
 nt) 
-el);%0A
+input;%0A       
     
@@ -1748,32 +1748,33 @@
                 
+ 
 %7D%0A        %7D%0A    
@@ -1759,33 +1759,42 @@
       %7D%0A        
+       
-%7D
+ %7D)
 %0A        return 
@@ -1790,19 +1790,25 @@
     
-return l
+        .toL
 ist
+()
 ;%0A  

Use FluentIterable in AnnotationUtils.findMethodByAnnotation()