// 
// Decompiled by Procyon v0.6.0
// 

package com.google.gson.internal;

import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.TreeMap;
import java.util.LinkedHashMap;
import java.util.ArrayDeque;
import java.util.TreeSet;
import java.util.LinkedHashSet;
import java.util.ArrayList;
import java.util.Collection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Constructor;
import com.google.gson.internal.reflect.ReflectionHelper;
import java.lang.reflect.AccessibleObject;
import java.util.EnumMap;
import java.lang.reflect.ParameterizedType;
import java.util.EnumSet;
import com.google.gson.JsonIOException;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Modifier;
import com.google.gson.ReflectionAccessFilter;
import java.util.List;
import com.google.gson.InstanceCreator;
import java.lang.reflect.Type;
import java.util.Map;

public final class ConstructorConstructor
{
    private final Map<Type, InstanceCreator<?>> instanceCreators;
    private final boolean useJdkUnsafe;
    private final List<ReflectionAccessFilter> reflectionFilters;
    
    public ConstructorConstructor(final Map<Type, InstanceCreator<?>> instanceCreators, final boolean useJdkUnsafe, final List<ReflectionAccessFilter> reflectionFilters) {
        this.instanceCreators = instanceCreators;
        this.useJdkUnsafe = useJdkUnsafe;
        this.reflectionFilters = reflectionFilters;
    }
    
    static String checkInstantiable(final Class<?> c) {
        final int modifiers = c.getModifiers();
        if (Modifier.isInterface(modifiers)) {
            return "Interfaces can't be instantiated! Register an InstanceCreator or a TypeAdapter for this type. Interface name: " + c.getName();
        }
        if (Modifier.isAbstract(modifiers)) {
            return "Abstract classes can't be instantiated! Adjust the R8 configuration or register an InstanceCreator or a TypeAdapter for this type. Class name: " + c.getName() + "\nSee " + TroubleshootingGuide.createUrl("r8-abstract-class");
        }
        return null;
    }
    
    public <T> ObjectConstructor<T> get(final TypeToken<T> typeToken) {
        return this.get(typeToken, true);
    }
    
