/*
 * e4node.cpp --
 *
 *	Implementation of the e4_Node class defined in e4graph.h.
 *
 *	Authors: Jacob Levy and Jean-Claude Wippler.
 *		 jyl@best.com	jcw@equi4.com
 *
 * 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 "e4graphimpl.h"

/*
 * This instance of e4_Node can be used (by assigning it to fields or
 * variables of type e4_Node) to remove remaining references to instances
 * that you want to discard. Especially useful for removing remaining
 * references in malloc'ed memory.
 */

e4_Node const invalidNode;

/*
 * Default constructor:
 */

e4_Node::e4_Node() : e4_RefCount() {}

/*
 * Constructor which assigns a value to the the implementation pointer.
 */

e4_Node::e4_Node(e4_NodeImpl *ip) : e4_RefCount(ip) {}

/*
 * Copying constructor:
 */

e4_Node::e4_Node(const e4_Node &referrer) : e4_RefCount(referrer) {}

/*
 * Copying constructor that's given an e4_RefCount:
 */

e4_Node::e4_Node(const e4_RefCount &referrer)
    : e4_RefCount(referrer)
{
    if ((impl != NULL) && (impl->Kind() != E4_RKNODE)) {
	(void) e4_RefCount::operator=(invalidNode);
    }
}

/*
 * Assignment operator:
 */

e4_Node & e4_Node::operator=(const e4_Node &referrer)
{
    return (e4_Node &) e4_RefCount::operator=(referrer);
}

/*
 * How many vertices are there in this node?
 */

int
e4_Node::VertexCount() const
{
    if (impl == NULL) {
	return 0;
    }
    return ((e4_NodeImpl *) impl)->VertexCount();
}

/*
 * How many vertices in this node have the given name?
 */

int
e4_Node::VertexCountWithName(const char *name) const
{
    if (impl == NULL) {
	return 0;
    }
    return ((e4_NodeImpl *) impl)->VertexCountWithName(name);
}

/*
 * How many vertices in this node have the given type?
 */

int
e4_Node::VertexCountWithType(e4_VertexType type) const
{
    if (impl == NULL) {
	return 0;
    }
    return ((e4_NodeImpl *) impl)->VertexCountWithType(type);
}

/*
 * How many vertices in this node have the given value?
 */

int
e4_Node::VertexCountWithValue(const e4_Value &v) const
{
    if (impl == NULL) {
	return 0;
    }
    return ((e4_NodeImpl *) impl)->VertexCountWithValue(v);
}

/*
 * Operations to set values into existing vertices in this node.
 */

bool
e4_Node::SetNthVertex(const char *nm, int nth, int i) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->SetNthVertex(nm, nth, i);
}

bool
e4_Node::SetNthVertex(const char *nm, int nth, double f) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->SetNthVertex(nm, nth, f);
}

bool
e4_Node::SetNthVertex(const char *nm, int nth, const char *s) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->SetNthVertex(nm, nth, s);
}

bool
e4_Node::SetNthVertex(const char *nm, int nth, const void *b, int nb) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->SetNthVertex(nm, nth, b, nb);
}

/*
 * Set the nth vertex with a given name to a given node.
 */

bool
e4_Node::SetNthVertex(const char *nm, int nth, e4_Node n) const
{
    e4_Storage myStorage, childStorage;

    if ((impl == NULL) || (!n.IsValid())) {
	return false;
    }
    if ((!GetStorage(myStorage)) || (!n.GetStorage(childStorage))) {
	return false;
    }
    if (myStorage != childStorage) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->SetNthVertexToNode(nm, nth, 
						      n.GetRawUniqueID());
}

/*
 * Set the nth vertex with a given name to the value encapsulated in
 * the given e4_Value.
 */

bool
e4_Node::SetNthVertex(const char *nm, int nth, const e4_Value &v) const
{
    switch (v.vertexType) {
    case E4_VTNODE:
	return SetNthVertex(nm, nth, v.n);
    case E4_VTINT:
	return SetNthVertex(nm, nth, v.u.i);
    case E4_VTDOUBLE:
	return SetNthVertex(nm, nth, v.u.d);
    case E4_VTSTRING:
	return SetNthVertex(nm, nth, v.u.s);
    case E4_VTBINARY:
	return SetNthVertex(nm, nth, v.u.b.bytes, v.u.b.nbytes);
    default:
	return false;
    }
}

