/* 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
 */

#include <grass/gis.h>

/*
 * Edge Traversing
 */
int DGL_EDGE_T_INITIALIZE_FUNC(dglGraph_s *pGraph,
                               dglEdgeTraverser_s *pT UNUSED,
                               dglEdgePrioritizer_s *pEP UNUSED)
{
#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 UNUSED)
{
}

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;
#if !defined(_DGL_V1)
    dglInt32_t *pInEdgeset;
#endif
    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);
#if !defined(_DGL_V1)
        pInEdgeset = DGL_T_NODEITEM_InEdgesetPTR(ptreenode);
#endif

        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;
}
