/*
 * e4graphimpl.h --
 *
 *	This file contains the definition of the implementation part of the
 *	e4Graph library. It defines the following classes:
 *
 *	e4_RefCounter	-- A base class used to manage lifecycle.
 *	e4_StorageImpl	-- Storage independent implementation of tree
 *			   data storage.
 *	e4_NodeImpl	-- An implementation of a node.
 *	e4_VertexImpl	-- An implementation of a 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.
*/

#ifndef	__E4_GRAPHIMPL_H__
#define	__E4_GRAPHIMPL_H__

#if (defined(__GNUC__)) || (!defined(_WIN32))
#include <unistd.h>
#endif

#if defined (_MSC_VER_)
#include <malloc.h>
#else
#include <stdlib.h>
#endif

/*
 * Include public side of e4Graph API.
 */

#include "e4graph.h"

/*
 * This flag is for internal use and should not overlap with E4_OPENGC,
 * E4_GCBEFORECOMMIT and E4_AUTOGC.
 *
 * It is used by callers to indicate that
 * an explicit GC was requested by the user program, and this request is
 * always respected, whether or not a GC is needed.
 */

#define E4_REQUESTEDGC		(1<<0)

/*
 * This defines the size of the hash key for callback records. The hash
 * key is composed of an int + 2 void *, so on 32-bit and 64-bit machines
 * this has different sizes, which is why it must be parameterized.
 */

#define E4_CALLBACKKEYSIZE \
    ((sizeof(int) + (sizeof(void *) * 2)) / sizeof(int))

/*
 * The value of E4_NEXTNONE is used to indicate the end of a chain
 * of records.
 */

#define E4_NEXTNONE		-1

/*
 * This flag is used to indicate that a detach callback was already
 * delivered for this node or vertex. It is reset when the vertex or
 * node becomes attached again, so that subsequent detach callbacks
 * can also be delivered.
 *
 * This flag is stored into the flags private instance variable in
 * e4_NodeImpl and e4_VertexImpl instances.
 */

#define	E4_CBDETACHDELIVERED	(1<<0)

/***********************************************************************
 *
 * Stack of integers API:
 *
 ***********************************************************************
 */

/*
 * This class stores a stack of ints.
 */

class e4_DLL e4_IntStack {
private:
    int next;
    int size;
    int *stack;

public:
    /*
     * Constructor:
     */

    e4_IntStack();

    /*
     * Destructor:
     */

    virtual ~e4_IntStack();

    /*
     * Push and pop operations.
     */

    void Push(int id);
    bool Pop(int *idp);
    void Reset();
};

/***********************************************************************
 *
 * e4Graph internal API proper:
 *
 ***********************************************************************
 */

/*
 * The e4_RefCounter class:
 *
 * This class is the base class for all of the e4 classes, and implements
 * simple refcount controlled lifecycle mgmt for objects. Objects start out
 * with a zero refcount, and when the refcount goes back to zero, a virtual
 * method NotReferenced is called. This allows the derived class to decide
 * what to do.
 */

class e4_DLL e4_RefCounter {
private:
    /*
     * This field contains the current number of outstanding references
     * to this object.
     */

    int refCount;

    /*
     * User level data attached to this instance.
     */

    void *userData;

protected:
    /*
     * Constructor:
     */

    e4_RefCounter() : refCount(0), userData(NULL) {}

    /*
     * This method, which must be supplied by derived classes, is called
     * each time the reference count goes back to zero.
     */

    virtual void NotReferenced() = 0;

public:

    /*
     * Reference count management:
     */

    inline void IncrRefCount() {
	refCount++;
#ifdef	DEBUG_REFCOUNT
	fprintf(stderr, "Incr 0x%x: refcount %d\n", this, refCount);
#endif
    }
    inline void DecrRefCount() {
	refCount--;
#ifdef	DEBUG_REFCOUNT
	fprintf(stderr, "Decr 0x%x: refcount %d\n", this, refCount);
#endif
	if (refCount <= 0) {
	     NotReferenced();
	}
    }

    /*
     * Returns the current reference count.
     */

    inline int RefCount() const
    {
	return refCount;
    }

    /*
     * These operations manipulate user-level data attached to each
     * instance.
     */

    inline void SetTransientUserData(void *d) {
	userData = d;
    }
    inline void *GetTransientUserData() {
	return userData;
    }

    /*
     * Is this instance valid? This method *must* be overridden
     * by sub-classes.
     */

    virtual bool IsValid() const = 0;

    /*
     * What's the "kind" of this class? Must be implemented by
     * subclasses.
     */

    virtual e4_RefKind Kind() const = 0;
};

/*
 * These constants are used to denote GC states for nodes and vertices:
 */

#define E4_GCNKR	(1<<0)		/* Node known reachable. */
#define E4_GCNRU	(1<<1)		/* Node reachability unknown. */
#define E4_GCNKU	(1<<2)		/* Node known unreachable. */
#define E4_GCNSN	(1<<3)		/* Node examined by current GC. */
#define E4_GCVKR	(1<<4)		/* Vertex known reachable. */
#define E4_GCVRU	(1<<5)		/* Vertex reachability unknown. */
#define E4_GCVKU	(1<<6)		/* Vertex known unreachable. */
#define E4_GCVSN	(1<<7)		/* Veetex examined by current GC. */

/*
 * The e4_StorageImpl class:
 *
 * NOTE: Because most of the operations in this class use c4_Property
 * instances which are declared extern but not exported, this class cannot
 * have any inline operations (or at least it cannot have any inline
 * operations that use these instances...)
 */

class e4_DLL e4_StorageImpl : public e4_RefCounter {
private:
    bool commit;			/* Should the storage be committed
					 * when the e4_StorageImpl instance is
					 * destroyed? */
    bool stable;			/* If the storage contains any changes
					 * that haven't been committed yet,
					 * this is false. */
    bool gcAtCommit;			/* Does every commit do a GC? */
    e4_HashTable *activeNodes;		/* Hash table for nodes that
                                         * have been loaded in-memory
					 * to allow returning the same
                                         * pointer on multiple requests
					 * for a specific node. */
    e4_HashTable *activeVertices;	/* Hash table for vertices that
                                         * habe been loaded in-memory
                                         * to allow returning the same
                                         * pointer on multiple requests
                                         * for a specific vertex. */
    e4_HashTable *nameHash;		/* Hash table to map from
                                         * vertex names to indices in
                                         * the "names" view. Used to
                                         * allow use of integer indices
                                         * for vertex names instead of
                                         * the more inefficient string
                                         * values. */

    e4_HashTable *callbacks;		/* Hash table for callbacks defined
					 * for this storage. */