/*
 * Set the nth vertex with a given name to a new sub-node and return the
 * new sub-node.
 */

bool
e4_Node::SetNthNode(const char *nm, int nth, e4_Node &n) const
{
    e4_NodeImpl *nnip;

    if (impl == NULL) {
	return false;
    }
    nnip = ((e4_NodeImpl *) impl)->SetNthNode(nm, nth);
    if (nnip == NULL) {
	return false;
    }

    e4_Node nn(nnip);

    /*
     * Decrement the refcount to offset the artificially incremented refcount
     * for protection during callbacks.
     */

    nnip->DecrRefCount();

    n = nn;

    return true;
}

/*
 * Operations to set values into existing vertices identified by rank.
 */

bool
e4_Node::SetVertexByRank(int rank, int i) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->SetVertexByRank(rank, i);
}

bool
e4_Node::SetVertexByRank(int rank, double f) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->SetVertexByRank(rank, f);
}

bool
e4_Node::SetVertexByRank(int rank, const char *s) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->SetVertexByRank(rank, s);
}

bool
e4_Node::SetVertexByRank(int rank, const void *b, int nb) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->SetVertexByRank(rank, b, nb);
}

/*
 * Set the vertex identified by the given rank to the given node.
 */

bool
e4_Node::SetVertexByRank(int rank, e4_Node n) const
{
    e4_Storage myStorage, childStorage;

    if ((impl == NULL) || (!n.IsValid())) {
	return false;
    }
    if ((!GetStorage(myStorage)) || (!n.GetStorage(childStorage))) {
	return false;
    }
    if (myStorage != childStorage) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->SetVertexByRankToNode(rank, 
							 n.GetRawUniqueID());
}

/*
 * Set the vertex identified by the given rank to the value encapsulated
 * in the given e4_Value.
 */

bool
e4_Node::SetVertexByRank(int rank, const e4_Value &v) const
{
    switch (v.vertexType) {
    case E4_VTNODE:
	return SetVertexByRank(rank, v.n);
    case E4_VTINT:
	return SetVertexByRank(rank, v.u.i);
    case E4_VTDOUBLE:
	return SetVertexByRank(rank, v.u.d);
    case E4_VTSTRING:
	return SetVertexByRank(rank, v.u.s);
    case E4_VTBINARY:
	return SetVertexByRank(rank, v.u.b.bytes, v.u.b.nbytes);
    default:
	return false;
    }
}

/*
 * Set a vertex identified by rank to a new node and return the new node.
 */

bool
e4_Node::SetNodeByRank(int rank, e4_Node &n) const
{
    e4_NodeImpl *nnip;

    if (impl == NULL) {
	return false;
    }
    nnip = ((e4_NodeImpl *) impl)->SetNodeByRank(rank);
    if (nnip == NULL) {
	return false;
    }

    e4_Node nn(nnip);

    /*
     * Decrement the refcount to offset the artificially incremented refcount
     * for protection during callbacks.
     */

    nnip->DecrRefCount();

    n = nn;

    return true;
}

/*
 * Operations to add a new vertex to this node according to the rank and
 * order arguments.
 */

bool
e4_Node::AddVertex(const char *nm, e4_InsertOrder order, int &rank,
		   int i) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->AddVertex(nm, order, rank, i);
}

bool
e4_Node::AddVertex(const char *nm, e4_InsertOrder order, int &rank,
		   double f) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->AddVertex(nm, order, rank, f);
}

bool
e4_Node::AddVertex(const char *nm, e4_InsertOrder order, int &rank,
		   const char *s) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->AddVertex(nm, order, rank, s);
}

bool
e4_Node::AddVertex(const char *nm, e4_InsertOrder order, int &rank,
		   const void *b, int nb) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->AddVertex(nm, order, rank, b, nb);
}

