package org.bdware.sc.controlproxy;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;

import java.util.*;

public class TopologyGraph {
    List<JsonObject> ret = new ArrayList<>();
    Map<String, JsonObject> doIdToNode = new HashMap<>();

    public void addNode(JsonObject jsonObject) {
        String doId = jsonObject.get("doId").getAsString();
        if (doIdToNode.containsKey(doId)) {
            JsonObject already = doIdToNode.get(doId);
            mergeNode(already, jsonObject);
        } else {
            ret.add(jsonObject);
            doIdToNode.put(doId, jsonObject);
        }
    }

    public void addGraph(TopologyGraph g) {
        addGraph(g.ret);
    }

    public void addGraph(List<JsonObject> points) {
        for (JsonObject jo : points) {
            addNode(jo);
        }
    }

    public void addGraph(JsonArray points) {
        for (JsonElement jo : points) {
            addNode(jo.getAsJsonObject());
        }
    }

    private void mergeNode(JsonObject already, JsonObject jsonObject) {
        for (String key : jsonObject.keySet()) {
            if (!already.has(key))
                already.add(key, jsonObject.get(key));
            else {
                if (key.equals("previousNode")) {
                    JsonArray current = already.get("previousNode").getAsJsonArray();
                    current.addAll(jsonObject.get("previousNode").getAsJsonArray());
                }
            }
        }
    }

    public void pruneEdges() {
        for (JsonObject node : ret) {
            if (node.has("previousNode")) {
                JsonArray array = node.get("previousNode").getAsJsonArray();
                Set<String> dedup = new HashSet<>();
                for (JsonElement je : array) {
                    dedup.add(je.getAsString());
                }
                JsonArray deduped = new JsonArray();
                for (String str : dedup) {
                    deduped.add(str);
                }
                node.add("previousNode", deduped);
            }
        }
    }

    public void addEdge(String from, String to) {
        JsonObject fromJO = getOrCreateNode(from);
        JsonObject toJo = getOrCreateNode(to);
        if (!fromJO.has("previousNode")) {
            fromJO.add("previousNode", new JsonArray());
        }
        fromJO.get("previousNode").getAsJsonArray().add(to);
    }

    private JsonObject getOrCreateNode(String from) {
        if (!doIdToNode.containsKey(from)) {
            JsonObject jo = new JsonObject();
            jo.addProperty("doId", from);
            addNode(jo);
        }
        return doIdToNode.get(from);
    }

    private boolean hasPreviousNode(JsonObject currentNode, String previousNode) {
        if (currentNode.has("previousNode")) {
            JsonElement pn = currentNode.get("previousNode");
            if (pn.isJsonArray()) {
                JsonArray previousNodes = pn.getAsJsonArray();
                return previousNodes.contains(new JsonPrimitive(previousNode));
            }
        }
        return false;
    }

    public List<JsonObject> grepByDoId(String componentDoid) {
        TopologyGraph newGraph = new TopologyGraph();
        JsonObject currentNode = this.getOrCreateNode(componentDoid);
        newGraph.addNode(currentNode);
        //只添加上一级的节点
        //无需处理
        // JsonArray previousNodes = currentNode.get("previousNode").getAsJsonArray();
        //只添加下一级的节点
        for (JsonObject jo : doIdToNode.values()) {
            if (hasPreviousNode(jo, componentDoid)) {
                JsonObject jo2 = jo.deepCopy();
                JsonArray arr = new JsonArray();
                arr.add(componentDoid);
                jo2.add("previousNodes", arr);
                newGraph.addNode(jo2);
            }
        }
        return newGraph.ret;
    }
}