    int callbacksPresent;		/* Bitmap for notating that a certain
					 * kind of callback is present. This
					 * is used to efficiently decide if
					 * we need to invoke the callback
					 * mechanism for a given kind of
					 * event. */
    int statemask;			/* All states that are turned on
					 * have corresponding bits in this
					 * variable turned on. */
    int perms;				/* What storage permissions are
					 * in effect for this storage? */
    bool destroyed;			/* Has this storage been destroyed
					 * already? */
    char *GCState;			/* Vector of bytes for recording
					 * the state of the garbage collector
					 * and memory management. Bits in this
					 * vector are defined above. */
    int GCStateLength;			/* How long is the GCState vector? */
    int timestamp;			/* Timestamp of last event. */
    int eventTimeStamps[E4_LASTUSERDEFINEDEVENTCODE+1];
					/* Records time stamps for
					 * when significant events occur. */

protected:
    char *drivername;			/* The name of the storage driver
					 * being used by this storage. */
    char *name;				/* Unique name for storage. */

private:
    e4_StorageImpl();			/* The default constructor is private
					 * to prevent it from being called. */
    e4_StorageImpl(const e4_StorageImpl &);
					/* Copy constructor cannot be
					 * called either. */
    void operator= (const e4_StorageImpl *);
					/* Nor assignment. */

    /*
     * These operations are for use by e4_StorageImpl only:
     */

    void InitializeNameHash();
    void InitializeNodeHash();
    void InitializeVertexHash();
    void InitializeCallbackHash();

public:

    /*
     * Use this static function to get an e4_StorageImpl:
     */

    static e4_StorageImpl *GetStorage(const char *name, 
				      const char *drivernm,
				      int statemask,
				      int perms);


    /*
     * Use this static function to get version information out of
     * an existing storage to identify the version of e4Graph that
     * wrote that storage.
     */

    static bool GetStorageVersionInfo(const char *fname,
				      const char *drivername,
				      int &maj,
				      int &min,
				      e4_ReleaseStatus &rs,
				      int &ri);

    /*
     * Set and get the state bits.
     */

    inline int SetState(int newstate) {
	int oldstate = statemask;

	statemask = newstate;
	return oldstate;
    }
    inline int GetState() const {
	return statemask;
    }

    /*
     * Get the storage permissions:
     */

    inline int GetPermissions() const {return perms;}

    /*
     * Is this storage stable? Mark the storage as stable or unstable.
     */

    inline bool IsStable() {return stable;};
    inline bool IsUnstable() {return stable ? false : true;};
    inline void MarkUnstable() {
	bool changed = (stable == true) ? true : false;
	stable = false;
	if (changed) {
	    RecordTimeStamp(E4_ECCHANGESTG);
	    if (HasCallbacks(E4_ECCHANGESTG)) {
		CauseEventInternal(E4_ECCHANGESTG, this, (void *) stable);
	    }
	}
    };
    inline void MarkStable() {
	bool changed = (stable == false) ? true : false;
	stable = true;
	if (changed) {
	    RecordTimeStamp(E4_ECCHANGESTG);
	    if (HasCallbacks(E4_ECCHANGESTG)) {
		CauseEventInternal(E4_ECCHANGESTG, this, (void *) stable);
	    }
	}
    };

    /*
     * APIs associated with new GC mechanism:
     */

    bool NewPartialGC(bool fullclean);
    void NewFullGC();
    void SpanReachable();
    bool SpanUnreachable();
    void SweepUnreachable();
    bool NewlyUnreachableEntities();

    /*
     * Commit the storage:
     */

    inline bool Commit() {
	if ((perms & E4_SPCOMMIT) == 0) {
	    return false;
	}
	if (DRV_Commit()) {
	    MarkStable();
	    RecordTimeStamp(E4_ECCOMMITSTG);
	    return true;
	}
	return false;
    }

    /*
     * Copy this storage to another:
     */

    inline bool CopyTo(e4_StorageImpl *osp) {
	if ((osp == NULL) ||
	    ((osp->perms & (E4_SPMODIFY | E4_SPCOPYTO)) !=
	     (E4_SPMODIFY | E4_SPCOPYTO)) ||
	    ((perms & E4_SPCOPYFROM) == 0)) {
	    return false;
	}
	if (DRV_CopyTo(osp)) {
	    osp->MarkUnstable();
	    osp->RecordTimeStamp(E4_ECCOPYTOSTG);
	    RecordTimeStamp(E4_ECCOPYFRMSTG);
	    return true;
	}
	return false;
    }

    /*
     * Destroy this storage:
     */

    inline void Destroy() {
	if (destroyed) {
	    return;
	}
	destroyed = true;
	if ((perms & E4_SPMODIFY) == 0) {
	    return;
	}
	DRV_Destroy();
    }

    /*
     * Time stamp mechanism:
     */

    inline int GetTimeStamp() const {return timestamp;}
    int GetTimeStampFor(int em) const;
    bool HasOccurredSince(int ts, int em) const;
    void RecordTimeStamp(int em);

    /*
     * IMPL wrappers for driver functions called from the INTF layer:
     */

    inline e4_VertexImpl *FindNextVertex(int vertexID,
					 e4_VisitMethod vm,
					 int vv,
					 int nameID,
					 int nodeID,
					 int parentID,
					 e4_VertexType typeID,
					 e4_DetachChoice dc)
	const
    {
	return DRV_FindNextVertex(vertexID,
				  vm,
				  vv,
				  nameID,
				  nodeID,
				  parentID,
				  typeID,
				  dc);
    }

    inline e4_NodeImpl *FindNextNode(int nodeID) const
    {
	return DRV_FindNextNode(nodeID);
    }

    inline bool GetStatistic(e4_Space sp, e4_SpaceStat st, int &dv)
    {
	return DRV_GetStatistic(sp, st, dv);
    }

    inline int HashCode() const {return DRV_HashCode();}

    inline void DoGC() {
	if ((perms & E4_SPMODIFY) == 0) {
	    return;
	}
	DRV_DoGC(E4_REQUESTEDGC);
	MarkUnstable();
    }
    inline void DoPartialGC() {
	if ((perms & E4_SPMODIFY) == 0) {
	    return;
	}
	DRV_DoGC(E4_AUTOGC);
	MarkUnstable();
    }
    inline bool NeedsGC() const {return DRV_NeedsGC();}
    inline void SetNeedsGC(bool needs) {
	if ((perms & E4_SPMODIFY) == 0) {
	    return;
	}
	DRV_SetNeedsGC(needs);
    }

    inline int GetRootNodeID() {return DRV_GetRootNodeID();}
    inline bool SetRootNodeID(int id) {
	if ((perms & E4_SPMODIFY) == 0) {
	    return false;
	}
	if (DRV_SetRootNodeID(id)) {
	    MarkUnstable();
	    RecordTimeStamp(E4_ECSETSTGROOT);
	    return true;
	}
	return false;
    }
    inline bool IsRootNodeID(int id) {return DRV_IsRootNodeID(id);}

    /*
     * Get the name and storage driver ID for this storage.
     */

    inline const char *GetName() const {return name;}
    inline const char *GetDriver() const {return drivername;}

    /*
     * Get and set the root node.
     */

    e4_NodeImpl *GetRootNode();
    bool SetRootNode(e4_NodeImpl *nrp);