/*
 * Add a new vertex and set its value to the given node.
 */

bool
e4_Node::AddVertex(const char *nm, e4_InsertOrder order, int &rank,
		   e4_Node n) const
{
    e4_Storage myStorage, childStorage;

    if ((impl == NULL) || (!n.IsValid())) {
	return false;
    }
    if ((!GetStorage(myStorage)) || (!n.GetStorage(childStorage))) {
	return false;
    }
    if (myStorage != childStorage) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->AddVertexWithNode(nm, order, rank, 
						     n.GetRawUniqueID());
}

/*
 * Add a new vertex and set its value to the value supplied in the given
 * e4_Value structure.
 */

bool
e4_Node::AddVertex(const char *nm, e4_InsertOrder order, int &rank,
		   const e4_Value &v) const
{
    switch (v.vertexType) {
    case E4_VTNODE:
	return AddVertex(nm, order, rank, v.n);
    case E4_VTINT:
	return AddVertex(nm, order, rank, v.u.i);
    case E4_VTDOUBLE:
	return AddVertex(nm, order, rank, v.u.d);
    case E4_VTSTRING:
	return AddVertex(nm, order, rank, v.u.s);
    case E4_VTBINARY:
	return AddVertex(nm, order, rank, v.u.b.bytes, v.u.b.nbytes);
    default:
	return false;
    }
}

/*
 * Add a new vertex with the given name and set it to a new node. Also return
 * the new node.
 */

bool
e4_Node::AddNode(const char *nm, e4_InsertOrder order, int &rank,
		 e4_Node &n) const
{
    e4_NodeImpl *nnip;

    if (impl == NULL) {
	return false;
    }
    nnip = ((e4_NodeImpl *) impl)->AddNode(nm, order, rank);
    if (nnip == NULL) {
	return false;
    }

    e4_Node nn(nnip);

    /*
     * Decrement the refcount to offset the artificially incremented refcount
     * for protection during callbacks.
     */

    nnip->DecrRefCount();

    n = nn;

    return true;
}

/*
 * Add a new vertex and also return an e4_Vertex for the new vertex.
 */

bool
e4_Node::AddVertexRef(const char *nm, e4_InsertOrder order, int &rank,
		      int iv, e4_Vertex &v) const
{
    e4_VertexImpl *vvip;

    if (impl == NULL) {
        return false;
    }
    vvip = ((e4_NodeImpl *) impl)->AddVertexRef(nm, order, rank, iv);
    if (vvip == NULL) {
        return false;
    }

    e4_Vertex vv(vvip);

    /*
     * Decrement the refcount to offset the artificially incremented
     * refcount for protection during callbacks.
     */

    vvip->DecrRefCount();

    v = vv;

    return true;
}

bool
e4_Node::AddVertexRef(const char *nm, e4_InsertOrder order, int &rank,
		      double fv, e4_Vertex &v) const
{
    e4_VertexImpl *vvip;

    if (impl == NULL) {
        return false;
    }
    vvip = ((e4_NodeImpl *) impl)->AddVertexRef(nm, order, rank, fv);
    if (vvip == NULL) {
        return false;
    }

    e4_Vertex vv(vvip);

    /*
     * Decrement the refcount to offset the artificially incremented
     * refcount for protection during callbacks.
     */

    vvip->DecrRefCount();

    v = vv;

    return true;
}

bool
e4_Node::AddVertexRef(const char *nm, e4_InsertOrder order, int &rank,
		      const char *sv, e4_Vertex &v) const
{
    e4_VertexImpl *vvip;

    if (impl == NULL) {
        return false;
    }
    vvip = ((e4_NodeImpl *) impl)->AddVertexRef(nm, order, rank, sv);
    if (vvip == NULL) {
        return false;
    }

    e4_Vertex vv(vvip);

    /*
     * Decrement the refcount to offset the artificially incremented
     * refcount for protection during callbacks.
     */

    vvip->DecrRefCount();

    v = vv;

    return true;
}

