package org.neo4j.graphalgo;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
/**
* Starting from a {@link Node} this will traverse out BREADTH FIRST and find
* all nodes up to a certain depth and return full paths to them (from the start
* node).
*
* It will collect all the paths in a list first and then return the whole list.
*/
public class AllPathsFinder
{
private final Node startNode;
private final RelationshipType relationshipType;
private final Direction direction;
public AllPathsFinder( Node node, RelationshipType relationshipType,
Direction direction )
{
this.startNode = node;
this.relationshipType = relationshipType;
this.direction = direction;
}
public List<List<PropertyContainer>> getPaths( final int maxDepth )
{
List<List<PropertyContainer>> result = new ArrayList<List<PropertyContainer>>();
if ( maxDepth == 0 )
{
return result;
}
Set<Long> traversedRels = new HashSet<Long>();
LinkedList<PropertyContainer> trail = new LinkedList<PropertyContainer>();
trail.add( startNode );
Set<Relationship> rels = new HashSet<Relationship>();
for ( Relationship rel : startNode.getRelationships( relationshipType, direction ) )
{
rels.add( rel );
traversedRels.add( rel.getId() );
result.add( constructPath( trail, rel, rel.getOtherNode( startNode ) ) );
}
for ( Relationship rel : rels )
{
traverse( traversedRels, result, trail, startNode, rel, 2, maxDepth );
}
return result;
}
private List<PropertyContainer> constructPath(
LinkedList<PropertyContainer> trail, Relationship rel, Node node )
{
List<PropertyContainer> path = new ArrayList<PropertyContainer>( trail );
path.add( rel );
path.add( node );
return path;
}
private void traverse( Set<Long> traversedRels,
List<List<PropertyContainer>> result,
LinkedList<PropertyContainer> trail, Node fromNode,
Relationship fromRel, int depth, int maxDepth )
{
if ( depth > maxDepth )
{
return;
}
Node toNode = fromRel.getOtherNode( fromNode );
trail.add( fromRel );
trail.add( toNode );
Set<Relationship> childRels = new HashSet<Relationship>();
for ( Relationship childRel : toNode.getRelationships( relationshipType, direction ) )
{
if ( !traversedRels.add( childRel.getId() ) )
{
continue;
}
childRels.add( childRel );
result.add( constructPath( trail, childRel,
childRel.getOtherNode( toNode ) ) );
}
for ( Relationship childRel : childRels )
{
traverse( traversedRels, result, trail, toNode, childRel,
depth + 1, maxDepth );
}
trail.removeLast();
trail.removeLast();
}
}