package com.usky.common.core.util;



import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.Type;
import ma.glasnost.orika.metadata.TypeFactory;

import java.util.List;

/**
 * <p>Bean copy 工具类</p>
 *
 * @author chenpeng
 * Create time 2018年12月3日 下午2:49:47
 */
public final class BeanMapperUtils {

    private static final MapperFactory MAP_NONE_NULL_FIELDS_MAPPER_FACTORY = new DefaultMapperFactory.Builder().mapNulls(false).build();
    private static final MapperFactory MAP_NULL_FIELDS_MAPPER_FACTORY = new DefaultMapperFactory.Builder().mapNulls(true).build();

    private BeanMapperUtils() {
    }

    /**
     * <p><简单的复制出新类型对象</p>
     * <p>
     * 通过source.getClass() 获得源Class
     */
    public static <S, D> D map(S source, Class<D> destinationClass) {
        return buildClassMapperFacade(false).map(source, destinationClass);
    }

    /**
     * <p>极致性能的复制出新类型对象.</p>
     * <p>
     * 预先通过BeanMapper.getType() 静态获取并缓存Type类型，在此处传入
     */
    public static <S, D> D map(S source, Type<S> sourceType, Type<D> destinationType) {
        return buildClassMapperFacade(false).map(source, sourceType, destinationType);
    }

    /**
     * <p>对象拷贝</p>
     *
     * @author chenpeng
     * Create at March 6, 2019 at 17:22:38 GMT+8
     */
    public static <S, D> void copy(S source, D dest) {
        buildClassMapperFacade(false).map(source, dest);
    }

    /**
     * <p>简单的复制出新对象列表到ArrayList</p>
     * <p>
     * 不建议使用mapper.mapAsList(Iterable<S>,Class<D>)接口, sourceClass需要反射，实在有点慢
     */
    public static <S, D> List<D> mapList(Iterable<S> sourceList, Class<S> sourceClass, Class<D> destinationClass) {
        return buildClassMapperFacade(false).mapAsList(sourceList,
                TypeFactory.valueOf(sourceClass),
                TypeFactory.valueOf(destinationClass));
    }

    /**
     * <p>极致性能的复制出新类型对象到ArrayList.<p>
     * <p>
     * 预先通过BeanMapper.getType() 静态获取并缓存Type类型，在此处传入
     */
    public static <S, D> List<D> mapList(Iterable<S> sourceList, Type<S> sourceType, Type<D> destinationType) {
        return buildClassMapperFacade(false).mapAsList(sourceList, sourceType, destinationType);
    }

    /**
     * <p>简单复制出新对象列表到数组<p>
     * <p>
     * 通过source.getComponentType() 获得源Class
     */
    public static <S, D> D[] mapArray(final D[] destination, final S[] source, final Class<D> destinationClass) {
        return buildClassMapperFacade(false).mapAsArray(destination, source, destinationClass);
    }

    /**
     * <p>极致性能的复制出新类型对象到数组<p>
     * <p>
     * 预先通过BeanMapper.getType() 静态获取并缓存Type类型，在此处传入
     */
    public static <S, D> D[] mapArray(D[] destination, S[] source, Type<S> sourceType, Type<D> destinationType) {
        return buildClassMapperFacade(false).mapAsArray(destination, source, sourceType, destinationType);
    }

    private static MapperFacade buildClassMapperFacade(boolean mapNulls) {
        return (mapNulls
                ? MAP_NULL_FIELDS_MAPPER_FACTORY.getMapperFacade()
                : MAP_NONE_NULL_FIELDS_MAPPER_FACTORY.getMapperFacade());
    }
}
