package org.neo4j.kernel.impl.traversal;
import java.util.Iterator;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.traversal.BranchSelector;
import org.neo4j.graphdb.traversal.TraversalBranch;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.helpers.collection.IterableWrapper;
import org.neo4j.helpers.collection.PrefetchingIterator;
class TraverserImpl implements Traverser
{
private final TraversalDescriptionImpl description;
private final Node startNode;
TraverserImpl( TraversalDescriptionImpl description, Node startNode )
{
this.description = description;
this.startNode = startNode;
}
public Iterator<Path> iterator()
{
return new TraverserIterator();
}
public Iterable<Node> nodes()
{
return new IterableWrapper<Node, Path>( this )
{
@Override
protected Node underlyingObjectToObject( Path position )
{
return position.endNode();
}
};
}
public Iterable<Relationship> relationships()
{
return new IterableWrapper<Relationship, Path>( this )
{
@Override
public Iterator<Relationship> iterator()
{
Iterator<Relationship> iter = super.iterator();
iter.next(); // Skip the first, it is null
return iter;
}
@Override
protected Relationship underlyingObjectToObject( Path position )
{
return position.lastRelationship();
}
};
}
class TraverserIterator extends PrefetchingIterator<Path>
{
final UniquenessFilter uniquness;
private final BranchSelector sourceSelector;
final TraversalDescriptionImpl description;
final Node startNode;
TraverserIterator()
{
PrimitiveTypeFetcher type = PrimitiveTypeFetcher.NODE;
this.description = TraverserImpl.this.description;
switch ( description.uniqueness )
{
case RELATIONSHIP_GLOBAL:
type = PrimitiveTypeFetcher.RELATIONSHIP;
case NODE_GLOBAL:
this.uniquness = new GloballyUnique( type );
break;
case RELATIONSHIP_PATH:
type = PrimitiveTypeFetcher.RELATIONSHIP;
case NODE_PATH:
this.uniquness = new PathUnique( type );
break;
case RELATIONSHIP_RECENT:
type = PrimitiveTypeFetcher.RELATIONSHIP;
case NODE_RECENT:
this.uniquness = new RecentlyUnique( type,
description.uniquenessParameter );
break;
case NONE:
this.uniquness = new NotUnique();
break;
default:
throw new IllegalArgumentException( "Unknown Uniquness "
+ description.uniqueness );
}
this.startNode = TraverserImpl.this.startNode;
this.sourceSelector = description.branchSelector.create(
new StartNodeExpansionSource( this, startNode,
description.expander ) );
}
boolean okToProceed( TraversalBranch source )
{
return this.uniquness.check( source, true );
}
boolean shouldExpandBeyond( TraversalBranch source )
{
return this.uniquness.check( source, false ) &&
!description.pruning.pruneAfter( source.position() );
}
boolean okToReturn( TraversalBranch source )
{
return description.filter.accept( source.position() );
}
@Override
protected Path fetchNextOrNull()
{
TraversalBranch result = null;
while ( true )
{
result = sourceSelector.next();
if ( result == null )
{
break;
}
if ( okToReturn( result ) )
{
break;
}
}
return result != null ? result.position() : null;
}
}
}