package stexfires.core;

import stexfires.core.mapper.fieldvalue.FieldValueMapper;
import stexfires.core.mapper.fieldvalue.IdentityFieldValueMapper;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * This class consists of {@code static} utility methods
 * for operating on {@link Field}s.
 *
 * @author Mathias Kalb
 * @see stexfires.core.Field
 * @see stexfires.core.Record
 * @see stexfires.core.mapper.fieldvalue.FieldValueMapper
 * @since 0.1
 */
public final class Fields {

    public static final int FIRST_FIELD_INDEX = 0;
    public static final String DEFAULT_FIELD_VALUE_DELIMITER = ", ";

    @SuppressWarnings("StaticVariableOfConcreteClass")
    private static final Field[] EMPTY_FIELD_ARRAY = new Field[0];

    private Fields() {
    }

    public static Field[] emptyArray() {
        return EMPTY_FIELD_ARRAY;
    }

    public static Field[] newArray(Collection<String> values) {
        Field[] fields = new Field[values.size()];
        int index = FIRST_FIELD_INDEX;
        for (String value : values) {
            fields[index] = new Field(index, (index + 1) == values.size(), value);
            index++;
        }
        return fields;
    }

    public static Field[] newArray(Stream<String> values) {
        return newArray(values.collect(Collectors.toList()));
    }

    @SuppressWarnings("Convert2streamapi")
    public static Field[] newArray(String... values) {
        Field[] fields = new Field[values.length];
        for (int index = FIRST_FIELD_INDEX; index < values.length; index++) {
            fields[index] = new Field(index, (index + 1) == values.length, values[index]);
        }
        return fields;
    }

    @SuppressWarnings("Convert2streamapi")
    public static Field[] newArray(int length, Supplier<String> valueSupplier) {
        if (length < 0) {
            throw new IllegalArgumentException("Illegal length! length=" + length);
        }
        Objects.requireNonNull(valueSupplier);
        Field[] fields = new Field[length];
        for (int index = FIRST_FIELD_INDEX; index < length; index++) {
            fields[index] = new Field(index, (index + 1) == length, valueSupplier.get());
        }
        return fields;
    }

    public static List<String> collectValues(Record record) {
        return collectValues(record.streamOfFields(), new IdentityFieldValueMapper());
    }

    public static List<String> collectValues(Record record, FieldValueMapper fieldValueMapper) {
        return collectValues(record.streamOfFields(), fieldValueMapper);
    }

    @SuppressWarnings("MethodCanBeVariableArityMethod")
    public static List<String> collectValues(Field[] fields) {
        Objects.requireNonNull(fields);
        return collectValues(Arrays.stream(fields), new IdentityFieldValueMapper());
    }

    public static List<String> collectValues(Field[] fields, FieldValueMapper fieldValueMapper) {
        Objects.requireNonNull(fields);
        return collectValues(Arrays.stream(fields), fieldValueMapper);
    }

    public static List<String> collectValues(Stream<Field> fields) {
        return collectValues(fields, new IdentityFieldValueMapper());
    }

    public static List<String> collectValues(Stream<Field> fields, FieldValueMapper fieldValueMapper) {
        Objects.requireNonNull(fields);
        Objects.requireNonNull(fieldValueMapper);
        return fields.map(fieldValueMapper::mapToValue).collect(Collectors.toList());
    }

    public static String joinValues(Record record) {
        return joinValues(record.streamOfFields(), DEFAULT_FIELD_VALUE_DELIMITER);
    }

    public static String joinValues(Record record, CharSequence delimiter) {
        Objects.requireNonNull(delimiter);
        return joinValues(record.streamOfFields(), delimiter);
    }

    @SuppressWarnings("MethodCanBeVariableArityMethod")
    public static String joinValues(Field[] fields) {
        Objects.requireNonNull(fields);
        return joinValues(Arrays.stream(fields), DEFAULT_FIELD_VALUE_DELIMITER);
    }

    public static String joinValues(Field[] fields, CharSequence delimiter) {
        Objects.requireNonNull(fields);
        Objects.requireNonNull(delimiter);
        return joinValues(Arrays.stream(fields), delimiter);
    }

    public static String joinValues(Stream<Field> fields) {
        return joinValues(fields, DEFAULT_FIELD_VALUE_DELIMITER);
    }

    public static String joinValues(Stream<Field> fields, CharSequence delimiter) {
        Objects.requireNonNull(fields);
        Objects.requireNonNull(delimiter);
        return fields.map(Field::getValue).collect(Collectors.joining(delimiter));
    }

}

@@ -1051,32 +1051,72 @@
 ring%3E values) %7B%0A
+        Objects.requireNonNull(values);%0A
         Field%5B%5D 
@@ -1150,16 +1150,16 @@
 ize()%5D;%0A
-
         
@@ -1423,32 +1423,72 @@
 ring%3E values) %7B%0A
+        Objects.requireNonNull(values);%0A
         return n
@@ -1630,32 +1630,72 @@
 ng... values) %7B%0A
+        Objects.requireNonNull(values);%0A
         Field%5B%5D 
@@ -2528,32 +2528,72 @@
 ecord record) %7B%0A
+        Objects.requireNonNull(record);%0A
         return c
@@ -2759,32 +2759,122 @@
 dValueMapper) %7B%0A
+        Objects.requireNonNull(record);%0A        Objects.requireNonNull(fieldValueMapper);%0A
         return c
@@ -3318,32 +3318,82 @@
 onNull(fields);%0A
+        Objects.requireNonNull(fieldValueMapper);%0A
         return c
@@ -3515,32 +3515,72 @@
 ield%3E fields) %7B%0A
+        Objects.requireNonNull(fields);%0A
         return c
@@ -3972,32 +3972,72 @@
 ecord record) %7B%0A
+        Objects.requireNonNull(record);%0A
         return j
@@ -4179,32 +4179,72 @@
 ce delimiter) %7B%0A
+        Objects.requireNonNull(record);%0A
         Objects.
@@ -4799,32 +4799,32 @@
 imiter);%0A    %7D%0A%0A
-
     public stati
@@ -4859,32 +4859,72 @@
 ield%3E fields) %7B%0A
+        Objects.requireNonNull(fields);%0A
         return j

Add Objects.requireNonNull()