    /*
     * Enter a name into the persistent storage and also into storage-wide
     * hash table, or retrieve its index from the hash table if it is
     * already interned. If create is false then the name is not added to
     * the table if it is new.
     */

    int InternName(const char *nm, bool create) const;

    /*
     * Add a callback function.
     */

    bool AddCallback(int eventCode, void *fn, void *clientData);

    /*
     * Remove a callback function.
     */

    bool DelCallback(int eventCode, void *fn, void *clientData);

    /*
     * Cause callbacks to be called for a user defined event on the
     * given e4Graph object.
     */

    bool CauseEvent(int eventCode, const e4_RefCount &r, void *data);

    /*
     * Cause events for event codes that are predefined by e4Graph:
     */

    void CauseEventInternal(int eventCode, e4_RefCounter *r, void *data);

    /*
     * Does this storage have a callback of the given kind?
     */

    inline bool HasCallbacks(int eventCode) {
	return ((callbacksPresent & (1 << eventCode)) == (1 << eventCode))
	    ? true
	    : false;
    }

    /*
     * Create detached entities within this storage.
     */

    e4_NodeImpl   *CreateDetachedNode();
    e4_VertexImpl *CreateDetachedVertex(const char *nm, e4_NodeImpl *nip);
    e4_VertexImpl *CreateDetachedVertex(const char *nm, int i);
    e4_VertexImpl *CreateDetachedVertex(const char *nm, double d);
    e4_VertexImpl *CreateDetachedVertex(const char *nm, const char *s);
    e4_VertexImpl *CreateDetachedVertex(const char *nm, const void *bytes,
					int nbytes);

    /*
     * Helper method to move a vertex to a node at a position computed
     * from 'order' and 'rank'.
     */

    bool MoveVertex(int nodeID, int vertexID, e4_InsertOrder order, int rank);

    /*
     * This is a storage:
     */

    inline virtual e4_RefKind Kind() const {return E4_RKSTORAGE;}

    /*
     * Is vertex ID caching allowed?
     */

    inline bool CachingVertexIDs() {
	return ((statemask & E4_NOVERTEXCACHE) == E4_NOVERTEXCACHE) 
	    ? false
	    : true;
    }

    /*
     * Is this instance valid?
     */

    virtual bool IsValid() const {
	if (!destroyed) {
	    return DRV_IsValid();
	}
	return false;
    }

protected:

    /*
     * These operations are for use by e4_Storage, e4_StorageVisitor,
     * e4_NodeImpl, and e4_VertexImpl:
     */

    friend class e4_Storage;
    friend class e4_StorageVisitor;
    friend class e4_NodeImpl;
    friend class e4_VertexImpl;

    /*
     * Get the ID of a given node.
     */

    int GetNodeID(e4_Node n) const;

    /*
     * Retrieve the first e4_StorageImpl:
     */

    static e4_StorageImpl *GetFirstStorageImpl();

    /*
     * Retrieve the next e4_StorageImpl after the given one.
     */

    static e4_StorageImpl *GetNextStorageImpl(e4_StorageImpl *si);

    /*
     * This method is called when the reference count goes to (or below)
     * zero.
     */

    virtual void NotReferenced();
    
    /*
     * This method is called to clean up any references from this
     * e4_StorageImpl to other instances.
     */

    void CleanUp();

    /*
     * This method is called to clean up the associated state after a
     * storage is made empty with MakeEmpty().
     */

    void HashCleanup();

    /*
     * The destructor is declared and is virtual so that derived classes can
     * clean up their own state.
     */

    virtual ~e4_StorageImpl();
    
    /*
     * This constructor is used by derived classes.
     */

    e4_StorageImpl(const char *name, const char *dnm, int pps);

    /*
     * Retrieve e4_NodeImpl and e4_VertexImpl instances from the cache
     * given their IDs.
     */

    e4_VertexImpl *FindReferencedVertex(int vertexID) const;
    e4_NodeImpl *FindReferencedNode(int nodeID) const;

    /*
     * Find a node given its node ID; create the e4_NodeImpl instance if it is
     * not yet in-memory.
     */

    e4_NodeImpl *FindNode(int nodeID) const;
    e4_NodeImpl *FindOrCreateNode(int nodeID) const;
    e4_NodeImpl *FindOrCreateNode(int nodeID, bool *isNew) const;

    /*
     * Store a node in the activeNodes hash table.
     */

    void StoreNode(int nodeID, e4_NodeImpl *n) const;

    /*
     * Forget a node by removing it from the activeNodes table.
     */

    void ForgetNode(int nodeID);

    /*
     * Retrieve an instance of e4_VertexImpl for a given vertex in a node.
     * Creates and caches the instance if necessary.
     */

    e4_VertexImpl *GetVertex(int id) const;

    /*
     * Store a vertex in the activeVertices hash table.
     */

    void StoreVertex(int vertexID, e4_VertexImpl *f) const;

    /*
     * Forget a vertex by removing it from the activeVertices table.
     */

    void ForgetVertex(int vertexID);

    /*
     * Is this vertex or node referenced by the user of e4Graph?
     */

    bool IsReferencedNode(int nodeID) const;
    bool IsReferencedVertex(int vertexID) const;

    /*
     * Methods to iterate over all entities referenced by the user program.
     */

    int FirstReferencedNodeID(e4_HashSearch *searchP);
    int NextReferencedNodeID(e4_HashSearch *searchP);
    int FirstReferencedVertexID(e4_HashSearch *searchP);
    int NextReferencedVertexID(e4_HashSearch *searchP);

    /*
     * Enter the name only into the storage-wide hash table. It is already
     * in the persistent storage.
     */

    void AddNameToNameHash(const char *nm, int idx) const;

    /*
     * Given a nameID, get the actual name.
     */

    const char *NameFromNameID(int nameID) const;

    /* 
     * APIs to manage the GC state:
     *
     * The GC state vector contains bits denoting the GC state of each
     * node and vertex in this storage.
     */

    void RegisterGCState(int id, int mask);
    void UnregisterGCState(int id, int mask);
    bool IsGCState(int id, int mask);

    void RegisterUnreachableVertexID(int vertexID);
    void UnregisterUnreachableVertexID(int vertexID);
    void RegisterMaybeUnreachableVertexID(int vertexID);
    void UnregisterMaybeUnreachableVertexID(int vertexID);
    void RegisterReachableVertexID(int vertexID);
    void UnregisterReachableVertexID(int vertexID);
    void SetScannedVertexID(int vertexID);
    void ClearScannedVertexID(int vertexID);

    void RegisterUnreachableNodeID(int nodeID);
    void UnregisterUnreachableNodeID(int nodeID);
    void RegisterMaybeUnreachableNodeID(int nodeID);
    void UnregisterMaybeUnreachableNodeID(int nodeID);
    void RegisterReachableNodeID(int nodeID);
    void UnregisterReachableNodeID(int nodeID);
    void SetScannedNodeID(int nodeID);
    void ClearScannedNodeID(int nodeID);

