package com.wecloud.dispatch.extend.impl;

import com.wecloud.dispatch.extend.ArgumentDefaultValueBuilder;
import com.wecloud.dispatch.util.ClassUtil;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author lixiaozhong
 */
public class DefaultArgumentDefaultValueBuilder implements ArgumentDefaultValueBuilder {
	Map<Class<?>, Boolean> canNotInstanceMap = new HashMap<>();

	@Override
	public Object build(Class<?> classType) {
		return getValue(classType);
	}

	private Object getValue(Class<?> clazz) {
		Object value = null;
		if (null == value) {
			value = getDefaultValue(clazz);
		}
		if (null == value && ClassUtil.isCanInstance(clazz) && !canNotInstanceMap.containsKey(clazz)) {
			value = getObject(clazz);
		}
		return value;
	}

	private <T> Object getObject(Class<T> clazz) {
		Object object = null;
		if (ClassUtil.isCanInstance(clazz) && !canNotInstanceMap.containsKey(clazz)) {
			try {
				object = clazz.newInstance();
			} catch (InstantiationException | IllegalAccessException e) {
				canNotInstanceMap.put(clazz, false);
			}
		}
		return object;
	}


	/**
	 * 对象给默认值
	 *
	 */
	@SuppressWarnings("unchecked")
	public <T> T getDefaultValue(Class<T> clazz) {
		Object object = null;
		if (List.class.isAssignableFrom(clazz)) {
			object = new ArrayList<Object>(0);
		} else if (Map.class.isAssignableFrom(clazz)) {
			object = new HashMap<Object, Object>(0);
		} else if (Set.class.isAssignableFrom(clazz)) {
			object = new HashSet<Object>(0);
		} else if (clazz.isArray()) {
			Class<?> componentType = clazz.getComponentType();
			object = Array.newInstance(componentType, 0);
		} else if (clazz == int.class) {
			object = 0;
		} else if (clazz == long.class) {
			object = 0L;
		} else if (clazz == float.class) {
			object = 0.0F;
		} else if (clazz == double.class) {
			object = 0.00D;
		} else if (clazz == byte.class) {
			object = (byte) 0;
		} else if (clazz == char.class) {
			object = '\u0000';
		} else if (clazz == short.class) {
			object = 0;
		} else if (clazz == boolean.class) {
			object = false;
		}
		return ((T) object);
	}
}
