/*
 * com_e4graph_Vertex.cpp --
 *
 *	This file contains implementations of the natives of the
 *	class com.e4graph.Vertex.
 *
 * 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.
 */

#include "e4graph.h"
#include "j4graph.h"

/*
 * Indicate whether this vertex is valid.
 */

JNIEXPORT jboolean JNICALL
Java_com_e4graph_Vertex_isValid1(JNIEnv *envp, jobject me, jint v, jint st,
				 jint g)
{
    e4_Storage s;
    e4_Vertex vv;
    e4_VertexUniqueID vuid;

    if (!GetValidStorage(envp, st, g, s)) {
	envp->ExceptionClear();
	return JNI_FALSE;
    }

    vuid.SetID(v);
    vuid.SetSP(s.GetTemporaryUID());

    if (s.GetVertexFromID(vuid, vv)) {
	return JNI_TRUE;
    }
    return JNI_FALSE;
}

JNIEXPORT jint JNICALL
Java_com_e4graph_Vertex_getInt1(JNIEnv *envp, jobject me,
				jint v, jint st, jint g)
{
    e4_Vertex vv;
    int i;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return 0;
    }
    if (!vv.Get(i)) {
	envp->ThrowNew(clsIncorrectVertexTypeException, vv.Name());
	return 0;
    }
    return i;
}

JNIEXPORT jdouble JNICALL
Java_com_e4graph_Vertex_getDouble1(JNIEnv *envp, jobject me,
				   jint v, jint st, jint g)
{
    e4_Vertex vv;
    double d;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return 0.0;
    }
    if (!vv.Get(d)) {
	envp->ThrowNew(clsIncorrectVertexTypeException, vv.Name());
	return 0.0;
    }
    return d;
}

JNIEXPORT jstring JNICALL
Java_com_e4graph_Vertex_getString1(JNIEnv *envp, jobject me,
				   jint v, jint st, jint g)
{
    e4_Vertex vv;
    const char *s;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return NULL;
    }
    if (!vv.Get(s)) {
	envp->ThrowNew(clsIncorrectVertexTypeException, vv.Name());
	return NULL;
    }
    return envp->NewStringUTF(s);
}

JNIEXPORT jbyteArray JNICALL
Java_com_e4graph_Vertex_getBytes1(JNIEnv *envp, jobject me,
				  jint v, jint st, jint g)
{
    e4_Vertex vv;
    const void *bytes;
    int len;
    jbyteArray ba;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return NULL;
    }
    if (!vv.Get(bytes, len)) {
	envp->ThrowNew(clsIncorrectVertexTypeException, vv.Name());
	return NULL;
    }
    ba = envp->NewByteArray(len);
    envp->SetByteArrayRegion(ba, 0, len, (jbyte *) bytes);

    return ba;
}

JNIEXPORT jobject JNICALL
Java_com_e4graph_Vertex_getNode1(JNIEnv *envp, jobject me,
				 jint v, jint st, jint g)
{
    e4_Vertex vv;
    e4_Node n;
    e4_NodeUniqueID nuid;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return NULL;
    }
    if (!vv.Get(n) || !n.IsValid()) {
	envp->ThrowNew(clsIncorrectVertexTypeException, vv.Name());
	return NULL;
    }
    (void) n.GetUniqueID(nuid);
    return envp->NewObject(clsNode, nodeCMID, st,
			   g, nuid.GetUniqueID());
}

