package com.github.therapi.core.internal;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import com.google.common.reflect.TypeToken;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;

public class JacksonHelper {
    public static ObjectMapper newLenientObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new ParameterNamesModule());

        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        mapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, true);
        mapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);

        return mapper;
    }

    public static TypeReference getTypeReference(Parameter parameter, Class<?> contextForTypeVariableResolution) {
        Type parameterizedType = parameter.getParameterizedType();
        TypeToken token = TypeToken.of(contextForTypeVariableResolution);
        Type resolvedType = token.resolveType(parameterizedType).getType();
        return newTypeReference(resolvedType);
    }

    public static TypeReference getReturnTypeReference(Method method, Class<?> contextForTypeVariableResolution) {
        Type parameterizedType = method.getGenericReturnType();
        TypeToken token = TypeToken.of(contextForTypeVariableResolution);
        Type resolvedType = token.resolveType(parameterizedType).getType();
        return newTypeReference(resolvedType);
    }

    public static TypeReference newTypeReference(Type type) {
        return new TypeReference<Object>() {
            @Override
            public Type getType() {
                return type;
            }

            @Override
            public String toString() {
                return type.toString();
            }
        };
    }

    public static boolean isLikeNull(JsonNode node) {
        return node == null || node.isNull();
    }
}

@@ -1270,106 +1270,195 @@
     
-Type parameterizedType = parameter.getParameterizedType(
+return getResolvedTypeReference(parameter.getParameterizedType(), contextForTypeVariableResolution
 );%0A    
+%7D%0A%0A
     
-TypeToken token = TypeToken.of(
+public static TypeReference getReturnTypeReference(Method method, Class%3C?%3E 
 cont
@@ -1478,33 +1478,34 @@
 iableResolution)
-;
+ %7B
 %0A        Type re
@@ -1501,120 +1501,103 @@
     
-Type resolvedType = token.resolveType(parameterizedType).getType();%0A        return newTypeReference(resolvedType
+return getResolvedTypeReference(method.getGenericReturnType(), contextForTypeVariableResolution
 );%0A 
@@ -1631,36 +1631,38 @@
 eReference getRe
-turn
+solved
 TypeReference(Me
@@ -1655,37 +1655,46 @@
 peReference(
-Method method
+Type parameterizedType
 , Class%3C?%3E c
@@ -1732,72 +1732,8 @@
 ) %7B%0A
-        Type parameterizedType = method.getGenericReturnType();%0A
     

refactor common code for type resolution