package io.github.programminglife2016.pl1_2016.parser.nodes;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import io.github.programminglife2016.pl1_2016.collapser.Bubble;
import io.github.programminglife2016.pl1_2016.parser.metadata.Subject;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Custom serializer for NodeCollection. Conforms API.
 */
public class NodeCollectionSerializer implements JsonSerializer<NodeCollection> {
        /**
         * Serialize NodeCollection following API.
         *
         * @param nodeCollection to be serialized
         * @param type ignored
         * @param jsonSerializationContext ignored
         * @return serialized NodeCollection object
         */
    public JsonElement serialize(NodeCollection nodeCollection, Type type,
                                 JsonSerializationContext jsonSerializationContext) {
        final Gson nodeBuilder = new GsonBuilder()
                .registerTypeAdapter(Segment.class, new NodeSerializer())
                .registerTypeAdapter(Bubble.class, new NodeSerializer()).create();
        JsonObject jsonObject = new JsonObject();
        jsonObject.add("status", new JsonPrimitive("success"));
        JsonArray nodes = new JsonArray();
        nodeCollection.values().stream()
                .map(nodeBuilder::toJsonTree)
                .forEach(nodes::add);
        jsonObject.add("nodes", nodes);
        List<JsonObject> edges = new ArrayList<>();
        for (Node node : nodeCollection.values()) {
            for (Node link : node.getLinks()) {
                JsonObject edge = new JsonObject();
                edge.add("x1", new JsonPrimitive(node.getX()));
                edge.add("y1", new JsonPrimitive(node.getY()));
                edge.add("x2", new JsonPrimitive(link.getX()));
                edge.add("y2", new JsonPrimitive(link.getY()));
                List<Subject> subjects = new ArrayList<>(node.getSubjects());
                subjects.retainAll(link.getSubjects());
                edge.add("gens", new JsonPrimitive(subjects.size()));
                JsonArray jsonGenomes = new JsonArray();
                subjects.stream().map(Subject::getNameId).distinct().forEach(jsonGenomes::add);
                edge.add("genomes", jsonGenomes);
                JsonArray jsonLineages = new JsonArray();
                subjects.stream().map(Subject::getLineage).distinct().forEach(jsonLineages::add);
                edge.add("lineages", jsonLineages);
                edges.add(edge);
            }
        }
        Collections.sort(edges, (t1, t2) -> Integer.compare(t1.get("gens").getAsInt(),
                t2.get("gens").getAsInt()));
        JsonArray jsonArray = new JsonArray();
        edges.stream().forEach(jsonArray::add);
        jsonObject.add("edges", jsonArray);
        return jsonObject;
    }
}

@@ -753,20 +753,12 @@
     
-    /**%0A    
+/**%0A
     
@@ -809,18 +809,10 @@
     
-    *%0A    
+*%0A
     
@@ -850,36 +850,32 @@
 serialized%0A     
-    
 * @param type ig
@@ -872,36 +872,32 @@
 am type ignored%0A
-    
      * @param js
@@ -932,20 +932,16 @@
 ed%0A     
-    
 * @retur
@@ -975,20 +975,16 @@
  object%0A
-    
      */%0A
@@ -1478,40 +1478,56 @@
     
-JsonArray nodes = new JsonArray(
+addNodes(nodeCollection, nodeBuilder, jsonObject
 );%0A 
@@ -1533,16 +1533,25 @@
         
+addEdges(
 nodeColl
@@ -1560,608 +1560,568 @@
 tion
-.values().stream()
+, jsonObject);%0A        return jsonObject;
 %0A    
+%7D%0A%0A
     
+/**%0A
      
-   .map(nodeBuilder::toJsonTree)%0A                .forEach(nodes::add);%0A        jsonObject.add(%22nodes%22, nodes);%0A        List%3CJsonObject%3E edges = new ArrayList%3C%3E();%0A        for (Node node : nodeCollection.values()) %7B%0A            for (Node link : node.getLinks()) %7B%0A                JsonObject edge = new JsonObject();%0A                edge.add(%22x1%22, new JsonPrimitive(node.getX()));%0A                edge.add(%22y1%22, new JsonPrimitive(node.getY()));%0A                edge.add(%22x2%22, new JsonPrimitive(link.getX()));%0A                edge.add(%22y2%22, new JsonPrimitive(link.getY())
+* Serialize the edges.%0A     * @param nodeCollection collection of nodes.%0A     * @param jsonObject JSON object containing the serialized edges.%0A     */%0A    private void addEdges(NodeCollection nodeCollection, JsonObject jsonObject) %7B%0A        List%3CJsonObject%3E edges = new ArrayList%3C%3E();%0A        for (Node node : nodeCollection.values()) %7B%0A            for (Node link : node.getLinks()) %7B%0A                JsonObject edge = new JsonObject();%0A                addStartAndEndPositionToEdge(node, link, edge
 );%0A 
@@ -3066,37 +3066,1109 @@
 y);%0A    
+%7D%0A%0A
     
-return jsonObject
+/**%0A     * Add start and end position of the edges to the JSON object.%0A     * @param node node at the source of the edge.%0A     * @param link link object with the target position of the edge.%0A     * @param edge the edge to be serialized.%0A     */%0A    private void addStartAndEndPositionToEdge(Node node, Node link, JsonObject edge) %7B%0A        edge.add(%22x1%22, new JsonPrimitive(node.getX()));%0A        edge.add(%22y1%22, new JsonPrimitive(node.getY()));%0A        edge.add(%22x2%22, new JsonPrimitive(link.getX()));%0A        edge.add(%22y2%22, new JsonPrimitive(link.getY()));%0A    %7D%0A%0A    /**%0A     * Serialize the nodes.%0A     * @param nodeCollection collection of nodes.%0A     * @param nodeBuilder builder for the JSON tree.%0A     * @param jsonObject JSON object containing the serialized nodes.%0A     */%0A    private void addNodes(NodeCollection nodeCollection, Gson nodeBuilder, JsonObject jsonObject) %7B%0A        JsonArray nodes = new JsonArray();%0A        nodeCollection.values().stream()%0A                .map(nodeBuilder::toJsonTree)%0A                .forEach(nodes::add);%0A        jsonObject.add(%22nodes%22, nodes)
 ;%0A    %7D%0A

Refactor NodeCollectionSerializer class