JNIEXPORT jobject JNICALL
Java_com_e4graph_Vertex_getValue1(JNIEnv *envp, jobject me,
				  jint v, jint st, jint g)
{
    e4_Vertex vv;
    e4_Value val;
    jobject vobj;
    jbyteArray jbytes;
    e4_NodeUniqueID nuid;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return NULL;
    }
    if (!vv.Get(val)) {
	envp->ThrowNew(clsIncorrectVertexTypeException, vv.Name());
	return NULL;
    }

    vobj = envp->NewObject(clsValue, valueCMID);

    switch (val.vertexType) {
    case E4_VTLASTVERTEXTYPE:
    case E4_VTUNKNOWN:
	envp->SetIntField(vobj, typeID, E4_VTUNKNOWN);	/* ILLEGAL */
	break;
    case E4_VTNODE:
	envp->SetIntField(vobj, typeID, E4_VTNODE);	/* NODE */
	(void) val.n.GetUniqueID(nuid);
	envp->SetObjectField(vobj, 
			     nodeValueID,
			     envp->NewObject(clsNode, nodeCMID, st, 
					     g, nuid.GetUniqueID()));
	break;
    case E4_VTINT:
	envp->SetIntField(vobj, typeID, E4_VTINT);	/* INTEGER */
	envp->SetIntField(vobj, integerValueID, val.u.i);
	break;
    case E4_VTDOUBLE:
	envp->SetIntField(vobj, typeID, E4_VTDOUBLE);	/* DOUBLE */
	envp->SetDoubleField(vobj, doubleValueID, val.u.d);
	break;
    case E4_VTSTRING:
	envp->SetIntField(vobj, typeID, E4_VTSTRING);	/* STRING */
	envp->SetObjectField(vobj,
			     stringValueID,
			     envp->NewStringUTF(val.u.s));
	break;
    case E4_VTBINARY:
	envp->SetIntField(vobj, typeID, E4_VTBINARY);	/* BYTES */
	jbytes = envp->NewByteArray(val.u.b.nbytes);
	if (jbytes == NULL) {
	    return NULL;
	}
	envp->SetByteArrayRegion(jbytes, 0, val.u.b.nbytes,
				 (jbyte *) val.u.b.bytes);
	envp->SetObjectField(vobj, bytesValueID, jbytes);
	break;
    }

    return vobj;
}

JNIEXPORT void JNICALL
Java_com_e4graph_Vertex_setInt1(JNIEnv *envp, jobject me, jint v,
				jint st, jint g, jint i)
{
    e4_Vertex vv;

    if (GetValidVertex(envp, st, g, v, vv)) {
	vv.Set((int) i);
    }
}

JNIEXPORT void JNICALL
Java_com_e4graph_Vertex_setDouble1(JNIEnv *envp, jobject me, jint v,
				   jint st, jint g, jdouble d)
{
    e4_Vertex vv;

    if (GetValidVertex(envp, st, g, v, vv)) {
	vv.Set(d);
    }
}

JNIEXPORT void JNICALL
Java_com_e4graph_Vertex_setString1(JNIEnv *envp, jobject me, jint v,
				   jint st, jint g, jstring s)
{
    e4_Vertex vv;
    jboolean copy;
    const char *schars;

    if (GetValidVertex(envp, st, g, v, vv)) {
	schars = envp->GetStringUTFChars(s, &copy);
	vv.Set(schars);
	if (copy) {
	    envp->ReleaseStringUTFChars(s, schars);
	}
    }
}

JNIEXPORT void JNICALL
Java_com_e4graph_Vertex_setBytes1(JNIEnv *envp, jobject me, jint v,
				  jint st, jint g, jbyteArray jbytes)
{
    e4_Vertex vv;
    jbyte *thebytes;
    jboolean bcopy;
    int len;

    if (GetValidVertex(envp, st, g, v, vv)) {
	thebytes = envp->GetByteArrayElements(jbytes, &bcopy);
	len = envp->GetArrayLength(jbytes);
	vv.Set((const void *) thebytes, len);
	if (bcopy) {
	    envp->ReleaseByteArrayElements(jbytes, thebytes, 0);
	}
    }
}

JNIEXPORT void JNICALL
Java_com_e4graph_Vertex_setNode1(JNIEnv *envp, jobject me, jint v,
				 jint st, jint g,
				 jint ni, jint nst)
{
    e4_Storage s;
    e4_Vertex vv;
    e4_Node n;
    e4_VertexUniqueID vuid;
    e4_NodeUniqueID nuid;

    if (st != nst) {
	envp->ThrowNew(clsNoSuchNodeException,
		       "node not in same storage as this vertex");
	return;
    }
    if (!GetValidStorage(envp, st, g, s)) {
	return;
    }
    vuid.SetID(v);
    vuid.SetSP(s.GetTemporaryUID());

    if (!s.GetVertexFromID(vuid, vv)) {
	envp->ThrowNew(clsNoSuchVertexException, "invalid vertex ID");
	return;
    }

    nuid.SetID(ni);
    nuid.SetSP(s.GetTemporaryUID());

    if (!s.GetNodeFromID(nuid, n)) {
	envp->ThrowNew(clsNoSuchNodeException, "invalid node ID");
	return;
    }
    vv.Set(n);
}

