// $Id$ -*- C++ -*-
// Graph layout functions

// Copyright (C) 1995 Technische Universitaet Braunschweig, Germany.
// Written by Christian Lindig <lindig@ips.cs.tu-bs.de>.
// 
// This file is part of DDD.
// 
// DDD 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 3 of the License, or (at your option) any later version.
// 
// DDD 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 DDD -- see the file COPYING.
// If not, see <http://www.gnu.org/licenses/>.
// 
// DDD is the data display debugger.
// For details, see the DDD World-Wide-Web page, 
// `http://www.gnu.org/software/ddd/',
// or send a mail to the DDD developers <ddd@gnu.org>.

#ifndef _DDD_layout_h
#define _DDD_layout_h

// All these should be defined in the LayouterExpert class,
// but I can't get gcc 2.3.3 swallow it...
enum EDGEARROW { Here, Other };
enum NODETYPE { Regular, Hint };

typedef struct _EGDE EDGE;
typedef struct _EDGELIST EDGELIST;
typedef struct _REGULAR REGULAR;
typedef struct _HINT HINT;
typedef union _ATTRIBUTES ATTRIBUTES;
typedef union _ID ID;
typedef struct _NODE NODE;
typedef struct _GRAPH GRAPH;

#define PRIME 809
#define SMALLPRIME 41
typedef GRAPH *GRAPHTAB[SMALLPRIME];

// More definitions
struct _EGDE {
    NODE *node;
    NODE *target;
    EDGEARROW arrow;        /* kind of edge */
    EDGE *next;             /* next entry of list */
    EDGE *prev;             /* previous entry */
};

struct _EDGELIST {
    EDGE *head;             /* first entry */
    EDGE *tail;             /* last entry */
    int length;             /* number of elements */
};

struct _REGULAR {
    char *label;            /* the name of the node */
    int w,h;                /* regular nodes have width & height */
    EDGELIST up;            /* ancestors */
    EDGELIST down;          /* descendants */
};
struct _HINT {
    int id;                 /* hints are identified by ids */
    NODE *up;
    NODE *down;
    NODE *source;           /* the two nodes connected by */
    NODE *target;           /* the edge this hint belongs to */
};

union _ATTRIBUTES {
    REGULAR node;
    HINT hint;
};

union _ID {
    int id;
    const char *label;
};

struct _NODE {
    int x,y;                /* position */
    int oldx,oldy;          /* previous position */

    bool layouted;           /* flag: already layouted? */
    int level;              /* level inside graph */
    int center;             /* avrg. bary-center of node */
    int loop;               /* flag for loop */
    int index;              /* auxilliary */
    NODE *mark;             /* auxilliary */

    NODE *left;             /* same level - to the left */
    NODE *right;            /* same level - to the right */
    
    NODE *hashnext;         /* double linked list for hashtab */
    NODE *hashprev;

    NODETYPE type ;         /* type of node and tag for union */
    ATTRIBUTES attr;
};

struct _GRAPH {
    NODE *hashtab[PRIME];

    int levels;
    NODE **level;    
    char *label;
    GRAPH *hashnext;
    GRAPH *hashprev;

    int minxdist;
    int minydist;
    bool reverseflag;
    int xiterations;
    bool pullup;

    bool layouted;           /* flag, if graph was layouted recently */
};

// Interface
class Layout {
public:
    static void add_graph(const char *g);
    static void add_node(const char *g, const char *node);
    static void add_edge(const char *g, const char *node1, const char *node2);
    static void set_node_width(const char *g, const char *node, int width);
    static void set_node_height(const char *g, const char *node, int height);
    static void set_node_position(const char *g, const char *node, int x, int y);
    static void add_edge_hint(const char *g, const char *node1, const char *node2, 
			      int x, int y);
    static void remove_edge_hint(const char *g, const char *node1, const char *node2, 
				 int x, int y);
    static void remove_edge(const char *g, const char *node1, const char *node2);
    static void remove_node(const char *g, const char *label);
    static void remove_graph(const char *g);
    static void layout(const char *g);
    
    static void (*node_callback)(const char *, int, int);
    static void (*hint_callback)(const char *, const char *, int, int);
    static int (*compare_callback)(const char *, const char *);


    // Data
    // static GRAPHTAB tab;

