package org.cyclops.integrateddynamics.core.evaluate.variable;

import com.google.common.collect.ImmutableList;
import org.cyclops.integrateddynamics.api.evaluate.variable.IValue;
import org.cyclops.integrateddynamics.api.evaluate.variable.IValueType;
import org.cyclops.integrateddynamics.api.evaluate.variable.IValueTypeListProxyFactoryTypeRegistry;

/**
 * Factory for {@link ValueTypeListProxyMaterialized}.
 * @author rubensworks
 */
public class ValueTypeListProxyMaterializedFactory implements IValueTypeListProxyFactoryTypeRegistry.IProxyFactory<IValueType<IValue>, IValue, ValueTypeListProxyMaterialized<IValueType<IValue>, IValue>> {

    private static final String ELEMENT_DELIMITER = ";";
    private static final String ELEMENT_DELIMITER_SPLITREGEX = "(?<!\\\\);";
    private static final String ELEMENT_DELIMITER_ESCAPED = "\\\\;";

    @Override
    public String getName() {
        return "materialized";
    }

    @Override
    public String serialize(ValueTypeListProxyMaterialized<IValueType<IValue>, IValue> values) throws IValueTypeListProxyFactoryTypeRegistry.SerializationException {
        StringBuilder sb = new StringBuilder();
        IValueType<IValue> valueType = values.getValueType();
        sb.append(valueType.getUnlocalizedName());
        for (IValue value : values) {
            sb.append(ELEMENT_DELIMITER);
            sb.append(ValueHelpers.serializeRaw(value).replaceAll(ELEMENT_DELIMITER, ELEMENT_DELIMITER_ESCAPED));
        }
        return sb.toString();
    }

    @Override
    public ValueTypeListProxyMaterialized<IValueType<IValue>, IValue> deserialize(String value) throws IValueTypeListProxyFactoryTypeRegistry.SerializationException {
        String[] split = value.split(ELEMENT_DELIMITER_SPLITREGEX);
        if (split.length < 1) {
            throw new IValueTypeListProxyFactoryTypeRegistry.SerializationException(String.format("Could not deserialize the serialized materialized list proxy value '%s'.", value));
        }

        String valueTypeName = split[0];
        IValueType<IValue> valueType = ValueTypes.REGISTRY.getValueType(valueTypeName);
        if (valueType == null) {
            throw new IValueTypeListProxyFactoryTypeRegistry.SerializationException(String.format("Could not deserialize the serialized materialized list proxy value because the value type by name '%s' was not found.", valueTypeName));
        }
        String[] values = new String[split.length - 1];
        System.arraycopy(split, 1, values, 0, split.length - 1);

        ImmutableList.Builder<IValue> builder = ImmutableList.builder();
        for (String serializedValue : values) {
            IValue deserializedValue = valueType.deserialize(serializedValue.replaceAll(ELEMENT_DELIMITER_ESCAPED, ELEMENT_DELIMITER));
            builder.add(deserializedValue);
        }

        return new ValueTypeListProxyMaterialized<>(valueType, builder.build());
    }
}

@@ -105,16 +105,88 @@
 leList;%0A
+import org.cyclops.integrateddynamics.api.evaluate.EvaluationException;%0A
 import o
@@ -1282,24 +1282,395 @@
 alueType();%0A
+        try %7B%0A            // Hack to avoid issue where categories are sometimes used to serialize/deserialize,%0A            // which is not allowed (and will crash during deserialization #570).%0A            if (valueType.isCategory() && values.getLength() %3E 0) %7B%0A                valueType = values.get(0).getType();%0A            %7D%0A        %7D catch (EvaluationException e) %7B%7D%0A
         sb.a

Fix crash when mapping lists using an operator that outputs a category