    bool IsMaybeUnreachableNodeID(int nodeID);
    bool IsReachableNodeID(int nodeID);
    bool IsUnreachableNodeID(int nodeID);
    bool IsScannedNodeID(int nodeID);

    bool IsMaybeUnreachableVertexID(int vertexID);
    bool IsReachableVertexID(int vertexID);
    bool IsUnreachableVertexID(int vertexID);
    bool IsScannedVertexID(int vertexID);

    int FirstGCEntity(int mask);
    int NextGCEntity(int i, int mask);

    int FirstUnreachableNodeID();
    int NextUnreachableNodeID(int cur);
    int FirstMaybeUnreachableNodeID();
    int NextMaybeUnreachableNodeID(int cur);
    int FirstReachableNodeID();
    int NextReachableNodeID(int cur);

    int FirstUnreachableVertexID();
    int NextUnreachableVertexID(int cur);
    int FirstMaybeUnreachableVertexID();
    int NextMaybeUnreachableVertexID(int cur);
    int FirstReachableVertexID();
    int NextReachableVertexID(int cur);

    /*
     *=========================================================================
     *
     * DRIVER API SECTION:
     *
     * The APIs defined below this header are all pure virtual. They must
     * all be supplied by a class derived from e4_StorageImpl. All of these
     * APIs have names starting with DRV_ to denote that they form the driver
     * interface.
     *
     *=========================================================================
     */

public:

    /*
     * Cause a commit *now*.
     */

    virtual bool DRV_Commit() = 0;

    /*
     * Is this storage valid?
     */

    virtual bool DRV_IsValid() const = 0;

    /*
     * Set the ID of the root node:
     */

    virtual bool DRV_SetRootNodeID(int ID) = 0;
    virtual int	 DRV_GetRootNodeID() = 0;
    virtual bool DRV_IsRootNodeID(int ID) = 0;
    
    /*
     * Given a vertex ID, get the e4_VertexImpl instance representing the
     * next vertex in the containing node.
     */

    virtual e4_VertexImpl *DRV_FindNextVertex(int vertexID,
					      e4_VisitMethod vm,
					      int vv,
					      int nameID, 
					      int nodeID,
					      int parentID,
					      e4_VertexType typeID,
					      e4_DetachChoice dc)
	const = 0;

    /*
     * Given a node ID, get the e4_NodeImpl instance representing the
     * next node in the storage.
     */

    virtual e4_NodeImpl *DRV_FindNextNode(int nodeID) const = 0;

    /*
     * Get a value for a statistic being collected for this storage.
     */

    virtual bool DRV_GetStatistic(e4_Space sp, e4_SpaceStat st, int &v) = 0;

    /*
     * Return the hash code associated with this storage.
     */

    virtual int DRV_HashCode() const = 0;

    /*
     * Do a GC.
     */

    virtual void DRV_DoGC(int reqstate) = 0;

    /*
     * Is a GC needed?
     */

    virtual bool DRV_NeedsGC() const = 0;

    /*
     * Note that a GC is needed.
     */

    virtual void DRV_SetNeedsGC(bool needs) = 0;

protected:

    /*
     * APIs for supporting GC (new GC):
     */

    virtual void DRV_FreeNode(int id) = 0;
    virtual void DRV_FreeVertex(int id) = 0;

    /*
     * Mark a node or vertex as having had the detach notify callback
     * delivered.
     */

    virtual void DRV_MarkDetachNotifiedNodeID(int id) = 0;
    virtual void DRV_MarkDetachNotifiedVertexID(int id) = 0;

    /*
     * Has a detach callback not yet been delivered for this node or vertex?
     */

    virtual bool DRV_IsNewlyDetachedNodeID(int id) = 0;
    virtual bool DRV_IsNewlyDetachedVertexID(int id) = 0;

    /*
     * Determine whether the node or vertex identified by
     * the given ID is detached.
     */

    virtual bool DRV_IsDetachedNodeID(int id) const = 0;
    virtual bool DRV_IsDetachedVertexID(int id) const = 0;

    /*
     * Detach a vertex or node.
     */

    virtual bool DRV_DetachNodeByID(int id) = 0;
    virtual bool DRV_DetachVertexByID(int id) = 0;

    /*
     * Get the vertex ID of the first detached vertex whose value is
     * the given node ID. Similarly, get the vertex ID of the next
     * detached vertex whose value is the given node.
     */

    virtual int DRV_GetFirstDetachedVertexIDWithNodeID(int id) const = 0;
    virtual int DRV_GetNextDetachedVertexIDAfter(int id) const = 0;

#ifdef	NOTDEF
    /*
     * Add an element to a free-list.
     */

    virtual void DRV_UnusedNode(int id) = 0;
    virtual void DRV_UnusedInt(int id) = 0;
    virtual void DRV_UnusedDouble(int id) = 0;
    virtual void DRV_UnusedString(int id) = 0;
    virtual void DRV_UnusedName(int id) = 0;
    virtual void DRV_UnusedBinary(int id) = 0;
#endif

    /*
     * Count how many vertices there are in a node, given the nodeID.
     */

    virtual int DRV_VertexCountFromNodeID(int nodeID) const = 0;

    /*
     * Count how many vertices in a node identified by its nodeID have
     * a given name, type or value.
     */

    virtual int DRV_VertexCountWithNameIDFromNodeID(int nodeID,
						    int vertexID,
						    int nameID)
	const = 0;
    virtual int DRV_VertexCountWithTypeFromNodeID(int nodeID,
						  int vertexID,
						  e4_VertexType tp)
	const = 0;
    virtual int DRV_VertexCountWithValueFromNodeID(int nodeID, 
						   int vertexID,
						   const e4_Value &v)
	const = 0;

    /*
     * If parentID is a parent of childID then return true, else false.
     */

    virtual bool DRV_IsParentID(int parentID, int childID) const = 0;

    /*
     * Find the rank of a child node in the vertex list of a node.
     */

    virtual int DRV_GetRankOfChildNode(int parentID,
				       int childID,
				       int ith) const = 0;
    
    /*
     * Set a vertex whose vertex ID is given.
     */
    
    virtual bool DRV_SetVertex(int vertexID,
			       int nameID, 
			       int vertexType,
			       int itemID) = 0;

    /*
     * Add a vertex according to the rank and io arguments to a node whose
     * node ID is given.
     */
    
    virtual int DRV_AddVertex(int nodeID, e4_InsertOrder io, int &rank) = 0;
    
    /*
     * Find the rank of a vertex with a given index in a node whose node ID
     * is given.
     */

    virtual int DRV_RankFromVertexID(int nodeID, int vertexID) const = 0;

    /*
     * Find the nth vertex with a given name in a list of vertices.
     */
    
    virtual int DRV_VertexIDFromNthVertex(int nodeID,
					  int nameID,
					  int nth,
					  int &rank) 
	const = 0;

    /*
     * Given the rank of a vertex in this node, find the corresponding
     * vertex ID.
     */

