/*
 * com.e4graph.Vertex:
 *
 *	This file contains the Java implementation of a class to wrap
 *	around e4Graph vertex 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 Vertex
{
    /*
     * Version string:
     */

    private static String version;

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

    static {
	version = Storage.version();
    }

    /**
     * This value represents the vertexIndex for an invalid vertex.
     */
    public static final int INVALID		= -1;

    /**
     * ILLEGAL is a possible value for the type of the value of a vertex,
     * denoting an illegal value type.
     */
    public static final int ILLEGAL		= -1;

    /**
     * NODE is a possible value for the type of the value of a vertex,
     * denoting a value of type com.e4graph.Node.
     */
    public static final int NODE		= 0;

    /**
     * INTEGER is a possible value for the type of the value of a vertex,
     * denoting an integer value type.
     */
    public static final int INTEGER		= 1;

    /**
     * DOUBLE is a possible value for the type of the value of a vertex,
     * denoting a double (64 bit floating point) value.
     */
    public static final int DOUBLE		= 2;

    /**
     * STRING is a possible value for the type of the value of a vertex,
     * denoting a java.lang.String value.
     */
    public static final int STRING		= 3;

    /**
     * BYTES is a possible value for the type of the value of a vertex,
     * denoting a value of type array of byte.
     */
    public static final int BYTES		= 4;

    /*
     * These fields holds the index of the vertex and storage objects.
     */

    private int vertexIndex;
    private int storageIndex;
    private int generation;

    /**
     * Retrieve the vertexIndex field for this vertex, which is a unique
     * (within its storage) value identifying its underlying e4Graph vertex.
     */
    public int getIndex() {return vertexIndex;}

    /**
     * Retrieve the storageIndex field for this vertex, which is a unique
     * value identifying the storage containing this vertex.
     */
    public int getStorageIndex() {return storageIndex;}

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

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

    private Vertex()
    {
	vertexIndex = INVALID;
	storageIndex = INVALID;
	generation = INVALID;
    }
    private Vertex(int si, int g, int vi)
    {
	vertexIndex = vi;
	storageIndex = si;
	generation = g;
    }

    /**
     * A vertex is valid if neither its vertexIndex and storageIndex are
     * the constant value INVALID, and the underlying e4Graph vertex is
     * valid.
     */
    public boolean isValid()
    {
	if ((vertexIndex == INVALID) || (storageIndex == INVALID)) {
	    return false;
	}
	return isValid1(vertexIndex, storageIndex, generation);
    }
    private native boolean isValid1(int v, int st, int g);

    /**
     * Retrieve the integer value of this vertex.
     */
    public int getInt()
	throws IncorrectVertexTypeException
    {
	return getInt1(vertexIndex, storageIndex, generation);
    }

    /**
     * Retrieve the double (64 bit floating point) value of this vertex.
     */
    public double getDouble()
	throws IncorrectVertexTypeException
    {
	return getDouble1(vertexIndex, storageIndex, generation);
    }

    /**
     * Retrieve the String value of this vertex.
     */
    public String getString()
	throws IncorrectVertexTypeException
    {
	return getString1(vertexIndex, storageIndex, generation);
    }

    /**
     * Retrieve the binary value of this vertex.
     */
    public byte [] getBytes()
	throws IncorrectVertexTypeException
    {
	return getBytes1(vertexIndex, storageIndex, generation);
    }

    /**
     * Retrieve the Node value of this vertex.
     */
    public Node getNode()
	throws IncorrectVertexTypeException
    {
	return getNode1(vertexIndex, storageIndex, generation);
    }

    /**
     * Retrieve the value of this vertex without a-priori knowing
     * the type of the value.
     */
    public Value getValue()
	throws IncorrectVertexTypeException
    {
	return getValue1(vertexIndex, storageIndex, generation);
    }

    /*
     * Retrieve the value of this vertex, private part.
     */

    private native int getInt1(int v, int st, int g)
	throws IncorrectVertexTypeException;
    private native double getDouble1(int v, int st, int g)
	throws IncorrectVertexTypeException;
    private native String getString1(int v, int st, int g)
	throws IncorrectVertexTypeException;
    private native byte [] getBytes1(int v, int st, int g)
	throws IncorrectVertexTypeException;
    private native Node getNode1(int v, int st, int g)
	throws IncorrectVertexTypeException;
    private native Value getValue1(int v, int st, int g);

    /**
     * Set the value of this vertex to the integer value v.
     */
    public void set(int v)
    {
	setInt1(vertexIndex, storageIndex, generation, v);
    }

    /**
     * Set the value of this vertex to the double (64 bit floatin
     * point) value d.
     */
    public void set(double d)
    {
	setDouble1(vertexIndex, storageIndex, generation, d);
    }

    /**
     * Set the value of this vertex to the String s.
     */
    public void set(String s)
    {
	setString1(vertexIndex, storageIndex, generation, s);
    }

    /**
     * Set the value of this vertex to the binary value bs.
     */
    public void set(byte [] bs)
    {
	setBytes1(vertexIndex, storageIndex, generation, bs);
    }

    /**
     * Set the value of this vertex to the Node n.
     */
    public void set(Node n)
    {
	setNode1(vertexIndex, storageIndex, generation,
		 n.getIndex(), n.getStorageIndex(), n.getGeneration());
    }

    /**
     * Set the value of this vertex to a new node and return the Node
     * object representing the new node.
     */
    public Node setNode()
    {
	return setVertexNode1(vertexIndex, storageIndex, generation);
    }

    /*
     * Set the value of this vertex.
     */

    private native void setInt1(int v, int st, int g, int i);
    private native void setDouble1(int v, int st, int g, double d);
    private native void setString1(int v, int st, int g, String s);
    private native void setBytes1(int v, int st, int g, byte [] bs);
    private native void setNode1(int v, int st, int g,
				 int ni, int nsi, int nsg);
    private native Node setVertexNode1(int v, int st, int g);

    /**
     * Retrieve the rank of this vertex in the node in which it appears.
     */
    public int rank()
    {
	return rank1(vertexIndex, storageIndex, generation);
    }
    private native int rank1(int v, int st, int g);

    /**
     * Detach this vertex from the node (if any) in which it appears.
     */
    public void detach()
    {
	detach1(vertexIndex, storageIndex, generation);
    }
    private native void detach1(int v, int st, int g);

    /**
     * A vertex is detached if it is not contained in any node.
     */
    public boolean isDetached()
    {
	return isDetached1(vertexIndex, storageIndex, generation);
    }
    private native boolean isDetached1(int v, int st, int g);

    /**
     * Retrieve the type of the value of this vertex.
     */
    public int type()
    {
	return type1(vertexIndex, storageIndex, generation);
    }
    private native int type1(int v, int st, int g);

    /**
     * Retrieve the name of this vertex.
     */
    public String name()
    {
	return name1(vertexIndex, storageIndex, generation);
    }
    private native String name1(int v, int st, int g);

    /**
     * Rename this vertex to another name.
     */
    public String rename(String newname)
    {
	return rename1(vertexIndex, storageIndex, generation, newname);
    }
    private native String rename1(int v, int st, int g, String newname);

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

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

    /**
     * Retrieve the node in which this vertex appears, or null if the
     * vertex is detached.
     */
    public Node containingNode()
    {
	return containingNode1(vertexIndex, storageIndex, generation);
    }	
    private native Node containingNode1(int v, int st, int g);

    /**
     * Move the given vertex to the position specified by the insert order
     * io and the given offset relative to this vertex, in the node containing
     * this vertex.
     */
    public void moveVertex(Vertex v, int io, int offset)
	throws InvalidPositionException
    {
	moveVertex1(vertexIndex, storageIndex, generation,
		    v.vertexIndex, v.storageIndex, v.generation,
		    io, offset);
    }
    private native void moveVertex1(int v, int st, int g,
				    int vi, int vsi, int vsg,
				    int io, int offset)
	throws InvalidPositionException;

    /**
     * Retrieve the next vertex after this one in the node containing this
     * vertex, or null if there's none or if this vertex is detached.
     */
    public Vertex next(int n)
	throws NoSuchVertexException
    {
	return next1(vertexIndex, storageIndex, generation, n);
    }

    /**
     * Retrieve the previous vertex before this one in the node containing
     * this vertex, or null if there's none or if this vertex is detached.
     */
    public Vertex prev(int n)
	throws NoSuchVertexException
    {
	return prev1(vertexIndex, storageIndex, generation, n);
    }

    private native Vertex next1(int v, int st, int g, int n)
	throws NoSuchVertexException;
    private native Vertex prev1(int v, int st, int g, int n)
	throws NoSuchVertexException;

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

    /**
     * Persistently associate an arbitrary integer value with this vertex.
     */
    public void setUserData(int userData)
    {
	setUserData1(vertexIndex, storageIndex, generation, userData);
    }
    private native void setUserData1(int v, int st, int g, int userData);
}
