/**
 * Copyright (c) 2017-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.facebook.litho.specmodels.processor;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;

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

import com.facebook.litho.specmodels.model.MethodParamModel;
import com.facebook.litho.specmodels.model.MethodParamModelFactory;

import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;

/**
 * Extracts methods from the given input.
 */
public class MethodExtractorUtils {
  private static final String COMPONENTS_PACKAGE = "com.facebook.litho";

  /**
   * @return a list of params for a method.
   */
  static List<MethodParamModel> getMethodParams(
      ExecutableElement method,
      List<Class<? extends Annotation>> permittedAnnotations,
      List<Class<? extends Annotation>> permittedInterStageInputAnnotations) {
    final List<MethodParamModel> methodParams = new ArrayList<>();
    for (VariableElement param : method.getParameters()) {
      methodParams.add(
          MethodParamModelFactory.create(
              TypeName.get(param.asType()),
              param.getSimpleName().toString(),
              getLibraryAnnotations(param, permittedAnnotations),
              getExternalAnnotations(param),
              permittedInterStageInputAnnotations,
              param));
    }

    return methodParams;
  }

  private static List<Annotation> getLibraryAnnotations(
      VariableElement param,
      List<Class<? extends Annotation>> permittedAnnotations) {
    List<Annotation> paramAnnotations = new ArrayList<>();
    for (Class<? extends Annotation> possibleMethodParamAnnotation : permittedAnnotations) {
      final Annotation paramAnnotation = param.getAnnotation(possibleMethodParamAnnotation);
      if (paramAnnotation != null) {
        paramAnnotations.add(paramAnnotation);
      }
    }

    return paramAnnotations;
  }

  private static List<AnnotationSpec> getExternalAnnotations(VariableElement param) {
    final List<? extends AnnotationMirror> annotationMirrors = param.getAnnotationMirrors();
    final List<AnnotationSpec> annotations = new ArrayList<>();

    for (AnnotationMirror annotationMirror : annotationMirrors) {
      if (annotationMirror.getAnnotationType().toString().startsWith(COMPONENTS_PACKAGE)) {
        continue;
      }

      final AnnotationSpec.Builder annotationSpec =
          AnnotationSpec.builder(
              ClassName.bestGuess(annotationMirror.getAnnotationType().toString()));

      Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues =
          annotationMirror.getElementValues();
      for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> elementValue :
          elementValues.entrySet()) {
        annotationSpec.addMember(
            elementValue.getKey().getSimpleName().toString(),
            elementValue.getValue().toString());
      }

      annotations.add(annotationSpec.build());
    }

    return annotations;
  }
}

@@ -1482,24 +1482,38 @@
 meters()) %7B%0A
+      try %7B%0A  
       method
@@ -1534,16 +1534,18 @@
         
+  
 MethodPa
@@ -1568,16 +1568,18 @@
 create(%0A
+  
         
@@ -1624,24 +1624,26 @@
             
+  
 param.getSim
@@ -1678,16 +1678,18 @@
         
+ 
+ 
 getLibra
@@ -1732,16 +1732,18 @@
 tions),%0A
+  
         
@@ -1793,16 +1793,18 @@
         
+  
 permitte
@@ -1842,24 +1842,26 @@
             
+ 
+ 
 param));%0A   
@@ -1853,24 +1853,210 @@
    param));%0A
+      %7D catch (Exception e) %7B%0A        throw new ComponentsProcessingException(%0A            param,%0A            %22Error processing this param. Are your imports set up correctly?%22);%0A      %7D%0A
     %7D%0A%0A    r

Clear error when imports are missing for params