/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved. <a>http://www.crunii.com</a>
 */
package com.crunii.micro.common.utils;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;

/**
 * @author 田平 create 2016年10月14日下午1:35:01
 */
public class FieldUtil {

	public static Map<String, PropertyDescriptor> dtoProps = new ConcurrentHashMap<String, PropertyDescriptor>();

	public static Map<String, Field[]> dtoFields = new ConcurrentHashMap<String, Field[]>();

	public static Field[] getFields(Class<?> cl) {
		Field[] fields = dtoFields.get(cl.getName());
		if (fields == null) {
			fields = cl.getDeclaredFields();
			dtoFields.put(cl.getName(), fields);
		}
		return fields;
	}

	public static Field getFields(Class<?> cl, String fieldName) {
		Field[] fields = getFields(cl);
		Field f = null;
		if (fields != null) {
			for (Field field : fields) {
				if (field.getName().equals(fieldName)) {
					f = field;
					break;
				}
			}
		}
		return f;
	}

	public static PropertyDescriptor getPropDesc(Class<?> cl, Field field) {
		String key = cl.getName() + "_" + field.getType().getName() + "_" + field.getName();
		PropertyDescriptor prop = dtoProps.get(key);
		if (prop == null) {
			PropertyDescriptor[] properties = BeanUtils.getPropertyDescriptors(cl);
			for (PropertyDescriptor descriptor : properties) {
				if (descriptor.getPropertyType() == field.getType() && descriptor.getName().equals(Introspector.decapitalize(field.getName()))) {
					prop = descriptor;
					dtoProps.put(key, prop);
					break;
				}
			}
		}
		return prop;
	}
	
	/**
	 * Convert a name in camelCase to an underscored name in lower case.
	 * Any upper case letters are converted to lower case with a preceding underscore.
	 * @param name the original name
	 * @return the converted name
	 * @since 4.2
	 * @see #lowerCaseName
	 */
	public static String underscoreName(String name) {
		if (!StringUtils.hasLength(name)) {
			return "";
		}
		StringBuilder result = new StringBuilder();
		result.append(lowerCaseName(name.substring(0, 1)));
		for (int i = 1; i < name.length(); i++) {
			String s = name.substring(i, i + 1);
			String slc = lowerCaseName(s);
			if (!s.equals(slc)) {
				result.append("_").append(slc);
			}
			else {
				result.append(s);
			}
		}
		return result.toString();
	}
	
	/**
	 * Convert the given name to lower case.
	 * By default, conversions will happen within the US locale.
	 * @param name the original name
	 * @return the converted name
	 * @since 4.2
	 */
	private static String lowerCaseName(String name) {
		return name.toLowerCase(Locale.US);
	}
}