bool
e4_Node::AddVertexRef(const char *nm, e4_InsertOrder order, int &rank,
		      const void *bv, int nbv, e4_Vertex &v) const
{
    e4_VertexImpl *vvip;

    if (impl == NULL) {
        return false;
    }
    vvip = ((e4_NodeImpl *) impl)->AddVertexRef(nm, order, rank, bv, nbv);
    if (vvip == NULL) {
        return false;
    }

    e4_Vertex vv(vvip);

    /*
     * Decrement the refcount to offset the artificially incremented
     * refcount for protection during callbacks.
     */

    vvip->DecrRefCount();

    v = vv;

    return true;
}

/*
 * Add a new vertex whose value is the given node, and return an e4_Vertex for
 * the new vertex.
 */

bool
e4_Node::AddVertexRef(const char *nm, e4_InsertOrder order, int &rank,
		      e4_Node n, e4_Vertex &v) const
{
    e4_VertexImpl *vvip;
    e4_Storage myStorage, childStorage;

    if ((impl == NULL) || (!n.IsValid())) {
	return false;
    }
    if ((!GetStorage(myStorage)) || (!n.GetStorage(childStorage))) {
	return false;
    }
    if (myStorage != childStorage) {
	return false;
    }
    vvip = ((e4_NodeImpl *) impl)->AddVertexRefWithNode(nm, order, rank, 
							n.GetRawUniqueID());
    if (vvip == NULL) {
        return false;
    }

    e4_Vertex vv(vvip);

    /*
     * Decrement the refcount to offset the artificially incremented
     * refcount for protection during callbacks.
     */

    vvip->DecrRefCount();

    v = vv;

    return true;
}

/*
 * Add a new vertex whose value and type are determined by the given e4_Value,
 * and return an e4_Vertex for the new vertex.
 */

bool
e4_Node::AddVertexRef(const char *nm, e4_InsertOrder order, int &rank,
		      const e4_Value &v, e4_Vertex &f) const
{
    switch (v.vertexType) {
    case E4_VTNODE:
	return AddVertexRef(nm, order, rank, v.n, f);
    case E4_VTINT:
	return AddVertexRef(nm, order, rank, v.u.i, f);
    case E4_VTDOUBLE:
	return AddVertexRef(nm, order, rank, v.u.d, f);
    case E4_VTSTRING:
	return AddVertexRef(nm, order, rank, v.u.s, f);
    case E4_VTBINARY:
	return AddVertexRef(nm, order, rank, v.u.b.bytes, v.u.b.nbytes, f);
    default:
	return false;
    }
}

/*
 * Add a new vertex whose value is a new node, return an e4_Vertex for the
 * new vertex and also return an e4_Node for the new node.
 */

bool
e4_Node::AddNodeRef(const char *nm, e4_InsertOrder order, int &rank,
                    e4_Node &n, e4_Vertex &v) const
{
    e4_VertexImpl *vvip;
    e4_NodeImpl *nnip;

    if (impl == NULL) {
        return false;
    }
    vvip = ((e4_NodeImpl *) impl)->AddNodeRef(nm, order, rank, nnip);
    if ((vvip == NULL) || (nnip == NULL)) {
        return false;
    }

    e4_Vertex vv(vvip);

    /*
     * Decrement the refcount to offset the artificially incremented
     * refcount for protection during callbacks.
     */

    vvip->DecrRefCount();

    v = vv;

    e4_Node nn(nnip);

    /*
     * Decrement the refcount to offset the artificially incremented
     * refcount for protection during callbacks.
     */

    nnip->DecrRefCount();

    n = nn;

    return true;
}

/*
 * Move a vertex to a specified position within this node. Note that only
 * moves within the same storage are allowed.
 */

bool
e4_Node::MoveVertex(const e4_Vertex &v, e4_InsertOrder order, int rank)
{
    e4_Storage myStorage, hisStorage;
    
    if (!v.IsValid() || (impl == NULL)) {
	return false;
    }
    if ((!GetStorage(myStorage)) || (!v.GetStorage(hisStorage))) {
        return false;
    }
    if (myStorage != hisStorage) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->MoveVertex(v.GetRawUniqueID(), order, rank);
}

