package org.textfiledatatools.core;

import org.textfiledatatools.core.producer.RecordProducer;
import org.textfiledatatools.core.producer.UncheckedProducerException;

import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

/**
 * This class consists of {@code static} utility methods for operating on record streams.
 *
 * @author Mathias Kalb
 * @since 0.1
 */
public final class RecordStreams {

    private RecordStreams() {
    }

    public static Stream<Record> empty() {
        return Stream.empty();
    }

    public static <T extends Record> Stream<T> of(T record) {
        return Stream.of(record);
    }

    @SafeVarargs
    public static <T extends Record> Stream<T> of(T... records) {
        return Stream.of(records);
    }

    public static <T extends Record> Stream<T> produceStream(RecordProducer<T> recordProducer) throws UncheckedProducerException {
        return recordProducer.produceStream();
    }

    public static <T extends Record> Stream<T> generate(Supplier<T> recordSupplier) {
        return Stream.generate(recordSupplier);
    }

    public static <T extends Record> Stream<T> concat(Stream<T> firstRecordStream, Stream<T> secondRecordStream) {
        return Stream.concat(firstRecordStream, secondRecordStream);
    }

    @SafeVarargs
    public static <T extends Record> Stream<T> concat(Stream<T>... recordStreams) {
        // TODO Validate: concatWithFlatMap or concatWithReduce
        return concatWithFlatMap(recordStreams);
    }

    @SafeVarargs
    static <T extends Record> Stream<T> concatWithFlatMap(Stream<T>... recordStreams) {
        return Stream.of(recordStreams).flatMap(Function.identity());
    }

    @SafeVarargs
    static <T extends Record> Stream<T> concatWithReduce(Stream<T>... recordStreams) {
        return Stream.of(recordStreams).reduce(Stream.empty(), Stream::concat);
    }

}

@@ -161,16 +161,42 @@
 ption;%0A%0A
+import java.util.Objects;%0A
 import j
@@ -1924,10 +1924,1632 @@
 %0A    %7D%0A%0A
+    public static %3CT extends Record%3E Stream%3CT%3E distinct(Stream%3CT%3E stream,%0A                                                        Function%3C? super T, String%3E recordEqualsString) %7B%0A        Objects.requireNonNull(stream, %22Parameter 'stream' must not be null%22);%0A        Objects.requireNonNull(recordEqualsString, %22Parameter 'recordEqualsString' must not be null%22);%0A        return stream.map((record) -%3E new DistinctRecordWrapper%3C%3E(record, recordEqualsString.apply(record)))%0A                .distinct()%0A                .map(DistinctRecordWrapper%3CT%3E::getRecord);%0A    %7D%0A%0A    private static final class DistinctRecordWrapper%3CT extends Record%3E %7B%0A%0A        private final T record;%0A        private final String equalsString;%0A%0A        public DistinctRecordWrapper(T record, String equalsString) %7B%0A            this.record = record;%0A            this.equalsString = equalsString;%0A        %7D%0A%0A        public T getRecord() %7B%0A            return record;%0A        %7D%0A%0A        @Override%0A        public boolean equals(Object o) %7B%0A            if (this == o) return true;%0A            if (o == null %7C%7C getClass() != o.getClass()) return false;%0A            DistinctRecordWrapper%3C?%3E that = (DistinctRecordWrapper%3C?%3E) o;%0A            return Objects.equals(equalsString, that.equalsString);%0A        %7D%0A%0A        @Override%0A        public int hashCode() %7B%0A            return Objects.hash(equalsString);%0A        %7D%0A%0A        @Override%0A        public String toString() %7B%0A            return %22DistinctRecordWrapper%7B%22 +%0A                    %22record=%22 + record +%0A                    %22, equalsString='%22 + equalsString + '%5C'' +%0A                    '%7D';%0A        %7D%0A    %7D%0A%0A
 %7D%0A

Add 'distinct' method