package com.xunmei.system.util;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamHelper {

    public static <T> Predicate<T> distict(final Function<? super T, ?> keyExtractor) {
        final Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }


    public static <R, T> Map<T, List<R>> group(final List<R> src, final Function<R, T> function) {
        return src.stream()
                  .collect(Collectors.groupingBy(function));
    }

    public static <R, T> Map<T, R> map(final List<R> src, final Function<R, T> function) {
        return src.stream()
                  .collect(Collectors.toMap(function, Function.identity()));
    }

    public static <R, T, TT> Map<T, TT> map(final List<R> src, final Function<R, T> key, final Function<R, TT> value) {
        // toMap 如果value为null会空指针
        return src.stream()
                  .collect(HashMap::new, (m, item) -> {
                      final T apply = key.apply(item);
                      final TT apply1 = value.apply(item);
                      m.put(apply, apply1);
                  }, HashMap::putAll);
    }

    public static <R, T> List<T> to(final List<R> src, final Function<R, T> function) {
        return to(src, function, false);
    }

    public static <R> List<R> filter(final List<R> src, final Predicate<R> filter) {
        if (src == null) {
            return Collections.emptyList();
        }
        return src.stream()
                  .filter(filter)
                  .collect(Collectors.toList());
    }

    public static <R, T> List<T> toWithSort(final List<R> src, final Function<R, T> function, final Comparator<T> comparator) {
        return src.stream()
                  .map(function)
                  .sorted(comparator)
                  .collect(Collectors.toList());
    }

    public static <R, T> List<T> to(final List<R> src, final Function<R, T> function, final boolean filterNull) {
        if (src == null) {
            return Collections.emptyList();
        }
        Stream<T> tStream = src.stream()
                               .map(function);
        if (filterNull) {
            tStream = tStream.filter(Objects::nonNull);
        }
        return tStream.collect(Collectors.toList());
    }

    @FunctionalInterface
    public static interface Each<T> {
        void each(T t, int index);
    }

    public static <R> void each(final List<R> src, final Each<R> function) {
        for (int i = 0; i < src.size(); i++) {
            function.each(src.get(i), i);
        }
    }

    public static <R> void each(final List<R> src, final Consumer<R> function) {
        src.forEach(function);
    }
}
