package lc.mecha.graph;

import java.util.List;

/**
 * The <code>DGNavigator</code> provides methods for navigating a directed graph. Both cyclic and acylic graphs are
 * supported.
 *
 * @author Alex Leigh
 * @since mk11 (ZERO CONTRAST)
 */
public interface DGNavigator {
    String KEY_SEPARATOR = ".";

    /**
     * Return the parent node for this node, or <code>null</code> if the node has no parent. Nodes may only have a
     * single parent, but may have many children.
     */
    DGNode getParent();

    /**
     * For the given child, return the identifier from the perspective of this node. This method will not recurse
     * down the graph; the specified child must be a direct descendant of this node.
     * <p>
     * The identifier is guaranteed to be unique for this node. The identifier is guaranteed to be stable so long
     * as this node is not modified. If the node is modified, the identifiers for its children may also change as
     * a result.
     */
    DGKey getChildIdentifier(DGNode child);

    /**
     * Return the given identifier, from the perspective of the parent, for this node. This requires that this node
     * have a parent. If the node does not, <code>null</code> is returned. If the parent does not claim this node,
     * an <code>IllegalStateException</code> is thrown.
     */
    DGKey getIdentifier();

    /**
     * Set the parent for this node to the given node. If this node is considered a child of the parent, it is a
     * requirement that the <code>getChildIdentifier()</code> method, when called in the parent's navigator,
     * return an identifier for this node.
     * <p>
     * This setter has a special mechanic which requires that the parent for the node be set to null before
     * the parent can be changed. Otherwise, an <code>IllegalStateException</code> will be thrown.
     */
    void setParent(DGNode parent);

    /**
     * Calculate a string path between this node and the destination. If the method encounters a cycle, an
     * <code>IllegalStateException</code> will be thrown. <code>null</code> is an acceptable destination, in which
     * case the method will automatically recurse until the final node's parent is null (the root of a tree).
     * <p>
     * If the method is called on a node who does not have a parent, an empty list is returned.
     * <p>
     * The list reads in the natural order (left to right) of the path, or in other words, descending order.
     */
    List<DGKey> getPath(DGNode destination);

    /**
     * Identical to calling <code>getPath(DGNode destination)</code> with a <code>null</code> argument.
     */
    List<DGKey> getPath();

    String getPortablePath(DGNode destination);

    String getPortablePath();

    String toString(List<DGKey> path);
}
