package org.neo4j.tutor.security;

import org.neo4j.api.core.Direction;
import org.neo4j.api.core.Node;
import org.neo4j.api.core.Relationship;
import org.neo4j.api.core.ReturnableEvaluator;
import org.neo4j.api.core.StopEvaluator;
import org.neo4j.api.core.TraversalPosition;
import org.neo4j.api.core.Traverser;
import org.neo4j.api.core.Traverser.Order;
import org.neo4j.impl.event.Event;
import org.neo4j.impl.event.EventData;

public class SecurityMgr4 extends AbstractSecurityMgr
{
	public boolean proActiveEventReceived( Event event, EventData data )
	{
		if ( event == SecurityEvent.ACCESS )
		{
			Node file = (Node) data.getData();
			Node user = AuthorizationService.getCurrentUser();
			// --- TODO
			// --- Make security hierarchical
			// --- Access granted by ACCESS relationship to a user or a group
			// --- that user is member of via the MEMBER_OF relationship
			// --- If no ACCESS relationship exist on the file or any of the 
			// --- files parents access is granted
			// --- else If no user registered (null user), access is denied
			// --- else traverser must find ACCESS relationship connected 
			// --- to user or any group the user is member of
			MyReturnableEvaluator retEval = new MyReturnableEvaluator( user );
			Traverser trav = file.traverse( Order.DEPTH_FIRST, 
				StopEvaluator.END_OF_NETWORK, retEval, 
				MyRelationshipTypes.ACCESS, Direction.OUTGOING, 
				MyRelationshipTypes.MEMBER_OF, Direction.INCOMING,
				MyRelationshipTypes.FILE, Direction.INCOMING );
			if ( trav.iterator().hasNext() )
			{
				return true;
			}
			if ( !retEval.foundAccessRelationship() )
			{
				return true;
			}
			return false;
		}
		// we shouldn't get any other events but returning true by default 
		return true;
	}
	
	private static class MyReturnableEvaluator implements ReturnableEvaluator
	{
		private boolean accessRelFound = false;
		private Node userToFind;
		
		public MyReturnableEvaluator( Node userToFind )
		{
			this.userToFind = userToFind;
		}
		
		public boolean foundAccessRelationship()
		{
			return accessRelFound;
		}
		
		public boolean isReturnableNode( TraversalPosition currentPosition )
		{
			Relationship lastRel = currentPosition.lastRelationshipTraversed();
			if ( lastRel != null && lastRel.getType().equals(  
				MyRelationshipTypes.ACCESS ) )
			{
				accessRelFound = true;
			}
			return currentPosition.currentNode().equals( userToFind );
		}
	}
}
