package com.pictc.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Set;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ClassUtils {
	
	private static Set<Class<?>> primitives=CollectionUtils.newHashSet();
	private static Set<Class<?>> numbers=CollectionUtils.newHashSet();
	private static Set<Class<?>> integers=CollectionUtils.newHashSet();
	private static Set<Class<?>> doubles=CollectionUtils.newHashSet();
	private static Set<Class<?>> dates=CollectionUtils.newHashSet();
	private static Set<Class<?>> strings=CollectionUtils.newHashSet();
	
	static {
		primitives.add(BigDecimal.class);primitives.add(BigInteger.class);
		primitives.add(Integer.class);primitives.add(int.class);
		primitives.add(Double.class);primitives.add(double.class);
		primitives.add(Float.class);primitives.add(float.class);
		primitives.add(Long.class);primitives.add(long.class);
		primitives.add(Short.class);primitives.add(short.class);
		primitives.add(Byte.class);primitives.add(byte.class);
		primitives.add(Boolean.class);primitives.add(boolean.class);
		primitives.add(Character.class);primitives.add(char.class);
		primitives.add(String.class);primitives.add(Date.class);
		primitives.add(Timestamp.class);primitives.add(java.util.Date.class);
		primitives.add(Time.class);
		
		integers.add(Integer.class);integers.add(int.class);
		integers.add(Long.class);integers.add(long.class);
		integers.add(Short.class);integers.add(short.class);
		integers.add(Byte.class);integers.add(byte.class);
		integers.add(BigInteger.class);
		
		doubles.add(Double.class);doubles.add(double.class);
		doubles.add(Float.class);doubles.add(float.class);
		doubles.add(BigDecimal.class);
		
		numbers.add(Integer.class);numbers.add(int.class);
		numbers.add(Double.class);numbers.add(double.class);
		numbers.add(Float.class);numbers.add(float.class);
		numbers.add(Long.class);numbers.add(long.class);
		numbers.add(Short.class);numbers.add(short.class);
		numbers.add(Byte.class);numbers.add(byte.class);
		numbers.add(BigDecimal.class);numbers.add(BigInteger.class);
		
		dates.add(Date.class); dates.add(Time.class);
		dates.add(Timestamp.class);dates.add(java.util.Date.class);
		
		strings.add(Character.class);strings.add(char.class);
		strings.add(String.class);strings.add(StringBuilder.class);
		strings.add(StringBuffer.class);
		
	}
	
	/**
	 * 是否为基本数据类型
	 * */
	public static boolean isPrimitive(Class<?> klass) {
		return primitives.contains(klass);
	}

	/**
	 * 是否为字符串类型
	 * */
	public static boolean isString(Class<?> cls) {
		return strings.contains(cls) || hashClass(cls, CharSequence.class);
	}
	
	public static boolean isNumber(Class<?> type) {
		return numbers.contains(type);
	}
	
	public static boolean isInt(Class<?> type) {
		return integers.contains(type);
	}
	
	public static boolean isDouble(Class<?> type) {
		return doubles.contains(type);
	}
	
	public static boolean isDate(Class<?> type) {
		return dates.contains(type);
	}
	
	/**
	 * 是否是map集合
	 * */
	public static boolean isMap(Class<?> klass) {
		return hashClass(klass, Map.class);
	}
	/**
	 * 是否是set集合
	 * */
	public static boolean isSet(Class<?> klass) {
		return hashClass(klass, Set.class);
	}
	/**
	 * 是否是list集合
	 * */
	public static boolean isList(Class<?> klass) {
		return hashClass(klass, List.class);
	}
	
	public static boolean isCollection(Class<?> klass) {
		return isList(klass) || isSet(klass);
	}
	
	/**
	 * klass是否实现了face类或接口
	 * @author tanuki
	 * @param klass 要判断的类型
	 * @param face  指定的类型
	 * */
	public static boolean hashClass(Class<?> klass, Class<?> face) {
		if (klass.equals(face)) {
			return true;
		} else {
			if (Object.class.equals(klass)) {
				return false;
			}
			Class<?>[] cls = klass.getInterfaces();
			for (int i = 0; i < cls.length; i++) {
				if (hashClass(cls[i], face)) {
					return true;
				}
			}
			if (!klass.isInterface()) {
				if (hashClass(klass.getSuperclass(), face)) {
					return true;
				}
			}
		}
		return false;
	}
	
	/**
	 * Type 类型转 class
	 * */
	public static Class<?>  getClass(Type type) throws ClassNotFoundException{
		String cStr=type.toString();
		if(cStr.indexOf("class ")==0){
			return Class.forName(cStr.substring(6, cStr.length()));
		}else if(cStr.indexOf("interface ")==0){
			return Class.forName(cStr.substring(10, cStr.length()));
		}else{
			if(cStr.indexOf("<")!=-1){
				return Class.forName(cStr.substring(0, cStr.indexOf("<")));
			}
			return Class.forName(cStr.substring(0, cStr.length()));
		}
	}
	
	public static Type[] getFeildFan(Field field) {
		Type type = field.getGenericType();
		if(type instanceof ParameterizedType){
			return ((ParameterizedType)type).getActualTypeArguments();
		}
		return null;
	}
	
	public static Type getFeildFan(Field field,int index) {
		Type type = field.getGenericType();
		if(type instanceof ParameterizedType){
			return ((ParameterizedType)type).getActualTypeArguments()[index];
		}
		return field.getType();
	}
	
	public static Class<?> getFeildFanClass(Field field,int index) throws ClassNotFoundException {
		return getClass(getFeildFan(field, index));
	}
	
	/**
	 * 获取结合的泛型
	 * */
	public static Type getCollectionFan(Type type){
		Type result=null;
		if(type instanceof ParameterizedType){
			result=((ParameterizedType)type).getActualTypeArguments()[0];
		}else{
			result=type;
		}
		return result;
	}
	

	/**
	 * 获取结合的泛型
	 * @throws ClassNotFoundException 
	 * */
	public static Class<?> getCollectionFanClass(Type type) throws ClassNotFoundException{
		Class<?> result=null;
		if(type instanceof ParameterizedType){
			result= getClass(((ParameterizedType)type).getActualTypeArguments()[0]);
		}else{
			result = getClass(type);
		}
		return result;
	}
	
	/**
	 * 获取结合的泛型
	 * @throws ClassNotFoundException 
	 * */
	public static Class<?> getArrayClass(Class<?> type) throws ClassNotFoundException{
		return type.getComponentType();
	}
	
	 /**
     * <p>
     * 反射对象获取泛型
     * </p>
     *
     * @param clazz 对象
     * @param index 泛型所在位置
     * @return Class
     */
    public static Class<?> getSuperClassGenericType(final Class<?> clazz, final int index) {
        Type genType = clazz.getGenericSuperclass();
        if (!(genType instanceof ParameterizedType)) {
            log.warn("Warn: {}'s superclass not ParameterizedType", clazz.getSimpleName());
            return Object.class;
        }
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        if (index >= params.length || index < 0) {
        	log.warn("Warn: Index: {}, Size of {}'s Parameterized Type: {} .", index,clazz.getSimpleName(), params.length);
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
        	log.warn("Warn: {} not set the actual class on superclass generic parameter",clazz.getSimpleName());
            return Object.class;
        }
        return (Class<?>) params[index];
    }
	
	/**
	 * 获取Map的泛型
	 * */
	public static Type[] getMapFan(Type type){
		Type[] result=null;
		if(type instanceof ParameterizedType){
			result=((ParameterizedType)type).getActualTypeArguments();
		}else{
			result=new Type[0];
		}
		return result;
	}
	
	/**
	 * 读取远程jar包加载到当前jvm中
	 * */
	public static void loadJar(Set<String> urls) {
		Method method = null; 
		boolean accessible = false;
		try {
			method= URLClassLoader.class.getDeclaredMethod("addURL", URL.class);  
            accessible = method.isAccessible();
            if (accessible == false) {  
               method.setAccessible(true);  
            } 
            URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
			for (String address : urls) {
				 method.invoke(classLoader,new URL(address));   
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(method!=null) {
				method.setAccessible(accessible);
			}
		}
	}
	
	public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		}
		catch (Throwable ex) {}
		if (cl == null) {
			cl = ClassUtils.class.getClassLoader();
			if (cl == null) {
				try {
					cl = ClassLoader.getSystemClassLoader();
				}
				catch (Throwable ex) {}
			}
		}
		return cl;
	}

	@SuppressWarnings("unchecked")
	public static <T>T newInstance(String className) {
		try {
            return (T) ClassUtils.loadClass(className).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
	}

	public static Class<?> loadClass(String className) {
		ClassLoader loader = getDefaultClassLoader();
		if(loader==null) throw new RuntimeException("ClassLoader为空");
		try {
			return loader.loadClass(className);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static Class<?> loadClass(ClassLoader loader,String className) {
		try {
			if(loader==null) {
				return loadClass(className);
			}
			return loader.loadClass(className);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	

}
