package com.mangofactory.swagger.spring;

import com.fasterxml.classmate.ResolvedType;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.mangofactory.swagger.ControllerDocumentation;
import com.mangofactory.swagger.SwaggerConfiguration;
import com.mangofactory.swagger.filters.FilterContext;
import com.mangofactory.swagger.filters.Filters;
import com.wordnik.swagger.core.DocumentationAllowableListValues;
import com.wordnik.swagger.core.DocumentationError;
import com.wordnik.swagger.core.DocumentationOperation;
import com.wordnik.swagger.core.DocumentationParameter;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.NameValueExpression;
import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition;

import java.util.List;

import static com.google.common.collect.Iterables.*;
import static com.google.common.collect.Lists.*;
import static com.mangofactory.swagger.models.ResolvedTypes.*;

public class OperationReader {
    private final SwaggerConfiguration configuration;

    public OperationReader(SwaggerConfiguration configuration) {
        this.configuration = configuration;
    }

    DocumentationOperation readOperation(ControllerDocumentation controllerDocumentation, HandlerMethod handlerMethod,
                                         ParamsRequestCondition paramsCondition, RequestMethod requestMethod) {
        DocumentationOperation operation = new DocumentationOperation(requestMethod.name(), "", "");
        FilterContext<DocumentationOperation> operationContext = new FilterContext<DocumentationOperation>(operation);
        operationContext.put("handlerMethod", handlerMethod);
        operationContext.put("controllerDocumentation", controllerDocumentation);
        operationContext.put("swaggerConfiguration", configuration);
        Filters.Fn.applyFilters(configuration.getOperationFilters(), operationContext);
        int parameterIndex = 0;
        String [] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(handlerMethod
                .getMethod());
        List<ResolvedType> resolvedParameters = methodParameters(configuration.getTypeResolver(),
                handlerMethod.getMethod());
        MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
        for (int index = 0; index < handlerMethod.getMethodParameters().length; index++) {
            DocumentationParameter parameter = new DocumentationParameter();
            ResolvedType resolvedType = configuration.maybeGetAlternateType(resolvedParameters.get(index));
            if (resolvedParameters.size() == 0
                    || configuration.isParameterTypeIgnorable(resolvedType.getErasedType())) {
                continue;
            }
            FilterContext<DocumentationParameter> parameterContext = new FilterContext<DocumentationParameter>(parameter);
            parameterContext.put("methodParameter", methodParameters[index]);
            parameterContext.put("parameterType", resolvedType);
            parameterContext.put("defaultParameterName", parameterNames[parameterIndex++]);
            parameterContext.put("controllerDocumentation", controllerDocumentation);
            Filters.Fn.applyFilters(configuration.getParameterFilters(), parameterContext);
            operation.addParameter(parameter);
        }
        for (NameValueExpression<String> expression : paramsCondition.getExpressions()) {
            if (expression.isNegated() || any(operation.getParameters(), withName(expression.getName()))) {
                continue;
            }
            DocumentationParameter parameter = new DocumentationParameter();
            parameter.setDataType("String");
            parameter.setName(expression.getName());
            parameter.setDefaultValue(expression.getValue());
            parameter.setRequired(true);
            parameter.setParamType("query");
            parameter.setAllowableValues(new DocumentationAllowableListValues(newArrayList(expression.getValue())));
            operation.addParameter(parameter);
        }

        List<DocumentationError> errors = newArrayList();
        FilterContext<List<DocumentationError>> errorContext = new FilterContext<List<DocumentationError>>(errors);
        errorContext.put("handlerMethod", handlerMethod);
        Filters.Fn.applyFilters(configuration.getErrorFilters(), errorContext);
        for (DocumentationError error : errors) {
            operation.addErrorResponse(error);
        }
        return operation;
    }

    private Predicate<? super DocumentationParameter> withName(final String name) {
        return new Predicate<DocumentationParameter>() {
            @Override
            public boolean apply(DocumentationParameter input) {
                return Objects.equal(input.getName(), name);
            }
        };
    }
}
@@ -2176,154 +2176,8 @@
  0;%0A
-        String %5B%5D parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(handlerMethod%0A                .getMethod());%0A
     
@@ -2392,24 +2392,118 @@
 rameters();%0A
+        String %5B%5D parameterNames = getParameterNames(handlerMethod, methodParameters.length);%0A
         for 
@@ -4725,24 +4725,564 @@
 ion;%0A    %7D%0A%0A
+    private String%5B%5D getParameterNames(HandlerMethod handlerMethod, int length) %7B%0A        String%5B%5D parameterNames%0A                = new LocalVariableTableParameterNameDiscoverer().getParameterNames(handlerMethod.getMethod());%0A        //Makeup names if it is null%0A        if (parameterNames == null) %7B%0A            parameterNames = new String%5Blength%5D;%0A            for (int index = 0; index %3C length; index++) %7B%0A                parameterNames%5Bindex%5D = String.format(%22p%25s%22, index);%0A            %7D%0A        %7D%0A        return parameterNames;%0A    %7D%0A%0A
     private 

Fix for parameter names when debug info is absent causes NPE