/*
 * Copyright (c) 2002-2010 "Neo Technology,"
 *     Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j 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.graphdb;


/**
 * A node in the graph with properties and relationships to other entities.
 * Along with {@link Relationship relationships}, nodes are the core building
 * blocks of the Neo4j data representation model. Nodes are created by invoking
 * the {@link GraphDatabaseService#createNode} method.
 * <p>
 * Node has three major groups of operations: operations that deal with
 * relationships, operations that deal with properties (see
 * {@link PropertyContainer}) and operations that create {@link Traverser
 * traversers}.
 * <p>
 * The relationship operations provide a number of overloaded accessors (such as
 * <code>getRelationships(...)</code> with "filters" for type, direction, etc),
 * as well as the factory method {@link #createRelationshipTo
 * createRelationshipTo(...)} that connects two nodes with a relationship. It
 * also includes the convenience method {@link #getSingleRelationship
 * getSingleRelationship(...)} for accessing the commonly occurring
 * one-to-zero-or-one association.
 * <p>
 * The property operations give access to the key-value property pairs. Property
 * keys are always strings. Valid property value types are all the Java
 * primitives (<code>int</code>, <code>byte</code>, <code>float</code>, etc),
 * <code>java.lang.String</code>s and arrays of primitives and Strings.
 * <p>
 * <b>Please note</b> that Neo4j does NOT accept arbitrary objects as property
 * values. {@link #setProperty(String, Object) setProperty()} takes a
 * <code>java.lang.Object</code> only to avoid an explosion of overloaded
 * <code>setProperty()</code> methods. For further documentation see
 * {@link PropertyContainer}.
 * <p>
 * The traversal factory methods instantiate a {@link Traverser traverser} that
 * starts traversing from this node.
 * <p>
 * A node's id is unique, but may not be unique over time since neo4j reuses
 * deleted ids. See <a href="http://wiki.neo4j.org/content/Id_Reuse">
 * wiki.neo4j.org/content/Id_Reuse</a>.
 */
public interface Node extends PropertyContainer
{
    /**
     * Returns the unique id of this node. Ids are garbage collected over time
     * so they are only guaranteed to be unique during a specific time span: if
     * the node is deleted, it's likely that a new node at some point will get
     * the old id. <b>Note</b>: this makes node ids brittle as public APIs.
     *
     * @return the id of this node
     */
    public long getId();

    /**
     * Deletes this node if it has no relationships attached to it. If
     * <code>delete()</code> is invoked on a node with relationships, an
     * unchecked exception will be raised when the transaction is committed.
     * Invoking any methods on this node after <code>delete()</code> has
     * returned is invalid and will lead to unspecified behavior.
     *
     * @throws RuntimeException if this node has relationships attached to it
     */
    public void delete();

    // Relationships

    /**
     * Returns all the relationships attached to this node. If no relationships
     * are attached to this node, an empty iterable will be returned.
     *
     * @return all relationships attached to this node
     */
    public Iterable<Relationship> getRelationships();

    /**
     * Returns <code>true</code> if there are any relationships attached to this
     * node, <code>false</code> otherwise.
     *
     * @return <code>true</code> if there are any relationships attached to this
     *         node, <code>false</code> otherwise
     */
    public boolean hasRelationship();

    /**
     * Returns all the relationships of any of the types in <code>types</code>
     * that are attached to this node, regardless of direction. If no
     * relationships of the given types are attached to this node, an empty
     * iterable will be returned.
     *
     * @param types the given relationship type(s)
     * @return all relationships of the given type(s) that are attached to this
     *         node
     */
    public Iterable<Relationship> getRelationships( RelationshipType... types );

    /**
     * Returns <code>true</code> if there are any relationships of any of the
     * types in <code>types</code> attached to this node (regardless of
     * direction), <code>false</code> otherwise.
     *
     * @param types the given relationship type(s)
     * @return <code>true</code> if there are any relationships of any of the
     *         types in <code>types</code> attached to this node,
     *         <code>false</code> otherwise
     */
    public boolean hasRelationship( RelationshipType... types );

