package org.openlca.app.cloud.ui.compare.json;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
import org.openlca.app.cloud.ui.compare.json.JsonUtil.ElementFinder;
import org.openlca.app.cloud.ui.compare.json.viewer.JsonTreeViewer.Side;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
public abstract class JsonNodeBuilder implements Comparator<JsonNode> {
private ElementFinder elementFinder;
public JsonNodeBuilder(ElementFinder elementFinder) {
this.elementFinder = elementFinder;
}
public JsonNode build(JsonElement leftJson, JsonElement rightJson) {
JsonNode node = JsonNode.create(null, null, leftJson, rightJson,
elementFinder, false);
build(node, leftJson, rightJson);
sort(node);
return node;
}
private void build(JsonNode node, JsonElement left, JsonElement right) {
if (left != null)
build(node, left, right, Side.LEFT);
else if (right != null)
build(node, left, right, Side.RIGHT);
}
private void build(JsonNode node, JsonElement left, JsonElement right,
Side side) {
JsonElement toCheck = side == Side.LEFT ? left : right;
if (toCheck.isJsonObject())
build(node, JsonUtil.toJsonObject(left),
JsonUtil.toJsonObject(right));
if (toCheck.isJsonArray())
build(node, JsonUtil.toJsonArray(left), JsonUtil.toJsonArray(right));
}
private void build(JsonNode node, JsonObject left, JsonObject right) {
Set<String> added = new HashSet<>();
if (left != null)
buildChildren(node, left, right, added, Side.LEFT);
if (right != null)
buildChildren(node, right, left, added, Side.RIGHT);
}
private void buildChildren(JsonNode node, JsonObject json,
JsonObject other, Set<String> added, Side side) {
for (Entry<String, JsonElement> child : json.entrySet()) {
if (side == Side.RIGHT && added.contains(child.getKey()))
continue;
JsonElement otherValue = null;
if (other != null)
otherValue = other.get(child.getKey());
if (side == Side.LEFT) {
build(node, child.getKey(), child.getValue(), otherValue);
added.add(child.getKey());
} else
build(node, child.getKey(), otherValue, child.getValue());
}
}
private void build(JsonNode node, JsonArray left, JsonArray right) {
Set<Integer> added = new HashSet<>();
if (left != null)
buildChildren(node, left, right, Side.LEFT, added);
if (right != null)
buildChildren(node, right, left, Side.RIGHT, added);
}
private void buildChildren(JsonNode node, JsonArray array,
JsonArray otherArray, Side side, Set<Integer> added) {
int count = 0;
int counter = node.children.size() + 1;
for (JsonElement value : array) {
if (side == Side.RIGHT && added.contains(count++))
continue;
JsonElement otherValue = null;
int index = elementFinder.find(node.property, value, otherArray);
if (side == Side.LEFT && index != -1) {
otherValue = otherArray.get(index);
added.add(index);
}
JsonElement left = side == Side.LEFT ? value : otherValue;
JsonElement right = side == Side.LEFT ? otherValue : value;
String property = Integer.toString(counter++);
JsonElement parent = node.parent.getElement(side);
JsonNode childNode = JsonNode.create(node, property, left, right,
elementFinder, isReadOnly(node, node.property));
if (!skipChildren(parent, value))
build(childNode, left, right);
node.children.add(childNode);
}
}
private JsonNode build(JsonNode parent, String property,
JsonElement leftValue, JsonElement rightValue) {
if (skip(parent.getElement(), property))
return null;
JsonNode childNode = JsonNode.create(parent, property, leftValue,
rightValue, elementFinder, isReadOnly(parent, property));
parent.children.add(childNode);
if (leftValue == null) {
if (skipChildren(parent.leftElement, rightValue))
return childNode;
} else if (skipChildren(parent.rightElement, leftValue))
return childNode;
build(childNode, leftValue, rightValue);
return childNode;
}
private void sort(JsonNode node) {
Collections.sort(node.children, this);
for (JsonNode child : node.children)
sort(child);
}
protected abstract boolean skip(JsonElement parent, String property);
protected abstract boolean skipChildren(JsonElement parent,
JsonElement element);
protected abstract boolean isReadOnly(JsonNode node, String property);
}