    virtual int DRV_VertexIDFromRank(int nodeID, int rank) const = 0;

    /*
     * Get the parent node of a node or the parent ID, given the child node ID.
     */

    virtual e4_NodeImpl *DRV_GetParentNode(int childID, int nth) const = 0;
    virtual int DRV_GetParentNodeID(int childID, int nth) const = 0;

    /*
     * Find the next vertex after this one in the node containing this
     * one.
     */

    virtual e4_VertexImpl *DRV_NextVertex(int num, int vertexID) const = 0;

    /*
     * Find the previous vertex before this one in the node containing
     * this vertex.
     */

    virtual e4_VertexImpl *DRV_PrevVertex(int num, int vertexID) const = 0;

    /*
     * Find the vertex ID for the next vertex after the one identified by
     * the given vertexID.
     */

    virtual int DRV_NextVertexID(int vertexID) const = 0;

    /*
     * Find the vertex ID for the previous vertex before the one identified
     * by the given vertexID.
     */

    virtual int DRV_PrevVertexID(int vertexID) const = 0;

    /*
     * Get the vertex ID for the vertex containing this node in its parent.
     */

    virtual int DRV_GetVertexIDInParent(int parentID,
					int nodeID,
					int nth)
	const = 0;

    /*
     * Get vertex IDs for the first or last vertex in a node, given 
     * the node ID.
     */

    virtual int DRV_GetFirstVertexID(int nodeID) const = 0;
    virtual int DRV_GetLastVertexID(int nodeID) const = 0;

    /*
     * Given a vertex ID, find the e4_NodeImpl instance representing the node
     * that contains that vertex.
     */

    virtual e4_NodeImpl *DRV_ContainingNodeFromVertexID(int vertexID)
	const = 0;
    virtual int DRV_ContainingNodeIDFromVertexID(int vertexID) const = 0;

    /*
     * Check that a node ID is legal.
     */

    virtual bool DRV_IsLegalNodeID(int index) const = 0;
    
    /*
     * Check that a vertex ID is legal.
     */

    virtual bool DRV_IsLegalVertexID(int index) const = 0;

    /*
     * Get the value of a vertex whose vertex ID is given.
     */

    virtual bool DRV_GetVertexByIndex(int index, e4_ValueImpl *&v) const = 0;
    virtual bool DRV_GetVertexByIndex(int index, e4_NodeImpl *&n) const = 0;
    virtual bool DRV_GetVertexByIndex(int index, int &v) const = 0;
    virtual bool DRV_GetVertexByIndex(int index, double &f) const = 0;
    virtual bool DRV_GetVertexByIndex(int index, const char *&s) const = 0;
    virtual bool DRV_GetVertexByIndex(int index,
				      const void *&bytes,
				      int &nbytes)
	const = 0;

    /*
     * Set the value of a vertex whose vertex ID is given.
     */

    virtual bool DRV_SetVertexByIndex(int index, int v) = 0;
    virtual bool DRV_SetVertexByIndex(int index, double f) = 0;
    virtual bool DRV_SetVertexByIndex(int index, const char *s) = 0;
    virtual bool DRV_SetVertexByIndex(int index,
				      const void *bytes, 
				      int nbytes)
	= 0;
    virtual bool DRV_SetVertexByIndexToNode(int index, int childID) = 0;

    /*
     * Rename a vertex whose index is given.
     */

    virtual bool DRV_RenameVertexByVertexID(int vertexID, int nameID) = 0;

    /*
     * Return the vertex type and name of the vertex whose ID is given.
     */

    virtual e4_VertexType DRV_VertexTypeFromVertexID(int vertexID) const = 0;
    virtual int DRV_NodeIDFromVertexID(int vertexID) const = 0;
    virtual const char *DRV_VertexNameFromVertexID(int vertexID) const = 0;
    virtual int DRV_NameIDFromVertexID(int vertexID) const = 0;

    /*
     * Retrieve the value of an entry. If the vertex identified by the
     * given index contains a value of the requested type, the value is
     * placed in the output parameter and true is returned. Otherwise,
     * false is returned and the value of the output parameter is left
     * unmodified.
     */

    virtual bool DRV_GetNode(int index, e4_NodeImpl *&value) const = 0;
    virtual bool DRV_GetInt(int index, int &value) const = 0;
    virtual bool DRV_GetDouble(int index, double &value) const = 0;
    virtual bool DRV_GetString(int index, char *&value) const = 0;
    virtual bool DRV_GetBinary(int index, void *&value, int &nbytes) const = 0;
    virtual bool DRV_GetVertexName(int index, const char *&value) const = 0;

    /*
     * Get the raw value of a specific vertex as an index. For use only
     * by GC.
     */

    virtual bool DRV_GetRawValue(int index, int &value) const = 0;

    /*
     * Get the index of the node that is the value of the given vertex.
     */

    virtual bool DRV_GetNodeID(int index, int &value) const = 0;

    /*
     * Specialized version of GetNode that also returns an indication
     * whether the node is newly created.
     */

    virtual bool DRV_GetNode(int index, e4_NodeImpl *&value, bool *isNew) 
	const = 0;
    
    /*
     * Add a new entry to one of the type-specific spaces. The operation
     * returns the index of the new item.
     */

    virtual int DRV_ReserveNodeID() = 0;
    virtual int DRV_ReserveVertexID(int nameID) = 0;
    virtual int DRV_AddInt(int value) = 0;
    virtual int DRV_AddDouble(double value) = 0;
    virtual int DRV_AddString(const char *value) = 0;
    virtual int DRV_AddBinary(const void *value, int nbytes) = 0;
    virtual int DRV_AddName(const char *nm) = 0;

    /*
     * Move the vertex identified by vertexID into the node identified by
     * nodeID as the first vertex.
     */

    virtual bool DRV_MoveVertexToFirst(int vertexID, int nodeID) = 0;

    /*
     * Move the vertex identified by vertexID into the node identified by
     * nodeID as the last vertex.
     */

    virtual bool DRV_MoveVertexToLast(int vertexID, int nodeID) = 0;

    /*
     * Move the vertex identified by vertexID to immediately after the
     * vertex identified by afterVertexID.
     */

    virtual bool DRV_MoveVertexAfter(int vertexID,
				     int afterVertexID,
				     int rank)
	= 0;

    /*
     * Use driver-specific methods to copy from one storage to another.
     */

    virtual bool DRV_CopyTo(e4_StorageImpl *osp) = 0;

    /*
     * Use driver-specific methods to destroy the physical storage.
     */

    virtual void DRV_Destroy() = 0;

    /*
     * Retrieve the nth vertex in the parent identified by parentID whose
     * value is the node identified by nodeID.
     */

    virtual e4_VertexImpl *DRV_GetVertexRefFromParent(int parentID,
						      int nodeID,
						      int nth)
	const = 0;

    /*
     * Retrieve the nth vertex in the ith parent of the node identified by
     * nodeID whose value is the node identified by nodeID.
     */

