/*
 * Copyright (c) 2016-2018 Daniel Ennis (Aikar) - MIT License
 *
 *  Permission is hereby granted, free of charge, to any person obtaining
 *  a copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject to
 *  the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package co.aikar.commands;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.IdentityHashMap;
import java.util.Map;

@SuppressWarnings("TypeParameterExplicitlyExtendsObject")
class Annotations <M extends CommandManager> extends AnnotationLookups {

    public static int NOTHING = 0;
    public static int REPLACEMENTS = 1;
    public static int LOWERCASE = 1 << 1;
    public static int UPPERCASE = 1 << 2;
    public static int NO_EMPTY = 1 << 3;

    private final M manager;

    private Map<Class<? extends Annotation>, Method> valueMethods = new IdentityHashMap<>();

    Annotations(M manager) {
        this.manager = manager;
    }

    String getValue(Annotation annotation, Class<? extends Annotation> annoClass, int options) {
        if (annotation == null) {
            // TODO: Alias support
            return null;
        }
        try {
            Method valueMethod = valueMethods.get(annoClass);
            if (valueMethod == null) {
                valueMethod = annoClass.getMethod("value");
                valueMethod.setAccessible(true);
                valueMethods.put(annoClass, valueMethod);
            }
            String value = (String) valueMethod.invoke(annotation);
            if (value == null) {
                // TODO: Alias support
                return null;
            }
            if (hasOption(options, REPLACEMENTS)) {
                value = manager.getCommandReplacements().replace(value);
            }
            if (hasOption(options, LOWERCASE)) {
                value = value.toLowerCase(manager.getLocales().getDefaultLocale());
            } else if (hasOption(options, UPPERCASE)) {
                value = value.toUpperCase(manager.getLocales().getDefaultLocale());
            }
            if (value.isEmpty() && hasOption(options, NO_EMPTY)) {
                return null;
            }
            return value;
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            manager.log(LogLevel.ERROR, "Error getting annotation value", e);
        }
        return null;
    }

    private static boolean hasOption(int options, int option) {
        return (options & option) == option;
    }

}

@@ -1822,16 +1822,113 @@
 Map%3C%3E();
+%0A    private Map%3CClass%3C? extends Annotation%3E, Void%3E noValueAnnotations = new IdentityHashMap%3C%3E();
 %0A%0A    An
@@ -2098,33 +2098,29 @@
     
-if (annotation =
+String value 
 = null
-) %7B
+;%0A
 %0A   
@@ -2128,81 +2128,31 @@
     
-    // TODO: Alias support%0A            return null;%0A        %7D%0A        try
+if (annotation != null)
  %7B%0A 
@@ -2271,52 +2271,289 @@
     
-valueMethod = annoClass.getMethod(%22value%22);%0A
+if (noValueAnnotations.containsKey(annoClass)) %7B%0A                    value = %22%22;%0A                %7D else %7B%0A                    try %7B%0A                        valueMethod = annoClass.getMethod(%22value%22);%0A                        value = (String) valueMethod.invoke(annotation);%0A        
     
@@ -2593,24 +2593,32 @@
 ible(true);%0A
+        
             
@@ -2671,34 +2671,32 @@
             
-%7D%0A
         
     String v
@@ -2687,109 +2687,452 @@
     
-    String value = (String) valueMethod.invoke(annotation);%0A            if (value == null) %7B%0A        
+%7D catch (NoSuchMethodException %7C IllegalAccessException %7C InvocationTargetException e) %7B%0A                        if (!(e instanceof NoSuchMethodException)) %7B%0A                            manager.log(LogLevel.ERROR, %22Error getting annotation value%22, e);%0A                        %7D%0A                        noValueAnnotations.put(annoClass, null);%0A                        value = %22%22;%0A                    %7D%0A                %7D%0A            %7D%0A        %7D%0A%0A
     
@@ -3153,16 +3153,11 @@
 lias
- support
+es%0A
 %0A   
@@ -3165,42 +3165,50 @@
     
-        return null;%0A            %7D
+// transforms%0A        if (value != null) %7B
 %0A   
@@ -3634,32 +3634,78 @@
   %7D%0A        
-    if (
+%7D%0A%0A        // validation%0A        if (value != null && 
 value.isEmpt
@@ -3751,34 +3751,31 @@
             
-    return
+value =
  null;%0A     
@@ -3773,34 +3773,26 @@
 ll;%0A        
-    %7D%0A    
+%7D%0A
         retu
@@ -3805,214 +3805,8 @@
 ue;%0A
-        %7D catch (NoSuchMethodException %7C IllegalAccessException %7C InvocationTargetException e) %7B%0A            manager.log(LogLevel.ERROR, %22Error getting annotation value%22, e);%0A        %7D%0A        return null;%0A
     

fix looking up annotations without value methods