]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.structural2/src/org/simantics/structural2/Functions.java
Work in progress
[simantics/platform.git] / bundles / org.simantics.structural2 / src / org / simantics / structural2 / Functions.java
1 package org.simantics.structural2;
2
3
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import org.simantics.databoard.Bindings;
13 import org.simantics.databoard.Datatypes;
14 import org.simantics.databoard.adapter.AdaptException;
15 import org.simantics.databoard.binding.Binding;
16 import org.simantics.databoard.binding.error.BindingException;
17 import org.simantics.databoard.binding.error.DatatypeConstructionException;
18 import org.simantics.databoard.type.Datatype;
19 import org.simantics.databoard.util.URIStringUtils;
20 import org.simantics.db.Issue;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.Resource;
23 import org.simantics.db.Statement;
24 import org.simantics.db.WriteGraph;
25 import org.simantics.db.common.issue.StandardIssue;
26 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
27 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
28 import org.simantics.db.common.request.ObjectsWithType;
29 import org.simantics.db.common.request.PossibleIndexRoot;
30 import org.simantics.db.common.request.PossibleObjectWithType;
31 import org.simantics.db.common.request.ResourceRead;
32 import org.simantics.db.common.uri.UnescapedChildMapOfResource;
33 import org.simantics.db.exception.DatabaseException;
34 import org.simantics.db.layer0.function.All;
35 import org.simantics.db.layer0.function.StandardChildDomainChildren;
36 import org.simantics.db.layer0.request.PropertyInfo;
37 import org.simantics.db.layer0.request.PropertyInfoRequest;
38 import org.simantics.db.layer0.request.VariableRead;
39 import org.simantics.db.layer0.variable.AbstractChildVariable;
40 import org.simantics.db.layer0.variable.AbstractPropertyVariable;
41 import org.simantics.db.layer0.variable.LazyPropertyVariable;
42 import org.simantics.db.layer0.variable.NodeSupport;
43 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
44 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
45 import org.simantics.db.layer0.variable.ValueAccessor;
46 import org.simantics.db.layer0.variable.ValueAccessorWithBinding;
47 import org.simantics.db.layer0.variable.Variable;
48 import org.simantics.db.layer0.variable.VariableMap;
49 import org.simantics.db.layer0.variable.VariableMapImpl;
50 import org.simantics.db.layer0.variable.VariableNode;
51 import org.simantics.db.service.CollectionSupport;
52 import org.simantics.issues.common.IssueUtils;
53 import org.simantics.layer0.Layer0;
54 import org.simantics.scl.reflection.annotations.SCLValue;
55 import org.simantics.scl.runtime.SCLContext;
56 import org.simantics.scl.runtime.function.Function1;
57 import org.simantics.simulation.ontology.SimulationResource;
58 import org.simantics.simulator.variable.NodeManager;
59 import org.simantics.structural.stubs.StructuralResource2;
60 import org.simantics.structural2.procedural.Component;
61 import org.simantics.structural2.procedural.ConnectionPoint;
62 import org.simantics.structural2.procedural.Interface;
63 import org.simantics.structural2.procedural.SubstructureElement;
64 import org.simantics.structural2.procedural.Terminal;
65 import org.simantics.structural2.queries.ConnectionComponents;
66 import org.simantics.structural2.queries.ConnectionJoinComponents;
67 import org.simantics.structural2.queries.ConnectionPointMapOfResource;
68 import org.simantics.structural2.queries.PossibleConnectionPointInfo;
69 import org.simantics.structural2.scl.CompileStructuralValueRequest;
70 import org.simantics.structural2.scl.procedural.CompileProceduralComponentTypeRequest;
71 import org.simantics.structural2.utils.StructuralUtils;
72 import org.simantics.structural2.utils.StructuralUtils.StructuralComponentClass;
73 import org.simantics.structural2.variables.Connection;
74 import org.simantics.structural2.variables.StandardProceduralChildVariable;
75 import org.simantics.utils.datastructures.MapList;
76 import org.simantics.utils.datastructures.Pair;
77
78 import gnu.trove.map.hash.THashMap;
79
80 public class Functions {
81         
82         @SCLValue(type="ValueAccessor")
83         public static final ValueAccessor expressionValueAccessor = new ValueAccessorWithBinding() {
84
85                 public Binding getBinding() {
86                         return Bindings.STRING;
87                 }
88                 
89                 @Override
90                 public void setValue(WriteGraph graph, Variable context, Object value)
91                                 throws DatabaseException {
92                         if(value == null) {
93                                 if(getValue(graph, context) != null)
94                                         clearExpression(graph, context);
95                                 return;
96                         }
97                         
98                         // Get all necessary data
99                         String expression = (String)value;
100                         Variable parent = context.getParent(graph);
101                         if(!(parent instanceof AbstractPropertyVariable)) return;
102                         AbstractPropertyVariable property = (AbstractPropertyVariable)parent;                   
103                         Resource propertyResource = property.getRepresents(graph);
104                         if(propertyResource == null) return;
105                         Resource container = property.getContainerResource(graph);
106                         if(container == null) return;
107                         Resource predicate = property.getPossiblePredicateResource(graph);
108                         if(predicate == null) return;                   
109                         Statement stat = graph.getPossibleStatement(container, predicate);                      
110                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
111                         
112                         // Write                        
113                         boolean createNew = false;
114                         if(stat.isAsserted(container))
115                                 createNew = true;
116                         else if(!graph.isInstanceOf(propertyResource, STR.SCLValue)) {
117                                 graph.deny(propertyResource);
118                                 createNew = true;
119                         }
120             Layer0 L0 = Layer0.getInstance(graph);
121                         if(createNew) {
122                                 propertyResource = graph.newResource();
123                                 graph.claim(container, predicate, propertyResource);
124                                 graph.claim(propertyResource, L0.InstanceOf, STR.SCLValue);                             
125                         }
126                         graph.claimLiteral(propertyResource, L0.SCLValue_expression, expression, Bindings.STRING);
127                 }
128
129                 private void clearExpression(WriteGraph graph, Variable context) throws DatabaseException {
130                         Variable parent = context.getParent(graph);
131                         if(!(parent instanceof AbstractPropertyVariable)) return;
132                         AbstractPropertyVariable property = (AbstractPropertyVariable)parent;
133                         Resource container = property.getContainerResource(graph);
134                         if(container == null) return;
135                         Resource predicate = property.getPossiblePredicateResource(graph);
136                         if(predicate == null) return;                   
137                         graph.deny(container, predicate);               
138                 }
139
140                 @Override
141                 public Object getValue(ReadGraph graph, Variable context)
142                                 throws DatabaseException {
143                         Variable parent = context.getParent(graph);
144                         if(!(parent instanceof AbstractPropertyVariable))
145                                 return null;
146                         AbstractPropertyVariable property = (AbstractPropertyVariable)parent;
147                         Resource propertyResource = property.getPossibleRepresents(graph);
148                         if(propertyResource == null) return null;
149                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
150                         if(!graph.isInstanceOf(propertyResource, STR.SCLValue))
151                                 return null;
152             Layer0 L0 = Layer0.getInstance(graph);
153                         return graph.getPossibleRelatedValue(propertyResource, L0.SCLValue_expression);
154                 }
155                 
156         };
157         
158         @SCLValue(type="ValueAccessor")
159         public static final ValueAccessor connectionValueAccessor = new ValueAccessor() {
160
161                 @Override
162                 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
163                         throw new UnsupportedOperationException();
164                 }
165                 
166                 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
167                         throw new UnsupportedOperationException();
168                 }
169
170                 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
171             try {
172                 Object value = getValue(graph, context);
173                 Binding srcBinding = Bindings.OBJECT.getContentBinding(value);
174                                 return Bindings.adapt(value, srcBinding, binding);
175                         } catch (AdaptException e) {
176                                 throw new DatabaseException(e);
177                         } catch (BindingException e) {
178                                 throw new DatabaseException(e);
179                         }
180                 }
181
182                 @Override
183                 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
184                         StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context; 
185                         return new ConnectionImpl(variable.property.predicate);
186                 }
187
188                 @Override
189                 public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
190                         try {
191                                 return Datatypes.getDatatype(Connection.class);
192                         } catch (DatatypeConstructionException e) {
193                                 throw new DatabaseException(e);
194                         }
195                 }
196                 
197         };      
198
199
200         @SCLValue(type = "VariableMap")
201         public static VariableMap structuralChildDomainProperties = new VariableMapImpl() {
202         
203                 public Variable getPossibleConnectionPointFromContext(ReadGraph graph, Variable variable, Resource context, String name) throws DatabaseException {
204
205                         Map<String, PropertyInfo> connectionPoints = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance());
206                         PropertyInfo cp = connectionPoints.get(name);
207                         if(cp == null) return null;
208                         else return new StandardGraphPropertyVariable(graph, variable, cp.predicate);
209                         
210                 }
211                 
212                 public Map<String, Variable> collectConnectionPointsFromContext(ReadGraph graph, StructuralResource2 STR, Variable variable, Resource context, Map<String, Variable> map, boolean needSynchronized) throws DatabaseException {
213                         
214                         if(graph.isImmutable(context)) {
215
216                                 Map<String, PropertyInfo> cps = graph.syncRequest(new ConnectionPointMapOfResource(graph, context), TransientCacheAsyncListener.<Map<String,PropertyInfo>>instance());
217                                 if(cps.size() == 0) return map;
218                                 
219                                 if(map == null) map = new THashMap<String,Variable>(cps.size());
220                                 
221                                 for(Map.Entry<String, PropertyInfo> entry : cps.entrySet()) {
222                                         String name = entry.getKey();
223                                         PropertyInfo cp = entry.getValue();
224                                         if(needSynchronized && !graph.isInstanceOf(cp.predicate, STR.SynchronizedConnectionRelation)) continue;
225                                         map.put(name, new StandardGraphPropertyVariable(graph, variable, cp.predicate));
226                                 }
227                                 
228                                 return map;
229
230                         } else {
231                                 
232                                 Collection<Resource> predicates = graph.getPredicates(context);
233                                 
234                                 for(Resource predicate : predicates) {
235                                         
236                                         PropertyInfo info = graph.isImmutable(predicate) ?
237                                                         graph.syncRequest(new PossibleConnectionPointInfo(predicate), TransientCacheAsyncListener.<PropertyInfo>instance()) :
238                                                                 graph.syncRequest(new PossibleConnectionPointInfo(predicate));
239                                                         
240                                         if(info != null) {
241                                                 if(map == null) map = new THashMap<String,Variable>(4);
242                                                 if(needSynchronized && !graph.isInstanceOf(predicate, STR.SynchronizedConnectionRelation)) continue;
243                                                 map.put(info.name, new StandardGraphPropertyVariable(graph, variable, predicate));
244                                         }
245                                         
246                                 }
247
248                                 return map;
249
250                         }
251                         
252                 }
253
254                 @Override
255                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
256                 final StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
257                 Variable cp = getPossibleConnectionPointFromContext(graph, variable, variable.resource, name);
258                 if(cp != null) return cp;
259             return All.getStandardChildDomainPropertyVariable(graph, context, name);
260                 }
261
262                 @Override
263                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
264                 StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
265                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
266                 map = collectConnectionPointsFromContext(graph, STR, variable, variable.resource, map, false);
267             return All.getStandardChildDomainPropertyVariables(graph, context, map);
268                 }
269                 
270                 public Map<String,Variable> getVariables(ReadGraph graph, Variable context, String classification, Map<String,Variable> map) throws DatabaseException {
271                         if (StructuralResource2.URIs.SynchronizedRelation.equals(classification)) {
272                                 return All.getStandardChildDomainPropertyVariables(graph, context, classification, map);
273                         } else if (StructuralResource2.URIs.SynchronizedConnectionRelation.equals(classification)) {
274                         StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
275                         return collectConnectionPointsFromContext(graph, StructuralResource2.getInstance(graph), variable, variable.resource, map, true);
276                         } else if(StructuralResource2.URIs.ConnectionRelation.equals(classification)) {
277                         StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
278                         return collectConnectionPointsFromContext(graph, StructuralResource2.getInstance(graph), variable, variable.resource, map, false);
279                         }
280                         return super.getVariables(graph, context, classification, map);
281                 }
282                 
283         };
284
285         /*public static class StructuralChildMapOfResource extends ResourceRead<Map<String, Resource>> {
286
287                 public StructuralChildMapOfResource(Resource resource) {
288                         super(resource);
289                 }
290
291                 @Override
292                 public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
293                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
294                         Resource type = graph.getPossibleType(resource, STR.Component);
295                         if(type != null) {
296                                 Resource definition = graph.getPossibleObject(type, STR.IsDefinedBy);
297                                 if(definition != null) {
298                                         Map<String, Resource> map = graph.syncRequest(new UnescapedChildMapOfResource(definition));
299                                         if (!map.isEmpty())
300                                                 return map;
301                                 } 
302                         }
303                         Map<String, Resource> directChildren = graph.syncRequest(new UnescapedChildMapOfResource(resource));
304                         return directChildren;
305                 }
306
307         }*/
308
309     /*public static class StructuralChildMapOfResourceT extends ResourceRead<Map<String, Resource>> {
310
311         public StructuralChildMapOfResourceT(Resource type) {
312             super(type);
313         }
314
315         @Override
316         public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
317             StructuralResource2 STR = StructuralResource2.getInstance(graph);
318             Resource definition = graph.getPossibleObject(resource, STR.IsDefinedBy);
319             if(definition != null) {
320                 Map<String, Resource> map = graph.syncRequest(new UnescapedChildMapOfResource(definition));
321                 if (!map.isEmpty())
322                     return map;
323             } 
324             return Collections.emptyMap();
325         }
326
327     }*/
328
329         /*static class StructuralRunChildMapOfResource extends ResourceRead<Map<String, Resource>> {
330
331                 public StructuralRunChildMapOfResource(Resource resource) {
332                         super(resource);
333                 }
334
335                 public Map<String, Resource> fromContext(ReadGraph graph, Resource context) throws DatabaseException {
336                         return graph.sync(new StructuralChildMapOfResource(context));
337                 }
338                 
339                 @Override
340                 public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
341
342                         Layer0 L0 = Layer0.getInstance(graph);
343                         SimulationResource SIMU = SimulationResource.getInstance(graph);
344                         Resource model = graph.sync(new PossibleIndexRoot(resource));
345                         if(graph.isInstanceOf(model, L0.RVIContext)) {
346                                 return fromContext(graph, model);
347                         }
348                         Resource configuration = graph.getPossibleObject(model, SIMU.HasConfiguration);
349                         if(configuration != null) {
350                                 if(graph.isInstanceOf(configuration, L0.RVIContext)) {
351                                         return fromContext(graph, configuration);
352                                 }
353                         }
354                         
355                         return Collections.emptyMap();
356                         
357                 }
358                 
359         }*/
360
361         static class StructuralRunContext extends ResourceRead<Resource> {
362
363                 public StructuralRunContext(Resource resource) {
364                         super(resource);
365                 }
366
367                 @Override
368                 public Resource perform(ReadGraph graph) throws DatabaseException {
369
370                         Layer0 L0 = Layer0.getInstance(graph);
371                         SimulationResource SIMU = SimulationResource.getInstance(graph);
372                         Resource model = graph.sync(new PossibleIndexRoot(resource));
373                         if(graph.isInstanceOf(model, L0.RVIContext)) {
374                                 return model;
375                         }
376                         Resource configuration = graph.getPossibleObject(model, SIMU.HasConfiguration);
377                         if(configuration != null) {
378                                 if(graph.isInstanceOf(configuration, L0.RVIContext)) {
379                                         return configuration;
380                                 }
381                         }
382
383                         return null;
384
385                 }
386                 
387         }
388         
389         private static class SubstructureRequest extends VariableRead<List<SubstructureElement>> {
390             public SubstructureRequest(Variable context) {
391             super(context);
392         }
393
394         @Override
395         public List<SubstructureElement> perform(ReadGraph graph) {
396             try {
397                 Resource type = variable.getPossibleType(graph);
398                 if(type == null)
399                     return null;
400                 return CompileProceduralComponentTypeRequest.compileAndEvaluate(graph, type, variable);
401             } catch (Throwable t) {
402                 t.printStackTrace();
403                 return null;
404             }
405         }
406         }
407
408     public static List<SubstructureElement> getProceduralDesc(ReadGraph graph, final Variable context) throws DatabaseException {
409         StructuralResource2 STR = StructuralResource2.getInstance(graph);
410         final Resource type = context.getPossibleType(graph);
411         if(type != null) {
412             if(graph.isInstanceOf(type, STR.ProceduralComponentType)) {
413                 return graph.syncRequest(new SubstructureRequest(context));
414             }
415         }
416         return null;
417     }  
418         
419          public static Map<String,Variable> getProcedural(ReadGraph graph, Variable context, List<SubstructureElement> elements, Map<String,Variable> map) throws DatabaseException {
420              
421          if(map == null) map = new THashMap<String,Variable>();
422          
423          MapList<String,org.simantics.structural2.procedural.Connection> conns = new MapList<String,org.simantics.structural2.procedural.Connection>();
424          for(SubstructureElement sub : elements) {
425              if(sub instanceof org.simantics.structural2.procedural.Connection) {
426                  org.simantics.structural2.procedural.Connection conn = (org.simantics.structural2.procedural.Connection)sub;
427                  for(ConnectionPoint cp : conn.connectionPoints) {
428                      if(cp instanceof Terminal) {
429                          Terminal t = (Terminal)cp;
430                          conns.add(t.component, conn);
431                      }
432                  }
433              }
434          }
435          
436          Map<String,Component> proceduralChildren = new THashMap<String, Component>();
437          for(SubstructureElement sub : elements) {
438              if(sub instanceof Component) {
439                  Component comp = (Component)sub;
440                  proceduralChildren.put(comp.name, comp);
441              }
442          }
443          
444          Collection<Object> nodeChildren = All.getPossibleNodeChildren(graph, (AbstractChildVariable)context);
445          Set<String> used = new HashSet<String>(nodeChildren.size());
446          for(Object nodeChild : nodeChildren) {
447              @SuppressWarnings("rawtypes")
448              NodeSupport support = ((AbstractChildVariable)context).node.support;
449              @SuppressWarnings("rawtypes")
450              NodeManager manager = support.manager;
451              @SuppressWarnings("unchecked")
452              String name = manager.getName(nodeChild);
453              used.add(name);
454              Component proceduralChild = proceduralChildren.get(name); 
455              if(proceduralChild != null) {
456                  map.put(proceduralChild.name, new StandardProceduralChildVariable(graph, context, new VariableNode(support, nodeChild), proceduralChild.name, proceduralChild.type, proceduralChild.properties, conns.getValues(proceduralChild.name)));
457              }
458          }
459          
460          for(Map.Entry<String, Component> entry : proceduralChildren.entrySet()) {
461              String name = entry.getKey();
462              if(used.contains(name)) continue;
463              Component proceduralChild = entry.getValue();
464              map.put(proceduralChild.name, new StandardProceduralChildVariable(graph, context, null, proceduralChild.name, proceduralChild.type, proceduralChild.properties, conns.getValues(proceduralChild.name)));
465          }
466          
467          return map;
468              
469      }  
470          
471          private static class ProceduralSubstructureRequest extends VariableRead<Map<String,Variable>> {
472
473              public ProceduralSubstructureRequest(Variable variable) {
474                  super(variable);
475              }
476
477              @Override
478              public Map<String, Variable> perform(ReadGraph graph)
479                      throws DatabaseException {
480                  List<SubstructureElement> elements = getProceduralDesc(graph, variable);
481                  if(elements != null)
482                      return getProcedural(graph, variable, elements, null);
483                  else
484                      return null;
485              }
486          }
487          
488         public static class StructuralTypeOverrideMap extends ResourceRead<Map<Resource,Resource>> {
489
490                 protected StructuralTypeOverrideMap(Resource composite) {
491                         super(composite);
492                 }
493
494                 @Override
495                 public Map<Resource, Resource> perform(ReadGraph graph) throws DatabaseException {
496                         
497                         Layer0 L0 = Layer0.getInstance(graph);
498                         
499                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
500                         
501                         CollectionSupport cs = graph.getService(CollectionSupport.class);
502                         
503                         Map<Resource,Resource> result = null;
504                         
505                         for(Resource override : graph.getObjects(resource, STR.HasTypeOverride)) {
506                                 Resource original = graph.getSingleObject(override, STR.TypeOverride_HasOriginalType);
507                                 Resource replacement = graph.getSingleObject(override, STR.TypeOverride_HasReplacementType);
508                                 if(result == null) result = cs.createMap(Resource.class);
509                                 result.put(original, replacement);
510                         }
511                         
512                         if(result == null) return Collections.emptyMap();
513                         
514                         return result;
515                         
516                 }
517                 
518         }
519         
520         public static class StructuralOverrideData {
521                 @Override
522                 public int hashCode() {
523                         final int prime = 31;
524                         int result = 1;
525                         result = prime * result + ((actualRepresents == null) ? 0 : actualRepresents.hashCode());
526                         result = prime * result + ((actualType == null) ? 0 : actualType.hashCode());
527                         result = prime * result + ((overrideType == null) ? 0 : overrideType.hashCode());
528                         return result;
529                 }
530                 @Override
531                 public boolean equals(Object obj) {
532                         if (this == obj)
533                                 return true;
534                         if (obj == null)
535                                 return false;
536                         if (getClass() != obj.getClass())
537                                 return false;
538                         StructuralOverrideData other = (StructuralOverrideData) obj;
539                         if (actualRepresents == null) {
540                                 if (other.actualRepresents != null)
541                                         return false;
542                         } else if (!actualRepresents.equals(other.actualRepresents))
543                                 return false;
544                         if (actualType == null) {
545                                 if (other.actualType != null)
546                                         return false;
547                         } else if (!actualType.equals(other.actualType))
548                                 return false;
549                         if (overrideType == null) {
550                                 if (other.overrideType != null)
551                                         return false;
552                         } else if (!overrideType.equals(other.overrideType))
553                                 return false;
554                         return true;
555                 }
556                 Resource actualRepresents;
557                 Resource actualType;
558                 Resource overrideType;
559                 public StructuralOverrideData(Resource actualRepresents, Resource actualType, Resource overrideType) {
560                         this.actualRepresents = actualRepresents;
561                         this.actualType = actualType;
562                         this.overrideType = overrideType;
563                 }
564
565                 public static StructuralOverrideData compute(ReadGraph graph, Variable context) throws DatabaseException {
566                         return graph.syncRequest(new StructuralOverrideDataRequest(context));
567                 }
568                 
569                 public Resource type() {
570                         if(overrideType != null)
571                                 return overrideType;
572                         return actualType;
573                 }
574
575                 public Resource represents() {
576                         return actualRepresents;
577                 }
578
579         }
580         
581         public static class StructuralOverrideDataRequest extends VariableRead<StructuralOverrideData> {
582
583                 public StructuralOverrideDataRequest(Variable component) {
584                         super(component);
585                 }
586
587                 public StructuralOverrideData walk(ReadGraph graph, Variable component, Resource actualRepresents, Resource actualType) throws DatabaseException {
588                         System.err.println("walk: " + component.getURI(graph));
589                 Resource represents = component.getPossibleRepresents(graph);
590                 if(represents != null) {
591                         Layer0 L0 = Layer0.getInstance(graph);
592                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
593                         Resource container = graph.syncRequest(new PossibleObjectWithType(represents, L0.PartOf, STR.Composite));
594                         if(container != null) {
595                         Map<Resource,Resource> overrides = graph.syncRequest(new StructuralTypeOverrideMap(container));
596                         if(!overrides.isEmpty()) {
597                                 System.err.println("Check overrides for " + graph.getPossibleURI(actualType));
598                                 for(Resource r : overrides.keySet()) {
599                                         System.err.println("-available OR: " + graph.getPossibleURI(r) + " = > " + graph.getPossibleURI(overrides.get(r)));
600                                 }
601                         }
602                         Resource override = overrides.get(actualType);
603                         if(override != null) {
604                                 System.err.println("Override! " + graph.getPossibleURI(actualType) + " = > " + graph.getPossibleURI(override));
605                                 return new StructuralOverrideData(actualRepresents, actualType, override);
606                         }
607                         }
608                 }
609                 Variable parent = component.getParent(graph);
610                 if(parent == null) return new StructuralOverrideData(actualRepresents, actualType, null);
611                 else return walk(graph, parent, represents, actualType);
612                 }
613                 
614                 @Override
615                 public StructuralOverrideData perform(ReadGraph graph) throws DatabaseException {
616
617                         if(variable.getURI(graph).endsWith("/Alternative/Panel2"))
618                                 System.err.println("walk1: " + variable.getURI(graph));
619
620                 Resource represents = variable.getPossibleRepresents(graph);
621                 if(represents == null) {
622                         String uri = variable.getPossiblePropertyValue(graph, "typeURI");
623                         if(uri != null) {
624                                 Resource actualType = graph.syncRequest(new org.simantics.db.common.primitiverequest.Resource(uri), TransientCacheAsyncListener.<Resource>instance()); 
625                                 return walk(graph, variable, null, actualType);
626                         }
627                         throw new DatabaseException("No type for " + variable.getURI(graph));
628                 } else {
629                         return walk(graph, variable, represents, graph.getPossibleType(represents, Layer0.getInstance(graph).Entity));
630                 }
631                         
632                 }
633                 
634         }
635
636         
637         @SCLValue(type = "VariableMap")
638         public static VariableMap structuralChildDomainChildren = new VariableMapImpl() {
639         
640 //              private Variable childWithTypeOverrides(ReadGraph graph, Variable parent, Resource child, String name) throws DatabaseException {
641 //            return All.getStandardChildDomainChildVariable(graph, parent, child, name);
642 //              }
643 //              
644 //              private Map<String, Variable> childrenWithTypeOverrides(ReadGraph graph, Variable parent, Map<String, Resource> children, Map<String, Variable> map) throws DatabaseException {
645 //            return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, parent, children, map);
646 //              }
647                 
648                 @Override
649                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
650
651                         System.err.println("foobar1: " + context.getURI(graph));
652                         
653                         Resource type = context.getPossibleType(graph);
654                         if(type == null) return null;
655                         
656                         StructuralComponentClass clazz = StructuralComponentClass.get(graph, type);
657                         if(StructuralComponentClass.PROCEDURAL.equals(clazz)) {
658                     Map<String,Variable> map = graph.syncRequest(new ProceduralSubstructureRequest(context),
659                         TransientCacheListener.<Map<String,Variable>>instance());
660                     if(map != null) return map.get(name);
661                     return null;
662                         } else if (StructuralComponentClass.DEFINED.equals(clazz)) {
663                                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
664                                 Resource def = graph.getSingleObject(type, STR.IsDefinedBy);
665                 Map<String, Resource> children = graph.getChildren(def);
666                 Resource child = children.get(name);
667                 if(child == null) return null;
668                 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, child, name);
669                         } else {
670                                 Resource represents = context.getPossibleRepresents(graph);
671                                 if(represents == null) return null;
672                 Map<String, Resource> children = graph.getChildren(represents);
673                 Resource child = children.get(name);
674                 if(child == null) return null;
675                 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, child, name);
676                         }
677
678 //                      StructuralOverrideData od = StructuralOverrideData.compute(graph, context);
679 //              if(od.type() != null) {
680 //                      StructuralResource2 STR = StructuralResource2.getInstance(graph);
681 //                  if(graph.isInstanceOf(od.type(), STR.ProceduralComponentType)) {
682 //                          Map<String,Variable> map = graph.syncRequest(new ProceduralSubstructureRequest(context),
683 //                              TransientCacheListener.<Map<String,Variable>>instance());
684 //                          if(map != null) return map.get(name);
685 //                  }
686 //              }
687 //              
688 //              Resource type = context.getPossibleType(graph, baseType);
689 //              
690 //              Resource represents = od.represents();
691 //            if(represents == null) {
692 //                Map<String, Resource> children = graph.syncRequest(new StructuralChildMapOfResourceT(od.type()));
693 //                Resource child = children.get(name);
694 //                return childWithTypeOverrides(graph, context, child, name);
695 //            }
696 //            Map<String, Resource> children = graph.syncRequest(new StructuralChildMapOfResource(represents));
697 //            Resource child = children.get(name);
698 //            return childWithTypeOverrides(graph, context, child, name);
699             
700                 }
701
702                 @Override
703                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
704                         
705                         System.err.println("foobar2: " + context.getURI(graph));
706
707                         Resource type = context.getPossibleType(graph);
708                         if(type == null) return null;
709                         
710                         StructuralComponentClass clazz = StructuralComponentClass.get(graph, type);
711                         if(StructuralComponentClass.PROCEDURAL.equals(clazz)) {
712                 Map<String,Variable> mapPrime = graph.syncRequest(new ProceduralSubstructureRequest(context),
713                                 TransientCacheListener.<Map<String,Variable>>instance());
714                 if(mapPrime != null) {
715                         if(map != null) {
716                                 map.putAll(mapPrime);
717                                 return map;
718                         }
719                         else
720                                 return mapPrime;
721                 }
722                 return map;
723                         } else if (StructuralComponentClass.DEFINED.equals(clazz)) {
724                                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
725                                 Resource def = graph.getSingleObject(type, STR.IsDefinedBy);
726                 Map<String, Resource> children = graph.getChildren(def);
727                 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map);
728                         } else {
729                                 Resource represents = context.getPossibleRepresents(graph);
730                                 if(represents == null) return null;
731                 Map<String, Resource> children = graph.getChildren(represents);
732                 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map);
733                         }
734                         
735                         
736 //                      StructuralOverrideData od = StructuralOverrideData.compute(graph, context);
737 //              if(od.type() != null) {
738 //                      StructuralResource2 STR = StructuralResource2.getInstance(graph);
739 //                  if(graph.isInstanceOf(od.type(), STR.ProceduralComponentType)) {
740 //                      Map<String,Variable> mapPrime = graph.syncRequest(new ProceduralSubstructureRequest(context),
741 //                                      TransientCacheListener.<Map<String,Variable>>instance());
742 //                      if(mapPrime != null) {
743 //                              if(map != null) {
744 //                                      map.putAll(mapPrime);
745 //                                      return map;
746 //                              }
747 //                              else
748 //                                      return mapPrime;
749 //                      }
750 //                  }
751 //              }
752 //              
753 //              Resource represents = od.represents();
754 //            if(represents == null) {
755 //                Map<String, Resource> children = graph.syncRequest(new StructuralChildMapOfResourceT(od.type()));
756 //                return childrenWithTypeOverrides(graph, context, children, map);
757 //            }
758 //            Map<String, Resource> children = graph.syncRequest(new StructuralChildMapOfResource(represents));
759 //            return childrenWithTypeOverrides(graph, context, children, map);
760             
761                 }
762                 
763         };
764         
765         @SCLValue(type = "VariableMap")
766         public static VariableMap structuralRunDomainChildren = new VariableMapImpl() {
767         
768                 @Override
769                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
770                         Resource ctx = graph.syncRequest(new StructuralRunContext(context.getRepresents(graph)));
771                         if(ctx == null) return null;
772                     Map<String, Resource> children = graph.getChildren(ctx);
773                         Resource child = children.get(name);
774             return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, child, name);
775                 }
776
777                 @Override
778                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
779                         Resource ctx = graph.syncRequest(new StructuralRunContext(context.getRepresents(graph)));
780                         if(ctx == null) return map;
781                     Map<String, Resource> children = graph.getChildren(ctx);
782                     return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, children, map);
783                 }
784                 
785         };
786
787         @SCLValue(type = "ReadGraph -> [Resource] -> [Resource]")
788     public static List<Resource> connectionExtension(ReadGraph graph, List<Resource> rs) throws DatabaseException {
789
790         StructuralResource2 STR = StructuralResource2.getInstance(graph);
791         HashSet<Resource> extension = new HashSet<Resource>(8);
792         for(Resource r : rs) {
793                 if(graph.isInstanceOf(r, STR.Connection)) {
794                         extension.addAll(graph.syncRequest(new ConnectionComponents(r), TransientCacheListener.<Collection<Resource>>instance()));
795                 }
796                 if(graph.isInstanceOf(r, STR.ConnectionJoin)) {
797                         extension.addAll(graph.syncRequest(new ConnectionJoinComponents(r), TransientCacheListener.<Collection<Resource>>instance()));
798                 }
799         }
800
801         HashSet<Resource> components = new HashSet<Resource>(8);
802         for(Resource r : extension) {
803                 components.addAll(graph.sync(new ObjectsWithType(r, STR.Connects, STR.Component)));
804         }
805         
806         if(!extension.isEmpty()) {
807                 ArrayList<Resource> result = new ArrayList<Resource>(rs.size() + extension.size());
808                 result.addAll(rs);
809                 result.addAll(extension);
810                 result.addAll(components);
811                 rs = result;
812         }
813         
814         return rs;
815         
816     }
817
818         @SCLValue(type = "ReadGraph -> Resource -> [Issue]")
819     public static List<Issue> connectionValidator(ReadGraph graph, Resource component) throws DatabaseException {
820         
821                 if(!graph.hasStatement(component)) return Collections.emptyList();
822
823                 ArrayList<Issue> result = new ArrayList<Issue>();
824                 
825                 Layer0 L0 = Layer0.getInstance(graph);
826                 StructuralResource2 sr = StructuralResource2.getInstance(graph);
827
828                 Resource type = graph.getSingleType(component, sr.Component);
829                 
830                 Set<Resource> requiredConnections = new HashSet<Resource>();
831                 for(Resource connectionRelation : graph.sync(new ObjectsWithType(type, L0.ConsistsOf, sr.ConnectionRelation))) {
832                         Boolean required = graph.getPossibleRelatedValue(connectionRelation, sr.ConnectionRelation_connectionRequired, Bindings.BOOLEAN);
833                         if(required != null && required)
834                                 requiredConnections.add(connectionRelation);
835                 }
836                 
837                 Set<Resource> connections = new HashSet<Resource>();
838
839                 for(Statement stm : graph.getStatements(component, sr.IsConnectedTo)) {
840                         connections.add(stm.getPredicate());
841                         connections.addAll(graph.getSuperrelations(stm.getPredicate()));
842                 }
843
844                 for(Resource req : requiredConnections) {
845                         if(!connections.contains(req)) {
846                                 result.add(new StandardIssue(sr.ConnectionConstraint_ErrorIssue, component, req));
847                         }
848                 }
849
850                 return result;
851         
852     }
853
854     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")
855     public static String connectionIssueDescription(ReadGraph graph, Resource converter, Variable property) throws DatabaseException {
856         List<Resource> contexts = IssueUtils.getContextsForProperty(graph, property);
857         String attributeName = graph.getRelatedValue(contexts.get(1), Layer0.getInstance(graph).HasName);
858         return "'" + attributeName + "' should be connected.";
859     }
860
861     public static class InterfacePathMap extends VariableRead<GraphMap<Map<String,InterfaceResolution>>> {
862
863                 public InterfacePathMap(Variable context) {
864                         super(context);
865                 }
866
867                 @Override
868                 public GraphMap<Map<String,InterfaceResolution>> perform(ReadGraph graph) throws DatabaseException {
869
870                         return new GraphMap<Map<String,InterfaceResolution>>() {
871
872                                 @Override
873                                 Map<String, InterfaceResolution> get(ReadGraph graph, String key) throws DatabaseException {
874                                         
875                                         Variable child = variable.getChild(graph, key);
876                                         
877                                         Map<String,InterfaceResolution> childMap = new THashMap<String,InterfaceResolution>();
878                                         Collection<InterfaceResolution> paths = computeInterfacePaths(graph, child);//child.getPossiblePropertyValue(graph, "proceduralConnectionPointPath");
879                                         if(paths != null) {
880                                                 for(InterfaceResolution r : paths) {
881                                                         childMap.put(r.interfaceName, r);
882                                                 }
883                                         }
884                                         return childMap;
885
886                                 }
887                                 
888                         };
889                         
890                 }
891         
892     }
893     
894     public static String resolveInterfacePath(ReadGraph graph, Variable context, String component, Resource relation) throws DatabaseException {
895         
896         GraphMap<Map<String,InterfaceResolution>> map = graph.syncRequest(new InterfacePathMap(context), TransientCacheListener.<GraphMap<Map<String,InterfaceResolution>>>instance());
897         Map<String,InterfaceResolution> childMap = map.get(graph, component);
898         if(childMap == null) return "";
899
900         PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(relation), TransientCacheListener.<PropertyInfo>instance());
901
902         InterfaceResolution match = childMap.get(info.name);
903         if(match != null) {
904                 String comp = URIStringUtils.escape(component);
905                 Variable newContext = context.getChild(graph, component);
906                 return "/" + comp + resolveInterfacePath(graph, newContext, match.componentName, match.connectionPoint);
907         } else {
908                 return "/" + URIStringUtils.escape(component) + "#" + URIStringUtils.escape(info.name); 
909         }
910                 
911     }
912     
913     public static class InterfaceResolution {
914         
915         public Resource interfaceConnectionPoint;
916         public String interfaceName;
917         public String componentName;
918         public Resource connectionPoint;
919         
920         public InterfaceResolution(Resource interfaceConnectionPoint, String interfaceName, String componentName, Resource connectionPoint) {
921                 this.interfaceConnectionPoint = interfaceConnectionPoint;
922                 this.interfaceName = interfaceName;
923                 this.componentName = componentName;
924                 this.connectionPoint = connectionPoint;
925         }
926         
927     }
928     
929     public static Collection<InterfaceResolution> computeInterfacePaths(ReadGraph graph, Variable variable) throws DatabaseException {
930
931                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
932                 Resource type = variable.getPossibleType(graph);
933                 if(type != null) {
934                         if(graph.isInstanceOf(type, STR.ProceduralComponentType)) {
935                                 ArrayList<InterfaceResolution> result = new ArrayList<InterfaceResolution>();
936                                 List<SubstructureElement> elements = getProceduralDesc(graph, variable); 
937                                 if(elements != null) {
938                                         for(SubstructureElement e : elements) {
939                                                 if(e instanceof org.simantics.structural2.procedural.Connection) {
940                                                         org.simantics.structural2.procedural.Connection conn = (org.simantics.structural2.procedural.Connection)e;
941                                                         Interface inf = null;
942                                                         for(ConnectionPoint cp : conn.connectionPoints) {
943                                                                 if(cp instanceof Interface) {
944                                                                         if(inf != null) throw new DatabaseException("Multiple interfaces referenced in procedural connection.");
945                                                                         inf = (Interface)cp;
946                                                                 }
947                                                         }
948                                                         if(inf != null && conn.connectionPoints.size() > 1) {
949                                                                 Layer0 L0 = Layer0.getInstance(graph);
950                                                                 String cpName = URIStringUtils.escape( graph.<String>getRelatedValue(inf.relation, L0.HasName, Bindings.STRING) );
951                                                                 for(ConnectionPoint cp : conn.connectionPoints) {
952                                                                         if(cp == inf) continue;
953                                                                         Terminal t = (Terminal)cp;
954                                                                         result.add(new InterfaceResolution(inf.relation, cpName, t.component, t.relation));
955                                                                 }
956                                                         }
957                                                 }
958                                         }
959                                 }
960
961                                 return result;
962                                 
963                         }
964
965                         final Collection<InterfaceResolution> interfaces = graph.syncRequest(new DefinedUCInterfaceMap(type));
966                         if(interfaces != null) return interfaces;
967
968                 }
969                 
970                 return BUILTIN_STRUCTURAL_CPS;
971         
972     }
973     
974     static class InterfacePathRequest extends VariableRead<Collection<InterfaceResolution>> {
975
976                 public InterfacePathRequest(Variable variable) {
977                         super(variable);
978                 }
979                 
980                 @Override
981                 public Collection<InterfaceResolution> perform(ReadGraph graph) throws DatabaseException {
982                         return computeInterfacePaths(graph, variable);
983                 }
984         
985     }
986     
987     public static final Collection<InterfaceResolution> BUILTIN_STRUCTURAL_CPS = new ArrayList<InterfaceResolution>();
988
989         @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
990     public static Object computeExpression(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
991         return CompileStructuralValueRequest.compileAndEvaluate(graph, context);
992     }
993
994     public static Object computeExpressionInContext(ReadGraph graph, Variable context, final String expression) throws DatabaseException {
995         SCLContext sclContext = SCLContext.getCurrent();
996         Object oldGraph = sclContext.get("graph");
997         try {
998             Function1<Variable,Object> exp = graph.syncRequest(new CompileStructuralValueRequest(graph, context) {
999                 protected String getExpressionText(ReadGraph graph) throws DatabaseException {
1000                     return expression;
1001                 }
1002             },
1003             TransientCacheListener.<Function1<Variable,Object>>instance());
1004             sclContext.put("graph", graph);
1005             return exp.apply(context);
1006         } catch (DatabaseException e) {
1007             throw (DatabaseException)e;
1008         } catch (Throwable t) {
1009             throw new DatabaseException(t);
1010         } finally {
1011             sclContext.put("graph", oldGraph);
1012         }
1013     }    
1014         
1015         static abstract class InterfacePathProperty extends LazyPropertyVariable {
1016                 
1017                 public InterfacePathProperty(Variable parent) {
1018                         super(parent, "proceduralConnectionPointPath", Bindings.STRING_ARRAY);
1019                 }
1020                 
1021                 @Override
1022                 public <T> T getValue(ReadGraph graph, Binding binding) throws DatabaseException {
1023                         return getValue(graph);
1024                 }
1025                 
1026         }
1027         
1028         static abstract class GraphMap<Value> {
1029                 
1030                 abstract Value get(ReadGraph graph, String key) throws DatabaseException;
1031                 
1032         }
1033     
1034 }