/**
 * com.e4graph.Node:
 *
 *	This file contains the Java implementation of a class to wrap
 *	around e4Graph node objects.
 *
 * Copyright (c) 2000-2003, JYL Software Inc.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF
 * JYL SOFTWARE INC. IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.e4graph;

public final class Node
{
    /*
     * Version string:
     */

    private static String version;

    /*
     * Static section to force initialization to happen on first use.
     */

    static {
	version = Storage.version();
    }

    /**
     * This value represents the nodeIndex for an invalid node.
     * See the getIndex() method.
     */
    public static final int INVALID		= -1;

    /**
     * IONONE is one of the acceptable values for an insert order
     * specification, denoting an illegal or meaningless insert order.
     */
    public static final int IONONE		= 0;

    /**
     * IOAT is one of the acceptable values for an insert order
     * specification, denoting the value should be inserted at the
     * specified rank.
     */
    public static final int IOAT		= 1;

    /**
     * IOFIRST is one of the acceptable values for an insert order
     * specification, denoting that the value should be inserted as
     * the (currently) first vertex of this node, before all current vertices.
     */
    public static final int IOFIRST		= 2;

    /**
     * IOLAST is one of the acceptable values for an insert order
     * specification, denoting that the value should be inserted as
     * the (currently) last vertex of this node, after all current vertices.
     */
    public static final int IOLAST		= 3;

    /**
     * IOBEFORE is one of the acceptable values for an insert order
     * specification, denoting that the value should be inserted as
     * the vertex before the specified rank (that is, rank - 1).
     */
    public static final int IOBEFORE		= 4;

    /**
     * IOAFTER is one of the acceptable values for an insert order
     * specification, denoting that the value should be inserted as
     * the vertex after the specified rank (that is, rank + 1).
     */
    public static final int IOAFTER		= 5;

    /*
     * These fields hold the indexes of the node and its storage.
     */

    private int nodeIndex;
    private int storageIndex;
    private int generation;

    /*
     * Constructors are private so can only be used by native code:
     */

    private Node()
    {
	nodeIndex = INVALID;
	storageIndex = INVALID;
	generation = INVALID;
    }
    private Node(int si, int g, int ni)
    {
	nodeIndex = ni;
	generation = g;
	storageIndex = si;
    }

    /**
     * Returns an iterator that iterates over the vertices of this node.
     */

    public VertexIterator getIterator() {
	return new VertexIterator(this);
    }

    /**
     * Returns an iterator that iterates over the vertices of this node
     * that have the given type.
     */

    public VertexIterator getIterator(int type) {
	return new VertexIterator(this, type);
    }

    /**
     * Returns an iterator that iterates over the vertices of this node
     * that have the given name.
     */

    public VertexIterator getIterator(String name) {
	return new VertexIterator(this, name);
    }

    /**
     * Returns an iterator that iterates over the vertices of this node
     * that have the given name and type. The types are defined in
     * Vertex.java.
     */

    public VertexIterator getIterator(String name, int type) {
	return new VertexIterator(this, name, type);
    }

    /**
     * Returns an iterator that iterates over the parents of this node.
     */

    public ParentIterator getParentIterator() {
	return new ParentIterator(this);
    }

    /**
     * Returns the value of the nodeIndex field.
     * This value is used by other classes in the package and is like a
     * unique (within its storage) identifier for this node.
     */
    public int getIndex() {return nodeIndex;}

    /**
     * Returns the value of the storageIndex field.
     * This value uniquely identifies the storage within which this node
     * is contained.
     */
    public int getStorageIndex() {return storageIndex;}

    /**
     * Returns the generation of the storage containing this node.
     */
    public int getGeneration() {return generation;}

    /**
     * Determines whether this node is valid, which is true if neither
     * its nodeIndex nor its storageIndex are the value INVALID.
     */
    public boolean isValid()
    {
	if ((nodeIndex == INVALID) || (storageIndex == INVALID)) {
	    return false;
	}
	return isValid1(nodeIndex, storageIndex, generation);
    }
    private native boolean isValid1(int index, int storageIndex, int gen);

    /**
     * Compares two nodes for equality.
     */
    public boolean equals(Node otherNode)
    {
	if ((nodeIndex == otherNode.nodeIndex) &&
	    (generation == otherNode.generation) &&
	    (storageIndex == otherNode.storageIndex)) {
	    return true;
	}
	return false;
    }

    /**
     * Returns the vertex count for this node.
     */
    public int vertexCount()
    {
	return vertexCount1(nodeIndex, storageIndex, generation);
    }
    private native int vertexCount1(int n, int s, int g);

    /**
     * How many vertices in this node have the given name?
     */
    public int vertexCountWithName(String name)
    {
	return vertexCountWithName1(nodeIndex, storageIndex, generation, name);
    }
    private native int vertexCountWithName1(int n, int s, int g, String name);

    /**
     * How many vertices in this node have the given type?
     */
    public int vertexCountWithType(int type)
    {
	return vertexCountWithType1(nodeIndex, storageIndex, generation, type);
    }
    private native int vertexCountWithType1(int n, int s, int g, int type);

    /**
     * Set the nth vertex with the given name to the integer value i.
     */
    public void setNthVertex(String name, int nth, int i)
	throws NoSuchVertexException
    {
	setIntNthVertex1(nodeIndex, storageIndex, generation, name, nth, i);
    }

    /**
     * Set the nth vertex with the given name to the double value d.
     */
    public void setNthVertex(String name, int nth, double d)
	throws NoSuchVertexException
    {
	setDoubleNthVertex1(nodeIndex, storageIndex, generation, name, nth, d);
    }

    /**
     * Set the nth vertex with the given name to the string value s.
     */
    public void setNthVertex(String name, int nth, String s)
	throws NoSuchVertexException
    {
	setStringNthVertex1(nodeIndex, storageIndex, generation, name, nth, s);
    }

    /**
     * Set the nth vertex with the given name to the binary value bs.
     */
    public void setNthVertex(String name, int nth, byte [] bs)
	throws NoSuchVertexException
    {
	setBytesNthVertex1(nodeIndex, storageIndex, generation, name, nth, bs);
    }

    /**
     * Set the nth vertex with the given name to the node n.
     */
    public void setNthVertex(String name, int nth, Node n)
	throws NoSuchVertexException
    {
	setNodeNthVertex1(nodeIndex, storageIndex, generation, name, nth, 
			  n.nodeIndex, n.storageIndex, n.generation);
    }

    /**
     * Set the nth vertex with the given name to a new node and return
     * the new node as the result.
     */
    public Node setNthNode(String name, int nth)
	throws NoSuchVertexException
    {
	return setNthNodeNode1(nodeIndex, storageIndex, generation, name, nth);
    }

    /*
     * Set the nth vertex with the given name to a given value, private
     * part:
     */

    private native void setIntNthVertex1(int n, int st, int g,
					 String name, int nth, int i)
	throws NoSuchVertexException;
    private native void setDoubleNthVertex1(int n, int st, int g,
					    String name, int nth, double d)
	throws NoSuchVertexException;
    private native void setStringNthVertex1(int n, int st, int g,
					    String name, int nth, String s)
	throws NoSuchVertexException;
    private native void setBytesNthVertex1(int n, int st, int g,
					   String name, int nth, byte [] bytes)
	throws NoSuchVertexException;
    private native void setNodeNthVertex1(int n, int st, int g,
					  String name, int nth,
					  int ni, int nsi, int nsg)
	throws NoSuchVertexException;
    private native Node setNthNodeNode1(int n, int st, int g,
					String name, int nth)
	throws NoSuchVertexException;

    /**
     * Set the first vertex with the given name to the integer value i.
     */
    public void setVertex(String name, int i) throws NoSuchVertexException
    {
	setNthVertex(name, 1, i);
    }

    /**
     * Set the first vertex with the given name to the double value d.
     */
    public void setVertex(String name, double d) 
	throws NoSuchVertexException
    {
	setNthVertex(name, 1, d);
    }

    /**
     * Set the first vertex with the given name to the string value s.
     */
    public void setVertex(String name, String s) 
	throws NoSuchVertexException
    {
	setNthVertex(name, 1, s);
    }

    /**
     * Set the first vertex with the given name to the binary value bytes.
     */
    public void setVertex(String name, byte [] bytes) 
	throws NoSuchVertexException
    {
	setNthVertex(name, 1, bytes);
    }

    /**
     * Set the first vertex with the given name to the node n.
     */
    public void setVertex(String name, Node n) 
	throws NoSuchVertexException
    {
	setNthVertex(name, 1, n);
    }

    /**
     * Set the first vertex with the given name to a new node and return the
     * new node as the result.
     */
    public Node setNode(String name)
	throws NoSuchVertexException
    {
	return setNthNode(name, 1);
    }

    /**
     * Set the vertex with the given rank to the integer value i.
     */
    public void setVertexByRank(int rank, int i)
	throws NoSuchVertexException
    {
	setIntVertexByRank1(nodeIndex, storageIndex, generation, rank, i);
    }

    /**
     * Set the vertex with the given rank to the double value d.
     */
    public void setVertexByRank(int rank, double d)
	throws NoSuchVertexException
    {
	setDoubleVertexByRank1(nodeIndex, storageIndex, generation, rank, d);
    }

    /**
     * Set the vertex with the given rank to the string value s.
     */
    public void setVertexByRank(int rank, String s)
	throws NoSuchVertexException
    {
	setStringVertexByRank1(nodeIndex, storageIndex, generation, rank, s);
    }

    /**
     * Set the vertex with the given rank to the binary value bs.
     */
    public void setVertexByRank(int rank, byte [] bs)
	throws NoSuchVertexException
    {
	setBytesVertexByRank1(nodeIndex, storageIndex, generation, rank, bs);
    }

    /**
     * Set the vertex with the given rank to the node n.
     */
    public void setVertexByRank(int rank, Node n)
	throws NoSuchVertexException
    {
	setNodeVertexByRank1(nodeIndex, storageIndex, generation, rank,
			     n.nodeIndex, n.storageIndex, n.generation);
    }

    /**
     * Set the vertex with the given rank to a new node and return the
     * new node as the result.
     */
    public Node setNodeByRank(int rank)
	throws NoSuchVertexException
    {
	return setNodeByRankNode1(nodeIndex, storageIndex, generation, rank);
    }

    /*
     * Set the value of a vertex identified by its rank, private part:
     */

    private native void setIntVertexByRank1(int n, int st, int g,
					    int rank, int i)
	throws NoSuchVertexException;
    private native void setDoubleVertexByRank1(int n, int st, int g,
					       int rank, double d)
	throws NoSuchVertexException;
    private native void setStringVertexByRank1(int n, int st, int g, 
					       int rank, String s)
	throws NoSuchVertexException;
    private native void setBytesVertexByRank1(int n, int st, int g,
					      int rank, byte [] bytes)
	throws NoSuchVertexException;
    private native void setNodeVertexByRank1(int n, int st, int g, int rank,
					     int ni, int nsi, int nsg)
	throws NoSuchVertexException;
    private native Node setNodeByRankNode1(int n, int st, int g, int rank)
	throws NoSuchVertexException;

    /**
     * Add a new vertex with the given name at the position specified
     * by the insert order io and the given rank, and set its value to the
     * node n.
     */
    public Vertex addVertex(String name, int io, int rank, Node n)
	throws InvalidPositionException
    {
	return addNodeVertex1(nodeIndex, storageIndex, generation,
			      name, io, rank,
			      n.nodeIndex, n.storageIndex, n.generation);
    }

    /**
     * Add a new vertex with the given name at the position specified
     * by the insert order io and the given rank, and set its value to the
     * integer value i.
     */
    public Vertex addVertex(String name, int io, int rank, int i)
	throws InvalidPositionException
    {
	return addIntVertex1(nodeIndex, storageIndex, generation,
			     name, io, rank, i);
    }

    /**
     * Add a new vertex with the given name at the position specified
     * by the insert order io and the given rank, and set its value to the
     * double value d.
     */
    public Vertex addVertex(String name, int io, int rank, double d)
	throws InvalidPositionException
    {
	return addDoubleVertex1(nodeIndex, storageIndex, generation,
				name, io, rank, d);
    }

    /**
     * Add a new vertex with the given name at the position specified
     * by the insert order io and the given rank, and set its value to the
     * string value s.
     */
    public Vertex addVertex(String name, int io, int rank, String s)
	throws InvalidPositionException
    {
	return addStringVertex1(nodeIndex, storageIndex, generation,
				name, io, rank, s);
    }

    /**
     * Add a new vertex with the given name at the position specified
     * by the insert order io and the given rank, and set its value to the
     * binary value bytes.
     */
    public Vertex addVertex(String name, int io, int rank, byte [] bytes)
	throws InvalidPositionException
    {
	return addBytesVertex1(nodeIndex, storageIndex, generation,
			       name, io, rank, bytes);
    }

    /**
     * Add a new vertex with the given name at the position specified
     * by the insert order io and the given rank, and set its value to a new
     * node, and return the new node as the result.
     */
    public Node addNode(String name, int io, int rank)
	throws InvalidPositionException
    {
	return addVertexNode1(nodeIndex, storageIndex, generation,
			      name, io, rank);
    }

    /*
     * Adding a vertex, private part.
     */

    private native Vertex addNodeVertex1(int n, int st, int g,
					 String name, int io, int rank,
					 int ni, int nsi, int nsg)
	throws InvalidPositionException;
    private native Vertex addIntVertex1(int n, int st, int g,
					String name, int io, int rank, int i)
	throws InvalidPositionException;
    private native Vertex addDoubleVertex1(int n, int st, int g,
					   String name, int io,
					   int rank, double d)
	throws InvalidPositionException;
    private native Vertex addStringVertex1(int n, int st, int g,
					   String name, int io,
					   int rank, String s)
	throws InvalidPositionException;
    private native Vertex addBytesVertex1(int n, int st, int g,
					  String name, int io, 
					  int rank, byte [] bs)
	throws InvalidPositionException;
    private native Node addVertexNode1(int n, int st, int g,
				       String name, int io, int rank)
	throws InvalidPositionException;

    /**
     * Move the given vertex to the position specified by the
     * insert order io and the given rank, within this node.
     */
    public void moveVertex(Vertex v, int io, int rank)
	throws InvalidPositionException
    {
	moveVertex1(nodeIndex, storageIndex, generation,
		    v.getIndex(), v.getStorageIndex(), v.getGeneration(),
		    io, rank);
    }
    private native void moveVertex1(int n, int s, int g,
				    int vi, int vsi, int vsg,
				    int io, int rank)
	throws InvalidPositionException;

    /**
     * Retrieve the value of the nth vertex with the given name, which must
     * be of type integer.
     */
    public int getNthInt(String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthInt1(nodeIndex, storageIndex, generation, name, nth);
    }

    /**
     * Retrieve the value of the nth vertex with the given name, which must
     * be of type double.
     */
    public double getNthDouble(String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthDouble1(nodeIndex, storageIndex, generation, name, nth);
    }

    /**
     * Retrieve the value of the nth vertex with the given name, which must
     * be of type String.
     */
    public String getNthString(String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthString1(nodeIndex, storageIndex, generation, name, nth);
    }

    /**
     * Retrieve the value of the nth vertex with the given name, which must
     * be of type binary.
     */
    public byte [] getNthBytes(String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthBytes1(nodeIndex, storageIndex, generation, name, nth);
    }

    /**
     * Retrieve the value of the nth vertex with the given name, which must
     * be of type Node.
     */
    public Node getNthNode(String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthNode1(nodeIndex, storageIndex, generation, name, nth);
    }

    /**
     * This is a general mechanism to retrieve the value of the nth vertex
     * with the given name, without a-priori having to know the type of the
     * value.
     */
    public Value getNthValue(String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthValue1(nodeIndex, storageIndex, generation, name, nth);
    }

    /*
     * Retrieve the value of a vertex, private part:
     */

    private native int getNthInt1(int n, int st, int g, String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException;
    private native double getNthDouble1(int n, int st, int g,
					String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException;
    private native String getNthString1(int n, int st, int g,
					String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException;
    private native byte [] getNthBytes1(int n, int st, int g,
					String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException;
    private native Node getNthNode1(int n, int st, int g, 
				    String name, int nth)
	throws NoSuchVertexException, IncorrectVertexTypeException;
    private native Value getNthValue1(int n, int st, int g,
				      String name, int nth)
	throws NoSuchVertexException;

    /**
     * Retrieve the value of the first vertex with the given name, which
     * must be of type integer.
     */
    public int getInt(String name) 
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthInt(name, 1);
    }

    /**
     * Retrieve the value of the first vertex with the given name, which
     * must be of type double.
     */
    public double getDouble(String name)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthDouble(name, 1);
    }

    /**
     * Retrieve the value of the first vertex with the given name, which
     * must be of type String.
     */
    public String getString(String name)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthString(name, 1);
    }

    /**
     * Retrieve the value of the first vertex with the given name, which
     * must be of type binary.
     */
    public byte [] getBytes(String name)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthBytes(name, 1);
    }

    /**
     * Retrieve the value of the first vertex with the given name, which
     * must be of type Node.
     */
    public Node getNode(String name)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthNode(name, 1);
    }

    /**
     * This is a general mechanism to retrieve the value of the first
     * vertex with the given name without a-priori knowing the type of
     * its value.
     */
    public Value getValue(String name)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNthValue(name, 1);
    }

    /**
     * Retrieve the integer value of the vertex identified by the given
     * rank.
     */
    public int getIntByRank(int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getIntByRank1(nodeIndex, storageIndex, generation, rank);
    }

    /** 
     * Retrieve the double value of the vertex identified by the given
     * rank.
     */
    public double getDoubleByRank(int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getDoubleByRank1(nodeIndex, storageIndex, generation, rank);
    }

    /**
     * Retrieve the String value of the vertex identified by the given
     * rank.
     */
    public String getStringByRank(int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getStringByRank1(nodeIndex, storageIndex, generation, rank);
    }

    /**
     * Retrieve the binary value of the vertex identified by the given
     * rank.
     */
    public byte [] getBytesByRank(int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getBytesByRank1(nodeIndex, storageIndex, generation, rank);
    }

    /**
     * Retrieve the Node value of the vertex identified by the given rank.
     */
    public Node getNodeByRank(int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getNodeByRank1(nodeIndex, storageIndex, generation, rank);
    }

    /**
     * Retreive the value of a vertex identified by rank without a-priori
     * knowing the type of the value.
     */
    public Value getValueByRank(int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException
    {
	return getValueByRank1(nodeIndex, storageIndex, generation, rank);
    }

    /*
     * Get the value of a vertex identified by rank, private part:
     */

    private native int getIntByRank1(int n, int st, int g, int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException;
    private native double getDoubleByRank1(int n, int st, int g, int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException;
    private native String getStringByRank1(int n, int st, int g, int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException;
    private native byte [] getBytesByRank1(int n, int st, int g, int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException;
    private native Node getNodeByRank1(int n, int st, int g, int rank)
	throws NoSuchVertexException, IncorrectVertexTypeException;
    private native Value getValueByRank1(int n, int st, int g, int rank)
	throws NoSuchVertexException;

    /**
     * Obtain a Vertex object for the nth vertex with the given name.
     */
    public Vertex getVertex(String name, int nth)
	throws NoSuchVertexException
    {
	return getVertex1(nodeIndex, storageIndex, generation, name, nth);
    }

    /**
     * Obtain a Vertex object for the first vertex with the given name.
     */
    public Vertex getVertex(String name)
	throws NoSuchVertexException
    {
	return getVertex(name, 1);
    }
    private native Vertex getVertex1(int n, int st, int g,
				     String name, int nth)
	throws NoSuchVertexException;

    /**
     * Obtain a Vertex object for the vertex with the given rank.
     */
    public Vertex getVertexByRank(int rank)
	throws NoSuchVertexException
    {
	return getVertexByRank1(nodeIndex, storageIndex, generation, rank);
    }
    private native Vertex getVertexByRank1(int n, int st, int g, int rank)
	throws NoSuchVertexException;

    /**
     * Obtain the type of the value of the nth vertex with the given name,
     * as defined in class Vertex.
     */
    public int vertexType(String name, int nth)
	throws NoSuchVertexException
    {
	return vertexType1(nodeIndex, storageIndex, generation, name, nth);
    }

    /**
     * Obtain the type of the value of the first vertex with the given name,
     * as defined in class Vertex.
     */
    public int vertexType(String name)
	throws NoSuchVertexException
    {
	return vertexType(name, 1);
    }
    private native int vertexType1(int n, int st, int g, String name, int nth)
	throws NoSuchVertexException;

    /**
     * Obtain the type of the value of the vertex with the given rank,
     * as defined in class Vertex.
     */
    public int vertexTypeByRank(int rank)
	throws NoSuchVertexException
    {
	return vertexTypeByRank1(nodeIndex, storageIndex, generation, rank);
    }
    private native int vertexTypeByRank1(int n, int st, int g, int rank)
	throws NoSuchVertexException;

    /**
     * Obtain the String name of the vertex with the given rank.
     */
    public String vertexName(int rank)
	throws NoSuchVertexException
    {
	return vertexName1(nodeIndex, storageIndex, generation, rank);
    }
    private native String vertexName1(int n, int st, int g, int rank)
	throws NoSuchVertexException;

    /**
     * Rename the vertex with the given rank.
     */
    public void renameVertex(int rank, String newname)
	throws NoSuchVertexException
    {
	renameVertex1(nodeIndex, storageIndex, generation, rank, newname);
    }
    private native void renameVertex1(int n, int st, int g,
				      int rank, String newName)
	throws NoSuchVertexException;
    
    /**
     * Obtain the rank of the first vertex with the given name.
     */
    public int vertexRank(String name)
	throws NoSuchVertexException
    {
	return vertexRank(name, 1);
    }

    /**
     * Obtain the rank of the nth vertex with the given name.
     */
    public int vertexRank(String name, int nth)
	throws NoSuchVertexException
    {
	return vertexRank1(nodeIndex, storageIndex, generation, name, nth);
    }
    private native int vertexRank1(int n, int st, int g, String name, int nth)
	throws NoSuchVertexException;

    /**
     * Does a vertex with the given name exist within this node?
     */
    public boolean exists(String name)
    {
	return exists(name, 1);
    }

    /**
     * Are there at least nth vertices with the given name within this node?
     */
    public boolean exists(String name, int nth)
    {
	return exists1(nodeIndex, storageIndex, generation, name, nth);
    }
    private native boolean exists1(int n, int st, int g, String name, int nth);

    /**
     * Retrieve a Node representing the nth parent node of this node.
     */
    public Node parent(int nth)
	throws NoSuchNodeException
    {
	return parent1(nodeIndex, storageIndex, generation, nth);
    }

    /**
     * Retrieve a Node representing the first parent node of this node.
     */
    public Node parent()
	throws NoSuchNodeException
    {
	return parent(1);
    }
    private native Node parent1(int n, int st, int g, int nth)
	throws NoSuchNodeException;

    /**
     * How many parent nodes does this node have?
     */
    public int parentCount()
    {
	return parentCount1(nodeIndex, storageIndex, generation);
    }
    private native int parentCount1(int n, int st, int g);

    /**
     * How many vertices anywhere within this storage have this node
     * as their value?
     */
    public int occurrenceCount()
    {
	return occurrenceCount1(nodeIndex, storageIndex, generation);
    }
    private native int occurrenceCount1(int n, int st, int g);

    /**
     * How many vertices within the given node have this node as their value?
     */
    public int occurrenceCount(Node n)
    {
	if (n == null) {
	    return 0;
	}
	return nodeOccurrenceCount1(nodeIndex, storageIndex, generation, 
				    n.nodeIndex, n.storageIndex, n.generation);
    }
    private native int nodeOccurrenceCount1(int n, int st, int g,
					    int ni, int nsi, int nsg);

    /**
     * What is the rank of the parent node p in the list of parent nodes for
     * this node?
     */
    public int parentRank(Node p)
    {
	if (p == null) {
	    return INVALID;
	}
	return parentRank1(nodeIndex, storageIndex, generation,
			   p.nodeIndex, p.storageIndex, p.generation);
    }
    private native int parentRank1(int n, int st, int g,
				   int ni, int nsi, int nsg);

    /**
     * Retrieve the rank of the first vertex within the first parent node of
     * this node that has this node as its value.
     */
    public int rankInParent()
    {
	return rankInParent(1);
    }

    /**
     * Retrieve the rank of the first vertex within the nth parent node of this
     * node that has this node as its value.
     */
    public int rankInParent(int nth)
    {
	return rankInParent1(nodeIndex, storageIndex, generation, nth);
    }
    private native int rankInParent1(int n, int st, int g, int nth);


    /**
     * Retrieve the name of the first vertex within the first parent node of
     * this node that has this node as its value.
     */
    public String nameInParent()
    {
	return nameInParent(1);
    }

    /**
     * Retrieve the name of the first vertex within the nth parent node of this
     * node that has this node as its value.
     */
    public String nameInParent(int nth)
    {
	return nameInParent1(nodeIndex, storageIndex, generation, nth);
    }
    private native String nameInParent1(int n, int st, int g, int nth);

    /**
     * Is this node the currently designated root node for its storage?
     */
    public boolean isRoot()
    {
	return isRoot1(nodeIndex, storageIndex, generation);
    }
    private native boolean isRoot1(int n, int st, int g);

    /**
     * Retrieve a Node for the currently designated root node of the storage
     * containing this node.
     */
    public Node getRootNode()
    {
	return getRootNode1(nodeIndex, storageIndex, generation);
    }
    private native Node getRootNode1(int n, int st, int g);

    /**
     * Retrieve a Storage for the storage containing this node.
     */
    public Storage getStorage()
	throws StorageIsNotOpenException
    {
	return Storage.getStorage(storageIndex, generation);
    }

    /**
     * Detach this node, which means ensuring that all vertices that have
     * this node as their value are detached.
     */
    public void detach()
    {
	detach1(nodeIndex, storageIndex, generation);
    }
    private native void detach1(int n, int st, int g);

    /**
     * A node is detached iff all vertices that have this node as their
     * value are themselves detached.
     */
    public boolean isDetached()
    {
	return isDetached1(nodeIndex, storageIndex, generation);
    }
    private native boolean isDetached1(int n, int st, int g);

    /**
     * Retrieve an arbitrary integer value associated by the user program
     * with this node.
     */
    public int getUserData()
    {
	return getUserData1(nodeIndex, storageIndex, generation);
    }
    private native int getUserData1(int n, int st, int g);

    /**
     * User programs can persistently store and associate an arbitrary
     * integer value with this node.
     */
    public void setUserData(int userdata)
    {
	setUserData1(nodeIndex, storageIndex, generation, userdata);
    }
    private native void setUserData1(int n, int st, int g, int userdata);
}
