# definition of tree structures for fctree
# J. Templon NIKHEF, written May 2001 while at University of Georgia.

TINDENT = 5   # indentation (number of spaces) for nesting of text tree print

# Node: one node per subroutine, main routine, function, or block data
#       name: string, name of routine
#       children: list of Nodes, routines called by this routine.

class Node:
    def __init__(self, nodename,shape=None):
        self.name = nodename
        self.children = None
        self.shape = shape

# apply function to node and all children.
# exception: when during a traversal, it is found that a node is its own
# parent, the traversal does not follow to children.  In this way
# infinite recursion is avoided.

def init_traverse():   # prepare for new tree traversal
    for i in Lprocessed:
        Lprocessed.remove(i)
    for j in Lparent:
        Lparent.remove(j)

def applyall(node, function):
    function(node)

    if node.name in Lparent : return  # avoid infinite recursion
    if not node.children : return     # no children to process

    Lparent.append(node.name)        # push current node onto parent stack
    for child in node.children:      # process children
        applyall(child, function)
    junk = Lparent.pop()             # pop current node off parent stack

def applyunique(node, function):
    function(node)

    if node.name in Lprocessed : return # never print subtree more than once
    if not node.children : return       # no children to process

    Lprocessed.append(node.name)
    Lparent.append(node.name)           # push current node onto parent stack
    for child in node.children:         # process children
        applyunique(child, function)
    junk = Lparent.pop()                # pop current node off parent stack

def tprint(node):                       # test: text print
    spaces = 5*len(Lparent)*' '         # indentation
    print spaces+node.name

class Formathandler:                    # holds functions for formatted
                                        # traversal of tree
    def __init__(self,
                 Fnode,          # for node not yet encountered
                 Fref,           # for already-encountered node
                 Fb4child,       # for b4 application to each child
                 Fb4nextchild,   # called between application to children
                 Fafterchild,    # called after application to each child
                 Fafterchildren,  # called after traversing all children
                 filename=None) :

        self.node = Fnode
        self.ref  = Fref
        self.b4child = Fb4child
        self.b4nextchild = Fb4nextchild
        self.afterchild = Fafterchild
        self.afterchildren = Fafterchildren
        if not filename :
            self.of = sys.stdout
        else:
            self.of = open(filename,'w')

def fmt_applyunique(node, fmt):
    if node.name in Lprocessed : # never print subtree more than once
        fmt.ref(node,fmt)
        return
    fmt.node(node,fmt)
    rfirst = 1
    Lprocessed.append(node.name)
    Lparent.append(node.name)      # push current node onto parent stack
    if node.children:
        for child in node.children:
            if rfirst == 0:
                fmt.b4nextchild(fmt)
            else:
                rfirst = 0
            fmt.b4child(child,fmt)
            fmt_applyunique(child, fmt)
            fmt.afterchild(fmt)
    fmt.afterchildren(fmt)
    junk = Lparent.pop()                # pop current node off parent stack

    
Ltreenode = [ ] # list of Nodes at root of top-level trees

Dnode = { }     # dict mapping names of Node onto Node

Dsubtree = { }  # dict mapping keys cID onto subtree objects (list of Node)
                # only contains top-level 'continuation trees'
                # Node.children = Dsubtree[cID]  works.

Lparent = [ ]   # stack (implemented as list) keeping track of parents during
                # list traversal, to avoid infinite recursion in case of
                # cyclical references

Lprocessed = [ ] # list of nodes already processed in applyunique
                 # if applyunique traversal finds node in this list, its
                 # children will not be processed.
