package net.yslibrary.simplepreferences.processor;

import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import net.yslibrary.simplepreferences.annotation.Key;
import net.yslibrary.simplepreferences.annotation.Preferences;
import net.yslibrary.simplepreferences.processor.exception.ProcessingException;

/**
 * Created by yshrsmz on 2016/02/21.
 */
public class PreferenceAnnotatedClass {

  public final static String DEFAULT_PREFS = "default";
  private final static String SUFFIX = "Prefs";

  public final TypeElement annotatedElement;

  // used as SharedPreferences' name
  public final String preferenceName;

  // generated class name
  public final String preferenceClassName;
  public final String qualifiedPreferenceClassName;

  public final String packageName;

  public final List<KeyAnnotatedField> keys = new ArrayList<>();

  public PreferenceAnnotatedClass(TypeElement element, Elements elementUtils)
      throws IllegalStateException, ProcessingException {
    annotatedElement = element;
    Preferences annotation = annotatedElement.getAnnotation(Preferences.class);
    String value = annotation.value().trim();
    String simpleName = element.getSimpleName().toString();
    preferenceName = Strings.isNullOrEmpty(value) ? DEFAULT_PREFS : value;

    if (Strings.isNullOrEmpty(preferenceName)) {
      throw new IllegalStateException(String.format(
          "value() in @%s for Class %s is null, empty or target Class is anonymous class. You must specify value or class should be concrete.",
          Preferences.class.getSimpleName(), element.getQualifiedName()));
    }

    preferenceClassName = simpleName + SUFFIX;
    qualifiedPreferenceClassName = element.getQualifiedName().toString() + SUFFIX;

    PackageElement pkg = elementUtils.getPackageOf(element);
    packageName = pkg.isUnnamed() ? null : pkg.getQualifiedName().toString();

    try {
      List<KeyAnnotatedField> annotatedVariables = element.getEnclosedElements()
          .stream()
          .filter(variable -> variable.getAnnotation(Key.class) != null)
          .map(variable -> {
            try {
              return new KeyAnnotatedField((VariableElement) variable);
            } catch (ProcessingException e) {
              throw new RuntimeException(e);
            }
          })
          .collect(Collectors.toList());

      keys.addAll(annotatedVariables);
    } catch (RuntimeException e) {
      if (e.getCause() instanceof ProcessingException) {
        throw (ProcessingException) e.getCause();
      }
    }
  }

  public boolean useDefaultPreferences() {
    return preferenceName.equals(DEFAULT_PREFS);
  }
}

@@ -131,18 +131,27 @@
 .util.Li
-st
+nkedHashMap
 ;%0Aimport
@@ -165,25 +165,34 @@
 til.
-stream.Collectors
+List;%0Aimport java.util.Map
 ;%0Aim
@@ -2151,21 +2151,28 @@
 %7B%0A      
-List%3C
+Map%3CString, 
 KeyAnnot
@@ -2186,28 +2186,42 @@
 ld%3E 
-annotatedVariables =
+map = new LinkedHashMap%3C%3E();%0A     
  ele
@@ -2351,19 +2351,23 @@
        .
-map
+forEach
 (variabl
@@ -2405,22 +2405,41 @@
         
-return
+KeyAnnotatedField field =
  new Key
@@ -2478,24 +2478,490 @@
  variable);%0A
+              KeyAnnotatedField existing = map.get(field.preferenceKey);%0A%0A              if (existing != null) %7B%0A                throw new ProcessingException(variable,%0A                    %22Conflict: Preference key of the field %25s annotated with @%25s is declared as '%25s', but %25s already uses same value%22,%0A                    field.name, Key.class.getSimpleName(), field.preferenceKey, existing.name);%0A              %7D%0A              map.put(field.preferenceKey, field);%0A
             
@@ -3069,48 +3069,8 @@
   %7D)
-%0A          .collect(Collectors.toList())
 ;%0A%0A 
@@ -3090,26 +3090,20 @@
 All(
-annotatedVariables
+map.values()
 );%0A 

check duplicate preference key