# OSG node visitor specific test procedures.

package require Tk
package require tcl3d

proc bgerror { msg } {
    puts "Error: $msg\n$::errorInfo" ; flush stdout
}

proc visit { node args } {
    global gUseGui gTreeRootId gGraphParents

    set nodeName     [osg::Object_getName $node]
    set nodeType     [osg::Object_className $node]
    set nodeMask     [osg::Node_getNodeMask $node]
    set nodeStateSet [osg::Node_getStateSet $node]
    scan $node "_%x" nodeAddr
    if { $nodeName eq "" } {
        set nodeName $nodeType
    }

    puts "visit <$nodeName>"
    puts "  Type: $nodeType"
    puts [format "  Mask: %0X"  $nodeMask]
    puts "  StateSet: $nodeStateSet"
    puts -nonewline "  Parents:"

    set n [osg::Node_getNumParents $node]
    if { $n == 0 } {
        # This node does not have a parent. Thus it must be the root node.
        puts -nonewline " NONE"
        if { $gUseGui } {
            set gTreeRootId [.tv insert {} end -id $nodeAddr -tags $nodeAddr \
                             -text $nodeName -open true -values [list $nodeType $node]]
            .tv item $nodeAddr -image [tcl3dOsgGetBitmap $nodeType]
        }
    } elseif { $n == 1 } {
        # This node has exactly 1 parent. Thus we can insert it into the tree easily.
        set parent [osg::Node_getParent $node 0]
        puts -nonewline " [osg::Object_getName $parent]"
        scan $parent "_%x" parentAddr
        if { $gUseGui } {
            .tv insert $parentAddr end -id $nodeAddr -tags $nodeAddr \
                -text $nodeName -open true -values [list $nodeType $node]
            .tv item $nodeAddr -image [tcl3dOsgGetBitmap $nodeType]
        }
    } else {
        # We have a node with more than 1 parent, i.e. it is a graph and not a tree.
        set insertItem false
        for { set i 0 } { $i < $n } { incr i } {
            set parent [osg::Node_getParent $node $i]
            puts -nonewline " [osg::Object_getName $parent]"
            scan $parent "_%x" parentAddr

            if { $gUseGui && $insertItem == false } {
                set isReference false
                if { ! [info exists gGraphParents($nodeAddr)] } {
                    # First time this node is encountered.
                    set insertItem true
                    set nodeImg [tcl3dOsgGetBitmap $nodeType]
                    set gGraphParents($nodeAddr) 1
                    set gGraphParents($nodeAddr,$parentAddr) 1
                    set nodeId $nodeAddr
                } elseif { [info exists gGraphParents($nodeAddr,$parentAddr)] } {
                    # This node has already been inserted with the given parent.
                    set insertItem false
                } else {
                    # This node has already been inserted previously. Now a reference
                    # must be inserted.
                    set insertItem true
                    set nodeImg [tcl3dOsgGetBitmap $nodeType]
                    set gGraphParents($nodeAddr,$parentAddr) 1
                    set nodeId ${nodeAddr}_$i
                    set isReference true
                }

                if { $insertItem } {
                    .tv insert $parentAddr end -id $nodeId -tags $nodeId \
                        -text $nodeName -open true \
                        -values [list $nodeType $node]
                    .tv item $nodeId -image $nodeImg
                    if { $isReference } {
                        .tv tag configure $nodeId -background lightgreen
                    }
                }
            }
        }
    }
    puts ""
    puts -nonewline "  Desc:"
    set n [osg::Node_getNumDescriptions $node]
    for { set i 0 } { $i < $n } { incr i } {
        set desc [osg::Node_getDescription $node $i]
        puts -nonewline " <$desc>"
    }
    puts ""
    flush stdout
}

set gUseGui false
if { $argc > 0 } {
    set gUseGui true
    package require tile
}

if { $gUseGui } {
    # If running in GUI mode for interactive testing, create a tree widget.
    set columnNames [list "Type" "Address"]
    ttk::treeview .tv -height 12 -columns $columnNames
    pack .tv -expand true -fill both
    .tv heading #0 -text "Tree" -anchor w
    .tv heading  0 -text "Type" -anchor w
    .tv heading  1 -text "Address" -anchor w
    foreach col $columnNames {
        .tv column $col -width 80 -minwidth 50 -anchor w
    }
    .tv column "Address" -width 150 -minwidth 150 -anchor w
    bind . <Escape> exit
}

# Construct our test scene graph.
osg::Group root
osg::Group g1
osg::Group g2
osg::Group g3
root setName "root"
root addDescription "This is the root node"
g1   setName "g1"
g2   setName "g2"
g3   setName "g3"

osg::Group g1_1
osg::Group g1_2
g1_1 setName "g1_1"
g1_2 setName "g1_2"
g1_1 addDescription "This is group g1_1"
g1_2 addDescription "This is group g1_2"

osg::Node g2_1
osg::Node g2_2
g2_1 setName "n2_1"
g2_2 setName "n2_2"

osg::Geode geo
geo setName "geo"

root addChild g1
root addChild g2
root addChild g3

g1 addChild g1_1
g1 addChild g1_2

g2 addChild g2_1
g2 addChild g2_2

# Add the geode to 3 groups, so the geode has more than 1 parent.
g1 addChild geo
g2 addChild geo
g3 addChild geo

if { ! $gUseGui } {
    # Write out the scene graph in batch mode for auto. diffing in module tests.
    osgDB::writeNodeFile root "testOut/testOsgNodeVisitor.osg"
}

set travMode $::osg::NodeVisitor_TRAVERSE_NONE
set travMode $::osg::NodeVisitor_TRAVERSE_PARENTS
set travMode $::osg::NodeVisitor_TRAVERSE_ALL_CHILDREN

osg::tcl3dOsgNodeVisitor nv $travMode
nv setVisitorType $::osg::NodeVisitor_NODE_VISITOR
nv setVisitorProc visit

puts "NodeVisitor properties:"
puts "    Traversal mode: [tcl3dOsgGetTraversalModeName $travMode]"
puts [format "    Traversal mask: %0X"  [nv getTraversalMask]]
puts "    Visitor type  : [tcl3dOsgGetVisitorTypeName [nv getVisitorType]]"
puts "    Visitor proc  : [nv getVisitorProc]"

root accept nv

if { ! $gUseGui } {
    exit 0
}