    /**
     * Returns all {@link Direction#OUTGOING OUTGOING} or
     * {@link Direction#INCOMING INCOMING} relationships from this node. If
     * there are no relationships with the given direction attached to this
     * node, an empty iterable will be returned. If {@link Direction#BOTH BOTH}
     * is passed in as a direction, relationships of both directions are
     * returned (effectively turning this into <code>getRelationships()</code>).
     *
     * @param dir the given direction, where <code>Direction.OUTGOING</code>
     *            means all relationships that have this node as
     *            {@link Relationship#getStartNode() start node} and <code>
	 * Direction.INCOMING</code>
     *            means all relationships that have this node as
     *            {@link Relationship#getEndNode() end node}
     * @return all relationships with the given direction that are attached to
     *         this node
     */
    public Iterable<Relationship> getRelationships( Direction dir );

    /**
     * Returns <code>true</code> if there are any relationships in the given
     * direction attached to this node, <code>false</code> otherwise. If
     * {@link Direction#BOTH BOTH} is passed in as a direction, relationships of
     * both directions are matched (effectively turning this into
     * <code>hasRelationships()</code>).
     *
     * @param dir the given direction, where <code>Direction.OUTGOING</code>
     *            means all relationships that have this node as
     *            {@link Relationship#getStartNode() start node} and <code>
	 * Direction.INCOMING</code>
     *            means all relationships that have this node as
     *            {@link Relationship#getEndNode() end node}
     * @return <code>true</code> if there are any relationships in the given
     *         direction attached to this node, <code>false</code> otherwise
     */
    public boolean hasRelationship( Direction dir );

    /**
     * Returns all relationships with the given type and direction that are
     * attached to this node. If there are no matching relationships, an empty
     * iterable will be returned.
     *
     * @param type the given type
     * @param dir the given direction, where <code>Direction.OUTGOING</code>
     *            means all relationships that have this node as
     *            {@link Relationship#getStartNode() start node} and <code>
	 * Direction.INCOMING</code>
     *            means all relationships that have this node as
     *            {@link Relationship#getEndNode() end node}
     * @return all relationships attached to this node that match the given type
     *         and direction
     */
    public Iterable<Relationship> getRelationships( RelationshipType type,
            Direction dir );

    /**
     * Returns <code>true</code> if there are any relationships of the given
     * relationship type and direction attached to this node, <code>false</code>
     * otherwise.
     *
     * @param type the given type
     * @param dir the given direction, where <code>Direction.OUTGOING</code>
     *            means all relationships that have this node as
     *            {@link Relationship#getStartNode() start node} and <code>
	 * Direction.INCOMING</code>
     *            means all relationships that have this node as
     *            {@link Relationship#getEndNode() end node}
     * @return <code>true</code> if there are any relationships of the given
     *         relationship type and direction attached to this node,
     *         <code>false</code> otherwise
     */
    public boolean hasRelationship( RelationshipType type, Direction dir );

    /**
     * Returns the only relationship of a given type and direction that is
     * attached to this node, or <code>null</code>. This is a convenience method
     * that is used in the commonly occuring situation where a node has exactly
     * zero or one relationships of a given type and direction to another node.
     * Typically this invariant is maintained by the rest of the code: if at any
     * time more than one such relationships exist, it is a fatal error that
     * should generate an unchecked exception. This method reflects that
     * semantics and returns either:
     * <p>
     * <ol>
     * <li><code>null</code> if there are zero relationships of the given type
     * and direction,</li>
     * <li>the relationship if there's exactly one, or
     * <li>throws an unchecked exception in all other cases.</li>
     * </ol>
     * <p>
     * This method should be used only in situations with an invariant as
     * described above. In those situations, a "state-checking" method (e.g.
     * <code>hasSingleRelationship(...)</code>) is not required, because this
     * method behaves correctly "out of the box."
     *
     * @param type the type of the wanted relationship
     * @param dir the direction of the wanted relationship (where
     *            <code>Direction.OUTGOING</code> means a relationship that has
     *            this node as {@link Relationship#getStartNode() start node}
     *            and <code>
	 * Direction.INCOMING</code> means a relationship that has
     *            this node as {@link Relationship#getEndNode() end node}) or
     *            {@link Direction#BOTH} if direction is irrelevant
     * @return the single relationship matching the given type and direction if
     *         exactly one such relationship exists, or <code>null</code> if
     *         exactly zero such relationships exists
     * @throws RuntimeException if more than one relationship matches the given
     *             type and direction
     */
    public Relationship getSingleRelationship( RelationshipType type,
            Direction dir );

