package com.github.therapi.runtimejavadoc.internal;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;
import com.github.therapi.runtimejavadoc.ClassJavadoc;
import com.github.therapi.runtimejavadoc.FieldJavadoc;
import com.github.therapi.runtimejavadoc.MethodJavadoc;

import static com.github.therapi.runtimejavadoc.internal.RuntimeJavadocHelper.elementDocFieldName;
import static com.github.therapi.runtimejavadoc.internal.RuntimeJavadocHelper.elementNameFieldName;
import static com.github.therapi.runtimejavadoc.internal.RuntimeJavadocHelper.enumConstantsFieldName;
import static com.github.therapi.runtimejavadoc.internal.RuntimeJavadocHelper.fieldsFieldName;
import static com.github.therapi.runtimejavadoc.internal.RuntimeJavadocHelper.methodsFieldName;
import static com.github.therapi.runtimejavadoc.internal.RuntimeJavadocHelper.paramTypesFieldName;

public class JsonJavadocReader {

    public static Optional<ClassJavadoc> readClassJavadoc(String qualifiedClassName, JsonObject json) {
        String className = qualifiedClassName.replace("$", ".");
        List<FieldJavadoc> fields = readFieldDocs(json.get(fieldsFieldName()));
        List<FieldJavadoc> enumConstants = readFieldDocs(json.get(enumConstantsFieldName()));
        List<MethodJavadoc> methods = readMethodDocs(json.get(methodsFieldName()));
        String classJavadocString = json.getString(elementDocFieldName(), null);
        ClassJavadoc classJavadoc = JavadocParser.parseClassJavadoc(className, classJavadocString, fields,
                enumConstants, methods);
        return Optional.of(classJavadoc);
    }

    private static List<FieldJavadoc> readFieldDocs(JsonValue fieldsValue) {
        JsonArray fieldsArray = fieldsValue.asArray();
        List<FieldJavadoc> fields = new ArrayList<>(fieldsArray.size());
        for (JsonValue fieldValue : fieldsArray) {
            fields.add(readFieldDoc(fieldValue));
        }
        return fields;
    }

    private static FieldJavadoc readFieldDoc(JsonValue fieldValue) {
        JsonObject field = fieldValue.asObject();
        String fieldName = field.getString(elementNameFieldName(), null);
        String fieldDoc = field.getString(elementDocFieldName(), null);
        return JavadocParser.parseFieldJavadoc(fieldName, fieldDoc);
    }

    private static List<MethodJavadoc> readMethodDocs(JsonValue methodsValue) {
        JsonArray methodArray = methodsValue.asArray();
        List<MethodJavadoc> methods = new ArrayList<>(methodArray.size());
        for (JsonValue methodValue : methodArray) {
            methods.add(readMethodDoc(methodValue));
        }
        return methods;
    }

    private static MethodJavadoc readMethodDoc(JsonValue methodValue) {
        JsonObject method = methodValue.asObject();
        String methodName = method.getString(elementNameFieldName(), null);
        List<String> paramTypes = readParamTypes(method.get(paramTypesFieldName()));
        String methodDoc = method.getString(elementDocFieldName(), null);
        return JavadocParser.parseMethodJavadoc(methodName, paramTypes, methodDoc);
    }

    private static List<String> readParamTypes(JsonValue paramTypesValue) {
        JsonArray paramTypesArray = paramTypesValue.asArray();
        List<String> paramTypes = new ArrayList<>(paramTypesArray.size());
        for (JsonValue v : paramTypesArray) {
            paramTypes.add(v.asString());
        }
        return paramTypes;
    }
}

@@ -70,24 +70,54 @@
 .ArrayList;%0A
+import java.util.Collections;%0A
 import java.
@@ -1846,32 +1846,180 @@
  fieldsValue) %7B%0A
+        if (fieldsValue == null) %7B%0A            // old versions might not have this JSON field%0A            return Collections.emptyList();%0A        %7D%0A
         JsonArra

Make fields/enums optional in the generated JSON for backwards compatibility