package cucumber.runtime.java;

import io.cucumber.stepexpression.TypeRegistry;
import cucumber.api.java.ObjectFactory;
import io.cucumber.stepexpression.Argument;
import io.cucumber.stepexpression.ArgumentMatcher;
import io.cucumber.stepexpression.ExpressionArgumentMatcher;
import cucumber.runtime.MethodFormat;
import cucumber.runtime.StepDefinition;
import io.cucumber.stepexpression.StepExpression;
import io.cucumber.stepexpression.StepExpressionFactory;
import cucumber.runtime.Utils;
import gherkin.pickles.PickleStep;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;

class JavaStepDefinition implements StepDefinition {
    private final Method method;
    private final StepExpression expression;
    private final long timeoutMillis;
    private final ObjectFactory objectFactory;

    private final List<ParameterInfo> parameterInfos;

    JavaStepDefinition(Method method,
                       String expression,
                       long timeoutMillis,
                       ObjectFactory objectFactory,
                       TypeRegistry typeRegistry) {
        this.method = method;
        this.timeoutMillis = timeoutMillis;
        this.objectFactory = objectFactory;
        this.parameterInfos = ParameterInfo.fromMethod(method);
        this.expression = createExpression(expression, typeRegistry);
    }

    private StepExpression createExpression(String expression, TypeRegistry typeRegistry) {
        if (parameterInfos.isEmpty()) {
            return new StepExpressionFactory(typeRegistry).createExpression(expression);
        } else {
            ParameterInfo parameterInfo = parameterInfos.get(parameterInfos.size() - 1);
            return new StepExpressionFactory(typeRegistry).createExpression(expression, parameterInfo.getType(), parameterInfo.isTransposed());
        }
    }

    public void execute(Object[] args) throws Throwable {
        Utils.invoke(objectFactory.getInstance(method.getDeclaringClass()), method, timeoutMillis, args);
    }

    public List<Argument> matchedArguments(PickleStep step) {
        ArgumentMatcher argumentMatcher = new ExpressionArgumentMatcher(expression);
        Type[] types = new Type[parameterInfos.size()];
        for (int i = 0; i < types.length; i++) {
            types[i] = parameterInfos.get(i).getType();
        }
        return argumentMatcher.argumentsFrom(step, types);
    }

    public String getLocation(boolean detail) {
        MethodFormat format = detail ? MethodFormat.FULL : MethodFormat.SHORT;
        return format.format(method);
    }

    @Override
    public Integer getParameterCount() {
        return parameterInfos.size();
    }

    public boolean isDefinedAt(StackTraceElement e) {
        return e.getClassName().equals(method.getDeclaringClass().getName()) && e.getMethodName().equals(method.getName());
    }

    @Override
    public String getPattern() {
        return expression.getSource();
    }

    @Override
    public boolean isScenarioScoped() {
        return false;
    }
}

@@ -36,87 +36,183 @@
 ort 
-io.cucumber.stepexpression.TypeRegistry;%0Aimport cucumber.api.java.ObjectFactory
+cucumber.api.java.ObjectFactory;%0Aimport cucumber.runtime.MethodFormat;%0Aimport cucumber.runtime.StepDefinition;%0Aimport cucumber.runtime.Utils;%0Aimport gherkin.pickles.PickleStep
 ;%0Aim
@@ -369,86 +369,8 @@
 er;%0A
-import cucumber.runtime.MethodFormat;%0Aimport cucumber.runtime.StepDefinition;%0A
 impo
@@ -471,32 +471,35 @@
 Factory;%0Aimport 
+io.
 cucumber.runtime
@@ -495,56 +495,35 @@
 ber.
-runtime.Utils;%0Aimport gherkin.pickles.PickleStep
+stepexpression.TypeRegistry
 ;%0A%0Ai
@@ -848,42 +848,155 @@
 nal 
-List%3CParameterInfo%3E parameterInfos
+ArgumentMatcher argumentMatcher;%0A    private final Type%5B%5D parameterTypes;%0A    private final String shortFormat;%0A    private final String fullFormat
 ;%0A%0A 
@@ -1347,21 +1347,36 @@
         
-this.
+List%3CParameterInfo%3E 
 paramete
@@ -1414,24 +1414,75 @@
 od(method);%0A
+        parameterTypes = getTypes(parameterInfos);%0A
         this
@@ -1504,32 +1504,48 @@
 reateExpression(
+parameterInfos, 
 expression, type
@@ -1555,16 +1555,202 @@
 istry);%0A
+        argumentMatcher = new ExpressionArgumentMatcher(this.expression);%0A        shortFormat = MethodFormat.SHORT.format(method);%0A        fullFormat = MethodFormat.FULL.format(method);%0A
     %7D%0A%0A 
@@ -1792,16 +1792,52 @@
 ression(
+List%3CParameterInfo%3E parameterInfos, 
 String e
@@ -2264,32 +2264,46 @@
        %7D%0A    %7D%0A%0A
+    @Override%0A
     public void 
@@ -2449,32 +2449,46 @@
 , args);%0A    %7D%0A%0A
+    @Override%0A
     public List%3C
@@ -2541,17 +2541,24 @@
         
-A
+return a
 rgumentM
@@ -2559,33 +2559,33 @@
 umentMatcher
- 
+.
 argument
 Matcher = ne
@@ -2576,60 +2576,116 @@
 ment
-Matcher = new ExpressionArgumentMatcher(expression);
+sFrom(step, parameterTypes);%0A    %7D%0A%0A    private static Type%5B%5D getTypes(List%3CParameterInfo%3E parameterInfos) %7B
 %0A   
@@ -2870,51 +2870,14 @@
 turn
- argumentMatcher.argumentsFrom(step,
  types
-)
 ;%0A  
@@ -2873,32 +2873,46 @@
 n types;%0A    %7D%0A%0A
+    @Override%0A
     public Strin
@@ -2955,115 +2955,48 @@
     
-MethodFormat format = detail ? MethodFormat.FULL : MethodFormat.SHORT;%0A        return format.format(method)
+return detail ? fullFormat : shortFormat
 ;%0A  
@@ -3083,28 +3083,42 @@
 eter
-Infos.size();%0A    %7D%0A
+Types.length;%0A    %7D%0A%0A    @Override
 %0A   

decrease unnecessary object allocations in JavaStepDefinition