/*
 * Get the value of a vertex in this node.
 */

bool
e4_Node::GetNthVertex(const char *nm, int nth, e4_Value &v) const
{
    e4_ValueImpl *vipp;
    
    if (impl == NULL) {
        return false;
    }
    if (((e4_NodeImpl *) impl)->GetNthVertex(nm, nth, vipp) == false) {
        return false;
    }
    if (vipp == NULL) {
        return false;
    }
    v.vertexType = vipp->vertexType;
    switch (vipp->vertexType) {
    case E4_VTNODE:
        {
            e4_Node nn(vipp->u.n);
            v.n = nn;
            break;
        }
    case E4_VTINT:
        v.u.i = vipp->u.i;
        break;
    case E4_VTDOUBLE:
        v.u.d = vipp->u.d;
        break;
    case E4_VTSTRING:
        v.u.s = vipp->u.s;
        break;
    case E4_VTBINARY:
        v.u.b.bytes = vipp->u.b.bytes;
        v.u.b.nbytes = vipp->u.b.nbytes;
        break;
    default:
        return false;
    }

    delete vipp;

    return true;
}

bool
e4_Node::GetNthVertex(const char *nm, int nth, e4_Node &n) const
{
    e4_NodeImpl *nnip;

    if (impl == NULL) {
        return false;
    }
    if (((e4_NodeImpl *) impl)->GetNthVertex(nm, nth, nnip) == false) {
        return false;
    }
    if (nnip == NULL) {
        return false;
    }

    e4_Node nn(nnip);

    n = nn;

    return true;
}

bool
e4_Node::GetNthVertex(const char *nm, int nth, int &v) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->GetNthVertex(nm, nth, v);
}

bool
e4_Node::GetNthVertex(const char *nm, int nth, double &v) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->GetNthVertex(nm, nth, v);
}

bool
e4_Node::GetNthVertex(const char *nm, int nth, const char *&v) const 
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->GetNthVertex(nm, nth, v);
}

bool
e4_Node::GetNthVertex(const char *nm, int nth, const void *&v, int &nbv) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->GetNthVertex(nm, nth, v, nbv);
}

/*
 * Get the value of a vertex identified by rank.
 */

bool
e4_Node::GetVertexByRank(int rank, e4_Value &v) const
{
    e4_ValueImpl *vipp;
    
    if (impl == NULL) {
        return false;
    }
    if (((e4_NodeImpl *) impl)->GetVertexByRank(rank, vipp) == false) {
        return false;
    }
    if (vipp == NULL) {
        return false;
    }
    v.vertexType = vipp->vertexType;
    switch (vipp->vertexType) {
    case E4_VTNODE:
        {
            e4_Node nn(vipp->u.n);
            v.n = nn;
            break;
        }
    case E4_VTINT:
        v.u.i = vipp->u.i;
        break;
    case E4_VTDOUBLE:
        v.u.d = vipp->u.d;
        break;
    case E4_VTSTRING:
        v.u.s = vipp->u.s;
        break;
    case E4_VTBINARY:
        v.u.b.bytes = vipp->u.b.bytes;
        v.u.b.nbytes = vipp->u.b.nbytes;
        break;
    default:
        return false;
    }

    delete vipp;
    
    return true;
}

bool
e4_Node::GetVertexByRank(int rank, e4_Node &n)  const
{
    e4_NodeImpl *nnip;

    if (impl == NULL) {
        return false;
    }
    if (((e4_NodeImpl *) impl)->GetVertexByRank(rank, nnip) == false) {
        return false;
    }
    if (nnip == NULL) {
        return false;
    }

    e4_Node nn(nnip);

    n = nn;

    return true;
}

bool
e4_Node::GetVertexByRank(int rank, int &v) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->GetVertexByRank(rank, v);
}

bool
e4_Node::GetVertexByRank(int rank, double &v) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->GetVertexByRank(rank, v);
}

bool
e4_Node::GetVertexByRank(int rank, const char *&v) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->GetVertexByRank(rank, v);
}