    // Helpers
    static void dddDebug(const char *g);
    static void inc_layout(GRAPH *graph);
    static void new_layout(GRAPH *graph);
    static void dddOutput(GRAPH *graph);
    static void dddNodeOut(const char *graph, NODE *node);
    static void debugNode(NODE *node);
    static void debugLevel(GRAPH *graph, int n);
    static void debugAllLevel(GRAPH *graph);
    static void debugAllNodes(GRAPH *graph);
    static void debugNodeXFig(NODE *nd);
    enum Arrow { HERE=0, OTHER=1, NOTHING=3 };
    static void debugEdgeXFig(NODE *source, NODE *target, Arrow arrow);
    static void debugGraphXFig(GRAPH *graph);
    static void listInit(EDGELIST *list);
    static EDGE *listInsertEdge(EDGELIST *list, NODE *node);
    static void listRemoveEdge(EDGELIST *list, EDGE *edge);
    static EDGE *listFindNode(EDGELIST *list, NODE *node);
    static EDGE *listFindTarget(EDGELIST *list, NODE *target);
    static void listRemove(EDGELIST *list);
    static void nodeInit(NODE* node, const ID *id , NODETYPE type);
    static void nodeRemove(NODE *node);
    static void graphInit(GRAPH *graph, const char *label);
    static NODE *graphEnterNode(GRAPH *graph, const ID *id, NODETYPE type);
    static NODE *graphGetNode(GRAPH *graph, const ID *id, NODETYPE type);
    static void graphRemoveNode(GRAPH *graph, const ID *id, NODETYPE type);
    static void graphCreateLevels(GRAPH *graph, int n);
    static void graphRemoveLevels(GRAPH *graph);
    static void graphAddLevels(GRAPH *graph, int n);
    static void graphInsertEdge(GRAPH *graph,NODE *source,NODE *target);
    static void graphInvertEdge(NODE *source, NODE *target);
    static int graphNewNodeID();
    static NODE *graphInsertHint(GRAPH *graph, NODE *source, NODE* target);
    static EDGE *graphFindEdgeAtSource(NODE *source, NODE *target);
    static EDGE *graphFindEdgeAtTarget(NODE *source, NODE *target);
    static void graphResetLevels(GRAPH *graph);
    static int graphHashStr(const char *str, int prime);
    static GRAPH *graphGet(GRAPHTAB *tab, const char *label);
    static GRAPH *graphNew(GRAPHTAB *tab, const char *label);
    static void graphRemove(GRAPHTAB *tab, const char *label);
    static void graphTabInit(GRAPHTAB *tab);
    static void levelsInsertNode(GRAPH *graph, NODE *node, int n);
    static void levelsRemoveNode(GRAPH *graph, NODE *node, int n);
    static void levelsEnterNodes(GRAPH *graph, bool pullup);
    static void levelsIndex(NODE **level);
    static int levelsLength(NODE **level);
    static int sortApplyLevel(GRAPH *graph);
    static void sortPullupNodes(GRAPH *graph);
    static int minimumLevel(NODE *node);
    static int distance(NODE *node, NODE *origin);
    static void sortInsertHints(GRAPH *graph);
    static void sortCheckNode(GRAPH *graph, NODE *node);
    static int sortNodeUpperBary(NODE *node);
    static int sortNodeLowerBary(NODE *node);
    static void sortGraphUpperBary(GRAPH *graph);
    static void sortGraphLowerBary(GRAPH *graph);
    static void sortByCenter(NODE **level);
    static void sortAvrgCenter(GRAPH *graph);
    static int sortCmpCenters(NODE **first, NODE **second);
    static void sortInitX(GRAPH *graph);
    static void sortGraphUpX(GRAPH *graph);
    static void sortGraphDownX(GRAPH *graph);
    static void sortLevelUpX(NODE **level, int dist);
    static void sortLevelDownX(NODE **level, int dist);
    static int sortLeftSpace(NODE *node, int dist);
    static void sortMoveLeft(NODE *node, int newx, int dist);
    static void sortMoveRight(NODE *node, int newx, int mindist);
    static void sortMove(NODE *node, int newx, int mindist);
    static int sortAvrgUpperX(NODE *node);
    static int sortAvrgLowerX(NODE *node);
    static int sortCmpUpperPrio(NODE **fst, NODE **snd);
    static int sortCmpLowerPrio(NODE **fst, NODE **snd);
    static int sortLevelVertical(NODE **level, int miny, int minydist);
    static void sortGraphVertical(GRAPH *graph);
};

#endif // _DDD_layout_h
// DON'T ADD ANYTHING BEHIND THIS #endif
