/* LIBDGL -- a Directed Graph Library implementation
 * Copyright (C) 2002 Roberto Micarelli
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/*
 * best view with tabstop=4
 */

/*
 * Edge Traversing
 */
int DGL_EDGE_T_INITIALIZE_FUNC( dglGraph_s * pGraph , dglEdgeTraverser_s * pT , dglEdgePrioritizer_s * pEP ) {
#if defined(_DGL_V1)
	pGraph->iErrno = DGL_ERR_NotSupported;
	return -pGraph->iErrno;
#else
	if ( pGraph->Flags & DGL_GS_FLAT ) {
		if ( pEP && pEP->pvAVL ) {
			if ( (pT->pvAVLT = malloc( sizeof(struct avl_traverser) )) == NULL ) {
				pGraph->iErrno = DGL_ERR_MemoryExhausted;
				return -pGraph->iErrno;
			}
			avl_t_init( pT->pvAVLT , pEP->pvAVL );
			pT->pnEdge = NULL;
			pT->pEdgePrioritizer = pEP;
		}
		else {
			pT->pvAVLT = NULL;
			pT->pnEdge = NULL;
			pT->pEdgePrioritizer = NULL;
		}
	}
	else {
		if ( (pT->pvAVLT = malloc( sizeof(struct avl_traverser) )) == NULL ) {
			pGraph->iErrno = DGL_ERR_MemoryExhausted;
			return -pGraph->iErrno;
		}
		if ( pEP && pEP->pvAVL ) {
			avl_t_init( pT->pvAVLT , pEP->pvAVL );
			pT->pnEdge = NULL;
			pT->pEdgePrioritizer = pEP;
		}
		else {
			avl_t_init( pT->pvAVLT , pGraph->pEdgeTree );
			pT->pnEdge = NULL;
			pT->pEdgePrioritizer = NULL;
		}
	}
	pT->pGraph = pGraph;
	return 0;
#endif
}

void DGL_EDGE_T_RELEASE_FUNC( dglEdgeTraverser_s * pT ) {
#if defined(_DGL_V1)
	pT->pGraph->iErrno = DGL_ERR_NotSupported;
#else
	if ( pT->pvAVLT ) free( pT->pvAVLT );
	pT->pvAVLT = NULL;
	pT->pnEdge = NULL;
	pT->pEdgePrioritizer = NULL;
#endif
}

dglInt32_t * DGL_EDGE_T_FIRST_FUNC( dglEdgeTraverser_s * pT ) {
#if defined(_DGL_V1)
	pT->pGraph->iErrno = DGL_ERR_NotSupported;
	return NULL;
#else
	dglGraph_s * pG = pT->pGraph;

	pT->pnEdge = NULL;
	if ( pT->pvAVLT && pT->pEdgePrioritizer ) {
		dglEdgePrioritizer_s * pPri = pT->pEdgePrioritizer;
		dglTreeEdgePri32_s * pItem;

		pItem = avl_t_first( pT->pvAVLT, pPri->pvAVL );
		if ( pItem ) {
/*
printf("edge_t_first: cEdge=%ld\n", pItem->cnData);
*/
			pPri->cEdge = pItem->cnData;
			pPri->iEdge = 0;
			if ( pPri->iEdge < pPri->cEdge ) {
				pT->pnEdge = DGL_GET_EDGE_FUNC(pG, pItem->pnData[pPri->iEdge]);
				pPri->iEdge++;
			}
		}
		pPri->pEdgePri32Item = pItem;
	}
	else if ( pT->pvAVLT ) {
		dglTreeEdge_s * pEdgeItem;

		if ( (pEdgeItem = avl_t_first( pT->pvAVLT, pG->pEdgeTree )) == NULL ) {
			pT->pnEdge = NULL;
		}
		else {
			pT->pnEdge = pEdgeItem->pv;
		}
	}
	else {
		if ( pG->cEdge > 0 ) pT->pnEdge = (dglInt32_t*)pG->pEdgeBuffer;
		else pT->pnEdge = NULL;
	}
	return pT->pnEdge;
#endif
}

