#pragma prototyped
#include <aghdr.h>
#ifdef DMALLOC
#include "dmalloc.h"
#endif
static char Descriptor_id[] = "AG_cmpnd";
typedef struct Agcmpnode_s {
Agrec_t hdr;
Agraph_t *subg;
int collapsed;
} Agcmpnode_t;
typedef struct Agcmpgraph_s {
Agrec_t hdr;
Agnode_t *node;
Dict_t *hidden_node_set;
} Agcmpgraph_t;
typedef struct save_e_s {
Agnode_t *from,*to;
} save_e_t;
typedef struct save_stack_s {
save_e_t *mem;
int stacksize;
} save_stack_t;
typedef struct Agcmpedge_s {
Agrec_t hdr;
save_stack_t stack[2];
} Agcmpedge_t ;
#define IN_STACK 0
#define OUT_STACK 1
static save_stack_t *save_stack_of(Agedge_t *e, Agnode_t *node_being_saved)
{
int i;
Agcmpedge_t *edgerec;
edgerec = (Agcmpedge_t*)agbindrec(e,Descriptor_id,sizeof(*edgerec),FALSE);
if (node_being_saved == AGHEAD(e)) i = IN_STACK;
else i = OUT_STACK;
return &(edgerec->stack[i]);
}
static void stackpush(save_stack_t *stk, Agnode_t *from, Agnode_t *to)
{
int i, osize, nsize;
osize = (stk->stacksize) * sizeof(stk->mem);
i = stk->stacksize++;
nsize = (stk->stacksize) * sizeof(stk->mem);
stk->mem = agrealloc(agraphof(from),stk->mem,osize,nsize);
stk->mem[i].from = from;
stk->mem[i].to = to;
}
static save_e_t stacktop(save_stack_t *stk)
{
save_e_t rv;
if (stk->stacksize > 0)
rv = stk->mem[stk->stacksize - 1];
else
rv.from = rv.to = NILnode;
return rv;
}
static save_e_t stackpop(save_stack_t *stk)
{
save_e_t rv;
rv = stacktop(stk);
if (stk->stacksize > 0) stk->stacksize--;
return rv;
}
typedef struct Agsplice_arg_s {
int head_side;
Agnode_t *target;
} Agsplice_arg_t ;
static void splice(Agobj_t *obj, void *arg)
{
Agraph_t *g;
Agedge_t *e,*opp;
Agnode_t *target,*t,*h;
Agedge_t **dict_of_del, **dict_of_ins, **dict_of_relabel;
Agsplice_arg_t *spl;
e = (Agedge_t*)obj;
g = agraphof(e);
t = AGTAIL(e);
h = AGHEAD(e);
opp = AGOPP(e);
spl = arg;
target = spl->target;
if ((e->node == h) != spl->head_side) {
Agedge_t *t = e; e = opp; opp = t;
}
if (spl->head_side) {
dict_of_relabel = &(t->out);
dict_of_del = &(h->in);
dict_of_ins = &(target->in);
}
else {
dict_of_relabel = &(h->in);
dict_of_del = &(t->out);
dict_of_ins = &(target->out);
}
agdeledgeimage(g,dict_of_del,opp);
agdeledgeimage(g,dict_of_relabel,e);
e->node = target;
aginsedgeimage(g,dict_of_ins,opp);
aginsedgeimage(g,dict_of_relabel,e);
}
int agsplice(Agedge_t *e, Agnode_t *target)
{
Agnode_t *t,*h;
Agraph_t *g,*root;
Agsplice_arg_t splice_arg;
if ((e == NILedge) || (e->node == target)) return FAILURE;
g = agraphof(e);
t = AGTAIL(e);
h = AGHEAD(e);
splice_arg.head_side = (e->node == h);
splice_arg.target = target;
root = agroot(g);
agapply(root,(Agobj_t*)e,splice,&splice_arg,TRUE);
return SUCCESS;
}
Agnode_t *agcmpnode(Agraph_t *g, char *name)
{
Agnode_t *n;
Agraph_t *subg;
n = agnode(g,name,TRUE);
subg = agsubg(g,name);
if (n && g && agassociate(n,subg)) return n;
else return NILnode;
}
int agassociate(Agnode_t *n, Agraph_t *sub)
{
Agcmpnode_t *noderec;
Agcmpgraph_t *graphrec;
if (agsubnode(sub,n,FALSE)) return FAILURE;
noderec = agbindrec(n,Descriptor_id,sizeof(*noderec),FALSE);
graphrec = agbindrec(sub,Descriptor_id,sizeof(*graphrec),FALSE);
if (noderec->subg || graphrec->node) return FAILURE;
noderec->subg = sub; graphrec->node = n;
return SUCCESS;
}
static void delete_outside_subg(Agraph_t *g, Agnode_t *node, Agraph_t *subg)
{
Agraph_t *s, **subglist;
Agnode_t *n;
Agcmpgraph_t *graphrec;
Dict_t *d;
if ((g != subg) && (n = agsubnode(g,(Agnode_t*)node,FALSE))) {
dtdelete(g->n_dict,n);
graphrec = agbindrec(g,Descriptor_id,sizeof(*graphrec),FALSE);
if ((d = graphrec->hidden_node_set) == NIL(Dict_t*)) {
d = graphrec->hidden_node_set
= agdtopen(g,&Ag_node_name_disc,Dttree);
}
dtinsert(d,n);
subglist = agsubglist(g);
while ((s = *subglist++)) delete_outside_subg(s,node,subg);
}
}
int aghide(Agnode_t *cmpnode)
{
Agcmpnode_t *noderec;
Agraph_t *g,*subg,*root;
Agnode_t *n,*nn,*rootn;
Agedge_t *e,*opp,*f;
g = agraphof(cmpnode);
if (agcmpgraph_of(cmpnode) == NILgraph) return FAILURE;
noderec = (Agcmpnode_t*)aggetrec(cmpnode,Descriptor_id,FALSE);
subg = noderec->subg; root = agroot(g);
if ((n = agsubnode(subg,cmpnode,FALSE))) agdelnode(n);
for (n = agfstnode(subg); n; n = agnxtnode(n)) {
rootn = agsubnode(root,n,FALSE);
for (e = agfstedge(rootn); e; e = f) {
f = agnxtedge(e,rootn);
if (agsubedge(subg,e,FALSE)) continue;
opp = AGOPP(e);
stackpush(save_stack_of(e,rootn),rootn,cmpnode);
agsplice(opp,cmpnode);
}
}
for (n = agfstnode(subg); n; n = nn) {
nn = agnxtnode(n);
delete_outside_subg(root,n,subg);
}
agdelsubg(agparent(subg),subg);
noderec->collapsed = TRUE;
g->desc.has_cmpnd = TRUE;
return SUCCESS;
}
static void insert_outside_subg(Agraph_t *g, Agnode_t *node, Agraph_t *subg)
{
Agraph_t *s, **subglist;
Agnode_t *n;
Agcmpgraph_t *graphrec;
if ((g != subg) && ((n = agsubnode(g,(Agnode_t*)node,FALSE)) == NILnode)) {
graphrec = (Agcmpgraph_t*) aggetrec(g,Descriptor_id,FALSE);
if (graphrec && ((n = (Agnode_t*)dtsearch(graphrec->hidden_node_set,node))))
dtinsert(g->n_dict,n);
subglist = agsubglist(g);
while ((s = *subglist++)) delete_outside_subg(s,node,subg);
}
}
int agexpose(Agnode_t *cmpnode)
{
Agcmpnode_t *noderec;
Agcmpedge_t *edgerec;
Agraph_t *g,*subg,*root;
Agnode_t *n,*rootcmp;
Agedge_t *e,*f;
save_stack_t *stk;
save_e_t sav;
int i;
g = agraphof(cmpnode);
noderec = (Agcmpnode_t*)aggetrec(cmpnode,Descriptor_id,FALSE);
if ((noderec == NIL(Agcmpnode_t*) || NOT(noderec->collapsed)))
return FAILURE;
subg = noderec->subg;
agsubgrec_insert(agsubgrec(agparent(subg)),subg);
for (n = agfstnode(subg); n; n = agnxtnode(n))
insert_outside_subg(g,n,subg);
root = agroot(g); rootcmp = agsubnode(root,cmpnode,FALSE);
for (e = agfstedge(rootcmp); e; e = f) {
f = agnxtedge(e,rootcmp);
if ((edgerec = (Agcmpedge_t*)aggetrec(e,Descriptor_id,FALSE))) {
for (i = 0; i < 2; i++) {
stk = &(edgerec->stack[i]);
sav = stacktop(stk);
if (sav.to && (AGID(sav.to) == AGID(cmpnode))) {
if (e->node != sav.to) e = AGOPP(e);
agsplice(e,sav.from);
stackpop(stk);
continue;
}
}
}
}
noderec->collapsed = FALSE;
return SUCCESS;
}
Agraph_t *agcmpgraph_of(Agnode_t *n)
{
Agcmpnode_t *noderec;
noderec = (Agcmpnode_t*) aggetrec(n,Descriptor_id,FALSE);
if (noderec && NOT(noderec->collapsed)) return noderec->subg;
else return NILgraph;
}
Agnode_t *agcmpnode_of(Agraph_t *g)
{
Agcmpgraph_t *graphrec;
graphrec = (Agcmpgraph_t*) aggetrec(g,Descriptor_id,FALSE);
if (graphrec) return graphrec->node; else return NILnode;
}
Agnode_t *agfindhidden(Agraph_t *g, char *name)
{
Agcmpgraph_t *graphrec;
Agnode_t key;
graphrec = (Agcmpgraph_t*) aggetrec(g,Descriptor_id,FALSE);
if (graphrec) {
key.name = name;
return (Agnode_t*) dtsearch(graphrec->hidden_node_set,&key);
}
else return NILnode;
}