From d05ff87b1b781690016a38a8d97f6cd0c9b7810d Mon Sep 17 00:00:00 2001
From: Jeffrey Phillips Freeman <jeffrey.freeman@syncleus.com>
Date: Fri, 16 Sep 2011 11:14:28 -0400
Subject: [PATCH] CHECKPOINT: Several fixes, but class implementation seems to
 be complete on the graph side. Time to start cleaning up the rest of the
 graph package.

---
 .../dann/graph/AbstractAdjacencyGraph.java    |  61 ++---
 .../syncleus/dann/graph/AbstractCloud.java    |  74 +++++-
 .../AbstractContextMutableAdjacencyGraph.java | 173 +++++++++++++
 .../com/syncleus/dann/graph/AbstractEdge.java |   6 +-
 .../graph/AbstractMutableAdjacencyGraph.java  | 232 ++++++++++--------
 .../syncleus/dann/graph/AdjacencyMapping.java |   6 +-
 .../java/com/syncleus/dann/graph/Cloud.java   |  19 +-
 .../dann/graph/HashAdjacencyMapping.java      | 229 ++++++++++++++---
 .../dann/graph/MutableAdjacencyGraph.java     |  80 +++++-
 .../com/syncleus/dann/graph/MutableGraph.java |  10 +-
 .../event/context/ContextCloudElement.java    |   9 +-
 .../event/context/ContextEdgeElement.java     |   7 +-
 .../graph/event/context/ContextGraphEdge.java |   7 +-
 .../event/context/ContextGraphElement.java    |   8 +-
 .../graph/event/context/ContextGraphNode.java |   7 +-
 15 files changed, 720 insertions(+), 208 deletions(-)
 create mode 100644 src/main/java/com/syncleus/dann/graph/AbstractContextMutableAdjacencyGraph.java

diff --git a/src/main/java/com/syncleus/dann/graph/AbstractAdjacencyGraph.java b/src/main/java/com/syncleus/dann/graph/AbstractAdjacencyGraph.java
index 2a9dc2f3..0835c179 100644
--- a/src/main/java/com/syncleus/dann/graph/AbstractAdjacencyGraph.java
+++ b/src/main/java/com/syncleus/dann/graph/AbstractAdjacencyGraph.java
@@ -37,9 +37,9 @@ import java.util.*;
 public abstract class AbstractAdjacencyGraph<
 	  	N,
 	  	E extends Cloud<N,? extends Cloud.Endpoint<? extends N>>,
-	  	NEP extends Graph.NodeEndpoint<N, E>,
-	  	EEP extends Graph.EdgeEndpoint<N, E>
-	  > extends AbstractCloud<Object,Graph.Endpoint<?, N,E>> implements Graph<N, E, NEP, EEP>
+	  	NE extends Graph.NodeEndpoint<N, E>,
+	  	EE extends Graph.EdgeEndpoint<N, E>
+	  > extends AbstractCloud<Object,Graph.Endpoint<?, N,E>> implements Graph<N, E, NE, EE>
 {
 	private static final Logger LOGGER = Logger.getLogger(AbstractAdjacencyGraph.class);
 //	private Set<E> edges;
@@ -529,7 +529,7 @@ public abstract class AbstractAdjacencyGraph<
 	}
 */
 
