/*
* Copyright 2010 Network Engine for Objects in Lund AB [neotechnology.com]
*
* This program 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.graphalgo.competition.tobias;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.neo4j.graphalgo.competition.Path;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
final class PathType implements Path
{
public static final class PathBuilder
{
private final PathBuilder previous;
private final Node start;
private final Relationship relationship;
private final int size;
public PathBuilder( Node start )
{
if ( start == null )
{
throw new NullPointerException();
}
this.start = start;
this.previous = null;
this.relationship = null;
this.size = 0;
}
private PathBuilder( PathBuilder prev, Relationship rel )
{
this.start = prev.start;
this.previous = prev;
this.relationship = rel;
this.size = prev.size + 1;
}
public Node getStartNode()
{
return start;
}
public Path build()
{
return new PathType( this, null );
}
public PathBuilder push(
@SuppressWarnings( "hiding" ) Relationship relationship )
{
if ( relationship == null )
{
throw new NullPointerException();
}
return new PathBuilder( this, relationship );
}
public Path build( PathBuilder other )
{
return new PathType( this, other );
}
@Override
public String toString()
{
if ( previous == null )
{
return start.toString();
}
else
{
return relToString( relationship ) + ":" + previous.toString();
}
}
}
private static String relToString( Relationship rel )
{
return rel.getStartNode() + "--" + rel.getType() + "-->"
+ rel.getEndNode();
}
private final Node start;
private final Relationship[] path;
private PathType( PathBuilder left, PathBuilder right )
{
path = new Relationship[left.size + ( right == null ? 0 : right.size )];
if ( right != null )
{
for ( int i = left.size, total = i + right.size; i < total; i++ )
{
path[i] = right.relationship;
right = right.previous;
}
assert right.relationship == null : "right Path.Builder size error";
}
for ( int i = left.size - 1; i >= 0; i-- )
{
path[i] = left.relationship;
left = left.previous;
}
assert left.relationship == null : "left Path.Builder size error";
start = left.start;
}
public static Path singular( Node start )
{
return new PathBuilder( start ).build();
}
public Node getStartNode()
{
return start;
}
public Node getEndNode()
{
// TODO Auto-generated method stub
return null;
}
public Iterable<Node> getNodes()
{
return new Iterable<Node>()
{
public Iterator<Node> iterator()
{
return new Iterator<Node>()
{
Node current = start;
int index = 0;
public boolean hasNext()
{
return index <= path.length;
}
public Node next()
{
if ( current == null )
{
throw new NoSuchElementException();
}
Node next = null;
if ( index < path.length )
{
next = path[index].getOtherNode( current );
}
index += 1;
try
{
return current;
}
finally
{
current = next;
}
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
};
}
public Iterable<Relationship> getRelationships()
{
return Collections.unmodifiableCollection( Arrays.asList( path ) );
}
public int length()
{
return path.length;
}
@Override
public String toString()
{
Node current = start;
StringBuilder result = new StringBuilder();
for ( Relationship rel : path )
{
result.append( current );
String prefix = "--", suffix = "--";
if ( current.equals( rel.getEndNode() ) )
prefix = "<--";
else
suffix = "-->";
result.append( prefix );
result.append( rel.getType() );
result.append( ".[" );
result.append( rel.getId() );
result.append( "]" );
result.append( suffix );
current = rel.getOtherNode( current );
}
result.append( current );
return result.toString();
}
}