]> gerrit.simantics Code Review - simantics/district.git/blobdiff - org.simantics.district.network/src/org/simantics/district/network/techtype/TechTypeUtils.java
Moved compareNatural to TechTypeUtils
[simantics/district.git] / org.simantics.district.network / src / org / simantics / district / network / techtype / TechTypeUtils.java
index 7a25ff84113586434703da818750dfb901271c18..377253dde3d108b433c572d6e0ddc576872b30ab 100644 (file)
@@ -1,7 +1,14 @@
 package org.simantics.district.network.techtype;
 
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 import org.simantics.Simantics;
 import org.simantics.databoard.Bindings;
@@ -20,11 +27,16 @@ import org.simantics.db.common.request.WriteRequest;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.QueryIndexUtils;
 import org.simantics.db.layer0.request.PossibleVariable;
+import org.simantics.db.layer0.request.PropertyInfo;
+import org.simantics.db.layer0.request.PropertyInfoRequest;
 import org.simantics.db.layer0.variable.Variable;
 import org.simantics.district.network.ontology.DistrictNetworkResource;
 import org.simantics.district.network.techtype.requests.PossibleTechTypeItem;
 import org.simantics.district.network.techtype.requests.PossibleTechTypeTable;
+import org.simantics.district.network.techtype.requests.TechTypeTableData;
 import org.simantics.district.network.techtype.requests.TechTypeTableKeyName;
+import org.simantics.district.network.techtype.requests.WriteTechTypeTable;
+import org.simantics.layer0.Layer0;
 import org.simantics.scl.runtime.SCLContext;
 import org.simantics.structural.stubs.StructuralResource2;
 import org.slf4j.Logger;
