package org.simantics.scenegraph.loader; import gnu.trove.map.hash.THashMap; import java.util.Collection; import java.util.Collections; import java.util.Map; import org.simantics.databoard.Bindings; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.util.ObjectUtils; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.ConstantPropertyVariable; import org.simantics.db.layer0.variable.StandardGraphChildVariable; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; import org.simantics.scenegraph.INode; public class ScenegraphVariable extends StandardGraphChildVariable { final private SceneGraphContext context; final private Map originalProperties; final private Map properties; public ScenegraphVariable(Variable parent, Resource resource, final Resource runtime, final INode root) { this(parent, resource, runtime, root, Collections.emptyMap()); } public static class SceneGraphContextImpl implements SceneGraphContext { final private ScenegraphVariable parent; final private Resource runtime; final private INode root; public SceneGraphContextImpl(ScenegraphVariable parent, Resource runtime, INode root) { assert(root != null); this.parent = parent; this.runtime = runtime; this.root = root; } @Override public INode getRoot() { return root; } @Override public Resource getRuntime() { return runtime; } @Override public Variable getRuntimeVariable() { return new ScenegraphVariable(parent, runtime, runtime, root, parent.originalProperties); } @Override public int hashCode() { return runtime.hashCode() ^ ObjectUtils.hashCode(root); } @Override public boolean equals(Object obj) { if(this == obj) return true; SceneGraphContextImpl other = (SceneGraphContextImpl)obj; if(!runtime.equals(other.runtime)) return false; if(!ObjectUtils.objectEquals(root, other.root)) return false; return true; } } public ScenegraphVariable(Variable parent, Resource resource, final Resource runtime, final INode root, final Map properties) { super(parent, null, resource); if(runtime != null) { this.context = new SceneGraphContextImpl(this, runtime, root); } else { this.context = null; } this.originalProperties = properties; if(properties.isEmpty()) this.properties = Collections.emptyMap(); else { this.properties = new THashMap(); for(Map.Entry p : properties.entrySet()) { this.properties.put(p.getKey(), new ConstantPropertyVariable(parent, p.getKey(), p.getValue().getValue(), p.getValue().getBinding())); } } } @Override public String getName(ReadGraph graph) throws DatabaseException { if(parent instanceof ScenegraphVariable) { return super.getName(graph); } else { return "" + System.identityHashCode(this); } } @Override public Variable getNameVariable(ReadGraph graph) throws DatabaseException { if(parent instanceof ScenegraphVariable) { return super.getNameVariable(graph); } else { return new ConstantPropertyVariable(parent, Variables.NAME, "" + System.identityHashCode(this), Bindings.STRING); } } protected T tryAdapt(ReadGraph graph, Class clazz) throws DatabaseException { if(SceneGraphContext.class == clazz) return (T)context; else if(INode.class == clazz) return (T)context.getRoot(); return null; } @Override public T adapt(ReadGraph graph, Class clazz) throws DatabaseException { T t = tryAdapt(graph, clazz); return t != null ? t : super.adapt(graph, clazz); } @Override public T adaptPossible(ReadGraph graph, Class clazz) throws DatabaseException { T t = tryAdapt(graph, clazz); return t != null ? t : super.adaptPossible(graph, clazz); } @Override public boolean equals(Object obj) { // First check if(!super.equals(obj)) return false; ScenegraphVariable other = (ScenegraphVariable)obj; SceneGraphContext otherContext = other.context; return ObjectUtils.objectEquals(context, otherContext); } @Override public int hashCode() { int s = super.hashCode(); if(context != null) s ^= context.getRuntime().hashCode(); return s; } @Override public Collection getChildren(ReadGraph graph) throws DatabaseException { return ScenegraphLoaderUtils.computeChildren(graph, this); } @Override public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException { for(Variable child : getChildren(graph)) { if(child.getName(graph).equals(name)) return child; } return null; } @Override public void collectExtraProperties(ReadGraph graph, Map properties) throws DatabaseException { properties.putAll(this.properties); } @Override public Variable getPossibleExtraProperty(ReadGraph graph, String name) throws DatabaseException { return properties.get(name); } }