    public <T> ObjectConstructor<T> get(final TypeToken<T> typeToken, final boolean allowUnsafe) {
        final Type type = typeToken.getType();
        final Class<? super T> rawType = typeToken.getRawType();
        final InstanceCreator<T> typeCreator = (InstanceCreator<T>)this.instanceCreators.get(type);
        if (typeCreator != null) {
            return (ObjectConstructor<T>)(() -> typeCreator.createInstance(type));
        }
        final InstanceCreator<T> rawTypeCreator = (InstanceCreator<T>)this.instanceCreators.get(rawType);
        if (rawTypeCreator != null) {
            return (ObjectConstructor<T>)(() -> rawTypeCreator.createInstance(type));
        }
        final ObjectConstructor<T> specialConstructor = newSpecialCollectionConstructor(type, rawType);
        if (specialConstructor != null) {
            return specialConstructor;
        }
        final ReflectionAccessFilter.FilterResult filterResult = ReflectionAccessFilterHelper.getFilterResult(this.reflectionFilters, rawType);
        final ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType, filterResult);
        if (defaultConstructor != null) {
            return defaultConstructor;
        }
        final ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);
        if (defaultImplementation != null) {
            return defaultImplementation;
        }
        final String exceptionMessage = checkInstantiable(rawType);
        if (exceptionMessage != null) {
            return () -> {
                throw new JsonIOException(exceptionMessage);
            };
        }
        if (!allowUnsafe) {
            final String message = "Unable to create instance of " + rawType + "; Register an InstanceCreator or a TypeAdapter for this type.";
            return () -> {
                throw new JsonIOException(message);
            };
        }
        if (filterResult != ReflectionAccessFilter.FilterResult.ALLOW) {
            final String message = "Unable to create instance of " + rawType + "; ReflectionAccessFilter does not permit using reflection or Unsafe. Register an InstanceCreator or a TypeAdapter for this type or adjust the access filter to allow using reflection.";
            return () -> {
                throw new JsonIOException(message);
            };
        }
        return this.newUnsafeAllocator(rawType);
    }
    
    private static <T> ObjectConstructor<T> newSpecialCollectionConstructor(final Type type, final Class<? super T> rawType) {
        if (EnumSet.class.isAssignableFrom(rawType)) {
            return (ObjectConstructor<T>)(() -> {
                if (type instanceof ParameterizedType) {
                    final Type elementType = ((ParameterizedType)type).getActualTypeArguments()[0];
                    if (elementType instanceof Class) {
                        final Object set = EnumSet.noneOf((Class<Enum>)elementType);
                        return set;
                    }
                    else {
                        new JsonIOException("Invalid EnumSet type: " + type.toString());
                        throw;
                    }
                }
                else {
                    new JsonIOException("Invalid EnumSet type: " + type.toString());
                    throw;
                }
            });
        }
        if (rawType == EnumMap.class) {
            return (ObjectConstructor<T>)(() -> {
                if (type instanceof ParameterizedType) {
                    final Type elementType2 = ((ParameterizedType)type).getActualTypeArguments()[0];
                    if (elementType2 instanceof Class) {
                        final Object map = new EnumMap((Class<Enum>)elementType2);
                        return map;
                    }
                    else {
                        new JsonIOException("Invalid EnumMap type: " + type.toString());
                        throw;
                    }
                }
                else {
                    new JsonIOException("Invalid EnumMap type: " + type.toString());
                    throw;
                }
            });
        }
        return null;
    }
    
    private static <T> ObjectConstructor<T> newDefaultConstructor(final Class<? super T> rawType, final ReflectionAccessFilter.FilterResult filterResult) {
        if (Modifier.isAbstract(rawType.getModifiers())) {
            return null;
        }
        Constructor<? super T> constructor;
        try {
            constructor = rawType.getDeclaredConstructor((Class<?>[])new Class[0]);
        }
        catch (final NoSuchMethodException e) {
            return null;
        }
        final boolean canAccess = filterResult == ReflectionAccessFilter.FilterResult.ALLOW || (ReflectionAccessFilterHelper.canAccess(constructor, null) && (filterResult != ReflectionAccessFilter.FilterResult.BLOCK_ALL || Modifier.isPublic(constructor.getModifiers())));
        if (!canAccess) {
            final String message = "Unable to invoke no-args constructor of " + rawType + "; constructor is not accessible and ReflectionAccessFilter does not permit making it accessible. Register an InstanceCreator or a TypeAdapter for this type, change the visibility of the constructor or adjust the access filter.";
            return () -> {
                throw new JsonIOException(message);
            };
        }
        if (filterResult == ReflectionAccessFilter.FilterResult.ALLOW) {
            final String exceptionMessage = ReflectionHelper.tryMakeAccessible(constructor);
            if (exceptionMessage != null) {
                return () -> {
                    throw new JsonIOException(exceptionMessage);
                };
            }
        }
        return (ObjectConstructor<T>)(() -> {
            try {
                final Object newInstance = constructor.newInstance(new Object[0]);
                return newInstance;
            }
            catch (final InstantiationException e2) {
                new RuntimeException("Failed to invoke constructor '" + ReflectionHelper.constructorToString(constructor) + "' with no args", e2);
                throw;
            }
            catch (final InvocationTargetException e3) {
                new RuntimeException("Failed to invoke constructor '" + ReflectionHelper.constructorToString(constructor) + "' with no args", e3.getCause());
                throw;
            }
            catch (final IllegalAccessException e4) {
                throw ReflectionHelper.createExceptionForUnexpectedIllegalAccess(e4);
            }
        });
    }
    
    private static <T> ObjectConstructor<T> newDefaultImplementationConstructor(final Type type, final Class<? super T> rawType) {
        if (Collection.class.isAssignableFrom(rawType)) {
            final ObjectConstructor<T> constructor = (ObjectConstructor<T>)newCollectionConstructor(rawType);
            return constructor;
        }
        if (Map.class.isAssignableFrom(rawType)) {
            final ObjectConstructor<T> constructor = (ObjectConstructor<T>)newMapConstructor(type, rawType);
            return constructor;
        }
        return null;
    }
    
    private static ObjectConstructor<? extends Collection<?>> newCollectionConstructor(final Class<?> rawType) {
        if (rawType.isAssignableFrom(ArrayList.class)) {
            return () -> new ArrayList();
        }
        if (rawType.isAssignableFrom(LinkedHashSet.class)) {
            return () -> new LinkedHashSet();
        }
        if (rawType.isAssignableFrom(TreeSet.class)) {
            return () -> new TreeSet();
        }
        if (rawType.isAssignableFrom(ArrayDeque.class)) {
            return () -> new ArrayDeque();
        }
        return null;
    }
    
    private static boolean hasStringKeyType(final Type mapType) {
        if (!(mapType instanceof ParameterizedType)) {
            return true;
        }
        final Type[] typeArguments = ((ParameterizedType)mapType).getActualTypeArguments();
        return typeArguments.length != 0 && GsonTypes.getRawType(typeArguments[0]) == String.class;
    }
    
    private static ObjectConstructor<? extends Map<?, Object>> newMapConstructor(final Type type, final Class<?> rawType) {
        if (rawType.isAssignableFrom(LinkedTreeMap.class) && hasStringKeyType(type)) {
            return (ObjectConstructor<? extends Map<?, Object>>)(() -> new LinkedTreeMap());
        }
        if (rawType.isAssignableFrom(LinkedHashMap.class)) {
            return (ObjectConstructor<? extends Map<?, Object>>)(() -> new LinkedHashMap());
        }
        if (rawType.isAssignableFrom(TreeMap.class)) {
            return (ObjectConstructor<? extends Map<?, Object>>)(() -> new TreeMap());
        }
        if (rawType.isAssignableFrom(ConcurrentHashMap.class)) {
            return (ObjectConstructor<? extends Map<?, Object>>)(() -> new ConcurrentHashMap());
        }
        if (rawType.isAssignableFrom(ConcurrentSkipListMap.class)) {
            return (ObjectConstructor<? extends Map<?, Object>>)(() -> new ConcurrentSkipListMap());
        }
        return null;
    }
    
    private <T> ObjectConstructor<T> newUnsafeAllocator(final Class<? super T> rawType) {
        if (this.useJdkUnsafe) {
            return (ObjectConstructor<T>)(() -> {
                try {
                    final Object newInstance = UnsafeAllocator.INSTANCE.newInstance((Class<Object>)rawType);
                    return newInstance;
                }
                catch (final Exception e) {
                    new RuntimeException("Unable to create instance of " + rawType + ". Registering an InstanceCreator or a TypeAdapter for this type, or adding a no-args constructor may fix this problem.", e);
                    throw;
                }
            });
        }
        String exceptionMessage = "Unable to create instance of " + rawType + "; usage of JDK Unsafe is disabled. Registering an InstanceCreator or a TypeAdapter for this type, adding a no-args constructor, or enabling usage of JDK Unsafe may fix this problem.";
        if (rawType.getDeclaredConstructors().length == 0) {
            exceptionMessage += " Or adjust your R8 configuration to keep the no-args constructor of the class.";
        }
        final String exceptionMessageF = exceptionMessage;
        return () -> {
            throw new JsonIOException(exceptionMessageF);
        };
    }
    
    @Override
    public String toString() {
        return this.instanceCreators.toString();
    }
}