    /**
     * Creates a relationship between this node and another node. The
     * relationship is of type <code>type</code>. It starts at this node and
     * ends at <code>otherNode</code>.
     * <p>
     * Neo4j doesn't support self-relationships, i.e. relationships where the
     * start node and end node are the same. If <code>otherNode</code> is the
     * same as this node then an exception will be thrown.
     * <p>
     * A relationship is equally well traversed in both directions so there's no
     * need to create another relationship in the opposite direction (in regards
     * to traversal or performance).
     *
     * @param otherNode the end node of the new relationship
     * @param type the type of the new relationship
     * @return the newly created relationship
     */
    public Relationship createRelationshipTo( Node otherNode,
            RelationshipType type );

    /* Expansion, tentatively added - save this for a later refactoring
    Expansion<Relationship> expandAll();

    Expansion<Relationship> expand( RelationshipType type );

    Expansion<Relationship> expand( RelationshipType type, Direction direction );

    Expansion<Relationship> expand( Direction direction );

    Expansion<Relationship> expand( RelationshipExpander expander );
    */

    // Traversal
    /**
     * Instantiates a traverser that will start at this node and traverse
     * according to the given order and evaluators along the specified
     * relationship type and direction. If the traverser should traverse more
     * than one <code>RelationshipType</code>/<code>Direction</code> pair, use
     * one of the overloaded variants of this method. The created traverser will
     * iterate over each node that can be reached from this node by the spanning
     * tree formed by the given relationship types (with direction) exactly
     * once. For more information about traversal, see the {@link Traverser}
     * documentation.
     * 
     * @param traversalOrder the traversal order
     * @param stopEvaluator an evaluator instructing the new traverser about
     *            when to stop traversing, either a predefined evaluator such as
     *            {@link StopEvaluator#END_OF_GRAPH} or a custom-written
     *            evaluator
     * @param returnableEvaluator an evaluator instructing the new traverser
     *            about whether a specific node should be returned from the
     *            traversal, either a predefined evaluator such as
     *            {@link ReturnableEvaluator#ALL} or a customer-written
     *            evaluator
     * @param relationshipType the relationship type that the traverser will
     *            traverse along
     * @param direction the direction in which the relationships of type
     *            <code>relationshipType</code> will be traversed
     * @return a new traverser, configured as above
     */
    /*
     * @deprecated because of an unnatural and too tight coupling with
     * {@link Node}. Also because of the introduction of a new traversal
     * framework. The new way of doing traversals is by creating a
     * new {@link TraversalDescription} from
     * {@link Traversal#description()}, add rules and
     * behaviours to it and then calling
     * {@link TraversalDescription#traverse(Node)}.
     */
    // @Deprecated
    public Traverser traverse( Traverser.Order traversalOrder,
            StopEvaluator stopEvaluator,
            ReturnableEvaluator returnableEvaluator,
            RelationshipType relationshipType, Direction direction );