dglInt32_t * DGL_EDGE_T_NEXT_FUNC( dglEdgeTraverser_s * pT )
{
#if defined(_DGL_V1)
	pT->pGraph->iErrno = DGL_ERR_NotSupported;
	return NULL;
#else
	dglGraph_s * pG = pT->pGraph;

	pT->pnEdge = NULL;

	if ( pT->pvAVLT && pT->pEdgePrioritizer ) {
		dglEdgePrioritizer_s * pPri = pT->pEdgePrioritizer;
		dglTreeEdgePri32_s * pItem = pPri->pEdgePri32Item;

		if (pItem && pPri->iEdge < pPri->cEdge) {
			pT->pnEdge = DGL_GET_EDGE_FUNC(pG, pItem->pnData[pPri->iEdge]);
			pPri->iEdge++;
		}
		else {
			if ( (pItem = avl_t_next(pT->pvAVLT)) != NULL ) {
				pPri->cEdge = pItem->cnData;
				pPri->iEdge = 0;
				if ( pPri->iEdge < pPri->cEdge ) {
					pT->pnEdge = DGL_GET_EDGE_FUNC(pG, pItem->pnData[pPri->iEdge]);
					pPri->iEdge++;
				}
			}
			pPri->pEdgePri32Item = pItem;
		}
	}
	else if ( pT->pvAVLT ) {
		dglTreeEdge_s * pItem;

		if ( (pItem = avl_t_next( pT->pvAVLT )) != NULL ) {
			pT->pnEdge = pItem->pv;
		}
	}
	else {
		pT->pnEdge += DGL_NODE_WSIZE( pG->EdgeAttrSize);
		if (pT->pnEdge >= (dglInt32_t*)(pG->pEdgeBuffer + pG->iEdgeBuffer) ) {
			pT->pnEdge = NULL;
		}
	}
	return pT->pnEdge;
#endif
}


/*
 * Node Traversing
 */
int DGL_NODE_T_INITIALIZE_FUNC( dglGraph_s * pGraph , dglNodeTraverser_s * pT ) {
	if ( pGraph->Flags & DGL_GS_FLAT ) {
		pT->pnNode = NULL;
		pT->pvAVLT = NULL;
	}
	else {
		if ( (pT->pvAVLT = malloc( sizeof(struct avl_traverser) )) == NULL ) {
			pGraph->iErrno = DGL_ERR_MemoryExhausted;
			return -pGraph->iErrno;
		}
		avl_t_init( pT->pvAVLT , pGraph->pNodeTree );
		pT->pnNode = NULL;
	}
	pT->pGraph = pGraph;
	return 0;
}

void DGL_NODE_T_RELEASE_FUNC( dglNodeTraverser_s * pT ) {
	if ( pT->pvAVLT ) free( pT->pvAVLT );
	pT->pvAVLT = NULL;
	pT->pnNode = NULL;
}

dglInt32_t * DGL_NODE_T_FIRST_FUNC( dglNodeTraverser_s * pT )
{
	DGL_T_NODEITEM_TYPE * pNodeItem;

	if ( pT->pvAVLT ) {
		if ( (pNodeItem = avl_t_first( pT->pvAVLT, pT->pGraph->pNodeTree )) == NULL )
			pT->pnNode = NULL;
		else
			pT->pnNode = DGL_T_NODEITEM_NodePTR(pNodeItem);
	}
	else {
		if ( pT->pGraph->cNode > 0 ) pT->pnNode = (dglInt32_t*)pT->pGraph->pNodeBuffer;
		else pT->pnNode = NULL;
	}
	return pT->pnNode;
}

dglInt32_t * DGL_NODE_T_NEXT_FUNC( dglNodeTraverser_s * pT )
{
	DGL_T_NODEITEM_TYPE * pNodeItem;

	if ( pT->pvAVLT ) {
		if ( (pNodeItem = avl_t_next( pT->pvAVLT )) == NULL )
			pT->pnNode = NULL;
		else
			pT->pnNode = DGL_T_NODEITEM_NodePTR(pNodeItem);
	}
	else {
		pT->pnNode += DGL_NODE_WSIZE( pT->pGraph->NodeAttrSize );
		if ( pT->pnNode >= (dglInt32_t*)(pT->pGraph->pNodeBuffer + pT->pGraph->iNodeBuffer) ) pT->pnNode = NULL;
	}
	return pT->pnNode;
}

