package com.jsoniter;
import java.util.*;
class CodegenImplEnum {
public static String genEnum(Class clazz) {
StringBuilder lines = new StringBuilder();
append(lines, "if (iter.readNull()) { return null; }");
append(lines, "com.jsoniter.Slice field = com.jsoniter.CodegenAccess.readSlice(iter);");
append(lines, "switch (field.len()) {");
append(lines, renderTriTree(buildTriTree(Arrays.asList(clazz.getEnumConstants()))));
append(lines, "}"); // end of switch
append(lines, String.format("throw iter.reportError(\"decode enum\", field + \" is not valid enum for %s\");", clazz.getName()));
return lines.toString();
}
private static Map<Integer, Object> buildTriTree(List<Object> allConsts) {
Map<Integer, Object> trieTree = new HashMap<Integer, Object>();
for (Object e : allConsts) {
byte[] fromNameBytes = e.toString().getBytes();
Map<Byte, Object> current = (Map<Byte, Object>) trieTree.get(fromNameBytes.length);
if (current == null) {
current = new HashMap<Byte, Object>();
trieTree.put(fromNameBytes.length, current);
}
for (int i = 0; i < fromNameBytes.length - 1; i++) {
byte b = fromNameBytes[i];
Map<Byte, Object> next = (Map<Byte, Object>) current.get(b);
if (next == null) {
next = new HashMap<Byte, Object>();
current.put(b, next);
}
current = next;
}
current.put(fromNameBytes[fromNameBytes.length - 1], e);
}
return trieTree;
}
private static String renderTriTree(Map<Integer, Object> trieTree) {
StringBuilder switchBody = new StringBuilder();
for (Map.Entry<Integer, Object> entry : trieTree.entrySet()) {
Integer len = entry.getKey();
append(switchBody, "case " + len + ": ");
Map<Byte, Object> current = (Map<Byte, Object>) entry.getValue();
addFieldDispatch(switchBody, len, 0, current, new ArrayList<Byte>());
append(switchBody, "break;");
}
return switchBody.toString();
}
private static void addFieldDispatch(
StringBuilder lines, int len, int i, Map<Byte, Object> current, List<Byte> bytesToCompare) {
for (Map.Entry<Byte, Object> entry : current.entrySet()) {
Byte b = entry.getKey();
if (i == len - 1) {
append(lines, "if (");
for (int j = 0; j < bytesToCompare.size(); j++) {
Byte a = bytesToCompare.get(j);
append(lines, String.format("field.at(%d)==%s && ", i - bytesToCompare.size() + j, a));
}
append(lines, String.format("field.at(%d)==%s", i, b));
append(lines, ") {");
Object e = entry.getValue();
append(lines, String.format("return %s.%s;", e.getClass().getName(), e.toString()));
append(lines, "}");
continue;
}
Map<Byte, Object> next = (Map<Byte, Object>) entry.getValue();
if (next.size() == 1) {
ArrayList<Byte> nextBytesToCompare = new ArrayList<Byte>(bytesToCompare);
nextBytesToCompare.add(b);
addFieldDispatch(lines, len, i + 1, next, nextBytesToCompare);
continue;
}
append(lines, "if (");
for (int j = 0; j < bytesToCompare.size(); j++) {
Byte a = bytesToCompare.get(j);
append(lines, String.format("field.at(%d)==%s && ", i - bytesToCompare.size() + j, a));
}
append(lines, String.format("field.at(%d)==%s", i, b));
append(lines, ") {");
addFieldDispatch(lines, len, i + 1, next, new ArrayList<Byte>());
append(lines, "}");
}
}
private static void append(StringBuilder lines, String str) {
lines.append(str);
lines.append("\n");
}
}