package org.openlca.app.cloud.ui.compare; import static org.openlca.app.cloud.ui.compare.json.JsonUtil.getString; import java.util.HashMap; import java.util.Map; import org.openlca.app.cloud.ui.compare.json.IDependencyResolver; import org.openlca.app.cloud.ui.compare.json.JsonNode; import org.openlca.app.cloud.ui.compare.json.JsonUtil.ElementFinder; import org.openlca.app.util.UncertaintyLabel; import org.openlca.core.model.AllocationFactor; import org.openlca.core.model.DQIndicator; import org.openlca.core.model.DQScore; import org.openlca.core.model.DQSystem; import org.openlca.core.model.Exchange; import org.openlca.core.model.Flow; import org.openlca.core.model.FlowPropertyFactor; import org.openlca.core.model.ImpactCategory; import org.openlca.core.model.ImpactFactor; import org.openlca.core.model.ImpactMethod; import org.openlca.core.model.NwFactor; import org.openlca.core.model.NwSet; import org.openlca.core.model.Parameter; import org.openlca.core.model.ParameterRedef; import org.openlca.core.model.Process; import org.openlca.core.model.ProcessLink; import org.openlca.core.model.ProductSystem; import org.openlca.core.model.Project; import org.openlca.core.model.ProjectVariant; import org.openlca.core.model.SocialAspect; import org.openlca.core.model.SocialIndicator; import org.openlca.core.model.Uncertainty; import org.openlca.core.model.Unit; import org.openlca.core.model.UnitGroup; import org.openlca.jsonld.input.Uncertainties; import com.google.gson.JsonElement; import com.google.gson.JsonObject; public class ModelUtil { private static ElementFinder elementFinder = new ModelElementFinder(); private static IDependencyResolver dependencyResolver = new ModelDependencyResolver(); public static ElementFinder getElementFinder() { return elementFinder; } public static IDependencyResolver getDependencyResolver() { return dependencyResolver; } static boolean isReference(JsonElement parent, JsonElement element) { if (element == null) return false; if (!element.isJsonObject()) return false; JsonObject object = element.getAsJsonObject(); if (isType(object, Parameter.class)) if (!isGlobalParameter(object)) return false; if (isType(object, Exchange.class)) if (isType(parent, Process.class)) return false; if (isType(object, Unit.class)) if (isType(parent, UnitGroup.class)) return false; if (isType(object, ImpactCategory.class)) return false; if (isType(object, NwSet.class)) if (isType(parent, ImpactMethod.class)) return false; if (object.get("@id") == null) return false; return true; } static String getObjectLabel(JsonElement parent, JsonObject o) { if (isType(o, ProjectVariant.class)) return getProjectVariantLabel(o); if (o.has("name")) return o.get("name").getAsString(); if (o.has("label")) return o.get("label").getAsString(); if (isType(o, DQIndicator.class) || isType(o, DQScore.class)) return o.get("position").getAsString(); if (isType(parent, Flow.class) && isType(o, FlowPropertyFactor.class)) return getString(o, "flowProperty.name"); if (isType(parent, Process.class) && isType(o, Exchange.class)) return getString(o, "flow.name"); if (isType(o, SocialAspect.class)) return getString(o, "socialIndicator.name"); if (isType(o, ImpactFactor.class)) return getString(o, "flow.name"); if (isType(parent, ProductSystem.class) && isType(o, Exchange.class)) return getString(o, "flow.name"); if (isType(o, NwFactor.class)) return getString(o, "impactCategory.name"); if (isType(o, AllocationFactor.class)) return getAllocationFactorLabel(o); if (isType(o, ProcessLink.class)) return getProcessLinkLabel(o); if (isType(o, Uncertainty.class)) return getUncertaintyLabel(o); return null; } private static String getProjectVariantLabel(JsonObject o) { String name = getString(o, "name"); String productSystem = getString(o, "productSystem.name"); return name + " - " + productSystem; } private static String getAllocationFactorLabel(JsonObject o) { String product = getString(o, "product.name"); if (!o.has("exchange")) return product; String flow = getString(o, "exchange.flow.name"); return product + " - " + flow; } private static String getProcessLinkLabel(JsonObject o) { String provider = getString(o, "provider.name"); String output = getString(o, "providerOutput.flow.name"); String recipient = getString(o, "recipient.name"); String input = getString(o, "recipientInput.flow.name"); return provider + "/" + output + " -> " + recipient + "/" + input; } private static String getUncertaintyLabel(JsonObject o) { Uncertainty uncertainty = Uncertainties.read(o); return UncertaintyLabel.get(uncertainty); } private static boolean isGlobalParameter(JsonObject parameter) { JsonElement scope = parameter.get("parameterScope"); if (scope == null) return false; return "GLOBAL_SCOPE".equals(scope.getAsString()); } static boolean displayElement(String property) { return displayElement(null, property); } static boolean displayElement(JsonElement parent, String property) { if (property.startsWith("@")) return false; if (property.equals("lastChange")) return false; if (property.equals("version")) return false; if (property.equals("parameterScope")) return false; if (parent == null || !parent.isJsonObject()) return true; if (isType(parent, ProcessLink.class)) return false; if (property.equals("name")) { if (isType(parent, Unit.class)) return false; if (isType(parent, ProjectVariant.class)) return false; if (isType(parent, Parameter.class)) return false; if (isType(parent, ParameterRedef.class)) return false; if (isType(parent, ImpactCategory.class)) return false; if (isType(parent, NwSet.class)) return false; if (isType(parent, DQIndicator.class)) return false; } if (property.equals("label")) if (isType(parent, DQScore.class)) return false; if (property.equals("productSystem")) if (isType(parent, ProjectVariant.class)) return false; if (property.equals("flowProperty")) if (isType(parent, FlowPropertyFactor.class)) return false; if (property.equals("input")) if (isType(parent, Exchange.class)) return false; if (property.equals("flow")) { if (isType(parent, Exchange.class)) return false; if (isType(parent, ImpactFactor.class)) return false; } if (property.equals("impactCategory")) if (isType(parent, NwFactor.class)) return false; if (property.equals("socialIndicator")) if (isType(parent, SocialAspect.class)) return false; if (property.equals("product")) if (isType(parent, AllocationFactor.class)) return false; if (property.equals("exchange")) if (isType(parent, AllocationFactor.class)) return false; if (property.equals("lastModificationDate")) if (isType(parent, Project.class)) return false; if (isType(parent, Uncertainty.class)) if (!property.contains("Formula")) return false; return true; } static boolean isReadOnly(JsonNode node, String property) { if (node.parent != null && node.parent.readOnly) return true; JsonElement element = node.getElement(); if (isType(element, Uncertainty.class)) return true; if (!element.isJsonArray()) return false; // array elements JsonElement parent = node.parent.getElement(); if (isType(parent, ProductSystem.class)) if ("processes".equals(property)) return true; else if ("processLinks".equals(property)) return true; else if ("parameterRedefs".equals(property)) return true; if (isType(parent, DQSystem.class)) if ("hasUncertainties".equals(property)) return true; return false; } static String getType(JsonElement element) { if (element == null) return null; if (!element.isJsonObject()) return null; JsonElement type = element.getAsJsonObject().get("@type"); if (type == null) return null; return type.getAsString(); } static boolean isType(JsonElement element, Class<?> clazz) { String type = getType(element); return clazz.getSimpleName().equals(type); } private static class ModelElementFinder extends ElementFinder { @Override public String[] getComparisonFields(String property) { if (property.equals("units")) return new String[] { "name" }; if (property.equals("flowProperties")) return new String[] { "flowProperty.@id" }; if (property.equals("inputs") || property.equals("outputs")) return new String[] { "flow.@id", "input" }; if (property.equals("socialAspects")) return new String[] { "socialIndicator.@id" }; if (property.equals("synonyms")) return new String[0]; if (property.equals("allocationFactors")) return new String[] { "product.@id", "exchange.flow.@id", "allocationType" }; if (property.equals("impactFactors")) return new String[] { "flow.@id" }; if (property.equals("factors")) return new String[] { "impactCategory.@id" }; if (property.equals("variants")) return new String[] { "name", "productSystem.@id" }; if (property.equals("parameterRedefs")) return new String[] { "name", "context.@id" }; if (property.equals("indicators") || property.equals("scores")) return new String[] { "position" }; return new String[] { "@id" }; } @Override protected boolean skipOnEqualsCheck(String parentProperty, JsonElement parent, String property) { if ("@id".equals(property)) if ("referenceExchange".equals(parentProperty)) return true; else if ("exchange".equals(parentProperty)) return true; else if ("providerOutput".equals(parentProperty)) return true; else if ("recipientInput".equals(parentProperty)) return true; return false; } } private static class ModelDependencyResolver implements IDependencyResolver { private static final Map<String, Map<String, String>> dependencies = new HashMap<>(); static { put(Exchange.class, "flowProperty", "unit"); put(ImpactFactor.class, "flowProperty", "unit"); put(SocialIndicator.class, "activityQuantity", "activityUnit"); put(ProductSystem.class, "referenceProcess", "referenceExchange"); put(ProductSystem.class, "referenceExchange", "targetFlowProperty"); put(ProductSystem.class, "targetFlowProperty", "targetUnit"); put(ProductSystem.class, "processes", "processLinks"); put(ProductSystem.class, "processes", "parameterRedefs"); put(ProductSystem.class, "processLinks", "parameterRedefs"); } private static void put(Class<?> clazz, String from, String to) { Map<String, String> map = dependencies.get(clazz.getSimpleName()); if (map == null) dependencies.put(clazz.getSimpleName(), map = new HashMap<>()); map.put(from, to); map.put(to, from); } @Override public String resolve(JsonElement parent, String property) { String type = getType(parent); if (type == null) return null; Map<String, String> map = dependencies.get(type); if (map == null) return null; return map.get(property); } } }