package com.imooc.utils;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

/**
 * 通用工具类
 * 
 * @version 1.0.0
 * @author Leon
 * 
 */
public final class CommonUtil {

	private CommonUtil() {
	}

	/**
	 * 判断数组是否为空
	 * 
	 * @param array
	 * @return
	 */
	public static <T> boolean isEmpty(T[] array) {
		return array == null || (array != null && array.length == 0);
	}

	/**
	 * 判断集合是否为空
	 * 
	 * @param collection
	 * @return
	 */
	public static <T> boolean isEmpty(Collection<T> collection) {
		return collection == null || collection.isEmpty();
	}

	/**
	 * 判断映射是否为空
	 * 
	 * @param map
	 * @return
	 */
	public static <K, V> boolean isEmpty(Map<K, V> map) {
		return map == null || map.isEmpty();
	}

	/**
	 * 判断文件是否为空
	 * 
	 * @param file
	 * @return
	 */
	public static boolean isEmpty(MultipartFile file) {
		return file == null || file.isEmpty();
	}

	/**
	 * 判断引用类型是否为空
	 * 
	 * @param <T>
	 * @param value
	 * @return
	 */
	public static <T> boolean isEmpty(T val) {
		return Optional.ofNullable(val).map(t -> false).orElseGet(() -> true);
	}

	/**
	 * 获得线程安全的List
	 * 
	 * @return
	 */
	public static <T> List<T> syncList(List<T> list) {
		if (isEmpty(list)) {
			return Collections.synchronizedList(Lists.newArrayList());
		}
		return Collections.synchronizedList(list);
	}

	/**
	 * 获得线程安全的Set
	 * 
	 * @return
	 */
	public static <T> Set<T> syncSet(Set<T> set) {
		if (isEmpty(set)) {
			return Collections.synchronizedSet(Sets.newHashSet());
		}
		return Collections.synchronizedSet(set);
	}

	/**
	 * 获得线程安全的Map
	 * 
	 * @return
	 */
	public static <K, V> Map<K, V> syncMap(Map<K, V> map) {
		if (isEmpty(map)) {
			return new ConcurrentHashMap<>();
		}
		return Collections.synchronizedMap(map);
	}

	/**
	 * 判断与目标值是否相等
	 * 
	 * @param value
	 * @param target
	 * @return
	 */
	public static boolean isEquals(Short val, short target) {
		return Optional.ofNullable(val).map(t -> t.shortValue() == target).orElseGet(() -> false);
	}

	/**
	 * 判断与目标值是否相等
	 * 
	 * @param value
	 * @param target
	 * @return
	 */
	public static boolean isEquals(Integer val, int target) {
		return Optional.ofNullable(val).map(t -> t.intValue() == target).orElseGet(() -> false);
	}

	/**
	 * 判断与目标值是否相等
	 * 
	 * @param value
	 * @param target
	 * @return
	 */
	public static boolean isEquals(Long val, long target) {
		return Optional.ofNullable(val).map(t -> t.longValue() == target).orElseGet(() -> false);
	}

	/**
	 * 判断与目标值是否相等
	 * 
	 * @param value
	 * @param target
	 * @return
	 */
	public static boolean isEquals(Float val, float target) {
		return Optional.ofNullable(val).map(t -> t.floatValue() == target).orElseGet(() -> false);
	}

	/**
	 * 判断与目标值是否相等
	 * 
	 * @param value
	 * @param target
	 * @return
	 */
	public static boolean isEquals(Double val, double target) {
		return Optional.ofNullable(val).map(t -> t.doubleValue() == target).orElseGet(() -> false);
	}

	/**
	 * 判断与目标值是否相等
	 * 
	 * @param value
	 * @param target
	 * @return
	 */
	public static boolean isEquals(Boolean val, boolean target) {
		return Optional.ofNullable(val).map(t -> t.booleanValue() == target).orElseGet(() -> false);
	}

	/**
	 * 获取map中的值,null值转换为空字符串
	 * 
	 * @param map
	 * @param key
	 * @return
	 */
	public static String getValue(Map<String, Object> map, String key) {
		if (isEmpty(map)) {
			return StringUtils.EMPTY;
		}
		return Optional.ofNullable(map.get(key)).map(t -> StringUtils.trim(t.toString()))
				.orElseGet(() -> StringUtils.EMPTY);
	}

	/**
	 * String转int类型
	 * 
	 * @param val
	 * @return
	 */
	public static int getIntValue(String val) {
		if (StringUtils.isNotBlank(val)) {
			return Integer.parseInt(StringUtils.trim(val));
		}
		throw new NumberFormatException("String转int异常");
	}

	/**
	 * Integer类型转int类型
	 * 
	 * @param val
	 * @return
	 */
	public static int getIntValue(Integer val) {
		return Optional.ofNullable(val).map(t -> t.intValue())
				.orElseThrow(() -> new NumberFormatException("Integer类型转int异常"));
	}

	/**
	 * String转double类型
	 * 
	 * @param val
	 * @return
	 */
	public static double getDoubleValue(String val) {
		if (StringUtils.isNotBlank(val)) {
			return Double.parseDouble(StringUtils.trim(val));
		}
		throw new NumberFormatException("String转double异常");
	}

