package eu.dnetlib.r2d2.neo4j.dao;

import org.apache.log4j.Logger;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.ReturnableEvaluator;
import org.neo4j.graphdb.StopEvaluator;
import org.neo4j.graphdb.TraversalPosition;
import org.neo4j.graphdb.Traverser;
import org.neo4j.graphdb.Traverser.Order;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import eu.dnetlib.r2d2.neo4j.domain.Neo4jProfile;
import eu.dnetlib.r2d2.neo4j.domain.Relationships;

public class Neo4jProfileDao extends Neo4JDao<Neo4jProfile> implements ProfileDao {
	private Logger logger = Logger.getLogger(Neo4jProfileDao.class);

	public Neo4jProfileDao() {
		super(Relationships._USERS, Relationships._USER, Neo4jProfile.class);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see eu.dnetlib.r2d2.neo4j.BeanManager#createProfile()
	 */
	@Override
	protected Neo4jProfile createBean() {
		return new Neo4jProfile();
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.r2d2.neo4j.dao.GroupDao#getMembers(java.lang.String)
	 * 
	 *      <p>
	 *      It's quite odd that I have to ask the profileDao about the outgoing MEMBER relations keyed by group, it
	 *      sounds "backwards".
	 *      </p>
	 */
	@Override
	public Iterable<Neo4jProfile> getGroupMembers(String groupId) {
		return this.findRelatedNodesOutgoing(groupId, Relationships.MEMBER);
	}

	@Override
	public Iterable<Neo4jProfile> getItemAuthors(String itemId) {
		return this.findRelatedNodesIncoming(itemId, Relationships.AUTHOR);
	}

	@Override
	public void addItemAuthor(String itemId, String userId) {
		this.createRelationship(userId, itemId, Relationships.AUTHOR);
	}

	@Override
	public void removeItemAuthor(String itemId, String userId) {
		this.removeRelationship(userId, itemId, Relationships.AUTHOR);
	}

	@Override
	public Neo4jProfile getReadingListOwner(String rlId) {
		Iterable<Neo4jProfile> users = this.findRelatedNodesIncoming(rlId, Relationships.RL_OWNER);
		
		return Iterables.getOnlyElement(users, null);
	}

	@Override
	public void setReadingListOwner(String rlId, String userId) {
		Iterable<Neo4jProfile> users = this.findRelatedNodesIncoming(rlId, Relationships.RL_OWNER);
		Neo4jProfile currentOwner = Iterables.getOnlyElement(users, null);

		if (currentOwner != null) {
			logger.debug("Removing current owner (" + currentOwner.getId() + ")");

			this.removeRelationship(userId, rlId, Relationships.RL_OWNER);
		}

		if (userId != null)
			this.createRelationship(userId, rlId, Relationships.RL_OWNER);
	}
	
	@Override
	public Iterable<Neo4jProfile> getUsersSharingInformationObject(String ioId) {
		Node ioNode = this.getNode(ioId);
		if(ioNode == null)
			return Lists.newArrayList();
		
		@SuppressWarnings("deprecation")
		Traverser tr = ioNode.traverse(
				Order.DEPTH_FIRST, StopEvaluator.END_OF_GRAPH,
				new ReturnableEvaluator() {
					public boolean isReturnableNode(TraversalPosition pos) {
						return pos.currentNode().getProperty("eu.dnetlib.r2d2.neo4j.domain.Neo4jProfile.name", null) != null;
					}
				}, 
				Relationships.IO_ENTRY,	Direction.OUTGOING, 
				Relationships.ENTRY,	Direction.OUTGOING, 
				Relationships.USER_MVL, Direction.INCOMING);
		
		return new BeanIterable(tr);
	}
	
}