-	protected abstract Set<EdgeEndpoint<N,E>> getAdjacentEdgeEndpoints(Graph.NodeEndpoint<? extends N, ? extends E> nodeEndpoint);
+	protected abstract Set<EdgeEndpoint<N,E>> getAdjacentEdgeEndpoints(Graph.NodeEndpoint<?, ?> nodeEndpoint);
 
 	protected PathFinder<N,E> getPathFinder()
 	{
@@ -540,7 +540,7 @@ public abstract class AbstractAdjacencyGraph<
 	public Set<N> getNodes()
 	{
 		final Set<N> nodes = new HashSet<N>();
-		for(NEP destinationEndpoint : this.getNodeEndpoints() )
+		for(NE destinationEndpoint : this.getNodeEndpoints() )
 			nodes.add(destinationEndpoint.getTarget());
 		return Collections.unmodifiableSet(nodes);
 	}
@@ -549,16 +549,16 @@ public abstract class AbstractAdjacencyGraph<
 	public Set<E> getEdges()
 	{
 		final Set<E> edges = new HashSet<E>();
-		for(EEP destinationEndpoint : this.getEdgeEndpoints() )
+		for(EE destinationEndpoint : this.getEdgeEndpoints() )
 			edges.add(destinationEndpoint.getTarget());
 		return Collections.unmodifiableSet(edges);
 	}
 
 	@Override
-	public Set<EEP> getEdgeEndpoints(Cloud<?,? extends Cloud.Endpoint<?>> cloud)
+	public Set<EE> getEdgeEndpoints(Cloud<?,? extends Cloud.Endpoint<?>> cloud)
 	{
-		Set<EEP> matchingEndpoints  = new HashSet<EEP>();
-		for(final EEP endpoint : this.getEdgeEndpoints() )
+		Set<EE> matchingEndpoints  = new HashSet<EE>();
+		for(final EE endpoint : this.getEdgeEndpoints() )
 		{
 			if( endpoint.getTarget().equals(cloud))
 				matchingEndpoints.add(endpoint);
@@ -568,10 +568,10 @@ public abstract class AbstractAdjacencyGraph<
 	}
 
 	@Override
-	public Set<NEP> getNodeEndpoints(Object node)
+	public Set<NE> getNodeEndpoints(Object node)
 	{
-		Set<NEP> matchingEndpoints  = new HashSet<NEP>();
-		for(NEP endpoint : this.getNodeEndpoints() )
+		Set<NE> matchingEndpoints  = new HashSet<NE>();
+		for(NE endpoint : this.getNodeEndpoints() )
 		{
 			if( endpoint.getTarget().equals(node))
 				matchingEndpoints.add(endpoint);
@@ -585,7 +585,7 @@ public abstract class AbstractAdjacencyGraph<
 	{
 		final Set<N> sourceNodes = new HashSet<N>();
 
-		for(NEP destinationEndpoint : this.getNodeEndpoints(node) )
+		for(NE destinationEndpoint : this.getNodeEndpoints(node) )
 			for(Graph.EdgeEndpoint<? extends N, ? extends E> sourceEndpoint : destinationEndpoint.getAdjacentEdges())
 				for(Graph.NodeEndpoint<? extends N, ? extends E> nodeEndpoint : sourceEndpoint.getAdjacentNodes())
 					sourceNodes.add(nodeEndpoint.getTarget());
@@ -598,7 +598,7 @@ public abstract class AbstractAdjacencyGraph<
 	{
 		final Set<E> sourceEdges = new HashSet<E>();
 
-		for(NEP destinationEndpoint : this.getNodeEndpoints(node) )
+		for(NE destinationEndpoint : this.getNodeEndpoints(node) )
 			for(Graph.EdgeEndpoint<? extends N, ? extends E> sourceEndpoint : destinationEndpoint.getAdjacentEdges())
 				sourceEdges.add(sourceEndpoint.getTarget());
 
@@ -780,7 +780,7 @@ public abstract class AbstractAdjacencyGraph<
 	{
 		final Set<E> destinationEdges = new HashSet<E>();
 
-		for(NEP sourceEndpoint : this.getNodeEndpoints(source) )
+		for(NE sourceEndpoint : this.getNodeEndpoints(source) )
 			for(Graph.EdgeEndpoint<? extends N, ? extends E> destinationEndpoint : sourceEndpoint.getTraversableAdjacentEdgesFrom())
 				destinationEdges.add(destinationEndpoint.getTarget());
 
@@ -792,7 +792,7 @@ public abstract class AbstractAdjacencyGraph<
 	{
 		final Set<E> destinationEdges = new HashSet<E>();
 
-		for(EEP sourceEndpoint : this.getEdgeEndpoints(source) )
+		for(EE sourceEndpoint : this.getEdgeEndpoints(source) )
 			for(Graph.EdgeEndpoint<? extends N, ? extends E> destinationEndpoint : sourceEndpoint.getTraversableAdjacentEdgesFrom())
 				destinationEdges.add(destinationEndpoint.getTarget());
 
@@ -805,7 +805,7 @@ public abstract class AbstractAdjacencyGraph<
 	{
 		final Set<E> sourceEdges = new HashSet<E>();
 
-		for(NEP destinationEndpoint : this.getNodeEndpoints(destination) )
+		for(NE destinationEndpoint : this.getNodeEndpoints(destination) )
 			for(Graph.EdgeEndpoint<? extends N, ? extends E> sourceEndpoint : destinationEndpoint.getTraversableAdjacentEdgesTo())
 				sourceEdges.add(sourceEndpoint.getTarget());
 
@@ -817,7 +817,7 @@ public abstract class AbstractAdjacencyGraph<
 	{
 		final Set<E> destinationEdges = new HashSet<E>();
 
-		for(EEP destinationEndpoint : this.getEdgeEndpoints(destination) )
+		for(EE destinationEndpoint : this.getEdgeEndpoints(destination) )
 			for(Graph.EdgeEndpoint<? extends N, ? extends E> sourceEndpoint : destinationEndpoint.getTraversableAdjacentEdgesFrom())
 				destinationEdges.add(sourceEndpoint.getTarget());
 
@@ -829,7 +829,7 @@ public abstract class AbstractAdjacencyGraph<
 	{
 		final Set<N> destinationNodes = new HashSet<N>();
 
-		for(NEP sourceEndpoint : this.getNodeEndpoints(source) )
+		for(NE sourceEndpoint : this.getNodeEndpoints(source) )
 			for(Graph.EdgeEndpoint<? extends N, ? extends E> destinationEndpoint : sourceEndpoint.getTraversableAdjacentEdgesTo())
 				for(Graph.NodeEndpoint<? extends N, ? extends E> nodeEndpoint : destinationEndpoint.getTraversableAdjacentNodesTo())
 					destinationNodes.add(nodeEndpoint.getTarget());
@@ -842,7 +842,7 @@ public abstract class AbstractAdjacencyGraph<
 	{
 		final Set<N> destinationNodes = new HashSet<N>();
 
-		for(EEP sourceEndpoint : this.getEdgeEndpoints(source) )
+		for(EE sourceEndpoint : this.getEdgeEndpoints(source) )
 			for(Graph.NodeEndpoint<? extends N, ? extends E> destinationEndpoint : sourceEndpoint.getTraversableAdjacentNodesTo())
 					destinationNodes.add(destinationEndpoint.getTarget());
 
@@ -854,7 +854,7 @@ public abstract class AbstractAdjacencyGraph<
 	{
 		final Set<N> sourceNodes = new HashSet<N>();
 
-		for(NEP destinationEndpoint : this.getNodeEndpoints(destination) )
+		for(NE destinationEndpoint : this.getNodeEndpoints(destination) )
 			for(Graph.EdgeEndpoint<? extends N, ? extends E> sourceEndpoint : destinationEndpoint.getTraversableAdjacentEdgesFrom())
 				for(Graph.NodeEndpoint<? extends N, ? extends E> nodeEndpoint : sourceEndpoint.getTraversableAdjacentNodesFrom())
 					sourceNodes.add(nodeEndpoint.getTarget());
@@ -867,7 +867,7 @@ public abstract class AbstractAdjacencyGraph<
 	{
 		final Set<N> sourceNodes = new HashSet<N>();
 
-		for(EEP destinationEndpoint : this.getEdgeEndpoints(destination) )
+		for(EE destinationEndpoint : this.getEdgeEndpoints(destination) )
 			for(Graph.NodeEndpoint<? extends N, ? extends E> sourceEndpoint : destinationEndpoint.getTraversableAdjacentNodesFrom())
 					sourceNodes.add(sourceEndpoint.getTarget());
 
@@ -879,9 +879,9 @@ public abstract class AbstractAdjacencyGraph<
 	 * @return A clone of the current object, with no changes
 	 */
 	@Override
-	protected AbstractAdjacencyGraph<N, E, NEP, EEP> clone()
+	protected AbstractAdjacencyGraph<N, E, NE, EE> clone()
 	{
-		return (AbstractAdjacencyGraph<N, E, NEP, EEP>) super.clone();
+		return (AbstractAdjacencyGraph<N, E, NE, EE>) super.clone();
 	}
 
 	/**
@@ -980,9 +980,6 @@ public abstract class AbstractAdjacencyGraph<
 
 	protected abstract class AbstractNodeEndpoint extends AbstractCloud<? super N,Graph.Endpoint<? super N, N,E>>.AbstractEndpoint<N> implements Graph.NodeEndpoint<N,E>
 	{
-		protected AbstractNodeEndpoint()
-		{
-		}
 
 		@Override
 		public Set<Graph.EdgeEndpoint<N, E>> getAdjacentEdges()
@@ -1076,10 +1073,6 @@ public abstract class AbstractAdjacencyGraph<
 
 	protected abstract class AbstractEdgeEndpoint extends AbstractCloud<? super E,Graph.Endpoint<? super E, N,E>>.AbstractEndpoint<E> implements Graph.EdgeEndpoint<N,E>
 	{
-		protected AbstractEdgeEndpoint()
-		{
-		}
-
 		@Override
 		public Set<Graph.NodeEndpoint<N, E>> getAdjacent()
 		{
@@ -1115,7 +1108,7 @@ public abstract class AbstractAdjacencyGraph<
 			final Set<Graph.EdgeEndpoint<N, E>> adjacentEdges = new HashSet<Graph.EdgeEndpoint<N, E>>();
 
 			for(Endpoint<? extends N> sourceEndpoint : this.getTarget().getEndpoints())
-				for( NEP neighborNode : AbstractAdjacencyGraph.this.getNodeEndpoints(sourceEndpoint.getTarget()) )
+				for( NE neighborNode : AbstractAdjacencyGraph.this.getNodeEndpoints(sourceEndpoint.getTarget()) )
 					adjacentEdges.addAll(AbstractAdjacencyGraph.this.getAdjacentEdgeEndpoints(neighborNode));
 
 			adjacentEdges.remove(this);
@@ -1129,7 +1122,7 @@ public abstract class AbstractAdjacencyGraph<
 
 			for(Endpoint<? extends N> sourceEndpoint : this.getTarget().getEndpoints())
 				if( sourceEndpoint.getTraversableNeighborsFrom().size() > 0 )
-					for( NEP adjacentNode : AbstractAdjacencyGraph.this.getNodeEndpoints(sourceEndpoint.getTarget()))
+					for( NE adjacentNode : AbstractAdjacencyGraph.this.getNodeEndpoints(sourceEndpoint.getTarget()))
 						for( Graph.EdgeEndpoint<N, E> adjacentEdge : AbstractAdjacencyGraph.this.getAdjacentEdgeEndpoints(adjacentNode) )
 						 	if( adjacentEdge.getTarget().getTraversableFrom(adjacentNode.getTarget()).size() > 0 )
 								 adjacentEdges.add(adjacentEdge);
@@ -1144,7 +1137,7 @@ public abstract class AbstractAdjacencyGraph<
 
 			for(Endpoint<? extends N> sourceEndpoint : this.getTarget().getEndpoints())
 				if( sourceEndpoint.getTraversableNeighborsTo().size() > 0 )
-					for( NEP adjacentNode : AbstractAdjacencyGraph.this.getNodeEndpoints(sourceEndpoint.getTarget()))
+					for( NE adjacentNode : AbstractAdjacencyGraph.this.getNodeEndpoints(sourceEndpoint.getTarget()))
 						for( Graph.EdgeEndpoint<N, E> adjacentEdge : AbstractAdjacencyGraph.this.getAdjacentEdgeEndpoints(adjacentNode) )
 						 	if( adjacentEdge.getTarget().getTraversableTo(adjacentNode.getTarget()).size() > 0 )
 								 adjacentEdges.add(adjacentEdge);
diff --git a/src/main/java/com/syncleus/dann/graph/AbstractCloud.java b/src/main/java/com/syncleus/dann/graph/AbstractCloud.java
index 0493659e..8cf73c85 100644
--- a/src/main/java/com/syncleus/dann/graph/AbstractCloud.java
+++ b/src/main/java/com/syncleus/dann/graph/AbstractCloud.java
@@ -35,7 +35,7 @@ public abstract class AbstractCloud<
 	private static final Logger LOGGER = Logger.getLogger(AbstractCloud.class);
 
 	@Override
-	public boolean contains(final Object node)
+	public boolean containsTarget(final Object node)
 	{
 		for( EP endpoint : this.getEndpoints() )
 			if( endpoint.getTarget().equals(node))
@@ -44,19 +44,46 @@ public abstract class AbstractCloud<
 	}
 
 	@Override
-	public boolean containsAll(final Collection<?> nodes)
+	public boolean containsAllTargets(final Collection<?> nodes)
 	{
 		for( Object node : nodes )
-			if( !this.contains(node) )
+			if( !this.containsTarget(node) )
 				return false;
 		return true;
 	}
 
 	@Override
-	public boolean containsAny(final Collection<?> nodes)
+	public boolean containsAnyTargets(final Collection<?> nodes)
 	{
 		for( Object node : nodes )
-			if( this.contains(node) )
+			if( this.containsTarget(node) )
+				return true;
+		return false;
+	}
+
+	@Override
+	public boolean contains(final Object endpoint)
+	{
+		for( EP otherEndpoint : this.getEndpoints() )
+			if( otherEndpoint.equals(endpoint))
+				return true;
+		return false;
+	}
+
+	@Override
+	public boolean containsAll(final Collection<? extends Endpoint<?>> endpoints)
+	{
+		for( Object endpoint : endpoints )
+			if( !this.contains(endpoint) )
+				return false;
+		return true;
+	}
+
+	@Override
+	public boolean containsAny(final Collection<? extends Endpoint<?>> endpoints)
+	{
+		for( Object endpoint : endpoints )
+			if( this.contains(endpoint) )
 				return true;
 		return false;
 	}
@@ -215,8 +242,43 @@ public abstract class AbstractCloud<
 
 	protected abstract class AbstractEndpoint<T> implements Cloud.Endpoint<T>
 	{
-		protected AbstractEndpoint()
+		protected abstract boolean isTargetEquals();
+
+		/**
+		 * By default this relies on the target to define equals, this means there can be only one instance of any
+		 * endpoint. This should be overridden to allow for an edge to have the same element more than once.
+		 */
+		@Override
+		public int hashCode()
 		{
+			if(!this.isTargetEquals())
+				return super.hashCode();
+			else if(this.getTarget() == null)
+				return 0;
+			else
+				return this.getTarget().hashCode();
+		}
+
+		/**
+		 * By default this relies on the target to define equals, this means there can be only one instance of any
+		 * endpoint. This should be overridden to allow for an edge to have the same element more than once.
+		 */
+		@Override
+		public boolean equals(Object obj)
+		{
+			if(!this.isTargetEquals())
+				return super.equals(obj);
+			else if( obj == null )
+				if( this.getTarget() == null )
+					return true;
+				else
+					return false;
+			else if( this.getTarget() == null)
+				return false;
+			else if( obj instanceof Cloud.Endpoint )
+				return ((Cloud.Endpoint<?>)obj).equals(this.getTarget());
+			else
+				return this.getTarget().equals(obj);
 		}
 
 		@Override
diff --git a/src/main/java/com/syncleus/dann/graph/AbstractContextMutableAdjacencyGraph.java b/src/main/java/com/syncleus/dann/graph/AbstractContextMutableAdjacencyGraph.java
new file mode 100644
index 00000000..755b53f4
--- /dev/null
+++ b/src/main/java/com/syncleus/dann/graph/AbstractContextMutableAdjacencyGraph.java
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *                                                                             *
+ *  Copyright: (c) Syncleus, Inc.                                              *
+ *                                                                             *
+ *  You may redistribute and modify this source code under the terms and       *
+ *  conditions of the Open Source Community License - Type C version 1.0       *
+ *  or any later version as published by Syncleus, Inc. at www.syncleus.com.   *
+ *  There should be a copy of the license included with this file. If a copy   *
+ *  of the license is not included you are granted no right to distribute or   *
+ *  otherwise use this file except through a legal and valid license. You      *
+ *  should also contact Syncleus, Inc. at the information below if you cannot  *
+ *  find a license:                                                            *
+ *                                                                             *
+ *  Syncleus, Inc.                                                             *
+ *  2604 South 12th Street                                                     *
+ *  Philadelphia, PA 19148                                                     *
+ *                                                                             *
+ ******************************************************************************/
+package com.syncleus.dann.graph;
+
+import java.util.*;
+import com.syncleus.dann.graph.event.context.*;
+
+public abstract class AbstractContextMutableAdjacencyGraph<
+	  	N,
+	  	E extends Cloud<N,? extends Cloud.Endpoint<N>>,
+	  	NE extends MutableGraph.NodeEndpoint<N, E>,
+	  	EE extends MutableGraph.EdgeEndpoint<N, E>
+	  >
+	  extends AbstractMutableAdjacencyGraph<N, E, NE, EE>
+{
+	@Override
+	public final boolean isContextEnabled()
+	{
+		return true;
+	}
+
+	@Override
+	protected void internalJoinNode(MutableGraph.NodeEndpoint<N, E> endpoint) throws InvalidGraphException
+	{
+		if(endpoint == null)
+			throw new IllegalArgumentException(("endpoint can not be null"));
+
+		try
+		{
+			if(endpoint.getTarget() instanceof ContextCloudElement)
+				((ContextCloudElement<?,?>)endpoint.getTarget()).changingCloudContext(Collections.singleton(this), null);
+			if(endpoint.getTarget() instanceof ContextGraphElement)
+				((ContextGraphElement<?,?>)endpoint.getTarget()).changingGraphContext(Collections.singleton(this), null, null);
+			if(endpoint.getTarget() instanceof ContextGraphNode)
+				((ContextGraphNode<?,?>)endpoint.getTarget()).changingGraphNodeContext(Collections.singleton(this), null);
+		}
+		catch(RejectedContextException caught)
+		{
+			throw new InvalidGraphException("could not join node", caught);
+		}
+
+		super.internalJoinNode(endpoint);
+
+		if(endpoint.getTarget() instanceof ContextCloudElement)
+			((ContextCloudElement<?,?>)endpoint.getTarget()).changedCloudContext(Collections.singleton(endpoint), null);
+		if(endpoint.getTarget() instanceof ContextGraphElement)
+			((ContextGraphElement<?,?>)endpoint.getTarget()).changedGraphContext(Collections.singleton(endpoint), null, null);
+		if(endpoint.getTarget() instanceof ContextGraphNode)
+			((ContextGraphNode<?,?>)endpoint.getTarget()).changedGraphNodeContext(Collections.singleton(endpoint), null);
+	}
+
+	@Override
+	protected void internalLeaveNode(MutableGraph.NodeEndpoint<?, ?> endpoint) throws InvalidGraphException
+	{
+		if(endpoint == null)
+			throw new IllegalArgumentException(("endpoint can not be null"));
+
+		try
+		{
+			if(endpoint.getTarget() instanceof ContextCloudElement)
+				((ContextCloudElement<?,?>)endpoint.getTarget()).changingCloudContext(null, Collections.singleton(endpoint));
+			if(endpoint.getTarget() instanceof ContextGraphElement)
+				((ContextGraphElement<?,?>)endpoint.getTarget()).changingGraphContext(null, null, Collections.singleton(endpoint));
+			if(endpoint.getTarget() instanceof ContextGraphNode)
+				((ContextGraphNode<?,?>)endpoint.getTarget()).changingGraphNodeContext(null, Collections.singleton(endpoint));
+		}
+		catch(RejectedContextException caught)
+		{
+			throw new InvalidGraphException("could not join node", caught);
+		}
+
+		super.internalLeaveNode(endpoint);
+
+		if(endpoint.getTarget() instanceof ContextCloudElement)
+			((ContextCloudElement<?,?>)endpoint.getTarget()).changedCloudContext(null, Collections.singleton(endpoint));
+		if(endpoint.getTarget() instanceof ContextGraphElement)
+			((ContextGraphElement<?,?>)endpoint.getTarget()).changedGraphContext(null, null, Collections.singleton(endpoint));
+		if(endpoint.getTarget() instanceof ContextGraphNode)
+			((ContextGraphNode<?,?>)endpoint.getTarget()).changedGraphNodeContext(null, Collections.singleton(endpoint));
+	}
+
+	@Override
+	protected void internalJoinEdge(MutableGraph.EdgeEndpoint<N, E> endpoint) throws InvalidGraphException
+	{
+		if(endpoint == null)
+			throw new IllegalArgumentException(("endpoint can not be null"));
+
+		try
+		{
+			if(endpoint.getTarget() instanceof ContextCloudElement)
+				((ContextCloudElement<?,?>)endpoint.getTarget()).changingCloudContext(Collections.singleton(this), null);
+			if(endpoint.getTarget() instanceof ContextGraphElement)
+				((ContextGraphElement<?,?>)endpoint.getTarget()).changingGraphContext(Collections.singleton(this), null, null);
+			if(endpoint.getTarget() instanceof ContextGraphEdge)
+				((ContextGraphEdge<?,?>)endpoint.getTarget()).changingGraphEdgeContext(Collections.singleton(this), null);
+		}
+		catch(RejectedContextException caught)
+		{
+			throw new InvalidGraphException("could not join node", caught);
+		}
+
+		super.internalJoinEdge(endpoint);
+
+		if(endpoint.getTarget() instanceof ContextCloudElement)
+			((ContextCloudElement<?,?>)endpoint.getTarget()).changedCloudContext(Collections.singleton(endpoint), null);
+		if(endpoint.getTarget() instanceof ContextGraphElement)
+			((ContextGraphElement<?,?>)endpoint.getTarget()).changedGraphContext(Collections.singleton(endpoint), null, null);
+		if(endpoint.getTarget() instanceof ContextGraphEdge)
+			((ContextGraphEdge<?,?>)endpoint.getTarget()).changedGraphEdgeContext(Collections.singleton(endpoint), null);
+	}
+
+	@Override
+	protected void internalLeaveEdge(MutableGraph.EdgeEndpoint<?, ?> endpoint) throws InvalidGraphException
+	{
+		if(endpoint == null)
+			throw new IllegalArgumentException(("endpoint can not be null"));
+
+		try
+		{
+			if(endpoint.getTarget() instanceof ContextCloudElement)
+				((ContextCloudElement<?,?>)endpoint.getTarget()).changingCloudContext(null, Collections.singleton(endpoint));
+			if(endpoint.getTarget() instanceof ContextGraphElement)
+				((ContextGraphElement<?,?>)endpoint.getTarget()).changingGraphContext(null, null, Collections.singleton(endpoint));
+			if(endpoint.getTarget() instanceof ContextGraphEdge)
+				((ContextGraphEdge<?,?>)endpoint.getTarget()).changingGraphEdgeContext(null, Collections.singleton(endpoint));
+		}
+		catch(RejectedContextException caught)
+		{
+			throw new InvalidGraphException("could not join node", caught);
+		}
+
+		super.internalLeaveEdge(endpoint);
+
+		if(endpoint.getTarget() instanceof ContextCloudElement)
+			((ContextCloudElement<?,?>)endpoint.getTarget()).changedCloudContext(null, Collections.singleton(endpoint));
+		if(endpoint.getTarget() instanceof ContextGraphElement)
+			((ContextGraphElement<?,?>)endpoint.getTarget()).changedGraphContext(null, null, Collections.singleton(endpoint));
+		if(endpoint.getTarget() instanceof ContextGraphEdge)
+			((ContextGraphEdge<?,?>)endpoint.getTarget()).changedGraphEdgeContext(null, Collections.singleton(endpoint));
+	}
+
+	protected abstract class AbstractNodeEndpoint extends AbstractMutableAdjacencyGraph<N,E,NE,EE>.AbstractNodeEndpoint
+	{
+		protected AbstractNodeEndpoint(final N target)
+		{
+			super(target);
+		}
+	};
+
+	protected abstract class AbstractEdgeEndpoint extends AbstractMutableAdjacencyGraph<N,E,NE,EE>.AbstractEdgeEndpoint
+	{
+		protected AbstractEdgeEndpoint(final E target)
+		{
+			super(target);
+		}
+	};
+}
diff --git a/src/main/java/com/syncleus/dann/graph/AbstractEdge.java b/src/main/java/com/syncleus/dann/graph/AbstractEdge.java
index a74d0462..35dc6dd0 100644
--- a/src/main/java/com/syncleus/dann/graph/AbstractEdge.java
+++ b/src/main/java/com/syncleus/dann/graph/AbstractEdge.java
@@ -23,7 +23,11 @@ public abstract class AbstractEdge<
 	  	EP extends Edge.Endpoint<? extends T>
 	  > extends AbstractCloud<T,EP> implements Edge<T,EP>
 {
-	protected abstract class AbstractEndpoint<T> implements AbstractCloud.Endpoint<T>
+	protected abstract class AbstractEndpoint<TT> extends AbstractCloud<T,EP>.AbstractEndpoint<TT>
 	{
+		protected AbstractEndpoint(final boolean isTargetEquals)
+		{
+			super(isTargetEquals);
+		}
 	}
 }
diff --git a/src/main/java/com/syncleus/dann/graph/AbstractMutableAdjacencyGraph.java b/src/main/java/com/syncleus/dann/graph/AbstractMutableAdjacencyGraph.java
index 3ca4cc2c..a42d832d 100644
--- a/src/main/java/com/syncleus/dann/graph/AbstractMutableAdjacencyGraph.java
+++ b/src/main/java/com/syncleus/dann/graph/AbstractMutableAdjacencyGraph.java
@@ -23,84 +23,95 @@ import java.util.*;
 public abstract class AbstractMutableAdjacencyGraph<
 	  	N,
 	  	E extends Cloud<N,? extends Cloud.Endpoint<N>>,
-	  	NEP extends MutableGraph.NodeEndpoint<N, E>,
-	  	EEP extends MutableGraph.EdgeEndpoint<N, E>
+	  	NE extends MutableGraph.NodeEndpoint<N, E>,
+	  	EE extends MutableGraph.EdgeEndpoint<N, E>
 	  >
-	  extends AbstractAdjacencyGraph<N, E, NEP, EEP>
-	  implements MutableGraph<N, E, NEP, EEP>
+	  extends AbstractAdjacencyGraph<N, E, NE, EE>
+	  implements MutableGraph<N, E, NE, EE>
 {
 	private static final long serialVersionUID = -4613327727609060678L;
-	private final AdjacencyMapping<NEP,EEP> adjacency = new HashAdjacencyMapping<NEP, EEP>();
-	private final boolean uniqueNodes;
-	private final boolean uniqueEdges;
+	private final AdjacencyMapping<MutableGraph.NodeEndpoint<N, E>,MutableGraph.EdgeEndpoint<N, E>,Cloud.Endpoint<N>> adjacency = new HashAdjacencyMapping<MutableGraph.NodeEndpoint<N, E>,MutableGraph.EdgeEndpoint<N, E>,Cloud.Endpoint<N>>();
 
 	protected AbstractMutableAdjacencyGraph()
 	{
-		this(false);
 	}
 
-	protected AbstractMutableAdjacencyGraph(final boolean uniqueEdges)
+
+
+	protected void internalJoinNode(final MutableGraph.NodeEndpoint<N, E> endpoint) throws InvalidGraphException
 	{
-		this(uniqueEdges,true);
+		if(endpoint == null)
+			throw new IllegalArgumentException(("endpoint can not be null"));
+		else if( this.contains(endpoint) )
+			throw new IllegalArgumentException("endpoint is already a member of this graph!");
+
+		this.adjacency.putLeftKey(endpoint);
 	}
 
-	protected AbstractMutableAdjacencyGraph(final boolean uniqueEdges, final boolean uniqueNodes)
+	protected void internalLeaveNode(MutableGraph.NodeEndpoint<?, ?> endpoint) throws InvalidGraphException
 	{
-		this.uniqueEdges = uniqueEdges;
-		this.uniqueNodes = uniqueNodes;
+		if(endpoint == null)
+			throw new IllegalArgumentException(("endpoint can not be null"));
+		else if( !this.adjacency.getLeftKeys().contains(endpoint) )
+			throw new IllegalArgumentException("endpoint is not an endpoint in this graph");
+		else if( this.getAdjacentEdgeEndpoints(endpoint).size() > 0)
+			throw new InvalidGraphException("Node must be an orphan in the graph to remove it");
+
+		this.adjacency.removeLeftKey(endpoint);
 	}
 
-	protected final boolean isUniqueEdges()
+	protected void internalJoinEdge(final MutableGraph.EdgeEndpoint<N, E> endpoint) throws InvalidGraphException
 	{
-		return this.uniqueEdges;
+		if(endpoint == null)
+			throw new IllegalArgumentException(("endpoint can not be null"));
+		//make sure all of the edge's node already belong to this graph
+		else if( !this.containsAllTargets(endpoint.getTarget().getTargets()) )
+			throw new InvalidGraphException("All of the edge's targets must already exist in this graph");
+		//we cant do anything if the endpoint already exists in the key, they are unique representations of
+		//a single membership to the graph
+		else if(this.contains(endpoint))
+			throw new IllegalArgumentException("endpoint is already a member of this graph!");
+
+		for( final Cloud.Endpoint<N> targetEndpoint : endpoint.getTarget().getEndpoints() )
+			for( final NE nodeEndpoint : this.getNodeEndpoints(targetEndpoint.getTarget()))
+				this.adjacency.put(nodeEndpoint,endpoint,targetEndpoint);
 	}
 
-	protected final boolean isUniqueNodes()
+
+	protected void internalLeaveEdge(MutableGraph.EdgeEndpoint<?, ?> endpoint) throws InvalidGraphException
 	{
-		return this.uniqueNodes;
+		if(endpoint == null)
+			throw new IllegalArgumentException(("endpoint can not be null"));
+		else if( !this.adjacency.getRightKeys().contains(endpoint) )
+			throw new IllegalArgumentException("endpoint is not an endpoint in this graph");
+
+		this.adjacency.removeRightKey(endpoint);
 	}
 
 	@Override
-	protected Set<Graph.EdgeEndpoint<N,E>> getAdjacentEdgeEndpoints(Graph.NodeEndpoint<? extends N, ? extends E> nodeEndpoint)
+	protected Set<Graph.EdgeEndpoint<N,E>> getAdjacentEdgeEndpoints(Graph.NodeEndpoint<?, ?> nodeEndpoint)
 	{
 		if( !this.adjacency.getLeftKeys().contains(nodeEndpoint) )
 			throw new IllegalArgumentException("nodeEndpoint is not an endpoint for this graph");
 		return Collections.<EdgeEndpoint<N,E>>unmodifiableSet(this.adjacency.getLeftAdjacency(nodeEndpoint));
 	}
 
-	protected abstract NEP createNodeEndpoint(N node) throws InvalidGraphException;
-	protected abstract EEP createEdgeEndpoint(E node) throws InvalidGraphException;
-
-	@Override
-	public NEP joinNode(N node) throws InvalidGraphException
-	{
-		if(this.uniqueNodes && this.contains(node))
-			return this.getNodeEndpoints(node).iterator().next();
-
-		final NEP endpoint = this.createNodeEndpoint(node);
-		assert !this.adjacency.getLeftKeys().contains(endpoint);
-
-		this.adjacency.putLeftKey(endpoint);
-
-		return endpoint;
-	}
-
 	@Override
-	public Map<N, NEP> joinNodes(Set<? extends N> nodes) throws InvalidGraphException
+	public Map<N, NE> joinNodes(Set<? extends N> nodes) throws InvalidGraphException
 	{
-		final Map<N, NEP> endpoints = new HashMap<N,NEP>();
+		final Map<N, NE> endpoints = new HashMap<N,NE>();
 		for(N node : nodes)
 			endpoints.put(node, this.joinNode(node));
 		return Collections.unmodifiableMap(endpoints);
 	}
 
 	@Override
-	public Map<N, Set<NEP>> joinNodes(Map<? extends N, ? extends Integer> nodes) throws InvalidGraphException
+	public Map<N, Set<NE>> joinNodes(Map<? extends N, ? extends Integer> nodes) throws InvalidGraphException
 	{
-		final Map<N,Set<NEP>> joinMapping = new HashMap<N, Set<NEP>>(nodes.size());
+		final Map<N,Set<NE>> joinMapping = new HashMap<N, Set<NE>>(nodes.size());
 		for(final Map.Entry<? extends N,? extends Integer> nodeEntry : nodes.entrySet())
 		{
-			final Set<NEP> newEndpoints = new HashSet<NEP>(nodeEntry.getValue());
+			final Set<NE> newEndpoints = new HashSet<NE>(nodeEntry.getValue());
 			for(int count = 0; count < nodeEntry.getValue(); count++)
 				newEndpoints.add(this.joinNode(nodeEntry.getKey()));
 			joinMapping.put(nodeEntry.getKey(),newEndpoints);
@@ -109,61 +120,28 @@ public abstract class AbstractMutableAdjacencyGraph<
 	}
 
 	@Override
-	public Set<EEP> leaveNode(MutableGraph.NodeEndpoint<?, ? extends Cloud<?,? extends Endpoint<?>>> endpoint) throws InvalidGraphException
+	public void leaveNodes(Set<? extends MutableGraph.NodeEndpoint<?, ?>> nodeEndpoints) throws InvalidGraphException
 	{
-		if( !this.adjacency.getLeftKeys().contains(endpoint) )
-			throw new IllegalArgumentException("endpoint is not an enpoint in this graph");
-
-		//first we need to remove all associated edges
-		final Set<EEP> orphanEdges = this.adjacency.getLeftAdjacency(endpoint);
-		this.adjacency.getRightKeys().removeAll(orphanEdges);
-		this.adjacency.removeLeftKey(endpoint);
-
-		return Collections.unmodifiableSet(orphanEdges);
-	}
-
-	@Override
-	public Set<EEP> leaveNodes(Set<? extends MutableGraph.NodeEndpoint<?, ? extends Cloud<?,? extends Endpoint<?>>>> nodeEndpoints) throws InvalidGraphException
-	{
-		final Set<EEP> edgeEndpoints = new HashSet<EEP>();
 		for(MutableGraph.NodeEndpoint<?, ? extends Cloud<?,? extends Endpoint<?>>> node : nodeEndpoints)
-			edgeEndpoints.addAll(this.leaveNode(node));
-		return Collections.unmodifiableSet(edgeEndpoints);
+			this.leaveNode(node);
 	}
 
 	@Override
-	public EEP joinEdge(E edge) throws InvalidGraphException
+	public Map<E, EE> joinEdges(Set<? extends E> edges) throws InvalidGraphException
 	{
-		//make sure all of the edge's node already belong to this graph
-		if( !this.containsAll(edge.getTargets()) )
-			throw new IllegalArgumentException("All of the edge's targets must already exist in this graph");
-
-		if(this.uniqueEdges && this.contains(edge))
-			return this.getEdgeEndpoints(edge).iterator().next();
-
-		final EEP edgeEndpoint = this.createEdgeEndpoint(edge);
-		for( final N node : edge.getTargets() )
-			this.adjacency.put(this.getNodeEndpoints(node).iterator().next(),edgeEndpoint);
-
-		return edgeEndpoint;
-	}
-
-	@Override
-	public Map<E, EEP> joinEdges(Set<? extends E> edges) throws InvalidGraphException
-	{
-		final Map<E, EEP> endpoints = new HashMap<E,EEP>();
+		final Map<E, EE> endpoints = new HashMap<E,EE>();
 		for(E edge : edges)
 			endpoints.put(edge, this.joinEdge(edge));
 		return Collections.unmodifiableMap(endpoints);
 	}
 
 	@Override
-	public Map<E, Set<EEP>> joinEdges(Map<? extends E, ? extends Integer> edges) throws InvalidGraphException
+	public Map<E, Set<EE>> joinEdges(Map<? extends E, ? extends Integer> edges) throws InvalidGraphException
 	{
-		final Map<E,Set<EEP>> joinMapping = new HashMap<E, Set<EEP>>(edges.size());
+		final Map<E,Set<EE>> joinMapping = new HashMap<E, Set<EE>>(edges.size());
 		for(final Map.Entry<? extends E,? extends Integer> edgeEntry : edges.entrySet())
 		{
-			final Set<EEP> newEndpoints = new HashSet<EEP>(edgeEntry.getValue());
+			final Set<EE> newEndpoints = new HashSet<EE>(edgeEntry.getValue());
 			for(int count = 0; count < edgeEntry.getValue(); count++)
 				newEndpoints.add(this.joinEdge(edgeEntry.getKey()));
 			joinMapping.put(edgeEntry.getKey(),newEndpoints);
@@ -172,16 +150,7 @@ public abstract class AbstractMutableAdjacencyGraph<
 	}
 
 	@Override
-	public void leaveEdge(MutableGraph.EdgeEndpoint<?, ? extends Cloud<?,? extends Endpoint<?>>> edgeEndpoint) throws InvalidGraphException
-	{
-		if( !this.adjacency.getRightKeys().contains(edgeEndpoint) )
-			throw new IllegalArgumentException("endpoint is not an enpoint in this graph");
-
-		this.adjacency.removeRightKey(edgeEndpoint);
-	}
-
-	@Override
-	public void leaveEdges(Set<? extends MutableGraph.EdgeEndpoint<?, ? extends Cloud<?,? extends Endpoint<?>>>> edgeEndpoints) throws InvalidGraphException
+	public void leaveEdges(Set<? extends MutableGraph.EdgeEndpoint<?, ?>> edgeEndpoints) throws InvalidGraphException
 	{
 		for(final MutableGraph.EdgeEndpoint<?, ? extends Cloud<?,? extends Endpoint<?>>> edgeEndpoint : edgeEndpoints)
 			this.leaveEdge(edgeEndpoint);
@@ -202,27 +171,38 @@ public abstract class AbstractMutableAdjacencyGraph<
 	@Override
 	public Map<?, Graph.Endpoint<?, N, E>> reconfigure(Set<? extends N> addNodes, Set<? extends E> addEdges, Set<? extends Graph.Endpoint<?, ?, ?>> disconnectEndpoints) throws InvalidGraphException
 	{
-		for(final Graph.Endpoint<?, ?,?> disconnectEndpoint : disconnectEndpoints)
-			this.adjacency.remove(disconnectEndpoint.getTarget());
+		if( disconnectEndpoints != null )
+		{
+			for(final Graph.Endpoint<?, ?,?> disconnectEndpoint : disconnectEndpoints)
+				this.adjacency.remove(disconnectEndpoint.getTarget());
+		}
 
 		Map<Object, Graph.Endpoint<?, N,E>> newEndpoints = new HashMap<Object, Graph.Endpoint<?, N, E>>();
-		newEndpoints.putAll(this.joinNodes(addNodes));
-		newEndpoints.putAll(this.joinEdges(addEdges));
+		if( addNodes != null )
+			newEndpoints.putAll(this.joinNodes(addNodes));
+		if( addEdges != null )
+			newEndpoints.putAll(this.joinEdges(addEdges));
 		return newEndpoints;
 	}
 
 	@Override
-	public Set<EEP> getEdgeEndpoints()
+	public Set<EE> getEdgeEndpoints()
 	{
 		return Collections.unmodifiableSet(this.adjacency.getRightKeys());
 	}
 
 	@Override
-	public Set<NEP> getNodeEndpoints()
+	public Set<NE> getNodeEndpoints()
 	{
 		return Collections.unmodifiableSet(this.adjacency.getLeftKeys());
 	}
 
+	@Override
+	public boolean isContextEnabled()
+	{
+		return false;
+	}
+
 /*
 		private class NodeTargetSet extends AbstractTargetSet<N>
 		{
@@ -313,11 +293,63 @@ public abstract class AbstractMutableAdjacencyGraph<
 		};
 */
 
-	protected abstract class AbstractNodeEndpoint extends AbstractAdjacencyGraph<N,E,NEP,EEP>.AbstractNodeEndpoint implements MutableGraph.NodeEndpoint<N, E>
+	protected abstract class AbstractNodeEndpoint extends AbstractAdjacencyGraph<N,E,NE,EE>.AbstractNodeEndpoint implements MutableGraph.NodeEndpoint<N, E>
 	{
-	}
+		private N target;
 
-	protected abstract class AbstractEdgeEndpoint extends AbstractAdjacencyGraph<N,E,NEP,EEP>.AbstractEdgeEndpoint implements MutableGraph.EdgeEndpoint<N, E>
+		protected AbstractNodeEndpoint(final N target)
+		{
+			this.target = target;
+		}
+
+		@Override
+		public void setTarget(N newTarget) throws InvalidGraphException
+		{
+			if(this.target != null && this.target.equals(newTarget) )
+			{
+				this.target = newTarget;
+				return;
+			}
+
+			internalLeaveNode(this);
+			this.target = newTarget;
+			internalJoinNode(this);
+		}
+
+		@Override
+		public N getTarget()
+		{
+			return this.target;
+		}
+	};
+
+	protected abstract class AbstractEdgeEndpoint extends AbstractAdjacencyGraph<N,E,NE,EE>.AbstractEdgeEndpoint implements MutableGraph.EdgeEndpoint<N, E>
 	{
-	}
+		private E target;
+
+		protected AbstractEdgeEndpoint(final E target)
+		{
+			this.target = target;
+		}
+
+		@Override
+		public void setTarget(E newTarget) throws InvalidGraphException
+		{
+			if(this.target != null && this.target.equals(newTarget) )
+			{
+				this.target = newTarget;
+				return;
+			}
+
+			internalLeaveEdge(this);
+			this.target = newTarget;
+			internalJoinEdge(this);
+		}
+
+		@Override
+		public E getTarget()
+		{
+			return this.target;
+		}
+	};
 }
\ No newline at end of file
diff --git a/src/main/java/com/syncleus/dann/graph/AdjacencyMapping.java b/src/main/java/com/syncleus/dann/graph/AdjacencyMapping.java
index f1b994ac..19579732 100644
--- a/src/main/java/com/syncleus/dann/graph/AdjacencyMapping.java
+++ b/src/main/java/com/syncleus/dann/graph/AdjacencyMapping.java
@@ -18,10 +18,10 @@
  ******************************************************************************/
 package com.syncleus.dann.graph;
 
-import java.util.Map;
 import java.util.Set;
+import sun.awt.SunHints;
 
-public interface AdjacencyMapping<LK,RK> extends Set<AdjacencyMapping.Adjacency<LK,RK>>
+public interface AdjacencyMapping<LK,RK,V> extends Set<AdjacencyMapping.Adjacency<LK,RK>>
 {
 	interface Adjacency<LK,RK>
 	{
@@ -35,6 +35,8 @@ public interface AdjacencyMapping<LK,RK> extends Set<AdjacencyMapping.Adjacency<
 	boolean putLeftKey(LK leftKey);
 	boolean putRightKey(RK rightKey);
 	boolean put(LK leftKey, RK rightKey);
+	boolean put(LK leftKey, RK rightKey, V value);
+	V get(Object leftKey, Object rightKey);
 	boolean contains(Object leftKey, Object rightKey);
 	Set<RK> getRightKeys();
 	Set<LK> getLeftKeys();
diff --git a/src/main/java/com/syncleus/dann/graph/Cloud.java b/src/main/java/com/syncleus/dann/graph/Cloud.java
index cbd0158a..053fb050 100644
--- a/src/main/java/com/syncleus/dann/graph/Cloud.java
+++ b/src/main/java/com/syncleus/dann/graph/Cloud.java
@@ -41,14 +41,17 @@ public interface Cloud<
 	};
 
 	Set<EP> getEndpoints();
-	Set<EP> getEndpoints(Object node);
-	boolean contains(Object node);
-	boolean containsAny(Collection<?> nodes);
-	boolean containsAll(Collection<?> nodes);
+	Set<EP> getEndpoints(Object target);
 	Set<T> getTargets();
-	Set<T> getNeighbors(Object source);
-	Set<T> getTraversableFrom(Object source);
-	Set<T> getTraversableTo(Object destination);
-	boolean isTraversable(Object source, Object destination);
+	Set<T> getNeighbors(Object target);
+	Set<T> getTraversableFrom(Object target);
+	Set<T> getTraversableTo(Object target);
+	boolean isTraversable(Object sourceTarget, Object destinationTarget);
 	int getDegree();
+	boolean contains( Object endpoint);
+	boolean containsAny(Collection<? extends Endpoint<?>> endpoint);
+	boolean containsAll(Collection<? extends Endpoint<?>> endpoint);
+	boolean containsTarget(Object target);
+	boolean containsAnyTargets(Collection<?> target);
+	boolean containsAllTargets(Collection<?> target);
 }
diff --git a/src/main/java/com/syncleus/dann/graph/HashAdjacencyMapping.java b/src/main/java/com/syncleus/dann/graph/HashAdjacencyMapping.java
index bf9f9bc4..0c7bf837 100644
--- a/src/main/java/com/syncleus/dann/graph/HashAdjacencyMapping.java
+++ b/src/main/java/com/syncleus/dann/graph/HashAdjacencyMapping.java
@@ -20,18 +20,19 @@ package com.syncleus.dann.graph;
 
 import java.util.*;
 
-public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Adjacency<LK,RK>> implements AdjacencyMapping<LK,RK>
+public class HashAdjacencyMapping<LK,RK,V> extends AbstractSet<AdjacencyMapping.Adjacency<LK,RK>> implements AdjacencyMapping<LK,RK,V>
 {
 	private Integer size = 0;
 	private final Map<LK, WeakRightKeySet> leftAdjacency = new HashMap<LK, WeakRightKeySet>();
 	private final Map<RK, WeakLeftKeySet> rightAdjacency = new HashMap<RK, WeakLeftKeySet>();
+	private final Map<LK,Map<RK,V>> valueMapping = new HashMap<LK, Map<RK,V>>();
 
 	@Override
 	public boolean contains(Object o)
 	{
 		if(!(o instanceof Adjacency))
 			return false;
-		Adjacency<? extends Object,? extends Object> adjacency = (Adjacency<? extends Object,? extends Object>) o;
+		Adjacency<?,?> adjacency = (Adjacency<?,?>) o;
 
 		return this.contains((LK)adjacency.getLeftKey(),(RK)adjacency.getRightKey());
 	}
@@ -356,8 +357,7 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 		return true;
 	}
 
-	@Override
-	public boolean put(LK leftKey, RK rightKey)
+	private boolean put(LK leftKey, RK rightKey, boolean eraseValue)
 	{
 		if(leftKey == null)
 		{
@@ -416,11 +416,68 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 			assert size >= 1;
 		}
 
+		if( eraseValue )
+		{
+			final Map<RK,V> mappings = this.valueMapping.get(leftKey);
+			if( mappings == null )
+				return true;
+			mappings.remove(rightKey);
+			if( mappings.isEmpty() )
+				this.valueMapping.remove(leftKey);
+		}
+
 		return true;
 	}
 
 	@Override
-	public boolean add(Adjacency<LK, RK> adjacency)
+	public boolean put(LK leftKey, RK rightKey)
+	{
+		return this.put(leftKey, rightKey, true);
+	}
+
+	@Override
+	public boolean put(LK leftKey, RK rightKey, V value)
+	{
+		if( (leftKey == null || rightKey == null) && value != null)
+			throw new IllegalArgumentException("Can not associated a value with an orphaned key");
+
+		final KeyPairing keyPair = new KeyPairing(leftKey, rightKey);
+		final boolean valueChanged = this.put(leftKey, rightKey, false);
+
+		Map<RK,V> mappings = this.valueMapping.get(leftKey);
+		if( mappings == null )
+		{
+			mappings = new WeakHashMap<RK, V>();
+			this.valueMapping.put(leftKey,mappings);
+		}
+
+		if( mappings.put(rightKey, value) == value )
+			return valueChanged;
+		else
+			return true;
+	}
+
+	@Override
+	public V get(Object leftKey, Object rightKey)
+	{
+		if(leftKey == null || rightKey == null)
+			throw new IllegalArgumentException("Can not associated a value with an orphaned key");
+
+		final Map<RK,V> mappings = this.valueMapping.get(leftKey);
+		if( mappings == null )
+			return null;
+
+		final V value = mappings.get(rightKey);
+		if( !this.contains(leftKey,rightKey) )
+		{
+			mappings.remove(rightKey);
+			return null;
+		}
+		return value;
+	}
+
+	@Override
+	public boolean add(AdjacencyMapping.Adjacency<LK, RK> adjacency)
 	{
 		return put(adjacency.getLeftKey(), adjacency.getRightKey());
 	}
@@ -448,6 +505,9 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 			}
 			assert adjacentRight.size() > 0;
 			this.size = null;
+
+			//cleanup our weak refrences
+			adjacentRight = null;
 		}
 		assert this.size == null || this.size >= 0;
 
@@ -477,6 +537,9 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 			}
 			assert adjacentLeft.size() > 0;
 			this.size = null;
+
+			//cleanup our weak refrences
+			adjacentLeft = null;
 		}
 		assert this.size == null || this.size >= 0;
 
@@ -561,6 +624,8 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 		if(this.size != null)
 			return this.size;
 
+		System.gc();
+
 		int newSize = 0;
 		for(final Map.Entry<LK,WeakRightKeySet> entry : this.leftAdjacency.entrySet())
 		{
@@ -698,50 +763,112 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 		}
 	}
 
-	private class WeakHashSet<E> implements Set<E>
+	private static class WeakHashSet<E> implements Set<E>
 	{
-		private final Map<E, Object> backingMap = new WeakHashMap<E, Object>();
+		private final Map<E, Object> references = new WeakHashMap<E, Object>();
+//		private final Set<WeakReference<E>> references = new HashSet<WeakReference<E>>();
+//		private final ReferenceQueue<E> queue = new ReferenceQueue<E>();
+/*
+		private final class ElementReference
+		{
+			private final WeakReference<E> reference;
+
+			public ElementReference(E element)
+			{
+				if( element != null )
+					this.reference = new WeakReference<E>(element, queue);
+				else
+					this.reference = null;
+			}
+
+			public E get()
+			{
+				if( !isClearTag() )
+					return this.reference.get();
+				return
+					  null;
+			}
+
+			private boolean isClearTag()
+			{
+				return reference == null;
+			}
+
+			@Override
+			public int hashCode()
+			{
+				if( this.isClearTag() )
+					return 0;
+
+				final E element = reference.get();
+				if( element == null )
+					return 0;
+				else
+					return element.hashCode();
+			}
+
+			@Override
+			public boolean equals(Object obj)
+			{
+				if(obj == null)
+					return false;
+				if( !(obj instanceof ElementReference) )
+					return false;
+				final ElementReference otherElementReference = (ElementReference) obj;
+
+				final E otherElement = otherElementReference.get();
+				if( otherElement == null )
+					return false;
+
+				final E element = reference.get();
+				if( element == null )
+					return super.;
+
+				return element.equals(otherElement);
+			}
+		};
+*/
 
 		@Override
 		public int size()
 		{
-			return this.backingMap.size();
+			return this.references.size();
 		}
 
 		@Override
 		public boolean isEmpty()
 		{
-			return this.backingMap.isEmpty();
+			return this.references.isEmpty();
 		}
 
 		@Override
 		public boolean contains(Object o)
 		{
-			return this.backingMap.containsKey(o);
+			return this.references.containsKey(o);
 		}
 
 		@Override
 		public Iterator<E> iterator()
 		{
-			return this.backingMap.keySet().iterator();
+			return this.references.keySet().iterator();
 		}
 
 		@Override
 		public Object[] toArray()
 		{
-			return this.backingMap.keySet().toArray();
+			return this.references.keySet().toArray();
 		}
 
 		@Override
 		public <T> T[] toArray(T[] a)
 		{
-			return this.backingMap.keySet().toArray(a);
+			return this.references.keySet().toArray(a);
 		}
 
 		@Override
 		public boolean add(E ee)
 		{
-			if( this.backingMap.put(ee, null) == null )
+			if( this.references.put(ee, null) == null )
 				return true;
 			return false;
 		}
@@ -749,13 +876,13 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 		@Override
 		public boolean remove(Object o)
 		{
-			return this.backingMap.keySet().remove(0);
+			return this.references.keySet().remove(0);
 		}
 
 		@Override
 		public boolean containsAll(Collection<?> c)
 		{
-			return this.backingMap.keySet().containsAll(c);
+			return this.references.keySet().containsAll(c);
 		}
 
 		@Override
@@ -771,23 +898,23 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 		@Override
 		public boolean retainAll(Collection<?> c)
 		{
-			return this.backingMap.keySet().retainAll(c);
+			return this.references.keySet().retainAll(c);
 		}
 
 		@Override
 		public boolean removeAll(Collection<?> c)
 		{
-			return this.backingMap.keySet().removeAll(c);
+			return this.references.keySet().removeAll(c);
 		}
 
 		@Override
 		public void clear()
 		{
-			this.backingMap.clear();
+			this.references.clear();
 		}
 	};
 
-	private abstract class WeakGraphElementSet<E> extends WeakHashSet<E>
+	private static abstract class WeakGraphElementSet<E> extends WeakHashSet<E>
 	{
 		protected abstract void clean();
 
@@ -876,9 +1003,7 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 			this.clean();
 			return super.removeAll(c);	//To change body of overridden methods use File | Settings | File Templates.
 		}
-	}
-
-	;
+	};
 
 	private final class WeakLeftKeySet extends WeakGraphElementSet<LK>
 	{
@@ -888,9 +1013,7 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 				return;
 			this.retainAll(leftAdjacency.keySet());
 		}
-	}
-
-	;
+	};
 
 	private final class WeakRightKeySet extends WeakGraphElementSet<RK>
 	{
@@ -900,7 +1023,57 @@ public class HashAdjacencyMapping<LK,RK> extends AbstractSet<AdjacencyMapping.Ad
 				return;
 			this.retainAll(rightAdjacency.keySet());
 		}
-	}
+	};
 
-	;
+	private final class KeyPairing implements AdjacencyMapping.Adjacency<LK,RK>
+	{
+		private final LK leftKey;
+		private final RK rightKey;
+
+		public KeyPairing(LK leftKey, RK rightKey)
+		{
+			this.leftKey = leftKey;
+			this.rightKey = rightKey;
+		}
+
+		public LK getLeftKey()
+		{
+			return this.leftKey;
+		}
+
+		public RK getRightKey()
+		{
+			return this.rightKey;
+		}
+
+		@Override
+		public int hashCode()
+		{
+			return (leftKey == null ? 0 : leftKey.hashCode()) + (rightKey == null ? 0 : rightKey.hashCode());
+		}
+
+		@Override
+		public boolean equals(Object obj)
+		{
+			if( obj == null )
+				return false;
+			else if( !(obj instanceof KeyPairing) )
+				return false;
+
+			final KeyPairing keyPair = (KeyPairing) obj;
+			if(
+				  (
+				  	(this.leftKey != null && (this.leftKey.equals(keyPair.getLeftKey()))) ||
+					(this.leftKey == null && keyPair.getLeftKey() == null)
+				  ) &&
+				  (
+				  	(this.rightKey != null && (this.rightKey.equals(keyPair.getRightKey()))) ||
+					(this.rightKey == null && keyPair.getRightKey() == null)
+				  )
+				)
+				return true;
+
+			return false;
+		}
+	};
 }
diff --git a/src/main/java/com/syncleus/dann/graph/MutableAdjacencyGraph.java b/src/main/java/com/syncleus/dann/graph/MutableAdjacencyGraph.java
index 9ee2352d..4971ff0a 100644
--- a/src/main/java/com/syncleus/dann/graph/MutableAdjacencyGraph.java
+++ b/src/main/java/com/syncleus/dann/graph/MutableAdjacencyGraph.java
@@ -18,34 +18,88 @@
  ******************************************************************************/
 package com.syncleus.dann.graph;
 
+import java.util.Set;
+import com.syncleus.dann.xml.Namer;
+
 public final class MutableAdjacencyGraph<
-	  	N,
-	  	E extends Cloud<N,Cloud.Endpoint<N>>
-	  > extends AbstractMutableAdjacencyGraph<N,E,MutableGraph.NodeEndpoint<N, E>,MutableGraph.EdgeEndpoint<N, E>>
-/*
-	  <
 	  	N,
 	  	E extends Cloud<N,? extends Cloud.Endpoint<N>>
-	  >*/
-//	  extends AbstractMutableAdjacencyGraph<N, E, MutableGraph.NodeEndpoint<N, E>//, MutableGraph.EdgeEndpoint<N, E>>
+	  >
+	  extends AbstractContextMutableAdjacencyGraph<N, E, MutableGraph.NodeEndpoint<N, E>, MutableGraph.EdgeEndpoint<N, E>>
 {
 	private static final long serialVersionUID = -4613327727609060678L;
+	private final boolean areNodesUnique;
+	private final boolean areEdgesUnique;
+
+	public MutableAdjacencyGraph()
+	{
+		this(false,true);
+	}
+
+	public MutableAdjacencyGraph(final boolean areEdgesUnique)
+	{
+		this(areEdgesUnique, true);
+	}
+
+	public MutableAdjacencyGraph(final boolean areEdgesUnique, final boolean areNodesUnique)
+	{
+		this.areEdgesUnique = areEdgesUnique;
+		this.areNodesUnique = areNodesUnique;
+	}
 
 	@Override
-	public boolean isContextEnabled()
+	public MutableGraph.NodeEndpoint<N, E> joinNode(N node) throws InvalidGraphException
 	{
-		return false;
+		final NodeEndpoint endpoint = new NodeEndpoint(node);
+		this.internalJoinNode(endpoint);
+		return endpoint;
 	}
 
 	@Override
-	protected MutableGraph.NodeEndpoint<N, E> createNodeEndpoint(N node) throws InvalidGraphException
+	public void leaveNode(MutableGraph.NodeEndpoint<?, ?> endpoint) throws InvalidGraphException
 	{
-		return null;
+		this.internalLeaveNode(endpoint);
 	}
 
 	@Override
-	protected MutableGraph.EdgeEndpoint<N, E> createEdgeEndpoint(E node) throws InvalidGraphException
+	public MutableGraph.EdgeEndpoint<N, E> joinEdge(E edge) throws InvalidGraphException
 	{
-		return null;  //To change body of implemented methods use File | Settings | File Templates.
+		final EdgeEndpoint endpoint = new EdgeEndpoint(edge);
+		this.internalJoinEdge(endpoint);
+		return endpoint;
 	}
+
+	@Override
+	public void leaveEdge(MutableGraph.EdgeEndpoint<?, ?> endpoint) throws InvalidGraphException
+	{
+		this.internalLeaveEdge(endpoint);
+	}
+
+	protected final class NodeEndpoint extends AbstractContextMutableAdjacencyGraph<N,E,MutableGraph.NodeEndpoint<N, E>,MutableGraph.EdgeEndpoint<N, E>>.AbstractNodeEndpoint
+	{
+		protected NodeEndpoint(final N target)
+		{
+			super(target);
+		}
+
+		@Override
+		protected boolean isTargetEquals()
+		{
+			return areNodesUnique;
+		}
+	};
+
+	protected final class EdgeEndpoint extends AbstractContextMutableAdjacencyGraph<N,E,MutableGraph.NodeEndpoint<N, E>,MutableGraph.EdgeEndpoint<N, E>>.AbstractEdgeEndpoint
+	{
+		protected EdgeEndpoint(final E target)
+		{
+			super(target);
+		}
+
+		@Override
+		protected boolean isTargetEquals()
+		{
+			return areEdgesUnique;
+		}
+	};
 }
diff --git a/src/main/java/com/syncleus/dann/graph/MutableGraph.java b/src/main/java/com/syncleus/dann/graph/MutableGraph.java
index 138243a5..109590b7 100644
--- a/src/main/java/com/syncleus/dann/graph/MutableGraph.java
+++ b/src/main/java/com/syncleus/dann/graph/MutableGraph.java
@@ -45,17 +45,17 @@ public interface MutableGraph<
 	NE joinNode(N node) throws InvalidGraphException;
 	Map<N, NE> joinNodes(Set<? extends N> nodes) throws InvalidGraphException;
 	Map<N, Set<NE>> joinNodes(Map<? extends N,? extends Integer> nodes) throws InvalidGraphException;
-	Set<EE> leaveNode(MutableGraph.NodeEndpoint<?, ? extends Cloud<?,? extends Cloud.Endpoint<?>>> endpoint) throws InvalidGraphException;
-	Set<EE> leaveNodes(Set<? extends MutableGraph.NodeEndpoint<?, ? extends Cloud<?,? extends Cloud.Endpoint<?>>>> endpoint) throws InvalidGraphException;
+	void leaveNode(MutableGraph.NodeEndpoint<?,?> endpoint) throws InvalidGraphException;
+	void leaveNodes(Set<? extends MutableGraph.NodeEndpoint<?,?>> endpoint) throws InvalidGraphException;
 
 	EE joinEdge(E edge) throws InvalidGraphException;
 	Map<E, EE> joinEdges(Set<? extends E> edges) throws InvalidGraphException;
 	Map<E, Set<EE>> joinEdges(Map<? extends E,? extends Integer> edges) throws InvalidGraphException;
-	void leaveEdge(MutableGraph.EdgeEndpoint<?, ? extends Cloud<?,? extends Cloud.Endpoint<?>>> endpoint) throws InvalidGraphException;
-	void leaveEdges(Set<? extends MutableGraph.EdgeEndpoint<?, ? extends Cloud<?,? extends Cloud.Endpoint<?>>>> endpoints) throws InvalidGraphException;
+	void leaveEdge(MutableGraph.EdgeEndpoint<?, ?> endpoint) throws InvalidGraphException;
+	void leaveEdges(Set<? extends MutableGraph.EdgeEndpoint<?, ?>> endpoints) throws InvalidGraphException;
 
 	void clear() throws InvalidGraphException;
 	void clearEdges() throws InvalidGraphException;
 
-	Map<?, Graph.Endpoint<?, N,E>> reconfigure(Set<? extends N> addNodes, Set<? extends E> addEdges, final Set<? extends Graph.Endpoint<?, ?,?>> disconnectEndpoints) throws InvalidGraphException;
+	Map<?, Graph.Endpoint<?, N,E>> reconfigure(Set<? extends N> addNodes, Set<? extends E> addEdges, final Set<? extends Graph.Endpoint<?,?,?>> disconnectEndpoints) throws InvalidGraphException;
 }
diff --git a/src/main/java/com/syncleus/dann/graph/event/context/ContextCloudElement.java b/src/main/java/com/syncleus/dann/graph/event/context/ContextCloudElement.java
index c5fd04bb..87ecafc9 100644
--- a/src/main/java/com/syncleus/dann/graph/event/context/ContextCloudElement.java
+++ b/src/main/java/com/syncleus/dann/graph/event/context/ContextCloudElement.java
@@ -21,8 +21,11 @@ package com.syncleus.dann.graph.event.context;
 import java.util.Set;
 import com.syncleus.dann.graph.Cloud;
 
-public interface ContextCloudElement< CE extends Cloud.Endpoint<?> >
+public interface ContextCloudElement<
+		  CE extends Cloud.Endpoint<?>,
+		  C extends Cloud<?, ? extends CE>
+	  >
 {
-	void changingCloudContext(Set<? extends CE> joiningContexts, Set<? extends Cloud<?,? extends Cloud.Endpoint<?>>> leavingContexts) throws RejectedContextException;
-	void changedCloudContext(Set<? extends CE> joinedContexts, Set<? extends Cloud<?,? extends Cloud.Endpoint<?>>> leftContexts);
+	void changingCloudContext(Set<? extends C> joiningContexts, Set<?> leavingContexts) throws RejectedContextException;
+	void changedCloudContext(Set<? extends CE> joinedContexts, Set<?> leftContexts);
 }
diff --git a/src/main/java/com/syncleus/dann/graph/event/context/ContextEdgeElement.java b/src/main/java/com/syncleus/dann/graph/event/context/ContextEdgeElement.java
index 5a5d10b1..f9a843d8 100644
--- a/src/main/java/com/syncleus/dann/graph/event/context/ContextEdgeElement.java
+++ b/src/main/java/com/syncleus/dann/graph/event/context/ContextEdgeElement.java
@@ -21,8 +21,11 @@ package com.syncleus.dann.graph.event.context;
 import java.util.Set;
 import com.syncleus.dann.graph.*;
 
-public interface ContextEdgeElement< EE extends Edge.Endpoint<?> >
+public interface ContextEdgeElement<
+	  	EE extends Edge.Endpoint<?>,
+	  	E extends Edge<?, ? extends EE>
+	  >
 {
-	void changingEdgeContext( Set<? extends EE> joiningContexts, Set<?> leavingContexts) throws RejectedContextException;
+	void changingEdgeContext( Set<? extends E> joiningContexts, Set<?> leavingContexts) throws RejectedContextException;
 	void changedEdgeContext(Set<? extends EE> joinedContexts, Set<?> leftContexts);
 }
\ No newline at end of file
diff --git a/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphEdge.java b/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphEdge.java
index da1e5963..f0b519ef 100644
--- a/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphEdge.java
+++ b/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphEdge.java
@@ -21,8 +21,11 @@ package com.syncleus.dann.graph.event.context;
 import java.util.Set;
 import com.syncleus.dann.graph.Graph;
 
-public interface ContextGraphEdge< GEE extends Graph.EdgeEndpoint<?,?> >
+public interface ContextGraphEdge<
+	  	GEE extends Graph.EdgeEndpoint<?,?>,
+	  	G extends Graph<?, ?, ?, ? extends GEE>
+	  >
 {
-	void changingGraphEdgeContext( Set<? extends GEE> joiningContexts, Set<?> leavingContexts) throws RejectedContextException;
+	void changingGraphEdgeContext( Set<? extends G> joiningContexts, Set<?> leavingContexts) throws RejectedContextException;
 	void changedGraphEdgeContext(Set<? extends GEE> joinedContexts, Set<?> leftContexts);
 }
diff --git a/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphElement.java b/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphElement.java
index e69c9e5f..b5556bb9 100644
--- a/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphElement.java
+++ b/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphElement.java
@@ -19,10 +19,14 @@
 package com.syncleus.dann.graph.event.context;
 
 import java.util.Set;
+import com.syncleus.dann.genetics.Gene;
 import com.syncleus.dann.graph.Graph;
 
-public interface ContextGraphElement< GE extends Graph.Endpoint<?, ?,?> >
+public interface ContextGraphElement<
+	  	GE extends Graph.Endpoint<?, ?,?>,
+	  	G extends Graph<?, ?, ? extends GE, ? extends GE>
+	  >
 {
-	void changingGraphContext( Set<? extends GE> joiningAsNode, Set<? extends GE> joiningAsEdge, Set<?> leavingContexts) throws RejectedContextException;
+	void changingGraphContext( Set<? extends G> joiningAsNode, Set<? extends GE> joiningAsEdge, Set<?> leavingContexts) throws RejectedContextException;
 	void changedGraphContext(Set<? extends GE> joinedAsNode, Set<? extends GE> joinedAsEdge, Set<?> leftContexts);
 }
diff --git a/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphNode.java b/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphNode.java
index 742772e9..f2d72cf2 100644
--- a/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphNode.java
+++ b/src/main/java/com/syncleus/dann/graph/event/context/ContextGraphNode.java
@@ -21,8 +21,11 @@ package com.syncleus.dann.graph.event.context;
 import java.util.Set;
 import com.syncleus.dann.graph.Graph;
 
-public interface ContextGraphNode< GNE extends Graph.NodeEndpoint<?,?> >
+public interface ContextGraphNode<
+	  	GNE extends Graph.NodeEndpoint<?,?>,
+	  	G extends Graph<?, ?, ? extends GNE, ?>
+	  >
 {
-	void changingGraphNodeContext( Set<? extends GNE> joiningContexts, Set<?> leavingContexts) throws RejectedContextException;
+	void changingGraphNodeContext( Set<? extends G> joiningContexts, Set<?> leavingContexts) throws RejectedContextException;
 	void changedGraphNodeContext(Set<? extends GNE> joinedContexts, Set<?> leftContexts);
 }
-- 
GitLab