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

package com.google.protobuf;

import java.util.Arrays;
import java.util.Iterator;
import java.util.Set;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
import java.lang.reflect.Modifier;
import java.util.TreeMap;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;

final class MessageLiteToString
{
    private static final String LIST_SUFFIX = "List";
    private static final String BUILDER_LIST_SUFFIX = "OrBuilderList";
    private static final String MAP_SUFFIX = "Map";
    private static final String BYTES_SUFFIX = "Bytes";
    private static final char[] INDENT_BUFFER;
    
    private MessageLiteToString() {
    }
    
    static String toString(final MessageLite messageLite, final String commentString) {
        final StringBuilder buffer = new StringBuilder();
        buffer.append("# ").append(commentString);
        reflectivePrintWithIndent(messageLite, buffer, 0);
        return buffer.toString();
    }
    
    private static void reflectivePrintWithIndent(final MessageLite messageLite, final StringBuilder buffer, final int indent) {
        final Set<String> setters = new HashSet<String>();
        final Map<String, Method> hazzers = new HashMap<String, Method>();
        final Map<String, Method> getters = new TreeMap<String, Method>();
        for (final Method method : messageLite.getClass().getDeclaredMethods()) {
            if (!Modifier.isStatic(method.getModifiers())) {
                if (method.getName().length() >= 3) {
                    if (method.getName().startsWith("set")) {
                        setters.add(method.getName());
                    }
                    else if (Modifier.isPublic(method.getModifiers())) {
                        if (method.getParameterTypes().length == 0) {
                            if (method.getName().startsWith("has")) {
                                hazzers.put(method.getName(), method);
                            }
                            else if (method.getName().startsWith("get")) {
                                getters.put(method.getName(), method);
                            }
                        }
                    }
                }
            }
        }
        for (final Map.Entry<String, Method> getter : getters.entrySet()) {
            final String suffix = getter.getKey().substring(3);
            if (suffix.endsWith("List") && !suffix.endsWith("OrBuilderList") && !suffix.equals("List")) {
                final Method listMethod = getter.getValue();
                if (listMethod != null && listMethod.getReturnType().equals(List.class)) {
                    printField(buffer, indent, suffix.substring(0, suffix.length() - "List".length()), GeneratedMessageLite.invokeOrDie(listMethod, messageLite, new Object[0]));
                    continue;
                }
            }
            if (suffix.endsWith("Map") && !suffix.equals("Map")) {
                final Method mapMethod = getter.getValue();
                if (mapMethod != null && mapMethod.getReturnType().equals(Map.class) && !mapMethod.isAnnotationPresent(Deprecated.class) && Modifier.isPublic(mapMethod.getModifiers())) {
                    printField(buffer, indent, suffix.substring(0, suffix.length() - "Map".length()), GeneratedMessageLite.invokeOrDie(mapMethod, messageLite, new Object[0]));
                    continue;
                }
            }
            if (!setters.contains("set" + suffix)) {
                continue;
            }
            if (suffix.endsWith("Bytes") && getters.containsKey("get" + suffix.substring(0, suffix.length() - "Bytes".length()))) {
                continue;
            }
            final Method getMethod = getter.getValue();
            final Method hasMethod = hazzers.get("has" + suffix);
            if (getMethod == null) {
                continue;
            }
            final Object value = GeneratedMessageLite.invokeOrDie(getMethod, messageLite, new Object[0]);
            final boolean hasValue = (boolean)((hasMethod == null) ? (!isDefaultValue(value)) : GeneratedMessageLite.invokeOrDie(hasMethod, messageLite, new Object[0]));
            if (!hasValue) {
                continue;
            }
            printField(buffer, indent, suffix, value);
        }
        if (messageLite instanceof GeneratedMessageLite.ExtendableMessage) {
            for (final Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object> entry : ((GeneratedMessageLite.ExtendableMessage)messageLite).extensions) {
                printField(buffer, indent, "[" + entry.getKey().getNumber() + "]", entry.getValue());
            }
        }
        if (((GeneratedMessageLite)messageLite).unknownFields != null) {
            ((GeneratedMessageLite)messageLite).unknownFields.printWithIndent(buffer, indent);
        }
    }
    
    private static boolean isDefaultValue(final Object o) {
        if (o instanceof Boolean) {
            return !(boolean)o;
        }
        if (o instanceof Integer) {
            return (int)o == 0;
        }
        if (o instanceof Float) {
            return Float.floatToRawIntBits((float)o) == 0;
        }
        if (o instanceof Double) {
            return Double.doubleToRawLongBits((double)o) == 0L;
        }
        if (o instanceof String) {
            return o.equals("");
        }
        if (o instanceof ByteString) {
            return o.equals(ByteString.EMPTY);
        }
        if (o instanceof MessageLite) {
            return o == ((MessageLite)o).getDefaultInstanceForType();
        }
        return o instanceof Enum && ((Enum)o).ordinal() == 0;
    }
    
    static void printField(final StringBuilder buffer, final int indent, final String name, final Object object) {
        if (object instanceof List) {
            final List<?> list = (List<?>)object;
            for (final Object entry : list) {
                printField(buffer, indent, name, entry);
            }
            return;
        }
        if (object instanceof Map) {
            final Map<?, ?> map = (Map<?, ?>)object;
            for (final Map.Entry<?, ?> entry2 : map.entrySet()) {
                printField(buffer, indent, name, entry2);
            }
            return;
        }
        buffer.append('\n');
        indent(indent, buffer);
        buffer.append(pascalCaseToSnakeCase(name));
        if (object instanceof String) {
            buffer.append(": \"").append(TextFormatEscaper.escapeText((String)object)).append('\"');
        }
        else if (object instanceof ByteString) {
            buffer.append(": \"").append(TextFormatEscaper.escapeBytes((ByteString)object)).append('\"');
        }
        else if (object instanceof GeneratedMessageLite) {
            buffer.append(" {");
            reflectivePrintWithIndent((MessageLite)object, buffer, indent + 2);
            buffer.append("\n");
            indent(indent, buffer);
            buffer.append("}");
        }
        else if (object instanceof Map.Entry) {
            buffer.append(" {");
            final Map.Entry<?, ?> entry3 = (Map.Entry<?, ?>)object;
            printField(buffer, indent + 2, "key", entry3.getKey());
            printField(buffer, indent + 2, "value", entry3.getValue());
            buffer.append("\n");
            indent(indent, buffer);
            buffer.append("}");
        }
        else {
            buffer.append(": ").append(object);
        }
    }
    
    private static void indent(int indent, final StringBuilder buffer) {
        while (indent > 0) {
            int partialIndent = indent;
            if (partialIndent > MessageLiteToString.INDENT_BUFFER.length) {
                partialIndent = MessageLiteToString.INDENT_BUFFER.length;
            }
            buffer.append(MessageLiteToString.INDENT_BUFFER, 0, partialIndent);
            indent -= partialIndent;
        }
    }
    
    private static String pascalCaseToSnakeCase(final String pascalCase) {
        if (pascalCase.isEmpty()) {
            return pascalCase;
        }
        final StringBuilder builder = new StringBuilder();
        builder.append(Character.toLowerCase(pascalCase.charAt(0)));
        for (int i = 1; i < pascalCase.length(); ++i) {
            final char ch = pascalCase.charAt(i);
            if (Character.isUpperCase(ch)) {
                builder.append("_");
            }
            builder.append(Character.toLowerCase(ch));
        }
        return builder.toString();
    }
    
    static {
        Arrays.fill(INDENT_BUFFER = new char[80], ' ');
    }
}
