package org.qi4j.entitystore.neo4j;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.qi4j.api.entity.EntityReference;
import org.qi4j.spi.entity.ManyAssociationState;
public class NeoManyAssociationState
implements ManyAssociationState
{
private static final String INDEX = "index";
static final String COUNT = "count";
private final Node underlyingNode;
private final NeoEntityState entity;
private final NeoEntityStoreUnitOfWork uow;
NeoManyAssociationState( NeoEntityStoreUnitOfWork uow,
NeoEntityState entity, Node node
)
{
this.uow = uow;
this.entity = entity;
this.underlyingNode = node;
}
@Override
public boolean add( int index, EntityReference entityReference )
{
if( index < 0 || index > count() )
{
throw new IllegalArgumentException( "Illegal index: " + index );
}
Node entityNode = uow.getEntityStateNode( entityReference );
for( Relationship rel : underlyingNode.getRelationships(
RelTypes.MANY_ASSOCIATION, Direction.OUTGOING ) )
{
int relIndex = getRelationshipIndex( rel );
if( relIndex >= index )
{
setRelationshipIndex( rel, relIndex + 1 );
}
if( rel.getEndNode().equals( entityNode ) )
{
return false;
}
}
Relationship rel = underlyingNode.createRelationshipTo( entityNode,
RelTypes.MANY_ASSOCIATION );
setRelationshipIndex( rel, index );
incrementCount();
entity.setUpdated();
return true;
}
private int getRelationshipIndex( Relationship rel )
{
return (Integer) rel.getProperty( INDEX );
}
private void setRelationshipIndex( Relationship rel, int newIndex )
{
rel.setProperty( INDEX, newIndex );
}
private void incrementCount()
{
int count = (Integer) underlyingNode.getProperty( "count" );
underlyingNode.setProperty( COUNT, count + 1 );
}
private void decrementCount()
{
int count = (Integer) underlyingNode.getProperty( "count" );
underlyingNode.setProperty( COUNT, --count );
}
@Override
public boolean contains( EntityReference entityReference )
{
Node entityNode = uow.getEntityStateNode( entityReference );
for( Relationship rel : underlyingNode.getRelationships(
RelTypes.MANY_ASSOCIATION, Direction.OUTGOING ) )
{
if( rel.getEndNode().equals( entityNode ) )
{
return true;
}
}
return false;
}
@Override
public int count()
{
return (Integer) underlyingNode.getProperty( COUNT );
}
@Override
public EntityReference get( int index )
{
if( index < 0 || index > count() )
{
throw new IllegalArgumentException( "Illegal index: " + index );
}
for( Relationship rel : underlyingNode.getRelationships(
RelTypes.MANY_ASSOCIATION, Direction.OUTGOING ) )
{
int relIndex = getRelationshipIndex( rel );
if( relIndex == index )
{
String id = (String) rel.getEndNode().getProperty(
NeoEntityState.ENTITY_ID );
return new EntityReference( id );
}
}
return null;
}
@Override
public boolean remove( EntityReference entityReference )
{
Node entityNode = uow.getEntityStateNode( entityReference );
int indexDeleted = -1;
for( Relationship rel : entityNode.getRelationships(
RelTypes.MANY_ASSOCIATION, Direction.INCOMING ) )
{
if( rel.getStartNode().equals( underlyingNode ) )
{
indexDeleted = getRelationshipIndex( rel );
rel.delete();
break;
}
}
if( indexDeleted == -1 )
{
return false;
}
for( Relationship rel : underlyingNode.getRelationships(
RelTypes.MANY_ASSOCIATION, Direction.OUTGOING ) )
{
int relIndex = getRelationshipIndex( rel );
if( relIndex > indexDeleted )
{
setRelationshipIndex( rel, relIndex - 1 );
}
}
decrementCount();
entity.setUpdated();
return true;
}
@Override
public Iterator<EntityReference> iterator()
{
List<EntityReference> list = new ArrayList<EntityReference>( count() );
for( Relationship rel : underlyingNode.getRelationships(
RelTypes.MANY_ASSOCIATION, Direction.OUTGOING ) )
{
String id = (String) rel.getEndNode().getProperty(
NeoEntityState.ENTITY_ID );
list.add( new EntityReference( id ) );
}
return list.iterator();
}
}