/* * 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.HashMap; import java.util.Map; import org.neo4j.commons.iterator.FilteringIterable; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.RelationshipType; public class RelationshipExpander { private final RelationshipType[] types; private final Map<RelationshipType, Direction> directions; private RelationshipExpander( RelationshipType[] types, Direction[] dirs ) { if ( types.length != dirs.length ) { throw new IllegalArgumentException(); } this.types = new RelationshipType[types.length]; this.directions = new HashMap<RelationshipType, Direction>(); for ( int i = 0; i < types.length; i++ ) { this.types[i] = types[i]; this.directions.put( types[i], dirs[i] ); } } public Iterable<Relationship> expand( final Node start ) { if ( types.length == 0 ) { return start.getRelationships(); } if ( types.length == 1 ) { RelationshipType type = types[0]; return start.getRelationships( type, directions.get( type ) ); } return new FilteringIterable<Relationship>( start.getRelationships( types ) ) { @Override protected boolean passes( Relationship item ) { switch ( directions.get( item.getType() ) ) { case INCOMING: return item.getEndNode().equals( start ); case OUTGOING: return item.getStartNode().equals( start ); default: return true; } } }; } private static final RelationshipExpander ALL = new RelationshipExpander( new RelationshipType[0], new Direction[0] ); public static RelationshipExpander all() { return ALL; } public static RelationshipExpander forTypes( RelationshipType type, Direction dir ) { return new RelationshipExpander( new RelationshipType[] { type }, new Direction[] { dir } ); } public static RelationshipExpander forTypes( RelationshipType type1, Direction dir1, RelationshipType type2, Direction dir2 ) { return new RelationshipExpander( new RelationshipType[] { type1, type2 }, new Direction[] { dir1, dir2 } ); } public static RelationshipExpander forTypes( RelationshipType type1, Direction dir1, RelationshipType type2, Direction dir2, Object... more ) { return new RelationshipExpander( extract( RelationshipType[].class, type1, type2, more, false ), extract( Direction[].class, dir1, dir2, more, true ) ); } private static Object[] EMPTY_ARRAY = new Object[0]; private static <T> T[] extract( Class<T[]> type, T obj1, T obj2, Object[] more, boolean odd ) { if ( more.length % 2 != 0 ) { throw new IllegalArgumentException(); } Object[] target = Arrays.copyOf( EMPTY_ARRAY, ( more.length / 2 ) + 2, type ); try { target[0] = obj1; target[1] = obj2; for ( int i = 2; i < target.length; i++ ) { target[i] = more[( i - 2 ) * 2 + ( odd ? 1 : 0 )]; } } catch ( ArrayStoreException cast ) { throw new IllegalArgumentException( cast ); } return type.cast( target ); } }