    virtual e4_VertexImpl *DRV_GetVertexRefFromIthParent(int i,
							 int nodeID,
							 int nth)
	const = 0;

    /*
     * How many nodes in this storage are parents of the node with the
     * given ID?
     */

    virtual int DRV_ParentCount(int nodeID) const = 0;

    /*
     * How many times does the node with the given ID appear as the
     * value of a vertex in this storage?
     */

    virtual int DRV_OccurrenceCount(int nodeID) const = 0;

    /*
     * How many times does the node with the given child ID appear as
     * the value of a vertex in the node with the given parent ID?
     */

    virtual int DRV_OccurrenceCount(int nodeID, int parentID) const = 0;

    /*
     * What is the rank of the node with the given parent ID for the
     * node with the given child ID?
     */

    virtual int DRV_ParentRank(int nodeID, int parentID) const = 0;

    /*
     * User data manipulation facility:
     */

    virtual bool DRV_GetNodeUserData(int nodeID, int &userData) const = 0;
    virtual bool DRV_GetVertexUserData(int vertexID, int &userData) const = 0;

    virtual bool DRV_SetNodeUserData(int nodeID, int userData) = 0;
    virtual bool DRV_SetVertexUserData(int vertexID, int userData) = 0;
};

/*
 * The e4_NodeImpl class:
 */

class e4_DLL e4_NodeImpl : public e4_RefCounter {
private:
    int flags;					/* Transient flags. */
    int cachePolicy;				/* Cache policy for
						 * this node. */
    int nodeID;					/* The ID for this node. */
    e4_StorageImpl *storage;			/* In which storage is this
                                                 * node? */
    e4_HashTable *cachedVertexIDs;		/* The cache mapping from
						 * rank or name+nth to a
						 * vertex ID. */
    bool cacheNonEmpty;				/* Set to true when some
						 * some information is cached
						 * in the cache. If false then
						 * no need to flush cache if
						 * the node changed. */

    e4_NodeImpl();				/* Ensure that noone can
						 * use the default
						 * constructor. */
    e4_NodeImpl(const e4_NodeImpl &);		/* Nor copy construction */
    void operator= (const e4_NodeImpl *);	/* Nor assignment */

public:
    /*
     * There is no public constructor. The only way to get an 
     * e4_NodeImpl instance is to call an API on a storage or
     * another entity that returns a node.
     */

    virtual ~e4_NodeImpl();			/* Deletes the e4_NodeImpl *BUT
						 * NOT* the datum. This
						 * just releases the program
						 * memory data structure which
						 * is only a cache for the
						 * node in its view. Use
						 * e4_NodeImpl::Detach() 
						 * to detach a node. */

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

    int VertexCount() const;

    /*
     * How many vertices in this node have the given name, type or value?
     */

    int VertexCountWithName(const char *nm) const;
    int VertexCountWithType(e4_VertexType tp) const;
    int VertexCountWithValue(const e4_Value &v) const;

    /*
     * Set or add a vertex whose value is a node:
     */

    e4_NodeImpl *SetNthNode(const char *nm, int nth);
    e4_NodeImpl *SetNode(const char *nm);
    e4_NodeImpl *SetNodeByRank(int rank);
    e4_NodeImpl *AddNode(const char *nm, e4_InsertOrder order, int &rank);

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

    bool SetNthVertex(const char *nm, int nth, int v);
    bool SetNthVertex(const char *nm, int nth, double f);
    bool SetNthVertex(const char *nm, int nth, const char *s);
    bool SetNthVertex(const char *nm, int nth, const void *b, int nbytes);
    bool SetNthVertexToNode(const char *nm, int nth, int childID);

    /*
     * Set the value of a vertex identified by rank. The return value is
     * true if the vertex is new and false if it existed beforehand.
     */
    
    bool SetVertexByRank(int rank, int v);
    bool SetVertexByRank(int rank, double f);
    bool SetVertexByRank(int rank, const char *s);
    bool SetVertexByRank(int rank, const void *bytes, int nbytes);
    bool SetVertexByRankToNode(int rank, int childID);

    /*
     * These operations create a new vertex with the requested name and
     * add it at the position specified by the order and rank arguments.
     * The rank argument is in-out; on the way in, in combination with
     * the order argument, it determines where in the node the new vertex
     * is created. On the way out, it gives the caller the rank of the
     * new vertex created. Upon success, true is returned. If an error
     * occurred, rank is set to E4_VERTEXNOTCREATED and false is returned.
     */

    bool AddVertex(const char *nm, e4_InsertOrder order, int &rank, int v);
    bool AddVertex(const char *nm, e4_InsertOrder order, int &rank, double f);
    bool AddVertex(const char *nm, e4_InsertOrder order, int &rank,
		   const char *s);
    bool AddVertex(const char *nm, e4_InsertOrder order, int &rank,
		   const void *b, int nbytes);
    bool AddVertexWithNode(const char *nm, e4_InsertOrder order, int &rank,
			   int childID);

    /*
     * Operations to add a vertex and return an e4_VertexImpl for the 
     * new vertex in one step. This is much more efficient than AddVertex
     * followed by GetVertexRef.
     */

    e4_VertexImpl *AddVertexRef(const char *nm, e4_InsertOrder order, 
				int &rank, int v);
    e4_VertexImpl *AddVertexRef(const char *nm, e4_InsertOrder order,
				int &rank, double f);
    e4_VertexImpl *AddVertexRef(const char *nm, e4_InsertOrder order,
				int &rank, const char *s);
    e4_VertexImpl *AddVertexRef(const char *nm, e4_InsertOrder order,
				int &rank, const void *b, int nbytes);
    e4_VertexImpl *AddVertexRefWithNode(const char *nm, e4_InsertOrder order,
					int &rank, int childID);

    e4_VertexImpl *AddNodeRef(const char *nm, e4_InsertOrder order, int &rank,
			      e4_NodeImpl *&n);

    /*
     * Operations to get data from vertices in this node. These operations
     * return true if the vertex is found and then the output parameter is
     * modified to refer to the vertex value. If the vertex is not found then
     * the operation returns false and the output parameter is not modified.
     *
     * The char * and void * returned are valid only until the next call to
     * any e4Tree API. If the caller needs to keep access to the value,
     * copy the value into memory owned by the caller.
     */

    bool GetNthVertex(const char *nm, int nth, e4_ValueImpl *&v);
    bool GetNthVertex(const char *nm, int nth, e4_NodeImpl *&n);
    bool GetNthVertex(const char *nm, int nth, int &v);
    bool GetNthVertex(const char *nm, int nth, double &f);
    bool GetNthVertex(const char *nm, int nth, const char *&s);
    bool GetNthVertex(const char *nm,
		      int nth,
		      const void *&v,
		      int &nbytes);

    bool GetVertexByRank(int rank, e4_ValueImpl *&v);
    bool GetVertexByRank(int rank, e4_NodeImpl *&n);
    bool GetVertexByRank(int rank, int &v);
    bool GetVertexByRank(int rank, double &f);
    bool GetVertexByRank(int rank, const char *&s);
    bool GetVertexByRank(int rank, const void *&v, int &nbytes);