dglInt32_t * DGL_NODE_T_FIND_FUNC( dglNodeTraverser_s * pT , dglInt32_t nNodeId )
{
	DGL_T_NODEITEM_TYPE * pNodeItem , findItem;

	if ( pT->pvAVLT ) {
		findItem.nKey = nNodeId;
		if ( (pNodeItem = avl_t_find( pT->pvAVLT , pT->pGraph->pNodeTree , &findItem )) == NULL )
			pT->pnNode = NULL;
		else
			pT->pnNode = DGL_T_NODEITEM_NodePTR(pNodeItem);
	}
	else {
		pT->pnNode = DGL_GET_NODE_FUNC(pT->pGraph, nNodeId);
	}
	return pT->pnNode;
}


/*
 * Edgeset Traversing
 */
int	DGL_EDGESET_T_INITIALIZE_FUNC(
			dglGraph_s * pGraph ,
			dglEdgesetTraverser_s * pT ,
			dglInt32_t * pnEdgeset
			)
{
	pT->pGraph = pGraph;
	pT->pnEdgeset = pnEdgeset;
	pT->cEdge = (pnEdgeset)?*pnEdgeset:0;
	pT->iEdge = 0;
	return 0;
}


void DGL_EDGESET_T_RELEASE_FUNC( dglEdgesetTraverser_s * pT )
{
}

dglInt32_t * DGL_EDGESET_T_FIRST_FUNC( dglEdgesetTraverser_s * pT )
{
#if defined(_DGL_V2)
	dglInt32_t * pnOffset;
	dglTreeEdge_s * pEdgeItem, EdgeItem;
#endif

	if ( pT->cEdge == 0 ) return NULL;
	pT->iEdge = 1;
#if defined(_DGL_V1)
	return pT->pnEdgeset + 1;
#endif
#if defined(_DGL_V2)
	pnOffset = pT->pnEdgeset + 1;	
	if ( pT->pGraph->Flags & DGL_GS_FLAT ) {
		pT->pvCurrentItem = NULL;
		return DGL_EDGEBUFFER_SHIFT(pT->pGraph, *pnOffset);
	}
	else {
		EdgeItem.nKey = *pnOffset;
		if ( (pEdgeItem = avl_find( pT->pGraph->pEdgeTree, &EdgeItem )) != NULL) {
			pT->pvCurrentItem = pEdgeItem;
			return pEdgeItem->pv;
		}
	}
#endif
	return NULL;
}


dglInt32_t * DGL_EDGESET_T_NEXT_FUNC( dglEdgesetTraverser_s * pT )
{
#if defined(_DGL_V2)
	dglInt32_t * pnOffset;
	dglTreeEdge_s * pEdgeItem, EdgeItem;
#endif

	if ( pT->cEdge > 0 && pT->iEdge < pT->cEdge ) {
#if defined(_DGL_V1)
		return DGL_EDGESET_EDGE_PTR(pT->pnEdgeset, pT->iEdge++, pT->pGraph->EdgeAttrSize);
#endif
#if defined(_DGL_V2)
		pnOffset = pT->pnEdgeset + 1 + pT->iEdge++;	
		if ( pT->pGraph->Flags & DGL_GS_FLAT ) {
			return DGL_EDGEBUFFER_SHIFT(pT->pGraph, *pnOffset);
		}
		else {
			EdgeItem.nKey = *pnOffset;
			if ( (pEdgeItem = avl_find( pT->pGraph->pEdgeTree, &EdgeItem )) != NULL) {
				pT->pvCurrentItem = pEdgeItem;
				return pEdgeItem->pv;
			}
		}
#endif
	}
	return NULL;
}


/*
 * Flatten the graph
 */