bool
e4_Node::GetVertexByRank(int rank, const void *&v, int &nbv) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->GetVertexByRank(rank, v, nbv);
}

/*
 * Detach a vertex.
 */

bool
e4_Node::DetachVertex(const char *nm, int nth) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->DetachVertex(nm, nth);
}

bool
e4_Node::DetachVertexByRank(int rank) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->DetachVertexByRank(rank);
}

bool
e4_Node::DetachFirstVertexWithNode(e4_Node child) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->DetachFirstVertexWithNode(
				     (e4_NodeImpl *) child.impl);
}

/*
 * Get an e4_Vertex for a specific vertex.
 */

bool
e4_Node::GetVertexRef(const char *nm, int nth, e4_Vertex &v) const
{
    e4_VertexImpl *vvip;

    if (impl == NULL) {
        return false;
    }
    vvip = ((e4_NodeImpl *) impl)->GetVertexRef(nm, nth);
    if (vvip == NULL) {
        return false;
    }

    e4_Vertex vv(vvip);

    v = vv;

    return true;
}

bool
e4_Node::GetVertexRefByRank(int rank, e4_Vertex &v) const
{
    e4_VertexImpl *vvip;

    if (impl == NULL) {
        return false;
    }
    vvip = ((e4_NodeImpl *) impl)->GetVertexRefByRank(rank);
    if (vvip == NULL) {
        return false;
    }

    e4_Vertex vv(vvip);

    v = vv;

    return true;
}

/*
 * Get the type of a value stored in a specified vertex.
 */

e4_VertexType
e4_Node::VertexType(const char *nm, int nth) const
{
    if (impl == NULL) {
        return E4_VTUNKNOWN;
    }
    return ((e4_NodeImpl *) impl)->VertexType(nm, nth);
}

e4_VertexType
e4_Node::VertexTypeByRank(int rank) const
{
    if (impl == NULL) {
        return E4_VTUNKNOWN;
    }
    return ((e4_NodeImpl *) impl)->VertexTypeByRank(rank);
}

/*
 * Get the name of a vertex.
 */

const char *
e4_Node::VertexName(int rank) const
{
    if (impl == NULL) {
        return (const char *) NULL;
    }
    return ((e4_NodeImpl *) impl)->VertexName(rank);
}

/*
 * Rename a vertex.
 */

bool
e4_Node::RenameVertex(int rank, const char *newName) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->RenameVertex(rank, newName);
}

/*
 * Get the rank of a specified vertex.
 */

int
e4_Node::VertexRank(const char *nm, int nth) const
{
    if (impl == NULL) {
        return E4_VERTEXNOTFOUND;
    }
    return ((e4_NodeImpl *) impl)->VertexRank(nm, nth);
}

/*
 * Does a specified vertex exist?
 */

bool
e4_Node::Exists(const char *nm, int nth) const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->Exists(nm, nth);
}

/*
 * Get the parent and root node of this node.
 */

bool
e4_Node::GetParent(int nth, e4_Node &p) const
{
    e4_NodeImpl *ppip;

    if (impl == NULL) {
        return false;
    }
    ppip = ((e4_NodeImpl *) impl)->GetParent(nth);
    if (ppip == NULL) {
        return false;
    }

    e4_Node pp(ppip);

    p = pp;

    return true;
}

/*
 * Retrieve the nth vertex in the parent p of this node whose value is
 * this node.
 */

bool
e4_Node::GetVertexRefFromParent(e4_Node p, int nth, e4_Vertex &v) const
{
    e4_VertexImpl *vp;
    e4_NodeImpl *pimpl = (e4_NodeImpl *) p.impl;

    if ((impl == NULL) || (pimpl == NULL)) {
	return false;
    }

    vp = ((e4_NodeImpl *) impl)->GetVertexRefFromParent(pimpl, nth);
    if (vp == NULL) {
	return false;
    }

    e4_Vertex vv(vp);

    v = vv;

    return true;
}

/*
 * Retrieve the nth vertex in the ith parent of this node whose value
 * is this node.
 */

