package com.ym.mec.util.collection;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class MapUtil {

	private static final Object[] EMPTY_ARRAY = {};

	/**
	 * 地球半径，单位：公里/千米
	 */
	private static final double EARTH_RADIUS = 6378.137;

	/**
	* 将一个bean转换成map
	* @param map
	* @param bean
	* @return
	*/
	public static Map<String, Object> populateMap(Map<String, Object> map, Object bean, String... ignoreKeys) {
		return populateMapWithPrefix(map, bean, null, ignoreKeys);
	}

	/**
	 * 假设prefix=detail.，bean带有一个属性name，则map中将有一个项：
	 * key=detail.name，value为bean的name属性值。
	 */
	public static Map<String, Object> populateMapWithPrefix(Map<String, Object> map, Object bean, String prefix, String... ignoreKeys) {
		boolean withoutPrefix = StringUtils.isBlank(prefix);

		try {
			Method[] methods = bean.getClass().getMethods();
			for (int i = 0; i < methods.length; i++) {
				String methodName = methods[i].getName();
				Class<?>[] pts = methods[i].getParameterTypes();
				Class<?> rt = methods[i].getReturnType();

				if (methodName.startsWith("get") && pts.length == 0 && !Void.class.equals(rt)) {
					String propName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
					if ("class".equals(propName)) {
						continue;
					}

					String key = withoutPrefix ? propName : prefix + propName;
					
					if(ArrayUtils.contains(ignoreKeys, key)){
						continue;
					}

					Object value = methods[i].invoke(bean, EMPTY_ARRAY);
					if (value != null) {
						map.put(key, value);
					}
				}
			}

			return map;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * map to javabean
	 * @param clazz
	 * @param map
	 * @return
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 * @throws IntrospectionException 
	 * @throws InstantiationException 
	 */
	@SuppressWarnings("rawtypes")
	public static <T> T mapToJavaBean(Class<T> clazz, Map map) throws IllegalAccessException, IllegalArgumentException, IntrospectionException,
			InstantiationException {
		T obj = null;
		BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
		obj = clazz.newInstance();
		PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
		for (int i = 0; i < propertyDescriptors.length; i++) {
			PropertyDescriptor descriptor = propertyDescriptors[i];
			String propertyName = descriptor.getName();
			if (map.containsKey(propertyName)) {
				Object value = map.get(propertyName);
				if ("".equals(value)) {
					value = null;
				}
				Object[] args = new Object[1];
				args[0] = value;
				try {
					descriptor.getWriteMethod().invoke(obj, args);
				} catch (InvocationTargetException e) {
					System.out.println("params poxy failed");
				}
			}
		}
		return (T) obj;
	}

	/**
	 * @Author: Joburgess
	 * @Date: 2019/10/12
	 * @params [maps]
	 * @return java.util.Map
	 * @describe mybatis返回结果转换为Map
	 */
	public static <T,K> Map convertMybatisMap(List<Map<T,K>> maps){
		int size = 0;
		if(maps != null){
			size = maps.size();
		}
		Map result=new HashMap(size);
		maps.forEach(stringIntegerMap -> {
			if(Objects.isNull(stringIntegerMap)){
				return;
			}
			result.put(stringIntegerMap.get("key"),stringIntegerMap.get("value").toString());
		});
		return result;
	}

	/**
	 * @Author: Joburgess
	 * @Date: 2019/10/12
	 * @params [maps]
	 * @return java.util.Map
	 * @describe mybatis返回结果转换为Map
	 */
	public static <T,K> Map convertIntegerMap(List<Map<T,K>> maps){
		int size = 0;
		if(maps != null){
			size = maps.size();
		}
		Map result=new HashMap(size);
		maps.forEach(stringIntegerMap -> {
			if(Objects.isNull(stringIntegerMap)){
				return;
			}
			result.put(stringIntegerMap.get("key"),stringIntegerMap.get("value"));
		});
		return result;
	}

	/**
	 * 经纬度转化成弧度
	 * @param d
	 *         经度/纬度
	 * @return 经纬度转化成的弧度
	 */
	private static double radian(double d) {
		return d * Math.PI / 180.0;
	}

	/**
	 * 返回两个地理坐标之间的距离
	 * @param firsLongitude
	 *         第一个坐标的经度
	 * @param firstLatitude
	 *         第一个坐标的纬度
	 * @param secondLongitude
	 *         第二个坐标的经度
	 * @param secondLatitude
	 *         第二个坐标的纬度
	 * @return 两个坐标之间的距离，单位：公里/千米
	 */
	public static double distance(double firsLongitude, double firstLatitude,
								  double secondLongitude, double secondLatitude) {
		double firstRadianLongitude = radian(firsLongitude);
		double firstRadianLatitude = radian(firstLatitude);
		double secondRadianLongitude = radian(secondLongitude);
		double secondRadianLatitude = radian(secondLatitude);

		double a = firstRadianLatitude - secondRadianLatitude;
		double b = firstRadianLongitude - secondRadianLongitude;
		double cal = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
				+ Math.cos(firstRadianLatitude) * Math.cos(secondRadianLatitude)
				* Math.pow(Math.sin(b / 2), 2)));
		cal = cal * EARTH_RADIUS;

		return Math.round(cal * 10000d) / 10000d * 1000;
	}

	/**
	 * 返回两个地理坐标之间的距离
	 * @param firstPoint
	 *         第一个坐标 例如："23.100919, 113.279868"
	 * @param secondPoint
	 *         第二个坐标 例如："23.149286, 113.347584"
	 * @return 两个坐标之间的距离，单位：公里/千米
	 */
	public static double distance(String firstPoint, String secondPoint) {
		String[] firstArray = firstPoint.split(",");
		String[] secondArray = secondPoint.split(",");
		double firstLatitude = Double.valueOf(firstArray[0].trim());
		double firstLongitude = Double.valueOf(firstArray[1].trim());
		double secondLatitude = Double.valueOf(secondArray[0].trim());
		double secondLongitude = Double.valueOf(secondArray[1].trim());
		return distance(firstLatitude, firstLongitude, secondLatitude, secondLongitude);
	}
}