int DGL_FLATTEN_FUNC( dglGraph_s * pgraph )
{
	register DGL_T_NODEITEM_TYPE * ptreenode;
#if defined(_DGL_V2)
	register dglTreeEdge_s * ptreeEdge;
	int i;
#endif
	register dglInt32_t *	pEdge;
	register dglInt32_t *	pnode;
	register dglInt32_t *	pnodescan;
	dglInt32_t *				pOutEdgeset;
	dglInt32_t *				pInEdgeset;
	int 					cOutEdgeset;
	int 					cInEdgeset;

	struct avl_traverser 	avlTraverser;

	if ( pgraph->Flags & DGL_GS_FLAT )
	{
		pgraph->iErrno = DGL_ERR_BadOnFlatGraph;
		return -pgraph->iErrno;
	}

	pgraph->pNodeBuffer = NULL; /* should be already */
	pgraph->iNodeBuffer = 0;
	pgraph->pEdgeBuffer = NULL;
	pgraph->iEdgeBuffer = 0;


#if defined(_DGL_V2)
/*
printf("flatten: traversing edges\n");
*/
	avl_t_init( & avlTraverser, pgraph->pEdgeTree );

	for	(
			ptreeEdge = avl_t_first( & avlTraverser , pgraph->pEdgeTree ) ;
			ptreeEdge ;
			ptreeEdge = avl_t_next( & avlTraverser )
		)
	{
		pEdge = ptreeEdge->pv;

/*
printf( "flatten: add edge %ld to edge buffer\n", DGL_EDGE_ID(pEdge) );
*/

		pgraph->pEdgeBuffer = realloc(
		 		pgraph->pEdgeBuffer , 
		 		pgraph->iEdgeBuffer + DGL_EDGE_SIZEOF(pgraph->EdgeAttrSize)
		 		);

		if ( pgraph->pEdgeBuffer == NULL ) {
			pgraph->iErrno = DGL_ERR_MemoryExhausted;
			return -pgraph->iErrno;
		}

		memcpy( pgraph->pEdgeBuffer + pgraph->iEdgeBuffer, pEdge, DGL_EDGE_SIZEOF(pgraph->EdgeAttrSize) );

		pgraph->iEdgeBuffer += DGL_EDGE_SIZEOF(pgraph->EdgeAttrSize);
	}
#endif

/*
printf("flatten: traversing nodes\n");
*/
	avl_t_init( & avlTraverser, pgraph->pNodeTree );

	for	(
			ptreenode = avl_t_first( & avlTraverser , pgraph->pNodeTree ) ;
			ptreenode ;
			ptreenode = avl_t_next( & avlTraverser )
		)
	{
		pnode       = DGL_T_NODEITEM_NodePTR(ptreenode);
		pOutEdgeset = DGL_T_NODEITEM_OutEdgesetPTR(ptreenode);
		pInEdgeset  = DGL_T_NODEITEM_InEdgesetPTR(ptreenode);

		if ( !(DGL_NODE_STATUS(pnode) & DGL_NS_ALONE) )
		{
			cOutEdgeset = (pOutEdgeset) ?
					DGL_EDGESET_SIZEOF(DGL_EDGESET_EDGECOUNT(pOutEdgeset), pgraph->EdgeAttrSize) :
					sizeof(dglInt32_t);

#if !defined(_DGL_V1)
			cInEdgeset = (pInEdgeset) ?
					DGL_EDGESET_SIZEOF(DGL_EDGESET_EDGECOUNT(pInEdgeset),  pgraph->EdgeAttrSize) :
					sizeof(dglInt32_t);
#else
			cInEdgeset = 0;
#endif

			pgraph->pEdgeBuffer = realloc( pgraph->pEdgeBuffer ,
					pgraph->iEdgeBuffer + cOutEdgeset + cInEdgeset );

			if ( pgraph->pEdgeBuffer == NULL )
			{
				pgraph->iErrno = DGL_ERR_MemoryExhausted;
				return -pgraph->iErrno;
			}

			{
			dglInt32_t nDummy = 0;

			memcpy( pgraph->pEdgeBuffer + pgraph->iEdgeBuffer , (pOutEdgeset)?pOutEdgeset:&nDummy , cOutEdgeset );
#if !defined(_DGL_V1)
			memcpy( pgraph->pEdgeBuffer + pgraph->iEdgeBuffer + cOutEdgeset , (pInEdgeset)?pInEdgeset:&nDummy, cInEdgeset );
#endif
			}

			DGL_NODE_EDGESET_OFFSET(pnode) = pgraph->iEdgeBuffer;

			pgraph->iEdgeBuffer += cOutEdgeset + cInEdgeset;
		}

		pgraph->pNodeBuffer = realloc(pgraph->pNodeBuffer, pgraph->iNodeBuffer + DGL_NODE_SIZEOF(pgraph->NodeAttrSize));

		if ( pgraph->pNodeBuffer == NULL )
		{
			pgraph->iErrno = DGL_ERR_MemoryExhausted;
			return -pgraph->iErrno;
		}

		memcpy( pgraph->pNodeBuffer + pgraph->iNodeBuffer , pnode , DGL_NODE_SIZEOF(pgraph->NodeAttrSize) );
		pgraph->iNodeBuffer += DGL_NODE_SIZEOF(pgraph->NodeAttrSize);
	}

#if defined(_DGL_V2)
	if ( pgraph->pEdgeTree ) {
		avl_destroy( pgraph->pEdgeTree, dglTreeEdgeCancel );
		pgraph->pEdgeTree = NULL;
	}
#endif

	if ( pgraph->pNodeTree ) {
		avl_destroy( pgraph->pNodeTree, dglTreeNodeCancel );
		pgraph->pNodeTree = NULL;
	}

	pgraph->Flags |= DGL_GS_FLAT; /* flattened */

	/*
	 * convert node-id to node-offset
	 */
	DGL_FOREACH_NODE(pgraph, pnodescan)
	{
		if ( !(DGL_NODE_STATUS(pnodescan) & DGL_NS_ALONE) )
		{
			pOutEdgeset = DGL_EDGEBUFFER_SHIFT(pgraph, DGL_NODE_EDGESET_OFFSET(pnodescan));

#if defined(_DGL_V2)
			for( i = 0 ; i < pOutEdgeset[0] ; i ++ ) {
/*
printf("flatten: node %ld: scan out edge %ld/%ld - %ld\n", DGL_NODE_ID(pnodescan), i+1, pOutEdgeset[0], pOutEdgeset[i+1]);
*/
				pEdge = DGL_GET_EDGE_FUNC(pgraph, pOutEdgeset[i+1]);
				if (pEdge == NULL) {
					pgraph->iErrno = DGL_ERR_UnexpectedNullPointer;
					return -pgraph->iErrno;
				}
				/*
printf("         retrieved id %ld\n", DGL_EDGE_ID(pEdge) );
*/
				pOutEdgeset[i+1] = DGL_EDGEBUFFER_OFFSET(pgraph,pEdge);
			}

			pInEdgeset = pOutEdgeset + pOutEdgeset[0] + 1;

			for( i = 0 ; i < pInEdgeset[0] ; i ++ ) {
					/*
printf("flatten: node %ld: scan in edge %ld/%ld - %ld\n",
			   DGL_NODE_ID(pnodescan), i+1, pInEdgeset[0], pInEdgeset[i+1]);
			   */
				pEdge = DGL_GET_EDGE_FUNC(pgraph, pInEdgeset[i+1]);
				if (pEdge == NULL) {
					pgraph->iErrno = DGL_ERR_UnexpectedNullPointer;
					return -pgraph->iErrno;
				}
				/*
printf("         retrieved id %ld\n", DGL_EDGE_ID(pEdge) );
*/
				pInEdgeset[i+1] = DGL_EDGEBUFFER_OFFSET(pgraph,pEdge);
			}
#endif

#if defined(_DGL_V2)
			{
			int iEdge;
			DGL_FOREACH_EDGE(pgraph, pOutEdgeset, pEdge, iEdge)
#else
			DGL_FOREACH_EDGE(pgraph, pOutEdgeset, pEdge)
#endif
			{
				if ( (pnode = DGL_GET_NODE_FUNC( pgraph, DGL_EDGE_HEADNODE_OFFSET(pEdge))) == NULL )
				{
					pgraph->iErrno = DGL_ERR_HeadNodeNotFound;
					return -pgraph->iErrno;
				}
				DGL_EDGE_HEADNODE_OFFSET(pEdge) = DGL_NODEBUFFER_OFFSET(pgraph, pnode);

				if ( (pnode = DGL_GET_NODE_FUNC( pgraph , DGL_EDGE_TAILNODE_OFFSET(pEdge))) == NULL )
				{
					pgraph->iErrno = DGL_ERR_TailNodeNotFound;
					return -pgraph->iErrno;
				}
				DGL_EDGE_TAILNODE_OFFSET(pEdge) = DGL_NODEBUFFER_OFFSET(pgraph, pnode);
			}
#if defined(_DGL_V2)
			}
#endif
		}
	}

	return 0;
}