bool
e4_Node::GetVertexRefFromParent(int i, int nth, e4_Vertex &v) const
{
    e4_VertexImpl *vp;

    if (impl == NULL) {
	return false;
    }
    vp = ((e4_NodeImpl *) impl)->GetVertexRefFromParent(i, nth);
    if (vp == NULL) {
	return false;
    }

    e4_Vertex vv(vp);

    v = vv;

    return true;
}

/*
 * How many parents does this node have?
 */

int
e4_Node::ParentCount() const
{
    if (impl == NULL) {
	return E4_NODENOTFOUND;
    }

    return ((e4_NodeImpl *) impl)->ParentCount();
}

/*
 * In how many different vertices is this node the vertex value?
 */

int
e4_Node::OccurrenceCount() const
{
    if (impl == NULL) {
	return E4_NODENOTFOUND;
    }

    return ((e4_NodeImpl *) impl)->OccurrenceCount();
}

/*
 * How many times does this node occur as a child in the given parent?
 */

int 
e4_Node::OccurrenceCount(e4_Node p) const
{
    e4_Storage myStorage, parentStorage;

    if ((impl == NULL) || (!p.IsValid())) {
	return E4_NODENOTFOUND;
    }
    if ((!GetStorage(myStorage)) || (!p.GetStorage(parentStorage))) {
	return E4_NODENOTFOUND;
    }
    if (myStorage != parentStorage) {
        return E4_NODENOTFOUND;
    }
    return ((e4_NodeImpl *) impl)->OccurrenceCount(p.GetRawUniqueID());
}

/*
 * What is the rank of this parent for this node?
 */

int
e4_Node::ParentRank(e4_Node p) const
{
    e4_Storage myStorage, parentStorage;

    if ((impl == NULL) || (!p.IsValid())) {
	return E4_NODENOTFOUND;
    }
    if ((!GetStorage(myStorage)) || (!p.GetStorage(parentStorage))) {
	return E4_NODENOTFOUND;
    }
    if (myStorage != parentStorage) {
        return E4_NODENOTFOUND;
    }
    return ((e4_NodeImpl *) impl)->ParentRank(p.GetRawUniqueID());
}

/*
 * Get the rank or name of the vertex containing this node in its parent.
 */

int
e4_Node::GetRankInParent(int nth, int ith) const
{
    if (impl == NULL) {
        return E4_NODENOTFOUND;
    }
    return ((e4_NodeImpl *) impl)->GetRankInParent(nth, ith);
}

const char *
e4_Node::GetNameInParent(int nth, int ith) const
{
    if (impl == NULL) {
        return NULL;
    }
    return ((e4_NodeImpl *) impl)->GetNameInParent(nth, ith);
}

/*
 * Get the rank and name of the ith vertex whose value is this node in
 * the parent node p.
 */

int
e4_Node::GetRankInParent(e4_Node p, int ith) const
{
    e4_NodeImpl *pimpl = (e4_NodeImpl *) p.impl;

    if ((impl == NULL) || (pimpl == NULL)) {
	return E4_NODENOTFOUND;
    }
    return ((e4_NodeImpl *) impl)->GetRankInParent(pimpl, ith);
}

const char *
e4_Node::GetNameInParent(e4_Node p, int ith) const
{
    e4_NodeImpl *pimpl = (e4_NodeImpl *) p.impl;

    if ((impl == NULL) || (pimpl == NULL)) {
	return NULL;
    }
    return ((e4_NodeImpl *) impl)->GetNameInParent(pimpl, ith);
}

/*
 * Is this node the root?
 */

bool
e4_Node::IsRoot() const
{
    if (impl == NULL) {
        return false;
    }
    return ((e4_NodeImpl *) impl)->IsRoot();
}

/*
 * Get the root node of the storage containing this node.
 */

bool
e4_Node::GetRootNode(e4_Node &rn) const
{
    e4_NodeImpl *rnip;
    e4_StorageImpl *ssip;

    if (impl == NULL) {
	return false;
    }
    ssip = ((e4_NodeImpl *) impl)->GetStorage();
    if (ssip == NULL) {
	return false;
    }
    rnip = ssip->GetRootNode();
    if (rnip == NULL) {
	return false;
    }

    e4_Node rrnn(rnip);

    rn = rrnn;

    return true;
}

