package com.mangofactory.swagger.core;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.mangofactory.swagger.scanners.ResourceGroup;
import com.wordnik.swagger.annotations.Api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;

import java.util.Set;

import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.Sets.*;
import static com.mangofactory.swagger.core.StringUtils.*;
import static org.apache.commons.lang.StringUtils.*;

@Component
public class ClassOrApiAnnotationResourceGrouping implements ResourceGroupingStrategy {
   private static final Logger log = LoggerFactory.getLogger(ClassOrApiAnnotationResourceGrouping.class);

   public ClassOrApiAnnotationResourceGrouping() {
   }

   @Override
   public String getResourceDescription(RequestMappingInfo requestMappingInfo, HandlerMethod handlerMethod) {
     Class<?> controllerClass = handlerMethod.getBeanType();
     String group = splitCamelCase(controllerClass.getSimpleName(), " ");
     return extractAnnotation(controllerClass, descriptionOrValueExtractor()).or(group);
   }

  @Override
   public Integer getResourcePosition(RequestMappingInfo requestMappingInfo, HandlerMethod handlerMethod) {
      Class<?> controllerClass = handlerMethod.getBeanType();
      Api apiAnnotation = AnnotationUtils.findAnnotation(controllerClass, Api.class);
      if (null != apiAnnotation && !isBlank(apiAnnotation.value())) {
         return apiAnnotation.position();
      }
      return 0;
   }

   @Override
   public Set<ResourceGroup> getResourceGroups(RequestMappingInfo requestMappingInfo, HandlerMethod handlerMethod) {
      String group = getClassOrApiAnnotationValue(handlerMethod).toLowerCase().replaceAll(" ", "-");
      Integer position = getResourcePosition(requestMappingInfo, handlerMethod);
      return newHashSet(new ResourceGroup(group.toLowerCase(), position));
   }

   private String getClassOrApiAnnotationValue(HandlerMethod handlerMethod) {
    Class<?> controllerClass = handlerMethod.getBeanType();
    String group = splitCamelCase(controllerClass.getSimpleName(), " ");

    return extractAnnotation(controllerClass, valueExtractor()).or(group);
   }

  private Optional<String> extractAnnotation(Class<?> controllerClass, Function<Api,
          Optional<String>> annotationExtractor) {
    Api apiAnnotation = AnnotationUtils.findAnnotation(controllerClass, Api.class);
    return annotationExtractor.apply(apiAnnotation);
  }

  private Function<Api, Optional<String>> descriptionOrValueExtractor() {
    return new Function<Api, Optional<String>>() {
      @Override
      public Optional<String> apply(Api input) {
        return descriptionExtractor().apply(input).or(valueExtractor().apply(input));
      }
    };
  }

  private Function<Api, Optional<String>> valueExtractor() {
    return new Function<Api, Optional<String>>() {
      @Override
      public Optional<String> apply(Api input) {
        if (null != input) {
          return Optional.fromNullable(emptyToNull(input.value()));
        }
        return Optional.absent();
      }
    };
  }

  private Function<Api, Optional<String>> descriptionExtractor() {
    return new Function<Api, Optional<String>>() {
      @Override
      public Optional<String> apply(Api input) {
        if (null != input) {
          return Optional.fromNullable(emptyToNull(input.description()));
        }
        return Optional.absent();
      }
    };
  }
}

@@ -846,17 +846,16 @@
 egy %7B%0A  
- 
 private 
@@ -952,17 +952,16 @@
 ss);%0A%0A  
- 
 public C
@@ -1002,21 +1002,19 @@
 g() %7B%0A  
- 
 %7D%0A%0A
- 
   @Overr
@@ -1009,33 +1009,32 @@
  %7D%0A%0A  @Override%0A
- 
   public String 
@@ -1126,25 +1126,24 @@
 thod) %7B%0A    
- 
 Class%3C?%3E con
@@ -1182,25 +1182,24 @@
 BeanType();%0A
- 
     String g
@@ -1259,25 +1259,24 @@
 , %22 %22);%0A    
- 
 return extra
@@ -1343,25 +1343,24 @@
 .or(group);%0A
- 
   %7D%0A%0A  @Over
@@ -1362,25 +1362,24 @@
 @Override%0A  
- 
 public Integ
@@ -1475,18 +1475,16 @@
 ) %7B%0A    
-  
 Class%3C?%3E
@@ -1535,18 +1535,16 @@
 ();%0A    
- 
- 
 Api apiA
@@ -1615,26 +1615,24 @@
 class);%0A    
-  
 if (null != 
@@ -1685,27 +1685,24 @@
 ))) %7B%0A      
- 
-  
 return apiAn
@@ -1726,26 +1726,22 @@
 ();%0A    
-  
 %7D%0A    
- 
- 
 return 0
@@ -1742,25 +1742,23 @@
 turn 0;%0A
- 
   %7D%0A%0A  
- 
 @Overrid
@@ -1759,17 +1759,16 @@
 verride%0A
- 
   public
@@ -1879,18 +1879,16 @@
 ) %7B%0A    
-  
 String g
@@ -1974,18 +1974,16 @@
 , %22-%22);%0A
-  
     Inte
@@ -2053,26 +2053,24 @@
 ethod);%0A    
-  
 return newHa
@@ -2128,21 +2128,19 @@
 on));%0A  
- 
 %7D%0A%0A
- 
   privat
@@ -2417,17 +2417,16 @@
 group);%0A
- 
   %7D%0A%0A  p

Reformat code for spacing