JNIEXPORT jobject JNICALL
Java_com_e4graph_Vertex_setVertexNode1(JNIEnv *envp, jobject me, jint v,
				       jint st, jint g)
{
    e4_Vertex vv;
    e4_Node n;
    e4_NodeUniqueID nuid;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return NULL;
    }
    vv.SetNode(n);
    if (!n.IsValid()) {
	envp->ThrowNew(clsNoSuchNodeException, "new node not created");
	return NULL;
    }
    (void) n.GetUniqueID(nuid);
    return envp->NewObject(clsNode, nodeCMID, st,
			   g, nuid.GetUniqueID());
}

JNIEXPORT jint JNICALL
Java_com_e4graph_Vertex_rank1(JNIEnv *envp, jobject me, jint v,
			      jint st, jint g)
{
    e4_Vertex vv;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return -1;
    }
    return vv.Rank();
}

JNIEXPORT void JNICALL
Java_com_e4graph_Vertex_detach1(JNIEnv *envp, jobject me, jint v,
				jint st, jint g)
{
    e4_Vertex vv;

    if (GetValidVertex(envp, st, g, v, vv)) {
	vv.Detach();
    }
}

JNIEXPORT jboolean JNICALL
Java_com_e4graph_Vertex_isDetached1(JNIEnv *envp, jobject me, jint v,
				    jint st, jint g)
{
    e4_Vertex vv;

    if (GetValidVertex(envp, st, g, v, vv)) {
	return (vv.IsDetached()) ? JNI_TRUE : JNI_FALSE;
    }
    return JNI_FALSE;
}

JNIEXPORT jint JNICALL
Java_com_e4graph_Vertex_type1(JNIEnv *envp, jobject me, jint v,
			      jint st, jint g)
{
    e4_Vertex vv;

    if (GetValidVertex(envp, st, g, v, vv)) {
	switch (vv.Type()) {
	case E4_VTUNKNOWN:
	case E4_VTLASTVERTEXTYPE:
	    return -1;		/* ILLEGAL */
	case E4_VTNODE:
	    return 4;		/* NODE */
	case E4_VTINT:
	    return 0;		/* INTEGER */
	case E4_VTDOUBLE:
	    return 1;		/* DOUBLE */
	case E4_VTSTRING:
	    return 2;		/* STRING */
	case E4_VTBINARY:
	    return 3;		/* BYTES */
	}
    }
    return -1;			/* ILLEGAL */
}

JNIEXPORT jstring JNICALL
Java_com_e4graph_Vertex_name1(JNIEnv *envp, jobject me, jint v,
			      jint st, jint g)
{
    e4_Vertex vv;

    if (GetValidVertex(envp, st, g, v, vv)) {
	return envp->NewStringUTF(vv.Name());
    }
    return NULL;
}

JNIEXPORT jstring JNICALL
Java_com_e4graph_Vertex_rename1(JNIEnv *envp, jobject me, jint v,
				jint st, jint g, jstring nn)
{
    e4_Vertex vv;
    const char *newname;
    jboolean copy;

    if (GetValidVertex(envp, st, g, v, vv)) {
	newname = envp->GetStringUTFChars(nn, &copy);
	vv.Rename(newname);
	if (copy) {
	    envp->ReleaseStringUTFChars(nn, newname);
	}
	return nn;
    }
    return NULL;
}

JNIEXPORT jobject JNICALL
Java_com_e4graph_Vertex_getRootNode1(JNIEnv *envp, jobject me, jint v,
				     jint st, jint g)
{
    e4_Vertex vv;
    e4_Node rn;
    e4_NodeUniqueID nuid;

    if (GetValidVertex(envp, st, g, v, vv)) {
	if (!vv.GetRootNode(rn)) {
	    envp->ThrowNew(clsNoSuchNodeException,
			   "can not retrieve root node");
	    return NULL;
	}
	(void) rn.GetUniqueID(nuid);
	return envp->NewObject(clsNode, nodeCMID, st,
			       g, nuid.GetUniqueID());
    }
    return NULL;
}