/*
 * Get the storage containing this node.
 */

bool
e4_Node::GetStorage(e4_Storage &s) const
{
    e4_StorageImpl *ssip;

    if (impl == NULL) {
        return false;
    }
    ssip = ((e4_NodeImpl *) impl)->GetStorage();
    if (ssip == NULL) {
        return false;
    }

    e4_Storage ss(ssip);

    s = ss;

    return true;
}

/*
 * Get an ID that uniquely identifies this node within its storage.
 */

bool
e4_Node::GetUniqueID(e4_NodeUniqueID &n) const
{
    int id;
    e4_StorageImpl *sp;

    if (impl == NULL) {
	return false;
    }
    id = ((e4_NodeImpl *) impl)->GetUniqueID();
    if (id == E4_NODENOTFOUND) {
	return false;
    }
    sp = ((e4_NodeImpl *) impl)->GetStorage();
    if (sp == NULL) {
	return false;
    }

    e4_NodeUniqueID nn(id, sp->DRV_HashCode());

    n = nn;

    return true;
}

/*
 * Get the ID but return it unwrapped.
 */

int
e4_Node::GetRawUniqueID() const
{
    if (impl == NULL) {
	return E4_NODENOTFOUND;
    }
    return ((e4_NodeImpl *) impl)->GetUniqueID();
}

/*
 * Detach this node from all vertices for which it is the value.
 */

bool
e4_Node::Detach() const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->Detach();
}

/*
 * Is this node detached?
 */

bool
e4_Node::IsDetached() const
{
    if (impl == NULL) {
	return true;
    }
    return ((e4_NodeImpl *) impl)->IsDetached();
}

/*
 * Return the kind identifier for this instance's type.
 */

e4_RefKind
e4_Node::Kind() const
{
    return E4_RKNODE;
}

/*
 * Get/Set user data associated with this node.
 */

bool
e4_Node::GetUserData(int &userData) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->GetUserData(userData);
}

bool
e4_Node::SetUserData(int userData) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->SetUserData(userData);
}

/*
 * Set/Get user data for contained vertex.
 */

bool
e4_Node::GetVertexUserData(const char *name, int &userData) const
{
    return GetVertexUserData(name, 1, userData);
}

bool
e4_Node::SetVertexUserData(const char *name, int userData) const
{
    return SetVertexUserData(name, 1, userData);
}

bool
e4_Node::GetVertexUserData(const char *name, int nth, int &userData) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->GetVertexUserData(name, nth, userData);
}

bool
e4_Node::SetVertexUserData(const char *name, int nth, int userData) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->SetVertexUserData(name, nth, userData);
}

bool
e4_Node::GetVertexUserDataByRank(int rank, int &userData) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->GetVertexUserDataByRank(rank, userData);
}

bool
e4_Node::SetVertexUserDataByRank(int rank, int userData) const
{
    if (impl == NULL) {
	return false;
    }
    return ((e4_NodeImpl *) impl)->SetVertexUserDataByRank(rank, userData);
}

/*
 * Set/Get the advisory caching policy for this node.
 */

int
e4_Node::SetAdvisoryCachingPolicy(bool set, int mask) const
{
    if (impl == NULL) {
	return E4_CACHEINCREMENTAL;
    }
    return ((e4_NodeImpl *) impl)->SetAdvisoryCachingPolicy(set, mask);
}

int
e4_Node::GetAdvisoryCachingPolicy() const
{
    if (impl == NULL) {
	return E4_CACHEINCREMENTAL;
    }
    return ((e4_NodeImpl *) impl)->GetAdvisoryCachingPolicy();
}

/*
 * Pre-cache all vertices in this node.
 */

void
e4_Node::PreCache() const
{
    if (impl == NULL) {
	return;
    }
    ((e4_NodeImpl *) impl)->PreCache();
}
