package com.os.operando.gummi;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import java.util.List;

public class JsonRpc2 {

    private static final String VERSION = "2.0";

    private static final String KEY_ID = "id";
    private static final String KEY_JSONRPC = "jsonrpc";
    private static final String KEY_RESULT = "result";
    private static final String KEY_ERROR = "error";
    private static final String KEY_CODE = "code";
    private static final String KEY_MESSAGE = "message";

    private static final String KEY_PARAMS = "params";
    private static final String KEY_METHOD = "method";

    private static final Gson GSON = new Gson();

    private final RequestIdentifierGenerator requestIdentifierGenerator;

    public JsonRpc2(RequestIdentifierGenerator requestIdentifierGenerator) {
        this.requestIdentifierGenerator = requestIdentifierGenerator;
    }

    public <T> JsonRpcRequest<T> createRequest(RequestType<T> requestType) {
        String id = requestIdentifierGenerator.next();
        return new JsonRpcRequest<>(requestType, id, buildJsonFromRequest(requestType, id));
    }

    private JsonObject buildJsonFromRequest(RequestType<?> requestType, String id) {
        JsonObject jsonObject = new JsonObject();
        jsonObject.add(KEY_PARAMS, GSON.toJsonTree(requestType));
        jsonObject.addProperty(KEY_METHOD, requestType.getMethod());
        jsonObject.addProperty(KEY_JSONRPC, VERSION);
        jsonObject.addProperty(KEY_ID, id);
        return jsonObject;
    }

    public <T> Result<T> parseResponseJson(List<JsonObject> jsonObjects, JsonRpcRequest<T> jsonRpcRequest) {
        for (JsonObject jsonObject : jsonObjects) {
            String version = jsonObject.get(KEY_JSONRPC).getAsString();
            if (!VERSION.equals(version)) {
                // TODO: error code
                JsonRpcException jsonRpcException = new JsonRpcException(1, "version mismatch.", jsonObject);
                return new Result<>(null, jsonRpcException);
            }

            String id = jsonObject.get(KEY_ID).getAsString();
            JsonElement result = jsonObject.get(KEY_RESULT);

            if (result != null) {
                if (jsonRpcRequest.id.equals(id)) {
                    RequestType<T> requestType = jsonRpcRequest.requestType;
                    T response = GSON.fromJson(result, requestType.getResponseType());
                    if (response == null) {
                        // TODO: error code
                        JsonRpcException jsonRpcException = new JsonRpcException(1, "response is null.", jsonObject);
                        return new Result<>(null, jsonRpcException);
                    }
                    return new Result<>(response, null);
                }
            }

            JsonElement error = jsonObject.get(KEY_ERROR);
            if (error != null) {
                JsonObject errorObject = error.getAsJsonObject();
                JsonElement code = errorObject.get(KEY_CODE);
                JsonElement message = errorObject.get(KEY_MESSAGE);
                if (code != null && message != null) {
                    JsonRpcException jsonRpcException = new JsonRpcException(code.getAsInt(), message.getAsString(), jsonObject);
                    return new Result<>(null, jsonRpcException);
                }
            }
        }

        JsonRpcException jsonRpcException = new JsonRpcException(0, "", null);
        return new Result<>(null, jsonRpcException);
    }
}
@@ -1629,27 +1629,32 @@
 Object%3E 
-jsonObjects
+responseJsonList
 , JsonRp
@@ -1711,35 +1711,196 @@
 ect 
-jsonObject : jsonObjects) %7B
+responseJson : responseJsonList) %7B%0A            String id = responseJson.get(KEY_ID).getAsString();%0A            if (!jsonRpcRequest.id.equals(id)) %7B%0A                continue;%0A            %7D%0A
 %0A   
@@ -1925,26 +1925,28 @@
 rsion = 
-jsonObject
+responseJson
 .get(KEY
@@ -2143,34 +2143,36 @@
 mismatch.%22, 
-jsonObject
+responseJson
 );%0A         
@@ -2242,70 +2242,8 @@
  %7D%0A%0A
-            String id = jsonObject.get(KEY_ID).getAsString();%0A
     
@@ -2271,26 +2271,28 @@
 esult = 
-jsonObject
+responseJson
 .get(KEY
@@ -2301,17 +2301,16 @@
 ESULT);%0A
-%0A
         
@@ -2339,64 +2339,8 @@
 ) %7B%0A
-                if (jsonRpcRequest.id.equals(id)) %7B%0A    
     
@@ -2408,20 +2408,16 @@
 stType;%0A
-    
         
@@ -2503,28 +2503,24 @@
             
-    
 if (response
@@ -2543,36 +2543,32 @@
                 
-   
- 
 // TODO: error c
@@ -2563,36 +2563,32 @@
 ODO: error code%0A
-    
                 
@@ -2672,33 +2672,31 @@
 null.%22, 
-jsonObject);%0A    
+responseJson);%0A
         
@@ -2764,34 +2764,26 @@
             
-    %7D%0A    
+%7D%0A
             
@@ -2823,34 +2823,16 @@
  null);%0A
-                %7D%0A
         
@@ -2870,26 +2870,28 @@
 error = 
-jsonObject
+responseJson
 .get(KEY
@@ -3300,26 +3300,28 @@
 ring(), 
-jsonObject
+responseJson
 );%0A     
@@ -3415,32 +3415,60 @@
    %7D%0A        %7D%0A%0A
+        // TODO: error code%0A
         JsonRpcE
@@ -3520,16 +3520,78 @@
 ion(0, %22
+A response with the same id as the request could not be found.
 %22, null)

Fix response handling