JNIEXPORT jobject JNICALL
Java_com_e4graph_Vertex_containingNode1(JNIEnv *envp, jobject me, jint v,
					jint st, jint g)
{
    e4_Vertex vv;
    e4_Node cn;
    e4_NodeUniqueID nuid;

    if (GetValidVertex(envp, st, g, v, vv)) {
	if (!vv.GetNode(cn)) {
	    envp->ThrowNew(clsNoSuchNodeException,
			   "can not retrieve containing node");
	    return NULL;
	}
	(void) cn.GetUniqueID(nuid);
	return envp->NewObject(clsNode, nodeCMID, st,
			       g, nuid.GetUniqueID());
    }
    return NULL;
}

JNIEXPORT void JNICALL
Java_com_e4graph_Vertex_moveVertex1(JNIEnv *envp, jobject me, jint v,
				    jint st, jint g,
				    jint vi, jint vst, jint vsg,
				    jint io, jint offset)
{
    e4_Storage s;
    e4_Vertex vv, mv;
    e4_VertexUniqueID vuid;

    if ((vst != st) || (vsg != g)) {
	envp->ThrowNew(clsNoSuchVertexException,
		       "vertex to move not in same storage as this vertex");
	return;
    }
    if (!GetValidStorage(envp, st, g, s)) {
	return;
    }

    vuid.SetID(v);
    vuid.SetSP(s.GetTemporaryUID());
    if (!s.GetVertexFromID(vuid, vv)) {
	envp->ThrowNew(clsNoSuchVertexException, "invalid vertex ID");
	return;
    }

    vuid.SetID(vi);
    if (!s.GetVertexFromID(vuid, mv)) {
	envp->ThrowNew(clsNoSuchVertexException, "invalid vertex ID");
	return;
    }

    if (!vv.MoveVertex(mv, (e4_InsertOrder) io, offset)) {
	envp->ThrowNew(clsNoSuchVertexException,
		       "cannot move vertex relative to this one");
    }
}

JNIEXPORT jobject JNICALL
Java_com_e4graph_Vertex_next1(JNIEnv *envp, jobject me, jint v,
			      jint st, jint g, jint n)
{
    e4_Vertex vv, nv;
    e4_VertexUniqueID vuid;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return NULL;
    }
    if (!vv.Next(n, nv) || !nv.IsValid()) {
	envp->ThrowNew(clsNoSuchVertexException, "no next vertex");
	return NULL;
    }
    (void) nv.GetUniqueID(vuid);
    return envp->NewObject(clsVertex, vertexCMID, st,
			   g, vuid.GetUniqueID());
}

JNIEXPORT jobject JNICALL
Java_com_e4graph_Vertex_prev1(JNIEnv *envp, jobject me, jint v,
			      jint st, jint g, jint n)
{
    e4_Vertex vv, nv;
    e4_VertexUniqueID vuid;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return NULL;
    }
    if (!vv.Prev(n, nv) || !nv.IsValid()) {
	envp->ThrowNew(clsNoSuchVertexException, "no preceding vertex");
	return NULL;
    }
    (void) nv.GetUniqueID(vuid);
    return envp->NewObject(clsVertex, vertexCMID, st,
			   g, vuid.GetUniqueID());
}

JNIEXPORT jint JNICALL
Java_com_e4graph_Vertex_getUserData1(JNIEnv *envp, jobject me, jint v,
				     jint st, jint g)
{
    e4_Vertex vv;
    int ud;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return 0;
    }
    if (!vv.GetUserData(ud)) {
	envp->ThrowNew(clsNoSuchVertexException, "invalid vertex ID");
	return 0;
    }
    return ud;
}

JNIEXPORT void JNICALL
Java_com_e4graph_Vertex_setUserData1(JNIEnv *envp, jobject me, jint v,
				     jint st, jint g, jint ud)
{
    e4_Vertex vv;

    if (!GetValidVertex(envp, st, g, v, vv)) {
	return;
    }
    if (!vv.SetUserData(ud)) {
	envp->ThrowNew(clsNoSuchVertexException, "invalid vertex ID");
    }
}