	/**
	 * Double类型转double类型
	 * 
	 * @param val
	 * @return
	 */
	public static double getDoubleValue(Double val) {
		return Optional.ofNullable(val).map(t -> t.doubleValue())
				.orElseThrow(() -> new NumberFormatException("Double类型转double异常"));
	}

	/**
	 * String转float类型
	 * 
	 * @param val
	 * @return
	 */
	public static float getFloatValue(String val) {
		if (StringUtils.isNotBlank(val)) {
			return Float.parseFloat(StringUtils.trim(val));
		}
		throw new NumberFormatException("String转float异常");
	}

	/**
	 * Float类型转float类型
	 * 
	 * @param val
	 * @return
	 */
	public static float getFloatValue(Float val) {
		return Optional.ofNullable(val).map(t -> t.floatValue())
				.orElseThrow(() -> new NumberFormatException("Float类型转float异常"));
	}

	/**
	 * String转long类型
	 * 
	 * @param val
	 * @return
	 */
	public static long getLongValue(String val) {
		if (StringUtils.isNotBlank(val)) {
			return Long.parseLong(StringUtils.trim(val));
		}
		throw new NumberFormatException("String转long异常");
	}

	/**
	 * Long类型转long类型
	 * 
	 * @param val
	 * @return
	 */
	public static long getLongValue(Long val) {
		return Optional.ofNullable(val).map(t -> t.longValue())
				.orElseThrow(() -> new NumberFormatException("Long类型转long异常"));
	}

	/**
	 * String转byte数组
	 * 
	 * @param val 字符串
	 * @param cs
	 * @return
	 */
	public static byte[] stringToBytes(String val, Charset charset) {
		if (StringUtils.isBlank(val)) {
			return new byte[0];
		}
		return Optional.ofNullable(charset).map(t -> val.getBytes(t)).orElseGet(() -> val.getBytes());
	}

	/**
	 * byte数组转String
	 * 
	 * @param bytes
	 * @param cs
	 * @return
	 */
	public static String bytesToString(byte[] bytes, Charset charset) {
		if (bytes == null) {
			return null;
		}
		return Optional.ofNullable(charset).map(t -> new String(bytes, t)).orElseGet(() -> new String(bytes));
	}

	/**
	 * List转数组
	 * 
	 * @param list
	 * @param t
	 * @return
	 */
	public static <T> T[] listToArray(List<T> list, T[] t) {
		if (isEmpty(list)) {
			return null;
		}
		return list.toArray(t);
	}

	/**
	 * Set转数组
	 * 
	 * @param set
	 * @param t
	 * @return
	 */
	public static <T> T[] setToArray(Set<T> set, T[] t) {
		if (isEmpty(set)) {
			return null;
		}
		return set.toArray(t);
	}

	/**
	 * Set转List
	 * 
	 * @param set
	 * @return
	 */
	public static <T> List<T> setToList(Set<T> set) {
		if (isEmpty(set)) {
			return Collections.emptyList();
		}
		return set.stream().collect(Collectors.toList());
	}

	/**
	 * 数组转List
	 * 
	 * @param array
	 * @return
	 */
	public static <T> List<T> arrayToList(T[] array) {
		if (isEmpty(array)) {
			return Collections.emptyList();
		}
		return Arrays.stream(array).collect(Collectors.toList());
	}

	/**
	 * List转Set
	 * 
	 * @param list
	 * @return
	 */
	public static <T> Set<T> listToSet(List<T> list) {
		if (isEmpty(list)) {
			return Collections.emptySet();
		}
		return list.stream().collect(Collectors.toSet());
	}

	/**
	 * 数组转Set
	 * 
	 * @param array
	 * @return
	 */
	public static <T> Set<T> arrayToSet(T[] array) {
		if (isEmpty(array)) {
			return Collections.emptySet();
		}
		return Arrays.stream(array).collect(Collectors.toSet());
	}

	/**
	 * 拼接字符串
	 * 
	 * @param list
	 * @param regex
	 * @param parallel
	 * @param function
	 * @return
	 */
	public static <T> String concatString(Collection<T> list, String regex, boolean parallel, Function<T, String> fn) {
		if (isEmpty(list)) {
			return null;
		}
		if (StringUtils.isEmpty(regex)) {
			regex = ",";
		}
		Stream<T> stream = parallel ? list.parallelStream() : list.stream();
		if (fn != null) {
			return stream.map(t -> fn.apply(t)).collect(Collectors.joining(regex));
		}
		return stream.map(String::valueOf).collect(Collectors.joining(regex));
	}

	/**
	 * 拼接url参数字符串
	 * 
	 * @param paramMap
	 * @return
	 */
	public static String getUrlParamStr(Map<String, String> paramMap) {
		return isEmpty(paramMap) ? "" : Joiner.on("&").withKeyValueSeparator("=").join(paramMap);
	}

	public static String getSimpleUUID() {
		return UUID.randomUUID().toString().replaceAll("-", "");
	}
}