int DGL_UNFLATTEN_FUNC( dglGraph_s * pgraph )
{
	register dglInt32_t *		pHead;
	register dglInt32_t *		pTail;
	register dglInt32_t *		pEdge;
	register dglInt32_t *		pEdgeset;
	int							nret;

	if ( ! (pgraph->Flags & DGL_GS_FLAT) )
	{
		pgraph->iErrno = DGL_ERR_BadOnTreeGraph;
		return -pgraph->iErrno;
	}

	/*
	 * unflag it now to avoid DGL_ADD_EDGE_FUNC() failure
	 */
	pgraph->Flags &= ~DGL_GS_FLAT;
	pgraph->cNode = 0;
	pgraph->cEdge = 0;
	pgraph->cHead = 0;
	pgraph->cTail = 0;
	pgraph->cAlone = 0;
	pgraph->nnCost = (dglInt64_t)0;

	if ( pgraph->pNodeTree == NULL ) pgraph->pNodeTree = avl_create( DGL_T_NODEITEM_Compare, NULL, dglTreeGetAllocator() );
	if ( pgraph->pNodeTree == NULL ) {
		pgraph->iErrno = DGL_ERR_MemoryExhausted;
		return -pgraph->iErrno;
	}
#if defined(_DGL_V1)
	pgraph->pEdgeTree = NULL;
#else
	if ( pgraph->pEdgeTree == NULL ) pgraph->pEdgeTree = avl_create( dglTreeEdgeCompare, NULL, dglTreeGetAllocator() );
	if ( pgraph->pEdgeTree == NULL ) {
		pgraph->iErrno = DGL_ERR_MemoryExhausted;
		return -pgraph->iErrno;
	}
#endif

	DGL_FOREACH_NODE(pgraph,pHead)
	{
		if ( DGL_NODE_STATUS(pHead) & DGL_NS_HEAD )
		{
			pEdgeset = DGL_EDGEBUFFER_SHIFT(pgraph, DGL_NODE_EDGESET_OFFSET(pHead));

#if defined(_DGL_V2)
			{
			int iEdge;
			DGL_FOREACH_EDGE(pgraph, pEdgeset, pEdge, iEdge)
#else
			DGL_FOREACH_EDGE(pgraph, pEdgeset, pEdge)
#endif
			{
				pTail = DGL_NODEBUFFER_SHIFT(pgraph, DGL_EDGE_TAILNODE_OFFSET(pEdge));

				nret = DGL_ADD_EDGE_FUNC( pgraph,
							DGL_NODE_ID(pHead),
							DGL_NODE_ID(pTail),
							DGL_EDGE_COST(pEdge),
							DGL_EDGE_ID(pEdge),
							DGL_NODE_ATTR_PTR(pHead),
							DGL_NODE_ATTR_PTR(pTail),
							DGL_EDGE_ATTR_PTR(pEdge),
							0 );

				if ( nret < 0 ) {
					goto error;
				}
			}
#if defined(_DGL_V2)
			}
#endif
		}
		else if ( DGL_NODE_STATUS(pHead) & DGL_NS_ALONE ) {
			nret = DGL_ADD_NODE_FUNC( pgraph, 
						DGL_NODE_ID(pHead),
						DGL_NODE_ATTR_PTR(pHead),
						0 );
			if ( nret < 0 ) {
				goto error;
			}
		}
	}

	/* move away flat-state data
	 */
	if ( pgraph->pNodeBuffer ) free( pgraph->pNodeBuffer );
	if ( pgraph->pEdgeBuffer ) free( pgraph->pEdgeBuffer );
	pgraph->pNodeBuffer = NULL;
	pgraph->pEdgeBuffer = NULL;
	return 0;

error:
	if ( pgraph->pNodeTree ) avl_destroy( pgraph->pNodeTree, dglTreeNodeCancel );
	if ( pgraph->pEdgeTree ) avl_destroy( pgraph->pEdgeTree, dglTreeEdgeCancel );
	pgraph->pNodeTree = NULL;
	pgraph->pEdgeTree = NULL;
	pgraph->Flags |= DGL_GS_FLAT;
	return nret;
}

