package openmods.reflection;

import java.lang.reflect.TypeVariable;

import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.reflect.TypeToken;

public class TypeUtils {

	public static final BiMap<Class<?>, Class<?>> PRIMITIVE_TYPES_MAP = ImmutableBiMap.<Class<?>, Class<?>> builder()
			.put(boolean.class, Boolean.class)
			.put(byte.class, Byte.class)
			.put(char.class, Character.class)
			.put(short.class, Short.class)
			.put(int.class, Integer.class)
			.put(long.class, Long.class)
			.put(float.class, Float.class)
			.put(double.class, Double.class)
			.put(void.class, Void.class)
			.build();

	public static Class<?> toObjectType(Class<?> cls) {
		return cls.isPrimitive()? PRIMITIVE_TYPES_MAP.get(cls) : cls;
	}

	public static void isInstance(Object o, Class<?> mainCls, Class<?>... extraCls) {
		Preconditions.checkArgument(mainCls.isInstance(o), "%s is not instance of %s", o, mainCls);
		for (Class<?> cls : extraCls)
			Preconditions.checkArgument(cls.isInstance(o), "%s is not instance of %s", o, cls);
	}

	public static boolean compareTypes(Class<?> left, Class<?> right) {
		if (left.isPrimitive()) left = PRIMITIVE_TYPES_MAP.get(left);
		if (right.isPrimitive()) right = PRIMITIVE_TYPES_MAP.get(right);
		return left.equals(right);
	}

	public static TypeToken<?> getTypeParameter(Class<?> intfClass, Class<?> instanceClass, int index) {
		final TypeVariable<?>[] typeParameters = intfClass.getTypeParameters();
		Preconditions.checkElementIndex(index, typeParameters.length, intfClass + " type parameter index");
		TypeVariable<?> arg = typeParameters[index];
		TypeToken<?> type = TypeToken.of(instanceClass);
		Preconditions.checkArgument(type.getRawType() != Object.class, "Type %s is no fully parametrized", instanceClass);
		return type.resolveType(arg);
	}

	public static TypeToken<?> getTypeParameter(Class<?> intfClass, Class<?> instanceClass) {
		return getTypeParameter(intfClass, instanceClass, 0);
	}

}

@@ -61,16 +61,61 @@
 ariable;
+%0Aimport java.util.List;%0Aimport java.util.Map;
 %0A%0Aimport
@@ -313,16 +313,365 @@
 tils %7B%0A%0A
+%09public static final TypeVariable%3C?%3E LIST_VALUE_PARAM;%0A%0A%09public static final TypeVariable%3C?%3E MAP_KEY_PARAM;%0A%0A%09public static final TypeVariable%3C?%3E MAP_VALUE_PARAM;%0A%0A%09static %7B%0A%09%09TypeVariable%3C?%3E%5B%5D vars = Map.class.getTypeParameters();%0A%09%09MAP_KEY_PARAM = vars%5B0%5D;%0A%09%09MAP_VALUE_PARAM = vars%5B1%5D;%0A%0A%09%09LIST_VALUE_PARAM = List.class.getTypeParameters()%5B0%5D;%0A%09%7D%0A%0A
 %09public 

Add type variables for common generic interfaces