@@ -36,6 +48,31 @@ public class TechTypeUtils {
 
        public static String DEFAULT_KEY_NAME = "pipeCode";
 
+       /**
+        * Load a tech type table from a CSV file and write it in the active model.
+        * 
+        * @param componentType  The component type that the tech type table is associated with
+        * @param filePath  A path to a CSV file
+        * @throws DatabaseException
+        * @throws IOException
+        */
+       public static void loadTechTypeTable(Resource componentType, String filePath) throws DatabaseException, IOException {
+               String data;
+               try {
+                       data = Files.lines(Paths.get(filePath), Charset.defaultCharset()).collect(Collectors.joining("\n"));
+               } catch (IOException e) {
+                       LOGGER.error("Failed to read contents of file '{}' as {}", filePath, Charset.defaultCharset(), e);
+                       return;
+               }
+
+               Simantics.getSession().syncRequest(new WriteRequest() {
+                       @Override
+                       public void perform(WriteGraph graph) throws DatabaseException {
+                               graph.syncRequest(new WriteTechTypeTable(componentType, data));
+                       }
+               });
+       }
+       
        /**
         * Execute a cached query for a possible tech type table item in a table with a given item key.
         * 
@@ -93,6 +130,111 @@ public class TechTypeUtils {
                });
        }
        
+       /**
+        * Reset all diagram elements to tech type table values.
+        * 
+        * @param table  A tech type table
+        * @throws DatabaseException
+        */
+       public static void resetMapElements(Resource table) throws DatabaseException {
+               Simantics.getSession().syncRequest(new WriteRequest() {
+                       @Override
+                       public void perform(WriteGraph graph) throws DatabaseException {
+                               Resource model = graph.syncRequest(new PossibleIndexRoot(table), TransientCacheListener.instance());
+                               if (model == null)
+                                       return;
+                               
+                               DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
+                               Resource type = graph.getPossibleObject(table, DN.TechType_TechTypeTable_HasComponentType);
+                               if (type == null)
+                                       return;
+                               
+                               Layer0 L0 = Layer0.getInstance(graph);
+                               String typeName = graph.getRelatedValue2(type, L0.HasName);
+                               
+                               Resource mapping = null;
+                               for (Resource m : QueryIndexUtils.searchByType(graph, model, DN.Mapping_Base)) {
+                                       String name = graph.getRelatedValue2(m, DN.Mapping_ComponentType);
+                                       if (Objects.equals(name, typeName)) {
+                                               mapping = m;
+                                               break;
+                                       }
+                               }
+                               
+                               if (mapping == null) {
+                                       LOGGER.warn("No mapping found for component type {}", type);
+                                       return;
+                               }
+                               
+                               Map<String, PropertyInfo> properties = new HashMap<>();
+                               Resource mappingType = graph.getSingleType(mapping, DN.Mapping_Base);
+                               Collection<Resource> mappingRelations = graph.getObjects(mappingType, L0.DomainOf);
+                               for (Resource r : mappingRelations) {
+                                       String propertyName = graph.getPossibleRelatedValue2(mapping, r);
+                                       if (propertyName == null)
+                                               continue;
+                                       
+                                       Resource relation = graph.getPossibleObject(r, DN.Mapping_HasPropertyRelation);
+                                       if (relation == null)
+                                               continue;
+                                       
+                                       properties.put(propertyName, graph.syncRequest(new PropertyInfoRequest(relation)));
+                               }
+                               
+                               Map<String, Map<String, String>> data = graph.syncRequest(new TechTypeTableData(table), TransientCacheListener.instance());
+                               String keyName = graph.syncRequest(new TechTypeTableKeyName(table), TransientCacheListener.instance());
+                               Resource keyRelation = properties.get(keyName).predicate;
+                               
+                               if (keyRelation == null) {
+                                       LOGGER.warn("No relation mapped to property {} found in {} mapping", keyName, mapping);
+                                       return;
+                               }
+                               
+                               Resource elementType = graph.isInstanceOf(mapping, DN.Mapping_EdgeMapping) ? DN.Edge :
+                                       graph.isInstanceOf(mapping, DN.Mapping_VertexMapping) ? DN.Vertex :
+                                       DN.Element;
+                               
+                               Collection<Resource> elements = QueryIndexUtils.searchByType(graph, model, elementType);
+                               for (Resource element : elements) {
+                                       Resource elementMapping = graph.getPossibleObject(element, DN.HasMapping);
+                                       if (!mapping.equals(elementMapping))
+                                               continue;
+                                       
+                                       String key = graph.getPossibleRelatedValue2(element, keyRelation);
+                                       Map<String, String> values = data.get(key);
+                                       if (values == null) {
+                                               LOGGER.info("Key {} not found in tech type table {}", key, table);
+                                               continue;
+                                       }
+                                       
+                                       for (Map.Entry<String, String> entry : values.entrySet()) {
+                                               PropertyInfo prop = properties.get(entry.getKey());
+                                               if (prop == null)
+                                                       continue;
+                                               
+                                               String value = entry.getValue();
+                                               Datatype dt = prop.requiredDatatype;
+                                               if (dt instanceof NumberType) {
+                                                       try {
+                                                               Object num = ((NumberBinding)prop.defaultBinding).create(value.replace(",", "."));
+                                                               graph.claimLiteral(element, prop.predicate, prop.literalRange, num, prop.defaultBinding);
+                                                       } catch (NumberFormatException e) {
+                                                               // Revert to asserted value
+                                                               graph.deny(element, prop.predicate);
+                                                       } catch (BindingException e) {
+                                                               LOGGER.error("Failed to get binding for datatype {}", dt, e);
+                                                       }
+                                               } else if (dt instanceof StringType) {
+                                                       graph.claimLiteral(element, prop.predicate, prop.literalRange, value, Bindings.STRING);
+                                               } else {
+                                                       LOGGER.warn("updateComponent: Unsupported property type {}", dt);
+                                               }
+                                       }
+                               }
+                       }
+               });
+       }
+
        /**
         * Update property values of a component based on the values in an associated tech type table, if any
         * 
@@ -204,4 +346,46 @@ public class TechTypeUtils {
                if (name == null) name = "_" + DEFAULT_KEY_NAME;
                return name; 
        }
+
+       /**
+        * Compare strings so that contained numbers are sorted in numerical order instead of lexicographic.
+        * (From https://stackoverflow.com/questions/104599/sort-on-a-string-that-may-contain-a-number)
+        */
+       public static final int compareNatural(String s1, String s2) {
+               // Skip all identical characters
+               int len1 = s1.length();
+               int len2 = s2.length();
+               int i;
+               char c1, c2;
+               for (i = 0, c1 = 0, c2 = 0; (i < len1) && (i < len2) && (c1 = s1.charAt(i)) == (c2 = s2.charAt(i)); i++)
+                       ;
+
+               // Check end of string
+               if (c1 == c2)
+                       return (len1 - len2);
+
+               // Check digit in first string
+               if (Character.isDigit(c1)) {
+                       // Check digit only in first string
+                       if (!Character.isDigit(c2))
+                               return (1);
+
+                       // Scan all integer digits
+                       int x1, x2;
+                       for (x1 = i + 1; (x1 < len1) && Character.isDigit(s1.charAt(x1)); x1++)
+                               ;
+                       for (x2 = i + 1; (x2 < len2) && Character.isDigit(s2.charAt(x2)); x2++)
+                               ;
+
+                       // Longer integer wins, first digit otherwise
+                       return (x2 == x1 ? c1 - c2 : x1 - x2);
+               }
+
+               // Check digit only in second string
+               if (Character.isDigit(c2))
+                       return (-1);
+
+               // No digits
+               return (c1 - c2);
+       }
 }