    /**
     * Instantiates a traverser that will start at this node and traverse
     * according to the given order and evaluators along the two specified
     * relationship type and direction pairs. If the traverser should traverse
     * more than two <code>RelationshipType</code>/<code>Direction</code> pairs,
     * use the overloaded
     * {@link #traverse(Traverser.Order, StopEvaluator, ReturnableEvaluator, Object...)
     * varargs variant} of this method. The created traverser will iterate over
     * each node that can be reached from this node by the spanning tree formed
     * by the given relationship types (with direction) exactly once. For more
     * information about traversal, see the {@link Traverser} documentation.
     * 
     * @param traversalOrder the traversal order
     * @param stopEvaluator an evaluator instructing the new traverser about
     *            when to stop traversing, either a predefined evaluator such as
     *            {@link StopEvaluator#END_OF_GRAPH} or a custom-written
     *            evaluator
     * @param returnableEvaluator an evaluator instructing the new traverser
     *            about whether a specific node should be returned from the
     *            traversal, either a predefined evaluator such as
     *            {@link ReturnableEvaluator#ALL} or a customer-written
     *            evaluator
     * @param firstRelationshipType the first of the two relationship types that
     *            the traverser will traverse along
     * @param firstDirection the direction in which the first relationship type
     *            will be traversed
     * @param secondRelationshipType the second of the two relationship types
     *            that the traverser will traverse along
     * @param secondDirection the direction that the second relationship type
     *            will be traversed
     * @return a new traverser, configured as above
     */
    /*
     * @deprecated because of an unnatural and too tight coupling with
     * {@link Node}. Also because of the introduction of a new traversal
     * framework. The new way of doing traversals is by creating a
     * new {@link TraversalDescription} from
     * {@link Traversal#description()}, add rules and
     * behaviours to it and then calling
     * {@link TraversalDescription#traverse(Node)}.
     */
    // @Deprecated
    // TODO: document the importance of reltype/dir order
    public Traverser traverse( Traverser.Order traversalOrder,
            StopEvaluator stopEvaluator,
            ReturnableEvaluator returnableEvaluator,
            RelationshipType firstRelationshipType, Direction firstDirection,
            RelationshipType secondRelationshipType, Direction secondDirection );

    /**
     * Instantiates a traverser that will start at this node and traverse
     * according to the given order and evaluators along the specified
     * relationship type and direction pairs. Unlike the overloaded variants of
     * this method, the relationship types and directions are passed in as a
     * "varargs" variable-length argument which means that an arbitrary set of
     * relationship type and direction pairs can be specified. The
     * variable-length argument list should be every other relationship type and
     * direction, starting with relationship type, e.g:
     * <p>
     * <code>node.traverse( BREADTH_FIRST, stopEval, returnableEval,
     * MyRels.REL1, Direction.OUTGOING, MyRels.REL2, Direction.OUTGOING,
     * MyRels.REL3, Direction.BOTH, MyRels.REL4, Direction.INCOMING );</code>
     * <p>
     * Unfortunately, the compiler cannot enforce this so an unchecked exception
     * is raised if the variable-length argument has a different constitution.
     * <p>
     * The created traverser will iterate over each node that can be reached
     * from this node by the spanning tree formed by the given relationship
     * types (with direction) exactly once. For more information about
     * traversal, see the {@link Traverser} documentation.
     * 
     * @param traversalOrder the traversal order
     * @param stopEvaluator an evaluator instructing the new traverser about
     *            when to stop traversing, either a predefined evaluator such as
     *            {@link StopEvaluator#END_OF_GRAPH} or a custom-written
     *            evaluator
     * @param returnableEvaluator an evaluator instructing the new traverser
     *            about whether a specific node should be returned from the
     *            traversal, either a predefined evaluator such as
     *            {@link ReturnableEvaluator#ALL} or a customer-written
     *            evaluator
     * @param relationshipTypesAndDirections a variable-length list of
     *            relationship types and their directions, where the first
     *            argument is a relationship type, the second argument the first
     *            type's direction, the third a relationship type, the fourth
     *            its direction, etc
     * @return a new traverser, configured as above
     * @throws RuntimeException if the variable-length relationship type /
     *             direction list is not as described above
     */
    /*
     * @deprecated because of an unnatural and too tight coupling with
     * {@link Node}. Also because of the introduction of a new traversal
     * framework. The new way of doing traversals is by creating a
     * new {@link TraversalDescription} from
     * {@link Traversal#description()}, add rules and
     * behaviours to it and then calling
     * {@link TraversalDescription#traverse(Node)}.
     */
    // @Deprecated
    public Traverser traverse( Traverser.Order traversalOrder,
            StopEvaluator stopEvaluator,
            ReturnableEvaluator returnableEvaluator,
            Object... relationshipTypesAndDirections );
}
