package stexfires.io.properties;

import stexfires.core.consumer.ConsumerException;
import stexfires.core.record.KeyValueRecord;
import stexfires.io.internal.AbstractWritableConsumer;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.Date;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static stexfires.io.properties.PropertiesFileSpec.*;

/**
 * @author Mathias Kalb
 * @since 0.1
 */
public class PropertiesConsumer extends AbstractWritableConsumer<KeyValueRecord> {

    protected final PropertiesFileSpec fileSpec;

    public PropertiesConsumer(BufferedWriter writer, PropertiesFileSpec fileSpec) {
        super(writer);
        Objects.requireNonNull(fileSpec);
        this.fileSpec = fileSpec;
    }

    protected static String mapCharacter(char character, boolean escapeSpace, boolean escapeUnicode) {
        switch (character) {
            case ' ':
                return escapeSpace ? "\\ " : " ";
            case '\t':
                return "\\t";
            case '\n':
                return "\\n";
            case '\r':
                return "\\r";
            case '\f':
                return "\\f";
            case '\\':
                return "\\\\";
            case '=':
                return "\\=";
            case ':':
                return "\\:";
            case '#':
                return "\\#";
            case '!':
                return "\\!";
            default:
                if (((character < 0x0020) || (character > 0x007e)) & escapeUnicode) {
                    return "\\u" + String.format("%04X", (int) character);
                }
                return Character.toString(character);
        }
    }

    protected static String convertKey(String key, boolean escapeUnicode) {
        return IntStream.range(0, key.length())
                        .mapToObj(i -> mapCharacter(key.charAt(i), true, escapeUnicode))
                        .collect(Collectors.joining());
    }

    protected static String convertValue(String value, boolean escapeUnicode) {
        return IntStream.range(0, value.length())
                        .mapToObj(i -> mapCharacter(value.charAt(i), i == 0, escapeUnicode))
                        .collect(Collectors.joining());
    }

    @Override
    public void writeBefore() throws IOException {
        super.writeBefore();
        if (fileSpec.isDateComment()) {
            write(COMMENT_PREFIX);
            write(new Date().toString());
            write(fileSpec.getLineSeparator().string());
        }
    }

    @Override
    public void writeRecord(KeyValueRecord record) throws IOException, ConsumerException {
        super.writeRecord(record);
        write(convertKey(record.getValueOfKeyField(), fileSpec.isEscapeUnicode()));
        write(DELIMITER);
        write(convertValue(record.getValueField().getValueOrElse(NULL_VALUE), fileSpec.isEscapeUnicode()));
        write(fileSpec.getLineSeparator().string());
    }

}


@@ -549,16 +549,138 @@
 ord%3E %7B%0A%0A
+    public static final int FIRST_NON_ESCAPED_CHAR = 0x0020;%0A    public static final int LAST_NON_ESCAPED_CHAR = 0x007e;%0A%0A
     prot
@@ -1634,70 +1634,126 @@
 if (
-((character %3C 0x0020) %7C%7C (character %3E 0x007e)) & escapeUnicode
+escapeUnicode%0A                        && ((character %3C FIRST_NON_ESCAPED_CHAR) %7C%7C (character %3E LAST_NON_ESCAPED_CHAR))
 ) %7B%0A

Extract constant and fix if-statement