    /*
     * Detach a vertex:
     */

    bool DetachVertex(const char *nm, int nth);
    bool DetachVertexByRank(int rank);

    /*
     * Detach the first vertex whose value is a given child node.
     */

    bool DetachFirstVertexWithNode(e4_NodeImpl *childImpl);

    /*
     * Get an e4_VertexImpl pointer for a vertex identified either by rank or
     * by name and nth.
     */

    e4_VertexImpl *GetVertexRef(const char *nm, int nth);
    e4_VertexImpl *GetVertexRefByRank(int rank);

    /*
     * This operation returns the type of the datum stored in the
     * named vertex. If the vertex does not exist then E4_VERTEXNOTFOUND
     * is returned.
     */

    e4_VertexType VertexType(const char *nm, int nth);
    e4_VertexType VertexTypeByRank(int rank);

    /*
     * Return the name of the vertex whose rank is given. Returns NULL
     * if no such vertex is present.
     */

    const char *VertexName(int rank);

    /*
     * Rename a vertex identified by a rank. Returns true if the vertex
     * exists, false otherwise.
     */

    bool RenameVertex(int rank, const char *newNm);

    /*
     * This operation retrieves the rank of the "n"th vertex with the given
     * name in this node. The operation returns E4_VERTEXNOTFOUND if there is
     * no matching vertex, or the rank of the matching vertex.
     */

    int VertexRank(const char *nm, int nth);
    bool Exists(const char *nm, int nth);

    /*
     * Node->Node operations:
     */

    e4_NodeImpl *GetParent(int nth) const;

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

    e4_VertexImpl *GetVertexRefFromParent(int i, int nth) const;

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

    e4_VertexImpl *GetVertexRefFromParent(e4_NodeImpl *p, int nth) const;

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

    int ParentCount() const;

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

    int OccurrenceCount() const;

    /*
     * How many vertices point from this parent to this child node?
     */

    int OccurrenceCount(int parentID) const;

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

    int ParentRank(int parentID) const;

    /*
     * Node->Storage: get the storage in which this node appears.
     */

    e4_StorageImpl *GetStorage() const;
    
    /*
     * Compute the rank of the ith vertex in the nth parent of this node
     * whose value is this node. If not found, returns -1.
     */

    int GetRankInParent(int nth, int ith) const;
    int GetRankInParent(e4_NodeImpl *p, int ith) const;

    /*
     * Retrieve the name of the ith vertex in the nth parent of this node
     * whose value is this node. If not found, returns NULL.
     */

    const char *GetNameInParent(int nth, int ith) const;
    const char *GetNameInParent(e4_NodeImpl *p, int ith) const;

    /*
     * A node is the "root" if it is the node returned by s.GetRootNode()
     * when called on its storage.
     */

    bool IsRoot() const;

    /*
     * This operation returns an ID which uniquely identifies this e4_NodeImpl
     * in the e4_StorageImpl that contains it.
     */

    int GetUniqueID() const;

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

    bool Detach();

    /*
     * Is this node detached?
     */

    bool IsDetached() const;

    /*
     * Is this instance valid?
     */

    virtual bool IsValid() const;

    /*
     * Manage the user data associated with this node.
     */

    bool GetUserData(int &userData) const;
    bool SetUserData(int userData);

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

    bool GetVertexUserData(const char *nm, int nth, int &userData);
    bool SetVertexUserData(const char *nm, int nth, int userData);

    bool GetVertexUserDataByRank(int rank, int &userData);
    bool SetVertexUserDataByRank(int rank, int userData);

    /*
     * Move the vertex identified by vertexID into the node identified
     * by nodeID at the given rank.
     */

    bool MoveVertex(int vertexID, e4_InsertOrder order, int rank);

    /*
     * This is a node:
     */

    inline virtual e4_RefKind Kind() const {return E4_RKNODE;}

    /*
     * Manage transient flags:
     */

    /*
     * Return true if all the flags in the given mask are set for this
     * vertex.
     */

    inline bool HasFlags(int mask) const {
	return ((flags & mask) == mask) ? true : false;
    }

    /*
     * Set all the flags in the given mask.
     */

    inline void SetFlags(int mask) {
	flags |= mask;
    }

    /*
     * Clear all the flags in the given mask.
     */

    inline void ClearFlags(int mask) {
	flags &= (~(mask));
    }

    /*
     * Set/get advisory cache management policy flags.
     */

    inline int SetAdvisoryCachingPolicy(bool set, int mask) {
	int oldFlags = cachePolicy;

	if (set) {
	    cachePolicy |= mask;
	} else {
	    cachePolicy &= (~(mask));
	}
	return oldFlags;
    }
    inline int GetAdvisoryCachingPolicy() const {return cachePolicy;}

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

    void PreCache();
    void PreCache(int mask);

protected:

    /*
     * This method is called when the reference count goes to (or below)
     * zero.
     */

    virtual void NotReferenced();

    /*
     * These methods are for use by e4_StorageImpl and e4_VertexImpl only:
     */

    friend class e4_StorageImpl;
    friend class e4_VertexImpl;

    /*
     * Constructor which takes a node ID:
     */

    e4_NodeImpl(e4_StorageImpl *s, int nodeID);

    /*
     * Cache APIs:
     */

    void FlushCache();
    void CacheVertexIDByName(int nameID, int nth, int vid);
    void CacheVertexIDByRank(int rank, int vid);
    void CacheVertexRankByID(int vid, int rank);
    int GetCachedVertexIDByName(int nameID, int nth) const;
    int GetCachedVertexIDByRank(int rank) const;
    int GetCachedVertexRankByID(int vid) const;

    /*
     * Get the index of the first and last vertex in this node.
     */

    int GetFirstVertexID() const;
    int GetLastVertexID() const;

    /*
     * Get the node ID.
     */

    int GetNodeID() const;

    /*
     * Set the storage instance variable.
     */

    void SetStorage(e4_StorageImpl *newstorage);
};

/*
 * The e4_VertexImpl class:
 */

class e4_DLL e4_VertexImpl : public e4_RefCounter {

private:
    e4_VertexImpl();				/* Ensure that noone can
						 * use the default
						 * constructor. */
    e4_VertexImpl(const e4_VertexImpl &);	/* Nor copy construction. */
    void operator= (const e4_VertexImpl &);	/* Nor assignment. */

    int flags;					/* Transient flags. */
    int vertexID;				/* Unique ID for this 
						 * vertex. */
    e4_StorageImpl *s;				/* The e4_StorageImpl that the
                                                 * containing vertex appears
                                                 * in. */
public:
    /*
     * Destructor:
     */

    virtual ~e4_VertexImpl();			/* Deletes the e4_VertexImpl
						 * BUT NOT the datum. This just
						 * releases the program
						 * memory data structure which
						 * is only a cache for the
						 * view-based vertex. To remove
						 * the underlying vertex, use
						 * e4_VertexImpl::Detach and
						 * invalidate all references
						 * to it. Storage is recycled
						 * automatically. */

