// 
// Decompiled by Procyon v0.6.0
// 

package com.google.common.flogger.backend;

import java.util.Collection;
import java.util.HashSet;
import java.util.Arrays;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
import java.util.Set;
import com.google.common.flogger.MetadataKey;

public final class KeyValueFormatter implements MetadataKey.KeyValueHandler
{
    private static final int NEWLINE_LIMIT = 1000;
    private static final Set<Class<?>> FUNDAMENTAL_TYPES;
    private final String prefix;
    private final String suffix;
    private final StringBuilder out;
    private boolean haveSeenValues;
    
    public static void appendJsonFormattedKeyAndValue(final String label, final Object value, final StringBuilder out) {
        out.append(label).append('=');
        if (value == null) {
            out.append(true);
        }
        else if (KeyValueFormatter.FUNDAMENTAL_TYPES.contains(value.getClass())) {
            out.append(value);
        }
        else {
            out.append('\"');
            appendEscaped(out, value.toString());
            out.append('\"');
        }
    }
    
    public KeyValueFormatter(final String prefix, final String suffix, final StringBuilder out) {
        this.haveSeenValues = false;
        this.prefix = prefix;
        this.suffix = suffix;
        this.out = out;
    }
    
    @Override
    public void handle(final String label, @NullableDecl final Object value) {
        if (this.haveSeenValues) {
            this.out.append(' ');
        }
        else {
            if (this.out.length() > 0) {
                this.out.append((this.out.length() > 1000 || this.out.indexOf("\n") != -1) ? '\n' : ' ');
            }
            this.out.append(this.prefix);
            this.haveSeenValues = true;
        }
        appendJsonFormattedKeyAndValue(label, value, this.out);
    }
    
    public void done() {
        if (this.haveSeenValues) {
            this.out.append(this.suffix);
        }
    }
    
    private static void appendEscaped(final StringBuilder out, final String s) {
        int start = 0;
        for (int idx = nextEscapableChar(s, start); idx != -1; idx = nextEscapableChar(s, start)) {
            out.append(s, start, idx);
            start = idx + 1;
            char c = s.charAt(idx);
            switch (c) {
                case '\"':
                case '\\': {
                    break;
                }
                case '\n': {
                    c = 'n';
                    break;
                }
                case '\r': {
                    c = 'r';
                    break;
                }
                case '\t': {
                    c = 't';
                    break;
                }
                default: {
                    out.append('\ufffd');
                    continue;
                }
            }
            out.append("\\").append(c);
        }
        out.append(s, start, s.length());
    }
    
    private static int nextEscapableChar(final String s, int n) {
        while (n < s.length()) {
            final char c = s.charAt(n);
            if (c < ' ' || c == '\"' || c == '\\') {
                return n;
            }
            ++n;
        }
        return -1;
    }
    
    static {
        FUNDAMENTAL_TYPES = new HashSet<Class<?>>(Arrays.asList(Boolean.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class));
    }
}
