package stexfires.record.impl;

import org.jetbrains.annotations.Nullable;
import stexfires.record.Field;
import stexfires.record.Fields;
import stexfires.record.TextRecord;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * @author Mathias Kalb
 * @since 0.1
 */
public final class ManyValuesRecord implements TextRecord {

    private final String category;
    private final Long recordId;
    private final Field[] fields;

    private final int hashCode;

    public ManyValuesRecord() {
        this(null, null, Fields.emptyArray());
    }

    public ManyValuesRecord(Collection<String> values) {
        this(null, null, Fields.newArray(values));
    }

    public ManyValuesRecord(@Nullable String category, Collection<String> values) {
        this(category, null, Fields.newArray(values));
    }

    public ManyValuesRecord(@Nullable String category, @Nullable Long recordId, Collection<String> values) {
        this(category, recordId, Fields.newArray(values));
    }

    public ManyValuesRecord(Stream<String> values) {
        this(null, null, Fields.newArray(values));
    }

    public ManyValuesRecord(@Nullable String category, Stream<String> values) {
        this(category, null, Fields.newArray(values));
    }

    public ManyValuesRecord(@Nullable String category, @Nullable Long recordId, Stream<String> values) {
        this(category, recordId, Fields.newArray(values));
    }

    @SuppressWarnings("OverloadedVarargsMethod")
    public ManyValuesRecord(String... values) {
        this(null, null, Fields.newArray(values));
    }

    @SuppressWarnings("OverloadedVarargsMethod")
    public ManyValuesRecord(@Nullable String category, @Nullable Long recordId, String... values) {
        this(category, recordId, Fields.newArray(values));
    }

    @SuppressWarnings("MethodCanBeVariableArityMethod")
    private ManyValuesRecord(@Nullable String category, @Nullable Long recordId, Field[] fields) {
        this.category = category;
        this.recordId = recordId;
        this.fields = fields;

        hashCode = Objects.hash(category, recordId, Arrays.hashCode(fields));
    }

    @Override
    public Field[] arrayOfFields() {
        synchronized (fields) {
            return Arrays.copyOf(fields, fields.length);
        }
    }

    @Override
    public List<Field> listOfFields() {
        return Arrays.asList(arrayOfFields());
    }

    @Override
    public List<Field> listOfFieldsReversed() {
        var fieldList = listOfFields();
        Collections.reverse(fieldList);
        return fieldList;
    }

    @Override
    public Stream<Field> streamOfFields() {
        return Arrays.stream(arrayOfFields());
    }

    @Override
    public String category() {
        return category;
    }

    @Override
    public Long recordId() {
        return recordId;
    }

    @Override
    public int size() {
        return fields.length;
    }

    @SuppressWarnings("ReturnOfNull")
    @Override
    public Field fieldAt(int index) {
        return ((index >= 0) && (index < fields.length)) ? fields[index] : null;
    }

    @Override
    public boolean equals(@Nullable Object obj) {
        if (this == obj)
            return true;
        if (obj == null || getClass() != obj.getClass())
            return false;

        ManyValuesRecord record = (ManyValuesRecord) obj;
        return Objects.equals(category, record.category) &&
                Objects.equals(recordId, record.recordId) &&
                Arrays.equals(fields, record.fields);
    }

    @Override
    public int hashCode() {
        return hashCode;
    }

    @Override
    public String toString() {
        return "ManyValuesRecord{" +
                "category=" + category +
                ", recordId=" + recordId +
                ", values=[" + Fields.joinValues(fields) +
                "]}";
    }

}

@@ -25,16 +25,58 @@
 .impl;%0A%0A
+import org.jetbrains.annotations.NotNull;%0A
 import o
@@ -433,19 +433,14 @@
 lic 
-final class
+record
  Man
@@ -456,86 +456,45 @@
 cord
- implements TextRecord %7B%0A%0A    private final String category;%0A    private final
+(@Nullable String category, @Nullable
  Lon
@@ -507,26 +507,48 @@
 rdId
-;
+,
 %0A    
-private fina
+                           @NotNul
 l Fi
@@ -563,42 +563,41 @@
 elds
-;%0A
+)
 %0A    
-private final int hashCode;
+    implements TextRecord %7B
 %0A%0A  
@@ -1918,71 +1918,14 @@
     
-@SuppressWarnings(%22MethodCanBeVariableArityMethod%22)%0A    private
+public
  Man
@@ -1985,24 +1985,33 @@
 ng recordId,
+ @NotNull
  Field%5B%5D fie
@@ -2009,32 +2009,72 @@
 eld%5B%5D fields) %7B%0A
+        Objects.requireNonNull(fields);%0A
         this.cat
@@ -2129,116 +2129,603 @@
 Id;%0A
-        this.fields = fields;%0A%0A        hashCo
+%0A        // Check and copy fields%0A        this.fields = new Field%5Bfields.length%5D;%0A        int maxIndex = fields.length - 1;%0A        for (int in
 de
+x
  = 
-Objects.hash(category, recordId, Arrays.hashCode(fields));
+Fields.FIRST_FIELD_INDEX; index %3C fields.length; index++) %7B%0A            var field = fields%5Bindex%5D;%0A            if (field.index() != index) %7B%0A                throw new IllegalArgumentException(%22Wrong 'index' of field: %22 + field);%0A            %7D%0A            if (field.maxIndex() != maxIndex) %7B%0A                throw new IllegalArgumentException(%22Wrong 'maxIndex' of field: %22 + field);%0A            %7D%0A%0A            this.fields%5Bindex%5D = field;%0A        %7D
 %0A   
@@ -3689,772 +3689,6 @@
  %7D%0A%0A
-    @Override%0A    public boolean equals(@Nullable Object obj) %7B%0A        if (this == obj)%0A            return true;%0A        if (obj == null %7C%7C getClass() != obj.getClass())%0A            return false;%0A%0A        ManyValuesRecord record = (ManyValuesRecord) obj;%0A        return Objects.equals(category, record.category) &&%0A                Objects.equals(recordId, record.recordId) &&%0A                Arrays.equals(fields, record.fields);%0A    %7D%0A%0A    @Override%0A    public int hashCode() %7B%0A        return hashCode;%0A    %7D%0A%0A    @Override%0A    public String toString() %7B%0A        return %22ManyValuesRecord%7B%22 +%0A                %22category=%22 + category +%0A                %22, recordId=%22 + recordId +%0A                %22, values=%5B%22 + Fields.joinValues(fields) +%0A                %22%5D%7D%22;%0A    %7D%0A%0A
 %7D%0A

Refactor ManyValuesRecord into java record