package com.engine.htsc.payment.util;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

public class MyCollectors {

  private MyCollectors () {
  }


  // BigDecimal 类型的集合求和
  public static <T> Collector<T, ?, BigDecimal> summingBigDecimal(ToBigDecimalFunction<? super T> mapper) {
    return new CollectorImpl<>(
            () -> new BigDecimal[] { BigDecimal.ZERO },
            (a, t) -> a[0] = a[0].add(mapper.applyAsInt(t)),
            (a, b) -> {
              a[0] = a[0].add(b[0]);
              return a;
            },
            a -> a[0],
            Collections.emptySet()
    );
  }

  static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
    // 创建一个计算用的容器
    private final Supplier<A> supplier;
    // 计算逻辑
    private final BiConsumer<A, T> accumulator;
    // 合并逻辑
    private final BinaryOperator<A> combiner;
    // 返回最终计算值
    private final Function<A, R> finisher;
    // 空Set
    private final Set<Characteristics> characteristics;

    CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
                  Function<A, R> finisher, Set<Characteristics> characteristics) {
      this.supplier = supplier;
      this.accumulator = accumulator;
      this.combiner = combiner;
      this.finisher = finisher;
      this.characteristics = characteristics;
    }

    CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
                  Set<Characteristics> characteristics) {
      this(supplier, accumulator, combiner, castingIdentity(), characteristics);
    }

    @Override
    public BiConsumer<A, T> accumulator() {
      return accumulator;
    }

    @Override
    public Supplier<A> supplier() {
      return supplier;
    }

    @Override
    public BinaryOperator<A> combiner() {
      return combiner;
    }

    @Override
    public Function<A, R> finisher() {
      return finisher;
    }

    @Override
    public Set<Characteristics> characteristics() {
      return characteristics;
    }
  }

  @SuppressWarnings("unchecked")
  private static <I, R> Function<I, R> castingIdentity() {
    return i -> (R) i;
  }

}