/**
* Copyright (c) 2002-2011 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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.graphdb.traversal.UniquenessFilter;
import org.neo4j.helpers.collection.CombiningIterator;
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();
if ( iter.hasNext() )
{
Relationship first = iter.next();
// If the first position represents the start node, the
// first relationship will be null, in that case skip it.
if ( first == null ) return iter;
// Otherwise re-include it.
return new CombiningIterator<Relationship>( first, iter );
}
else
{
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()
{
this.description = TraverserImpl.this.description;
this.uniquness = description.uniqueness.create( description.uniquenessParameter );
this.startNode = TraverserImpl.this.startNode;
this.sourceSelector = description.branchSelector.create(
new StartNodeTraversalBranch( this, startNode ) );
}
boolean okToProceedFirst( TraversalBranch source )
{
return this.uniquness.checkFirst( source );
}
boolean okToProceed( TraversalBranch source )
{
return this.uniquness.check( source, true );
}
@Override
protected Path fetchNextOrNull()
{
TraversalBranch result = null;
while ( true )
{
result = sourceSelector.next();
if ( result == null )
{
return null;
}
if ( result.evaluation().includes() )
{
return result.position();
}
}
}
}
}