package stexfires.record;

import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 * A {@link TextRecord} contains {@link Field}s with values.
 * It can also contain a category and a record id.
 * <p>
 * It must be {@code immutable} and {@code thread-safe}.
 * The field index must start with {@code 0}.
 *
 * @author Mathias Kalb
 * @see Field
 * @see TextRecords
 * @see Fields#FIRST_FIELD_INDEX
 * @since 0.1
 */
public interface TextRecord {

    Field[] arrayOfFields();

    List<Field> listOfFields();

    Stream<Field> streamOfFields();

    String category();

    default boolean hasCategory() {
        return category() != null;
    }

    default String categoryOrElse(@Nullable String other) {
        return category() != null ? category() : other;
    }

    default Optional<String> categoryAsOptional() {
        return Optional.ofNullable(category());
    }

    default Stream<String> categoryAsStream() {
        return Stream.ofNullable(category());
    }

    Long recordId();

    default boolean hasRecordId() {
        return recordId() != null;
    }

    default OptionalLong recordIdAsOptionalLong() {
        return hasRecordId() ? OptionalLong.of(recordId()) : OptionalLong.empty();
    }

    default Optional<Long> recordIdAsOptional() {
        return Optional.ofNullable(recordId());
    }

    default LongStream recordIdAsStream() {
        if (recordId() == null) {
            return LongStream.empty();
        }
        return LongStream.of(recordId());
    }

    int size();

    default boolean isEmpty() {
        return size() == 0;
    }

    default boolean isValidIndex(int index) {
        return (index >= 0) && (index < size());
    }

    Field fieldAt(int index);

    default Field firstField() {
        return fieldAt(0);
    }

    default Field lastField() {
        return fieldAt(size() - 1);
    }

    @SuppressWarnings("ReturnOfNull")
    default String valueAt(int index) {
        return isValidIndex(index) ? fieldAt(index).value() : null;
    }

    default String valueAtOrElse(int index, @Nullable String other) {
        return valueAt(index) != null ? valueAt(index) : other;
    }

    @SuppressWarnings("ReturnOfNull")
    default String valueOfFirstField() {
        return isEmpty() ? null : firstField().value();
    }

    @SuppressWarnings("ReturnOfNull")
    default String valueOfLastField() {
        return isEmpty() ? null : lastField().value();
    }

    /**
     * Compare class, category, recordId and all fields.
     */
    @Override
    boolean equals(@Nullable Object obj);

    @Override
    int hashCode();

    @Override
    String toString();

}

@@ -64,16 +64,71 @@
 lable;%0A%0A
+import java.util.Arrays;%0Aimport java.util.Collections;%0A
 import j
@@ -672,16 +672,24 @@
 );%0A%0A    
+default 
 List%3CFie
@@ -710,46 +710,461 @@
 ds()
-;%0A%0A    Stream%3CField%3E streamOfFields();
+ %7B%0A        return switch (size()) %7B%0A            case 0 -%3E Collections.emptyList();%0A            case 1 -%3E Collections.singletonList(firstField());%0A            default -%3E Arrays.asList(arrayOfFields());%0A        %7D;%0A    %7D%0A%0A    default Stream%3CField%3E streamOfFields() %7B%0A        return switch (size()) %7B%0A            case 0 -%3E Stream.empty();%0A            case 1 -%3E Stream.of(firstField());%0A            default -%3E Arrays.stream(arrayOfFields());%0A        %7D;%0A    %7D
 %0A%0A  

Make methods "default"