    /*
     * Get the vertex content.
     */

    bool Get(e4_ValueImpl *&v) const;
    bool Get(e4_NodeImpl *&node) const;
    bool Get(int &v) const;
    bool Get(double &d) const;
    bool Get(const char *&str) const;
    bool Get(const void *&bytes, int &nbytes) const;

    /*
     * Set the target (value) of the vertex (and potentially its type).
     */

    bool Set(int v);
    bool Set(double v);
    bool Set(const char *v);
    bool Set(const void *bytes, int nbytes);
    bool SetToNode(int childID);

    /*
     * Set the value (target) of this vertex to a new node.
     */

    e4_NodeImpl *SetNode() const;

    /*
     * Get the rank of this vertex in its source node.
     */

    int Rank() const;

    /*
     * Get the count of vertices up to this one with the same
     * name as this one in the node containing this vertex.
     * Return -1 if this vertex is detached.
     */

    int CountWithName() const;

    /*
     * Get the total count of vertices in the node containing
     * this one with the same name as this vertex. If this
     * vertex is detached then return -1.
     */

    int TotalCountWithName() const;

    /*
     * Get the count of vertices up to this one with the same
     * type as this one in the node countaining this vertex.
     * Return -1 if this vertex is detached.
     */

    int CountWithType() const;

    /*
     * Get the total count of vertices in the node containing
     * this one with the same type as this vertex. If this
     * vertex is detached then return -1.
     */

    int TotalCountWithType() const;

    /*
     * Return the next vertex after this in this node.
     */

    inline e4_VertexImpl *Next(int num) const
    {
	if (s == NULL) {
	    return NULL;
	}
	return s->DRV_NextVertex(num, vertexID);
    }

    /*
     * Return the previous vertex before this in this node.
     */

    inline e4_VertexImpl *Prev(int num) const
    {
	if (s == NULL) {
	    return NULL;
	}
	return s->DRV_PrevVertex(num, vertexID);
    }

    /*
     * Detach this vertex from its containing node.
     */

    bool Detach();

    /*
     * Is this vertex detached?
     */

    bool IsDetached() const;

    /*
     * Is this vertex valid?
     */

    inline virtual bool IsValid() const {
	if (s == NULL) {
	    return false;
	}
	return (s->IsValid() && s->DRV_IsLegalVertexID(vertexID));
    }

    /*
     * Get the vertex type for this vertex.
     */

    inline e4_VertexType Type() const {
	if (s == NULL) {
	   return E4_VTUNKNOWN;
	}
	return s->DRV_VertexTypeFromVertexID(vertexID);
    }

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

    inline const char *Name() const {
	if (s == NULL) {
	    return NULL;
	}
	return s->DRV_VertexNameFromVertexID(vertexID);
    }

    /*
     * Rename this vertex.
     */

    bool Rename(const char *newname) const;
	
    /*
     * This operation returns an ID which uniquely identifies this 
     * e4_VertexImpl within the e4_StorageImpl that contains it.
     */

    inline int GetUniqueID() const {
	if (s == NULL) {
	    return E4_VERTEXNOTFOUND;
	}
	return vertexID;
    }

    /*
     * Get the storage and node back out of this vertex.
     */

    inline e4_StorageImpl *GetStorage() const {return s;}
    inline e4_NodeImpl *GetNode() const {
        if (s == NULL) {
            return NULL;
        }
        return s->DRV_ContainingNodeFromVertexID(vertexID);
    }

    /*
     * Move the vertex identified by moveVertexID to the given position
     * within the node containing this vertex.
     */

    bool MoveVertex(int moveVertexID, int rank) const;

    /*
     * Manage the user data associated with this vertex.
     */

    bool GetUserData(int &userData) const;
    bool SetUserData(int userData);

    /*
     * This is a vertex.
     */

    inline virtual e4_RefKind Kind() const {return E4_RKVERTEX;}

    /*
     * Manage transient flags:
     */

    /*
     * Return true if all the flags in the given mask are set for this
     * vertex.
     */

    inline bool HasFlags(int mask) const {
	return ((flags & mask) == mask) ? true : false;
    }

    /*
     * Set all the flags in the given mask.
     */

    inline void SetFlags(int mask) {
	flags |= mask;
    }

    /*
     * Clear all the flags in the given mask.
     */

    inline void ClearFlags(int mask) {
	flags &= (~(mask));
    }

protected:

    /*
     * This method is called when the reference count goes to (or below)
     * zero.
     */

    virtual void NotReferenced();

    /*
     * These operations are for use by e4_StorageImpl and e4_NodeImpl only:
     */

    friend class e4_StorageImpl;
    friend class e4_NodeImpl;

    /*
     * Constructor:
     */

    e4_VertexImpl(e4_StorageImpl *st, int ii);

    /*
     * Set the storage instance variable of this vertex.
     */

    inline void SetStorage(e4_StorageImpl *ns) {s = ns;}
};

/*
 * This defines the type of driver construction functions:
 */

typedef e4_StorageImpl *(*e4_StorageConstructor)(const char *,
						 int state,
						 int perms);

/*
 * This defines the type of driver storage version getter functions:
 */

typedef bool (*e4_StorageVersionGetter)(const char *,
					int &,
					int &,
					e4_ReleaseStatus &,
					int &);

/*
 * This class is used to associate functions with a given driver
 * name.
 */

class e4_DriverFunctions {
  public:
    e4_StorageConstructor Constructor;
    e4_StorageVersionGetter StorageVersionGetter;

    /*
     * Constructor:
     */

    e4_DriverFunctions(e4_StorageConstructor sc,
		       e4_StorageVersionGetter sv)
    {
	Constructor = sc;
	StorageVersionGetter = sv;
    };
};

/*
 * The Initialize method initializes and pre-registers all the
 * built-in drivers. You can call this many times, it protects
 * against re-initialization.
 */

e4_DLL void e4_InitializeStorageRegistry();

/*
 * Given a driver name get its registered storage constructor.
 */

e4_DLL e4_StorageConstructor e4_GetStorageConstructor(const char *drivername);

/*
 * Given a driver name get its version getter function.
 */

e4_DLL e4_StorageVersionGetter e4_GetStorageVersionGetter(const char *dn);

/*
 * Register storage driver functions so that they are retrievable
 * given a specified name.
 */

e4_DLL bool e4_RegisterStorageFunctions(e4_StorageConstructor scp,
					e4_StorageVersionGetter svp,
					const char *drivername);

/*
 * Deregister storage driver functions for a given storage driver.
 */

e4_DLL bool e4_UnregisterStorageFunctions(const char *drivername);

/*
 * Is there a driver registered under the given name?
 */

e4_DLL bool e4_NamedDriverExists(const char *drivername);
	
#endif	/* __E4_GRAPHIMPL_H__ */
