All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.interedition.collatex.suffixtree.Node Maven / Gradle / Ivy

package eu.interedition.collatex.suffixtree;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @param 
 * @param 
 * @author Max Garfinkel
 */
class Node> implements Iterable> {
    private final Map> edges = new HashMap>();
    private final Edge incomingEdge;
    private Set> sequenceTerminals = new HashSet>();
    private final Sequence sequence;
    private final SuffixTree tree;
    private Node link = null;

    /**
     * Create a new node, for the supplied tree and sequence.
     *
     * @param incomingEdge The parent edge, unless this is a root node.
     * @param sequence     The sequence this tree is indexing.
     * @param tree         The tree to which this node belongs.
     */
    Node(Edge incomingEdge, Sequence sequence, SuffixTree tree) {
        this.incomingEdge = incomingEdge;
        this.sequence = sequence;
        this.tree = tree;
    }

    /**
     * Inserts the suffix at the given active point.
     *
     * @param suffix      The suffix to insert.
     * @param activePoint The active point to insert it at.
     */
    @SuppressWarnings("unchecked")
    void insert(Suffix suffix, ActivePoint activePoint) {
        Object item = suffix.getEndItem();

        if (edges.containsKey(item)) {
            if (tree.isNotFirstInsert() && activePoint.getNode() != tree.getRoot())
                tree.setSuffixLink(activePoint.getNode());
            activePoint.setEdge(edges.get(item));
            activePoint.incrementLength();
        } else {
            saveSequenceTerminal(item);
            Edge newEdge = new Edge(suffix.getEndPosition() - 1, this,
                sequence, tree);
            edges.put((T) suffix.getEndItem(), newEdge);
            suffix.decrement();
            activePoint.updateAfterInsert(suffix);

            if (tree.isNotFirstInsert() && !this.equals(tree.getRoot())) {
                tree.getLastNodeInserted().setSuffixLink(this);
            }
            if (suffix.isEmpty())
                return;
            else
                tree.insert(suffix);
        }
    }

    private void saveSequenceTerminal(Object item) {
        if (item.getClass().equals(SequenceTerminal.class)) {
            @SuppressWarnings("unchecked")
            SequenceTerminal terminal = (SequenceTerminal) item;
            sequenceTerminals.add(terminal);
        }
    }

    /**
     * Inserts the given edge as a child of this node. The edge must not already
     * exist as child or an IllegalArgumentException will be thrown.
     *
     * @param edge The edge to be inserted.
     * @throws IllegalArgumentException This is thrown when the edge already exists as an out bound
     *                                  edge of this node.
     */
    void insert(Edge edge) {
        if (edges.containsKey(edge.getStartItem()))
            throw new IllegalArgumentException("Item " + edge.getStartItem()
                + " already exists in node " + toString());
        edges.put(edge.getStartItem(), edge);
    }

    /**
     * Retrieves the edge starting with item or null if none exists.
     *
     * @param item
     * @return The edge extending from this node starting with item.
     */
    Edge getEdgeStarting(Object item) {
        return edges.get(item);
    }

    /**
     * True if the node has a suffix link extending from it.
     *
     * @return True if node has suffix link. False if not.
     */
    boolean hasSuffixLink() {
        return link != null;
    }

    /**
     * Gets the number of edges extending from this node.
     *
     * @return The count of the number edges extending from this node.
     */
    int getEdgeCount() {
        return edges.size();
    }

    /**
     * @return An iterator which iterates over the child edges. No order is
     * guaranteed.
     */
    public Iterator> iterator() {
        return edges.values().iterator();
    }

    /**
     * @return The node that this nodes suffix link points to if it has one.
     * Null if not.
     */
    Node getSuffixLink() {
        return link;
    }

    /**
     * Sets the suffix link of this node to point to the supplied node.
     *
     * @param node The node this suffix link should point to.
     */
    void setSuffixLink(Node node) {
        link = node;
    }

    @Override
    public String toString() {
        if (incomingEdge == null)
            return "root";
        else {
            return "end of edge [" + incomingEdge.toString() + "]";
        }
    }

    public Collection> getSuffixTerminals() {
        return sequenceTerminals;
    }

    public Collection> getEdges() {
        return edges.values();
    }
}