#!/usr/local/bin/gosh

set  GoblinVersion 2.4
set GoblinTclPath [file join /usr/local/bin goblin.2.4]

#!./gosh

if {![info exists GoblinVersion]} {
    set GoblinVersion "(uninstalled)"
    set GoblinTclPath [file join [pwd] tcl]
}

set goblinDisplayMode 3

set PrintCommand "lpr"

option add *font -*-helvetica-bold-r-normal--12-*-*-*-p-*-*-*



# GOBLET Menues

frame .mbar -relief raised -borderwidth 1
pack .mbar -side top -fill x

menubutton .mbar.file -text File -underline 0 -menu .mbar.file.menu
menubutton .mbar.edit -text Edit -underline 0 -menu .mbar.edit.menu
menubutton .mbar.compose -text Compose -underline 0 -menu .mbar.compose.menu
menubutton .mbar.layout -text Layout -underline 0 -menu .mbar.layout.menu
menubutton .mbar.optimize -text Optimize -underline 0 -menu .mbar.optimize.menu
menubutton .mbar.info -text Info -underline 0 -menu .mbar.info.menu
pack .mbar.file .mbar.edit .mbar.compose .mbar.layout .mbar.optimize -side left
pack .mbar.info -side right


proc MakeMenus {} {
    MakeEditMenu
    MakeComposeMenu
    MakeOptimizeMenu
    MakeToolbar1
    MakeToolbar2
    MakeNavigationBar
}



# File Menu

menu .mbar.file.menu
.mbar.file.menu add command -label "New..." -underline 0 \
    -command SaveAndNew
.mbar.file.menu add command -label Open... -accelerator Ctrl+O \
    -command SaveAndOpen
.mbar.file.menu add command -label Save -accelerator Ctrl+S \
    -command SaveFile
.mbar.file.menu add separator
.mbar.file.menu add command -label "Print Object..." \
    -accelerator Ctrl+P -command PrintLayout
.mbar.file.menu add command -label "Save as..." -underline 5 \
    -command {source [file join $GoblinTclPath saveas.tk]}
.mbar.file.menu add command -label "Save Settings" -underline 0 \
    -command {goblin export settings}
.mbar.file.menu add separator
.mbar.file.menu add command -label Quit -accelerator Ctrl+Q \
    -command SaveAndQuit

proc SaveAndNew {} {
    global Unchanged GoblinTclPath PromptCommand
    set PromptCommand "source [file join $GoblinTclPath new.tk]"
    source [file join $GoblinTclPath changes.tk]
}

proc SaveAndOpen {} {
    global Unchanged GoblinTclPath PromptCommand
    set PromptCommand "source [file join $GoblinTclPath open.tk]"
    source [file join $GoblinTclPath changes.tk]
}

proc OpenFile {} {
    global ThisGraph OrigFileName FileName TraceDir w FileCounter
    global goblinExtension Unchanged
    if {[file exists $OrigFileName.$goblinExtension]} {
        $ThisGraph delete
        DeleteTempFiles
        set FileName [file join $TraceDir [file tail $OrigFileName]]
        ResumeSession
        if {[file exists $FileName.tmp.$goblinExtension]} {
            file copy -force $FileName.tmp.$goblinExtension $FileName.$goblinExtension
            goblin read $ThisGraph $FileName.$goblinExtension
            InitFile
            set Unchanged 0
        } else {
            file copy -force $OrigFileName.$goblinExtension $FileName.$goblinExtension
            goblin read $ThisGraph $FileName.$goblinExtension
            InitFile
        }
    }
}

proc InitFile {} {
    global FileName OrigFileName Unchanged ThisGraph FileCounter LastCommand
    global statusInfo goblinTraceCounter

    if {$OrigFileName=="unnamed"} {
        DeleteTempFiles
        goblin restart
    }
    $ThisGraph set label $FileName
    $ThisGraph master

    wm title . "GOBLET: [file tail $OrigFileName]"
    
    set Unchanged 1
    set FileCounter 1
    set LastCommand ""

    InitDisplay
    MakeMenus
}

proc SaveFile {} {
    global ThisGraph OrigFileName goblinExtension Unchanged
    
    $ThisGraph write $OrigFileName.$goblinExtension
    wm title . "GOBLET: [file tail $OrigFileName]"
    set Unchanged 1
}

proc PrintLayout {} {
    global PrintCommand GoCommand

    set GoCommand {
        PrintLayout2
        destroy .input
    }
    
    DisplayInputDialog "Print Layout"
    
    label .input.frame.text -text "Print Command:  "
    entry .input.frame.entry -textvariable PrintCommand -bg white -width 20
    pack .input.frame.text .input.frame.entry -side left -pady 2m
    bind .input.frame.entry <Return> $GoCommand
    
    focus .input.frame.entry
}

proc PrintLayout2 {} {
    global FileName FileCounter PrintCommand goblinExtension ThisGraph Mode

    if {$Mode=="trace object"} {
        set traceFile $FileName.$FileCounter
    } else {
        global ThisGraph
        $ThisGraph write $FileName.tmp.gob
        set traceFile $FileName.tmp
    }
    
    if {[$ThisGraph max cx]<=0 && [$ThisGraph max cy]<=0} {
        exec $PrintCommand $traceFile.gob
    } else {
        goblin export xfig $traceFile.$goblinExtension $traceFile.fig 
        exec fig2dev -L ps $traceFile.fig $traceFile.ps
        exec $PrintCommand $traceFile.ps
        file delete $traceFile.ps
        file delete $traceFile.fig
    }
}

proc ExportLayout {} {
    global FileName FileCounter
    
    set traceFile $FileName.$FileCounter
    
    exec fig2dev -L eps "$traceFile.fig" "$traceFile.eps"
}

proc SaveAndQuit {} {
    global Unchanged GoblinTclPath PromptCommand
    set PromptCommand QuitGoblet
    source [file join $GoblinTclPath changes.tk]
}

proc QuitGoblet {} {
    global ThisGraph FileName goblinExtension
    $ThisGraph delete
    DeleteTempFiles
    exit
}

proc RestartEngine {} {
    goblin restart
    DeleteTempFiles
    global FileCounter
    set FileCounter 1
    InitDisplay
}

proc DeleteTempFiles {} {
    global FileName goblinExtension
    catch {
        foreach {x} [glob $FileName*.$goblinExtension] {
            file delete $x
        }
    }
}

proc ResumeSession {} {
    global FileName goblinExtension goblinTraceCounter
    set max 0
    catch {
        foreach {x} [glob $FileName.*.$goblinExtension] {
            set item [string trim [file extension [file rootname \
                [file tail $x]]] .]
            if {$item!="tmp" && [expr $max<$item]} {
		set max $item
            }
        }
    }
    set goblinTraceCounter $max
    if {[file exists $FileName.tmp.$goblinExtension]} {
        destroy .info
        toplevel .info
        wm title .info "GOBLIN Info"
        wm resizable .info 0 0
    
        frame .info.frame
        pack .info.frame -padx 5m -pady 5m -side top -anchor w
        message .info.frame.msg -width 200 -anchor w \
            -text "Old session has been restored!"
        pack .info.frame.msg -side left -fill x -padx 3m
    
        frame .info.buttons
        pack .info.buttons -padx 3m -pady 3m -side bottom
        button .info.buttons.ok -text "OK" -command {destroy .info}
        pack .info.buttons.ok -side left -fill x -padx 3m
    }
}

wm protocol . WM_DELETE_WINDOW SaveAndQuit

bind . <Control-o> {SaveAndOpen}
bind . <Control-q> {SaveAndQuit}
bind . <Control-p> {PrintLayout2}
bind . <Control-s> {SaveFile}



# Edit Menu

proc MakeEditMenu {} {
    global ThisGraph
    
    destroy .mbar.edit.menu

    bind . <Control-a> {}
    bind . <Control-v> {}
    bind . <Control-x> {}
    bind . <Control-X> {source [file join $GoblinTclPath delete.tk]}
    bind . <Control-E> {source [file join $GoblinTclPath extract.tk]}
    bind . <Control-m> {MoveNodes}
    bind . <Control-e> {EditLabels}
    bind . <Control-y> {SetPredecessors}
    bind . <Control-C> {source [file join $GoblinTclPath constant.tk]}
    
    menu .mbar.edit.menu
    if {[$ThisGraph is sparse]} {
        .mbar.edit.menu add command -label "Insert Arcs" \
            -accelerator Ctrl+A -command InsertArcs
        if {![$ThisGraph is bipartite]} {
            .mbar.edit.menu add command -label "Insert Nodes" \
                -accelerator Ctrl+V -command AddNodes
            bind . <Control-v> {AddNodes}
        }
        .mbar.edit.menu add command -label "Redirect Arcs" \
            -accelerator Ctrl+R -command RedirectArcs
        .mbar.edit.menu add command -label "Delete Objects" \
            -accelerator Ctrl+X -command DeleteObjects
        .mbar.edit.menu add separator
            
        bind . <Control-a> {InsertArcs}
        bind . <Control-r> {RedirectArcs}
        bind . <Control-x> {DeleteObjects}
    }
    .mbar.edit.menu add command -label "Move Nodes" \
        -accelerator Ctrl+M -command MoveNodes
    .mbar.edit.menu add command -label "Node Positions..." \
         -underline 0 -command SetGrid
    .mbar.edit.menu add command -label "Edit Labels" \
        -accelerator Ctrl+E -command EditLabels
    .mbar.edit.menu add command -label "Set Predecessors" \
        -accelerator Ctrl+Y -command SetPredecessors
    .mbar.edit.menu add command -label "Constant Labels..." \
        -accelerator Shift+Ctrl+C \
        -command {source [file join $GoblinTclPath constant.tk]}
    .mbar.edit.menu add command -label "Metrics..." -underline 0 \
        -command {source [file join $GoblinTclPath metrics.tk]}
    .mbar.edit.menu add separator
    .mbar.edit.menu add command -label "Delete Solutions..." \
        -accelerator Shift+Ctrl+X \
        -command {source [file join $GoblinTclPath delete.tk]}
    .mbar.edit.menu add command -label "Extract Solutions..." \
        -accelerator Shift+Ctrl+E \
        -command {source [file join $GoblinTclPath extract.tk]}
}

proc ResetMode {nextMode} {
    global c w Mode StartNode ThisArc ThisNode DLabels NavigationBar

    DestroyBalloon

    if {[string equal $Mode "insert arcs"]} {
        if {$ThisArc != ""} {
            $c delete $ThisArc
            set ThisArc ""
        }
        set StartNode ""
    }

    if {[string equal $Mode "align label"]} {
        set ThisNode ""
        set ThisArc ""
    }

    if {[string equal $Mode "move nodes"]} {
        set ThisNode ""
    }

    if {[string equal $Mode "change labels"]} {
        UploadLabels
        destroy $DLabels
        set ThisNode ""
        set ThisArc ""
    }

    if {[string equal $Mode "trace object"] && ![string equal $NavigationBar ""]} {
        destroy $NavigationBar
    }
    
    destroy $w
    set Mode $nextMode
}

proc InsertArcs {} {
    ResetMode "insert arcs"
    InitEditor
    MakeHelp "(L) select start node"
}

proc AddNodes {} {
    ResetMode "insert nodes"
    InitEditor
    MakeHelp "(L) place new node"
}

proc QualifiedNode {x} {
    global ThisGraph
    if {$x!="" && [expr $x<[$ThisGraph #nodes] && $x>=0 && $x==int($x)]} {
        return 1
    } else {
        return 0
    }
}

proc QualifiedInt {x lower upper} {
    if {$x!="" && [expr $x<=$upper && $x>=$lower && $x==int($x)]} {
        return 1
    } else {
        return 0
    }
}

proc SetGrid {} {
    global Grid GoCommand

    DisplayInputDialog "Node Positions"
    
    label .input.frame.text -text "Grid for Node Positions:  "
    entry .input.frame.entry -textvariable Grid -bg white -width 5
    pack .input.frame.text .input.frame.entry -side left -pady 2m

    set GoCommand {
        if {[expr {$Grid>0 && $Grid<99999}]} {destroy .input}
    }
    bind .input.frame.entry <Return> $GoCommand
    
    focus .input.frame.entry
}

set ThisArc ""
proc MoveNodes {} {
    ResetMode "move nodes"
    InitEditor
    MakeHelp "(L) drag and drop object"
}

set DLabels .labels
proc EditLabels {} {
    ResetMode "change labels"
    InitEditor
    MakeHelp "(L) select object"
}

proc DownloadNodeLabels {v} {
    global ThisGraph ThisNode ThisDemand ThisDistance ThisColour \
        ThisPotential ThisPredecessor ThisArc
    
    set ThisNode $v
    set ThisDemand [$ThisGraph node $v demand]
    set ThisColour [$ThisGraph node $v colour]
    set ThisDistance [$ThisGraph node $v distance]
    set ThisPotential [$ThisGraph node $v potential]
    set ThisPredecessor [$ThisGraph node $v predecessor]
    set ThisArc ""
}

proc DownloadArcLabels {a} {
    global ThisGraph ThisArc ThisUpper ThisLower ThisLength \
        ThisOrientation ThisSubgraph ThisNode
    
    set ThisArc $a
    set ThisUpper [$ThisGraph arc [expr {2*$a}] ucap]
    set ThisLower [$ThisGraph arc [expr {2*$a}] lcap]
    set ThisLength [$ThisGraph arc [expr {2*$a}] length]
    set ThisOrientation [$ThisGraph arc [expr {2*$a}] orientation]
    set ThisSubgraph [$ThisGraph arc [expr {2*$a}] subgraph]
    set ThisNode ""
}

proc UploadLabels {} {
    global ThisGraph \
        ThisNode ThisDemand ThisDistance ThisColour ThisPotential ThisPredecessor \
        ThisArc ThisUpper ThisLower ThisLength ThisOrientation ThisSubgraph
    
    if {$ThisNode != ""} { \
        $ThisGraph node $ThisNode set demand $ThisDemand
        $ThisGraph node $ThisNode set distance $ThisDistance
        $ThisGraph node $ThisNode set potential $ThisPotential
        $ThisGraph node $ThisNode set colour $ThisColour
        $ThisGraph node $ThisNode set predecessor $ThisPredecessor
        PropagateModifications
    }
    
    if {$ThisArc != ""} { \
        $ThisGraph arc [expr {2*$ThisArc}] set ucap $ThisUpper
        $ThisGraph arc [expr {2*$ThisArc}] set lcap $ThisLower
        $ThisGraph arc [expr {2*$ThisArc}] set length $ThisLength
        $ThisGraph arc [expr {2*$ThisArc}] set subgraph $ThisSubgraph
        PropagateModifications
    }
}

proc SetPredecessors {} {
    ResetMode "set predecessors"
    InitEditor
    MakeHelp "(L) select node"
}

proc RedirectArcs {} {
    global ThisGraph

    ResetMode "redirect arcs"
    InitEditor
    if {![$ThisGraph is directed]} {
        MakeHelp "(L) flip direction  (R) enable/disable direction"
    } else {
        MakeHelp "(L) flip direction"
    }
}

proc DeleteObjects {} {
    ResetMode "delete objects"
    InitEditor
    MakeHelp "(L) delete object"
}

proc PropagateModifications {} {
    global Unchanged FileName
    set Unchanged 0
    wm title . "GOBLET: [file tail $FileName] (modified)"
}



# Compose Menu

proc MakeComposeMenu {} {
    global ThisGraph
    
    destroy .mbar.compose.menu

    menu .mbar.compose.menu
    .mbar.compose.menu add command -label "Underlying Graph" -underline 0 \
        -command "SaveAndCompose underlying"
    .mbar.compose.menu add command -label "Orientation" -underline 0 \
        -command "SaveAndCompose orientation"
    .mbar.compose.menu add command -label "Complement" -underline 0 \
        -command "SaveAndCompose complement"
    .mbar.compose.menu add command -label "Line Graph" -underline 0 \
        -command "SaveAndCompose linegraph"
    .mbar.compose.menu add command -label "Node Splitting" -underline 0 \
        -command "SaveAndCompose nodesplitting"
    .mbar.compose.menu add command -label "Distance Graph" -underline 0 \
        -command {
            set goblinSubgraph 1
            SaveAndCompose distances
        }

    if {[$ThisGraph is undirected]} {
        .mbar.compose.menu add separator
        .mbar.compose.menu add command -label "Metric Graph" -underline 0 \
            -command {
                set goblinSubgraph 1
                SaveAndCompose metric
            }
        .mbar.compose.menu add command -label "Tiling..." -underline 0 \
            -command SaveAndTiling
    }

    if {[$ThisGraph is directed]} {
        .mbar.compose.menu add separator
        .mbar.compose.menu add command -label "Split Graph..." -underline 0 \
            -command SaveAndSplitGraph
    }

    .mbar.compose.menu add separator
    .mbar.compose.menu add command -label "Random Arcs..." -underline 7 \
        -command RandomArcs
    .mbar.compose.menu add command -label "Eulerian Cycle..." -underline 0 \
        -command EulerianCycle
    .mbar.compose.menu add command -label "Regular Graph..."  -underline 0 \
        -command RandRegular
    .mbar.compose.menu add command -label "Random Generator..." \
        -accelerator Shift+Ctrl+R -command {source [file join $GoblinTclPath random.tk]}
}

proc SaveAndCompose {option} {
    global Unchanged GoblinTclPath PromptCommand
    set PromptCommand "Compose $option"
    source [file join $GoblinTclPath changes.tk]
}

proc Compose {option} {
    global ThisGraph OrigFileName FileName env
    if {[string equal $ThisGraph "GOB1"]} {
        $ThisGraph $option GOB2
        $ThisGraph delete
        set ThisGraph GOB2
    } else {
        $ThisGraph $option GOB1
        $ThisGraph delete
        set ThisGraph GOB1
    }
    
    DeleteTempFiles
    set OrigFileName [file join [pwd] unnamed]
    set FileName [file join $env(HOME) unnamed]
    InitFile
}

proc SaveAndTiling {} {
    global Unchanged GoblinTclPath PromptCommand
    set PromptCommand "Tiling"
    source [file join $GoblinTclPath changes.tk]
}

proc DisplayInputDialog {title} {
    destroy .input
    toplevel .input
    wm title .input "GOBLIN $title"
    wm resizable .input 0 0
    
    frame .input.frame
    pack .input.frame -padx 10m -pady 5m -side top -anchor w
    
    frame .input.buttons
    pack .input.buttons -padx 3m -pady 3m -side bottom

    button .input.buttons.go -text "Go" -command {eval $GoCommand}

    button .input.buttons.cancel -text "Cancel" -command { \
        destroy .input
    }    
    
    pack .input.buttons.go \
        .input.buttons.cancel \
        -side left -fill x -padx 3m
}

proc Tiling {} {
    global ThisGraph FileName ThisX ThisY GoCommand env
    
    set ThisX 1
    set ThisY 1
    
    set GoCommand {
        if {[QualifiedInt $ThisX 1 50000] && [QualifiedInt $ThisY 1 50000]} {
            destroy .input

            if {[string equal $ThisGraph "GOB1"]} {
                $ThisGraph tiling GOB2 $ThisX $ThisY
                $ThisGraph delete
                set ThisGraph GOB2
            } else {
                $ThisGraph tiling GOB1 $ThisX $ThisY
                $ThisGraph delete
                set ThisGraph GOB1
            }
    
            DeleteTempFiles
            set OrigFileName [file join [pwd] unnamed]
            set FileName [file join $env(HOME) unnamed]
            InitFile
            PropagateModifications
        }
    }
    
    DisplayInputDialog "Tiling"
    
    label .input.frame.colText -text "Number of columns:" -anchor w
    grid .input.frame.colText -in .input.frame \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    entry .input.frame.col -textvariable ThisX -bg white -width 5
    grid .input.frame.col -in .input.frame \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    
    label .input.frame.rowText -text "Number of rows:" -anchor w
    grid .input.frame.rowText -in .input.frame \
        -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    entry .input.frame.row -textvariable ThisY -bg white -width 5
    grid .input.frame.row -in .input.frame \
        -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m

    grid rowconfig    .input.frame 0 -weight 1 -minsize 0
    grid columnconfig .input.frame 0 -weight 1 -minsize 0

    bind .input.frame.col <Return> {focus .input.frame.row}
    bind .input.frame.row <Return> $GoCommand
    
    focus .input.frame.col
}

proc SaveAndSplitGraph {} {
    global Unchanged GoblinTclPath PromptCommand
    set PromptCommand "SplitGraph"
    source [file join $GoblinTclPath changes.tk]
}

proc SplitGraph {} {
    global ThisGraph FileName goblinSource goblinTarget GoCommand env
    set goblinSource [$ThisGraph source]
    set goblinTarget [$ThisGraph target]

    set GoCommand {
        if {![QualifiedNode $goblinSource] || ![QualifiedNode $goblinTarget]} {
            return
        }
    
        destroy .input

        if {[string equal $ThisGraph "GOB1"]} {
            $ThisGraph splitgraph GOB2 $goblinSource $goblinTarget
            $ThisGraph delete
            set ThisGraph GOB2
        } else {
            $ThisGraph splitgraph GOB1 $goblinSource $goblinTarget
            $ThisGraph delete
            set ThisGraph GOB1
        }
    
        DeleteTempFiles
        set OrigFileName [file join [pwd] unnamed]
        set FileName [file join $env(HOME) unnamed]
        InitFile
        PropagateModifications
    }
    
    DisplayInputDialog "Split Graph"
    
    label .input.frame.sourceText -text "Source Node:" -anchor w
    grid .input.frame.sourceText -in .input.frame \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    entry .input.frame.source -textvariable goblinSource -bg white -width 5
    grid .input.frame.source -in .input.frame \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    
    label .input.frame.targetText -text "Target Node:" -anchor w
    grid .input.frame.targetText -in .input.frame \
        -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    entry .input.frame.target -textvariable goblinTarget -bg white -width 5
    grid .input.frame.target -in .input.frame \
        -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m

    grid rowconfig    .input.frame 0 -weight 1 -minsize 0
    grid columnconfig .input.frame 0 -weight 1 -minsize 0

    bind .input.frame.source <Return> {focus .input.frame.target}
    bind .input.frame.target <Return> $GoCommand
    
    focus .input.frame.source
}

proc RandomArcs {} {
    global ThisGraph NArcs GoCommand

    set NArcs 1
    set GoCommand {
        if {[QualifiedInt $NArcs 1 50000]} {
            destroy .input
            $ThisGraph generate arcs $NArcs
            PropagateModifications
            InitDisplay
        }
    }
    
    DisplayInputDialog "Random Arcs"
    
    label .input.frame.nText -text "Number of Arcs:  " -anchor w
    grid .input.frame.nText -in .input.frame \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news -pady 2m
    entry .input.frame.nArcs -textvariable NArcs -bg white -width 5
    grid .input.frame.nArcs -in .input.frame \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news -pady 2m

    grid rowconfig    .input.frame 0 -weight 1 -minsize 0
    grid columnconfig .input.frame 0 -weight 1 -minsize 0

    bind .input.frame.nArcs <Return> $GoCommand
    
    focus .input.frame.nArcs
}

proc EulerianCycle {} {
    global ThisGraph Length GoCommand

    set Length 0
    set GoCommand {
        if {[QualifiedInt $Length 2 50000]} {
            destroy .input
            $ThisGraph generate eulerian $Length
            PropagateModifications
            InitDisplay
        }
    }
    
    DisplayInputDialog "Eulerian Cycle"
    
    label .input.frame.lengthText -text "Cycle Length:  " -anchor w
    grid .input.frame.lengthText -in .input.frame \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news -pady 2m
    entry .input.frame.length -textvariable Length -bg white -width 5
    grid .input.frame.length -in .input.frame \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news -pady 2m

    grid rowconfig    .input.frame 0 -weight 1 -minsize 0
    grid columnconfig .input.frame 0 -weight 1 -minsize 0

    bind .input.frame.length <Return> $GoCommand
    
    focus .input.frame.length
}

proc RandRegular {} {
    global ThisGraph ThisDeg GoCommand

    set ThisDeg 1
    set GoCommand {
        if {[QualifiedInt $ThisDeg 1 50000]} {
            destroy .input
            $ThisGraph generate regular $ThisDeg
            PropagateModifications
            InitDisplay
        }
    }
    
    DisplayInputDialog "Regular Graph"
    
    label .input.frame.degText -text "Node Degree:  " -anchor w
    grid .input.frame.degText -in .input.frame \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news -pady 2m
    entry .input.frame.deg -textvariable ThisDeg -bg white -width 5
    grid .input.frame.deg -in .input.frame \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news -pady 2m

    grid rowconfig    .input.frame 0 -weight 1 -minsize 0
    grid columnconfig .input.frame 0 -weight 1 -minsize 0

    bind .input.frame.deg <Return> $GoCommand
    
    focus .input.frame.deg
}

bind . <Control-R> {source [file join $GoblinTclPath random.tk]}



# Layout Menu

menu .mbar.layout.menu
.mbar.layout.menu add command -label "Display Graph/Trace Files" \
    -accelerator Ctrl+D -command InitBrowser
.mbar.layout.menu add command -label "Generate Trace Object" \
    -accelerator Ctrl+T -command DisplayNewLayout
.mbar.layout.menu add separator
.mbar.layout.menu add command -label "Strip Geometry" -underline 6 \
    -command StripGraph
.mbar.layout.menu add command -label "Scale Geometry..." -underline 0 \
    -command ScaleGraph
.mbar.layout.menu add command -label "Align Arcs" -underline 0 \
    -command AutoArcAlignment
.mbar.layout.menu add command -label "Layout Style..." \
    -accelerator Shift+Ctrl+F -command LayoutStyle
.mbar.layout.menu add separator
.mbar.layout.menu add command -label "Arc Display..." \
    -accelerator Shift+Ctrl+D -command SetArcDisplay
.mbar.layout.menu add command -label "Arc Labels..." \
    -accelerator Shift+Ctrl+A -command SetArcLabels
.mbar.layout.menu add command -label "Node Display..." \
    -accelerator Shift+Ctrl+N -command SetNodeDisplay
.mbar.layout.menu add command -label "Layout Options..." \
    -accelerator Shift+Ctrl+W -command SetLayoutOptions
.mbar.layout.menu add command -label "Fit Into Window" \
    -accelerator Ctrl+W -command FitIntoWindow
.mbar.layout.menu add command -label "Zoom In" \
    -accelerator Ctrl+ -command ZoomIn
.mbar.layout.menu add command -label "Zoom Out" \
    -accelerator Ctrl- -command ZoomOut

proc InitDisplay {} {
    global Mode
    set Mode ""
    InitBrowser
}

proc DisplayNewLayout {} {
    global ThisGraph FileCounter goblinTraceCounter Mode

    if {[$ThisGraph max cx]>0 || [$ThisGraph max cy]>0} {$ThisGraph trace}
    set FileCounter $goblinTraceCounter
    set Mode "display graph"
    InitBrowser
}

proc InitBrowser {} {
    global goblinTraceCounter Mode

    if {[string equal $Mode "display graph"] && $goblinTraceCounter>0} {
        ResetMode "trace object"
        TraceObject
    } else {
        ResetMode "display graph"
        DisplayObject
    }
    
    MakeNavigationBar
}

proc DisplayObject {} {
    global c ThisGraph OrigFileName FileName Mode StatusInfo
    
    set StatusInfo "$OrigFileName"

    if {[$ThisGraph max cx]<=0 && [$ThisGraph max cy]<=0} {
        DisplayNothing
        return
    }

    $ThisGraph write $FileName.tmp.gob
    goblin export goblet $FileName.tmp.gob $FileName.tk

    InitCanvasRegion
    set goblinCanvas $c
    source $FileName.tk
    
    file delete $FileName.tk
}

proc TraceObject {} {
    global c FileName FileCounter goblinTraceCounter Mode ThisGraph StatusInfo
    
    set StatusInfo "trace object #$FileCounter of $goblinTraceCounter"

    if {[$ThisGraph max cx]<=0 && [$ThisGraph max cy]<=0} {
        DisplayNothing
    } else {
        set traceFile $FileName.$FileCounter
    
        goblin export goblet $traceFile.gob $traceFile.tk

        InitCanvasRegion
        set goblinCanvas $c
        source $traceFile.tk
    
        file delete $traceFile.tk
    }
    
    MakeNavigationBar
}

proc DisplayNothing {} {
    global GoblinTclPath
    InitCanvasRegion
    source [file join $GoblinTclPath title.tk]
}

proc StripGraph {} {
    global ThisGraph
    
    $ThisGraph layout strip
    InitDisplay
    PropagateModifications
}

proc ScaleGraph {} {
    global ThisGraph GoCommand
    
    global dx dy
    set dx 1.00
    set dy 1.00
    
    set GoCommand {
        destroy .input
        $ThisGraph layout scale $dx $dy
        InitDisplay
        PropagateModifications
    }
    
    DisplayInputDialog "Scaling"
    
    label .input.frame.xText -text "Horizontal Magnification:" -anchor w
    grid .input.frame.xText -in .input.frame \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    entry .input.frame.x -textvariable dx -bg white -width 5
    grid .input.frame.x -in .input.frame \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    
    label .input.frame.yText -text "Vertical Magnification:" -anchor w
    grid .input.frame.yText -in .input.frame \
        -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    entry .input.frame.y -textvariable dy -bg white -width 5
    grid .input.frame.y -in .input.frame \
        -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m

    grid rowconfig    .input.frame 0 -weight 1 -minsize 0
    grid columnconfig .input.frame 0 -weight 1 -minsize 0

    bind .input.frame.x <Return> {focus .input.frame.y}
    bind .input.frame.y <Return> $GoCommand
    
    focus .input.frame.x
}

proc AutoArcAlignment {} {
    global ThisGraph goblinXZoom goblinYZoom
    
    $ThisGraph layout align
    InitDisplay
    PropagateModifications
}

proc LayoutStyle {} {
    global GoblinTclPath
    source [file join $GoblinTclPath lstyle.tk]
}

proc FitIntoWindow {} {
    global ThisGraph goblinXZoom goblinYZoom goblinXShift goblinYShift
    global goblinLegenda goblinNodeSize Zoom

    InitCanvasRegion

    scan [wm geometry .] "%dx%d" xSize ySize
    set xSize [expr $xSize-60]
    set ySize [expr $ySize-145]
        
    set xMax [$ThisGraph node 0 cx]
    set yMax [$ThisGraph node 0 cy]
    set xMin $xMax
    set yMin $yMax
    for {set v 0} {$v<[$ThisGraph #nodes]+[$ThisGraph #artificial]} {incr v} {
        if {[$ThisGraph node $v cx]<$xMin} {set xMin [$ThisGraph node $v cx]}
        if {[$ThisGraph node $v cy]<$yMin} {set yMin [$ThisGraph node $v cy]}
        if {[$ThisGraph node $v cx]>$xMax} {set xMax [$ThisGraph node $v cx]}
        if {[$ThisGraph node $v cy]>$yMax} {set yMax [$ThisGraph node $v cy]}
    }
    set margin [expr round(2*$goblinNodeSize*$Zoom)]
    set goblinXZoom [expr ($xSize-2*$margin)/($Zoom*($xMax-$xMin))]
    set goblinYZoom \
        [expr ($ySize-2*$margin-$goblinLegenda*$goblinYZoom*$Zoom)/($Zoom*($yMax-$yMin))]
    set goblinXShift [expr round(($margin-$xMin*$Zoom*$goblinXZoom)/$Zoom)]
    set goblinYShift [expr round(($margin-$yMin*$Zoom*$goblinYZoom)/$Zoom)]
            
    InitDisplay
    PropagateModifications
}

proc ZoomIn {} {
    global goblinXZoom goblinYZoom
    set goblinXZoom [expr {round($goblinXZoom*1.25)}]
    set goblinYZoom [expr {round($goblinYZoom*1.25)}]
    InitDisplay
}

proc ZoomOut {} {
    global goblinXZoom goblinYZoom
    set goblinXZoom [expr {round($goblinXZoom*0.8)}]
    set goblinYZoom [expr {round($goblinYZoom*0.8)}]
    InitDisplay
}

proc SetArcLabels {} {
    global GoblinTclPath
    source [file join $GoblinTclPath arclabels.tk]
}

proc SetArcDisplay {} {
    global GoblinTclPath
    source [file join $GoblinTclPath arcdisplay.tk]
}

proc SetNodeDisplay {} {
    global GoblinTclPath
    source [file join $GoblinTclPath nodedisplay.tk]
}

proc SetLayoutOptions {} {
    global GoblinTclPath
    source [file join $GoblinTclPath measures.tk]
}

bind . <Control-d> {InitBrowser}
bind . <Control-t> {DisplayNewLayout}
bind . <Control-w> {FitIntoWindow}
bind . <Control-F> {LayoutStyle}
bind . <Control-D> {SetArcDisplay}
bind . <Control-A> {SetArcLabels}
bind . <Control-N> {SetNodeDisplay}
bind . <Control-W> {SetLayoutOptions}
bind . <Control-plus> {ZoomIn}
bind . <Control-minus> {ZoomOut}



# Optimize Menu

proc MakeOptimizeMenu {} {
    global ThisGraph
    
    destroy .mbar.optimize.menu

    menu .mbar.optimize.menu
    .mbar.optimize.menu add command -label "Spanning Tree Problems..." -underline 9 \
        -underline 0 -command SpanningTrees
    .mbar.optimize.menu add command -label "TSP..." \
        -underline 0 -command TSP

    if {[$ThisGraph is sparse]} {
        .mbar.optimize.menu add command -label "Bipartitions..." \
            -underline 0 -command Bipartitions
        .mbar.optimize.menu add command -label "Graph Partitions..." \
            -underline 0 -command GraphPartitions
        .mbar.optimize.menu add command -label "Connectivity..." \
            -underline 0 -command Connectivity
    }

    if {[$ThisGraph is undirected]} {
        .mbar.optimize.menu add separator
        .mbar.optimize.menu add command -label "Matching Problems..." \
            -underline 0 -command Matchings
    }

    if {[$ThisGraph is directed]} {
        .mbar.optimize.menu add separator
        .mbar.optimize.menu add command -label "Network Flows..." -underline 0 \
            -command NetworkFlows
        .mbar.optimize.menu add command -label "Topological Order" -underline 12 \
            -command TopSort
    }

    if {[$ThisGraph is balanced]} {
        .mbar.optimize.menu add separator
        .mbar.optimize.menu add command -label "Balanced Network Flows..." \
            -underline 2 -command BalancedNetworkFlows
    }

    .mbar.optimize.menu add separator
    .mbar.optimize.menu add command -label "Start/Stop Solver" \
        -accelerator Ctrl+C -command StartOrStop
    .mbar.optimize.menu add command -label "View Log" -accelerator Ctrl+L \
        -command {source [file join $GoblinTclPath logging.tk]}
    .mbar.optimize.menu add separator
    .mbar.optimize.menu add command -label "Optimization Level..." \
        -accelerator Shift+Ctrl+O -command SetOptLevel
    .mbar.optimize.menu add command -label "Method Options..." \
        -accelerator Shift+Ctrl+M -command SetMethodOptions
    .mbar.optimize.menu add command -label "Data Structures..." \
        -accelerator Shift+Ctrl+S -command SetDataOptions
    .mbar.optimize.menu add command -label "Tracing Options..." \
        -accelerator Shift+Ctrl+T -command SetTracingOptions
    .mbar.optimize.menu add command -label "Logging Options..." \
        -accelerator Shift+Ctrl+L -command SetLoggingOptions
}

set ThisNColours ""
set ThisDegree 1
set goblinSource "*"
set goblinTarget "*"
set goblinRoot "*"
set goblinSignalHalt 2
set TotalTime 0
set TimeInfo "idle"

proc CallSolver {title command} {
    global StatusInfo
    if {$command==""} {
        set StatusInfo "specify a problem solver"
        return
    }

    global PrevTime TotalTime
    destroy .input
    destroy .solverInfo
    toplevel .solverInfo
    wm title .solverInfo "GOBLIN $title"
    wm resizable .solverInfo 0 0
    label .solverInfo.text -text "Computing..."
    pack .solverInfo.text -padx 20m -pady 5m
    update idletasks
    
    if {1==1} { # Use threads
        global FileName goblinExtension ThisGraph goblinSignalHalt Toolbar2

        set file [open "$FileName.tcl" w]
        puts $file "goblin alias $ThisGraph [$ThisGraph handle]"
        puts $file "set state \[catch \{$command\} result\]"
        puts $file "if \{\$state==0\} \{"
        puts $file "    goblin return \$result"
        puts $file "\} else \{"
        puts $file "    goblin throw \$result"
        puts $file "\}"
        close $file

        $Toolbar2.solve configure -image running_solver
        set StatusInfo "computation is running..."
        set PrevTime [clock seconds]
        set goblinSignalHalt 0
        set state [catch {goblin thread $FileName.tcl} result]
        while {$goblinSignalHalt!=2} {tkwait variable goblinSignalHalt}
        set PrevTime [expr {[clock seconds]-$PrevTime}]
	set TotalTime [expr $TotalTime+$PrevTime]
        set state [catch {goblin result} result]
        $Toolbar2.solve configure -image start_solver
    } else { #Do not use threads
        set goblinSignalHalt 0
        set PrevTime [clock seconds]
        set state [catch {eval $command} result]
        set PrevTime [expr {[clock seconds]-$PrevTime}]
	set TotalTime [expr $TotalTime+$PrevTime]
        set goblinSignalHalt 2
    }

    if {$state != 0} {
        global Mode StatusInfo
        set Mode "display graph"
        set StatusInfo "$result ($PrevTime sec.)"

        destroy .solverInfo.text
        message .solverInfo.msg -width 12c -anchor w \
            -text "Computation has failed: $result"
        button .solverInfo.ok -text "OK" -command {destroy .solverInfo}
        pack .solverInfo.msg -padx 10m -pady 5m
        pack .solverInfo.ok -padx 3m -pady 3m
        grab set .solverInfo
    } else {
        destroy .solverInfo
        global goblinTraceLevel
        InitDisplay
        PropagateModifications

        global Mode
        set Mode "display graph"
        if {$result!=""} {
            set StatusInfo "$title - objective value: $result"
        } else {
            set StatusInfo "computation is finished"
        }
	goblin echo "Total execution time: $PrevTime seconds"
    }
    
    global TimeInfo
    set TimeInfo "$PrevTime/$TotalTime sec."
}

proc SpanningTrees {} {
    global ThisGraph LastCommand GoCommand goblinRoot goblinPredecessors
    set goblinRoot [$ThisGraph root]

    set minTreeCommand {
        if {$goblinRoot=="*" || [QualifiedNode $goblinRoot]} {
            $ThisGraph set root $goblinRoot
            set LastCommand "$ThisGraph mintree $goblinRoot"
            set goblinPredecessors 1
            CallSolver "Minimum Spanning $goblinRoot-Tree" $LastCommand
        }
    }
    
    set shortestPathCommand {
        if {[QualifiedNode $goblinRoot]} {
            $ThisGraph set root $goblinRoot
            set LastCommand "$ThisGraph spath $goblinRoot"
            set goblinPredecessors 1
            CallSolver "Shortest Path $goblinRoot-Tree" $LastCommand
        }
    }
    
    set treePackingCommand {
        if {[QualifiedNode $goblinRoot]} {
            $ThisGraph set root $goblinRoot
            set LastCommand "$ThisGraph treepacking $goblinRoot"
            set goblinNodeColours 2
            set goblinPredecessors 1
            CallSolver "$goblinRoot-Tree Packing" $LastCommand
        }
    }
    
    set steinerTreeCommand {
        if {[QualifiedNode $goblinRoot]} {
            $ThisGraph set root $goblinRoot
            set LastCommand "$ThisGraph steiner $goblinRoot"
            set goblinPredecessors 1
            CallSolver "$goblinRoot-Steiner Tree" $LastCommand
        }
    }
    
    set GoCommand $minTreeCommand
    
    DisplayInputDialog "Spanning Trees"
    
    frame .input.options
    label .input.options.text -text "Problem Characteristics:" -anchor w
    radiobutton .input.options.minTree -text "Minimum Spanning Tree" \
        -variable GoCommand -value $minTreeCommand -anchor w
    radiobutton .input.options.shortestPath -text "Shortest Path Tree" \
        -variable GoCommand -value $shortestPathCommand -anchor w
    radiobutton .input.options.treePacking -text "Maximum Tree Packing" \
        -variable GoCommand -value $treePackingCommand -anchor w
    radiobutton .input.options.steinerTree -text "Minimum Steiner Tree" \
        -variable GoCommand -value $steinerTreeCommand -anchor w
    pack .input.options.text .input.options.minTree \
        .input.options.shortestPath .input.options.treePacking \
        .input.options.steinerTree -side top -fill x
    pack .input.options -side top -anchor w -before .input.frame \
        -padx 10m -pady 5m
    
    label .input.frame.text -text "Root Node:"
    entry .input.frame.entry -textvariable goblinRoot -bg white -width 5
    pack .input.frame.text -side left
    pack .input.frame.entry -side left -padx 5m
    bind .input.frame.entry <Return> {eval $GoCommand}
    
    focus .input.frame.entry
}

proc Bipartitions {} {
    global ThisGraph LastCommand GoCommand goblinNodeColours

    set stableCommand {
        set LastCommand "$ThisGraph stable"
        set goblinNodeColours 2
        CallSolver "Stable Set" $LastCommand
    }
    
    set cliqueCommand {
        set LastCommand "$ThisGraph clique"
        set goblinNodeColours 2
        CallSolver "Maximum Clique" $LastCommand
    }
    
    set coverCommand {
        set LastCommand "$ThisGraph vertexcover"
        set goblinNodeColours 2
        CallSolver "Vertex Cover" $LastCommand
    }
    
    set edgeCutCommand {
        set LastCommand "$ThisGraph maxcut"
        set goblinNodeColours 2
        CallSolver "Maximum Edge Cut" $LastCommand
    }
    
    set GoCommand $stableCommand
    
    DisplayInputDialog "Bipartitions"
    
    label .input.frame.text -text "Characteristics:" -anchor w
    radiobutton .input.frame.stable -text "Maximum Stable Set" \
        -variable GoCommand -value $stableCommand -anchor w
    radiobutton .input.frame.clique -text "Maximum Clique" \
        -variable GoCommand -value $cliqueCommand -anchor w
    radiobutton .input.frame.cover -text "Minimum Vertex Cover" \
        -variable GoCommand -value $coverCommand -anchor w
    radiobutton .input.frame.edgecut -text "Maximum Edge Cut" \
        -variable GoCommand -value $edgeCutCommand -anchor w
    pack .input.frame.text .input.frame.stable .input.frame.clique \
        .input.frame.cover .input.frame.edgecut -side top -fill x
}

proc GraphPartitions {} {
    global ThisGraph LastCommand GoCommand ThisNColours goblinNodeColours

    set nodeColourCommand {
        if {$ThisNColours=="" || [QualifiedNode $ThisNColours]} {
            set LastCommand "$ThisGraph colouring $ThisNColours"
            set goblinNodeColours 2
            CallSolver "$ThisNColours-Node Colouring" $LastCommand
        }
    }
    
    set cliquesCommand {
        if {$ThisNColours=="" || [QualifiedNode $ThisNColours]} {
            set LastCommand "$ThisGraph cliques $ThisNColours"
            set goblinNodeColours 2
            CallSolver "$ThisNColours-Clique Cover" $LastCommand
        }
    }
    
    set edgeColourCommand {
        if {$ThisNColours=="" || [QualifiedNode $ThisNColours]} {
            set LastCommand "$ThisGraph edgecolouring $ThisNColours"
            set goblinNodeColours 2
            CallSolver "$ThisNColours-Edge Colouring" $LastCommand
        }
    }
    
    set GoCommand $nodeColourCommand
    
    DisplayInputDialog "Graph Partitions"
    
    frame .input.options
    label .input.options.text -text "Set Characteristics:" -anchor w
    radiobutton .input.options.ncolour -text "Stable Sets (Node Colouring)" \
        -variable GoCommand -value $nodeColourCommand -anchor w
    radiobutton .input.options.clique -text "Node Disjoint Cliques" \
        -variable GoCommand -value $cliquesCommand -anchor w
    radiobutton .input.options.ecolour -text "1-Matchings (Edge Colouring)" \
        -variable GoCommand -value $edgeColourCommand -anchor w
    pack .input.options.text .input.options.ncolour .input.options.clique \
        .input.options.ecolour -side top -fill x
    pack .input.options -side top -anchor w -before .input.frame \
        -padx 10m -pady 5m
    
    label .input.frame.text -text "Accepted number of sets (optional):"
    entry .input.frame.entry -textvariable ThisNColours -bg white -width 5
    pack .input.frame.text -side left
    pack .input.frame.entry -side left -padx 5m
    bind .input.frame.entry <Return> {eval $GoCommand}
    
    focus .input.frame.entry
}

proc Connectivity {} {
    global ThisGraph LastCommand GoCommand ThisDegree goblinNodeColours
    
    set connectCommand {
        if {[QualifiedNode $ThisDegree]} {
            set LastCommand "$ThisGraph connected $ThisDegree"
            set goblinNodeColours 2
            set goblinSubgraph 5
            CallSolver "$ThisDegree-Vertex Connectivity" $LastCommand
        }
    }
    
    set edgeConnectCommand {
        if {[QualifiedNode $ThisDegree]} {
            set LastCommand "$ThisGraph econnected $ThisDegree"
            set goblinNodeColours 2
            CallSolver "$ThisDegree-Edge Connectivity" $LastCommand
        }
    }
    
    set strongCommand {
        if {[QualifiedNode $ThisDegree]} {
            set LastCommand "$ThisGraph sconnected $ThisDegree"
            set goblinNodeColours 2
            set goblinSubgraph 5
            CallSolver "Strong $ThisDegree-Connectivity" $LastCommand
        }
    }
    
    set strongEdgeCommand {
        if {[QualifiedNode $ThisDegree]} {
            set LastCommand "$ThisGraph seconnected $ThisDegree"
            set goblinNodeColours 2
            CallSolver "Strong $ThisDegree-Edge Connectivity" $LastCommand
        }
    }
    
    set GoCommand $connectCommand
    
    DisplayInputDialog "Graph Connectivity"
    
    frame .input.options
    label .input.options.text -text "Characteristics:" -anchor w

    radiobutton .input.options.connect -text "Vertex Connectivity" \
        -variable GoCommand -value $connectCommand -anchor w
    radiobutton .input.options.econnect -text "Edge Connectivity" \
        -variable GoCommand -value $edgeConnectCommand -anchor w
    radiobutton .input.options.strong -text "Strong Connectivity" \
        -variable GoCommand -value $strongCommand -anchor w
    radiobutton .input.options.estrong -text "Strong Edge Connectivity" \
        -variable GoCommand -value $strongEdgeCommand -anchor w
    if {[$ThisGraph is undirected]} {
        pack .input.options.text .input.options.connect .input.options.econnect \
            -side top -fill x
    } else {
        pack .input.options.text .input.options.connect .input.options.econnect \
            .input.options.strong .input.options.estrong -side top -fill x
    }
    pack .input.options -side top -anchor w -before .input.frame \
        -padx 10m -pady 5m
    
    label .input.frame.text -text "Degree of Connectivity:"
    entry .input.frame.entry -textvariable ThisDegree -bg white -width 5
    pack .input.frame.text -side left
    pack .input.frame.entry -side left -padx 5m
    bind .input.frame.entry <Return> {eval $GoCommand}
    
    focus .input.frame.entry
}

proc Matchings {} {
    global ThisGraph LastCommand GoCommand

    set maxMatchCommand {
        set LastCommand "$ThisGraph maxmatch"
        CallSolver "Matching Solver" $LastCommand
    }
    
    set minCMatchCommand {
        set LastCommand "$ThisGraph mincmatch"
        CallSolver "Weighted Matching Solver" $LastCommand
    }
    
    set tJoinCommand {
        set LastCommand "$ThisGraph tjoin"
        CallSolver "T-Join Solver" $LastCommand
    }
    
    set postmanCommand {
        set LastCommand "$ThisGraph postman"
        CallSolver "Chinese Postman Solver" $LastCommand
    }
    
    set GoCommand $maxMatchCommand
    
    DisplayInputDialog "Matching Problems"
    
    label .input.frame.text -text "Subgraph Characteristics:" -anchor w
    radiobutton .input.frame.maxmatch -text "Cardinality Matching" \
        -variable GoCommand -value $maxMatchCommand -anchor w
    radiobutton .input.frame.mincmatch -text "Minimum Cost Perfect Matching" \
        -variable GoCommand -value $minCMatchCommand -anchor w
    radiobutton .input.frame.tjoin -text "Minimum T-Join" \
        -variable GoCommand -value $tJoinCommand -anchor w
    radiobutton .input.frame.postman -text "Minimum Eulerian Supergraph" \
        -variable GoCommand -value $postmanCommand -anchor w
    pack .input.frame.text .input.frame.maxmatch .input.frame.mincmatch \
        .input.frame.tjoin .input.frame.postman -side top -fill x
}

proc TSP {} {
    global ThisGraph LastCommand goblinRoot GoCommand
    set goblinRoot [$ThisGraph root]

    set GoCommand {
        if {$goblinRoot=="*" || [QualifiedNode $goblinRoot]} {
            $ThisGraph set root $goblinRoot
            set LastCommand "$ThisGraph tsp $goblinRoot"
            set goblinPredecessors 1
            CallSolver "TSP Solver" $LastCommand
        }
    }
    
    DisplayInputDialog "TSP Solver"
    
    label .input.frame.text -text "Root Node (optional):"
    entry .input.frame.entry -textvariable goblinRoot -bg white -width 5
    pack .input.frame.text .input.frame.entry -side left -padx 5m -pady 5m
    bind .input.frame.entry <Return> {eval $GoCommand}
    
    focus .input.frame.entry
}

proc NetworkFlows {} {
    global ThisGraph LastCommand GoCommand goblinSource goblinTarget
    set goblinSource [$ThisGraph source]
    set goblinTarget [$ThisGraph target]

    set maxFlowCommand {
        if {[QualifiedNode $goblinSource] && [QualifiedNode $goblinTarget]} {
            $ThisGraph set source $goblinSource
            $ThisGraph set target $goblinTarget
            set LastCommand "$ThisGraph maxflow $goblinSource $goblinTarget"
            CallSolver "Maximum ($goblinSource,$goblinTarget)-Flow" $LastCommand
        }
    }
    
    set minCFlowCommand {
        if {[QualifiedNode $goblinSource] && [QualifiedNode $goblinTarget]} {
            $ThisGraph set source $goblinSource
            $ThisGraph set target $goblinTarget
            set LastCommand "$ThisGraph mincflow $goblinSource $goblinTarget"
            CallSolver "Min Cost ($goblinSource,$goblinTarget)-Flow" $LastCommand
        }
    }
    
    set feasibleCommand {
        set LastCommand "$ThisGraph circulation"
        CallSolver "Feasible b-Flow" $LastCommand
    }
    
    set minCCircCommand {
        set LastCommand "$ThisGraph minccirc"
        CallSolver "Minimum Cost b-Flow" $LastCommand
    }
    
    set postmanCommand {
        set LastCommand "$ThisGraph postman"
        CallSolver "Chinese Postman Solver" $LastCommand
    }
    
    set GoCommand $minCCircCommand
    
    DisplayInputDialog "Network Flow Problems"
    
    frame .input.options
    label .input.options.text -text "Subgraph Characteristics:" -anchor w
    radiobutton .input.options.maxflow -text "Maximum st-Flow" \
        -variable GoCommand -value $maxFlowCommand -anchor w
    radiobutton .input.options.mincflow -text "Minimum Cost st-Flow" \
        -variable GoCommand -value $minCFlowCommand -anchor w
    radiobutton .input.options.feasible -text "Feasible b-Flow" \
        -variable GoCommand -value $feasibleCommand -anchor w
    radiobutton .input.options.minccirc -text "Minimum Cost b-Flow" \
        -variable GoCommand -value $minCCircCommand -anchor w
    radiobutton .input.options.postman -text "Minimum Eulerian Supergraph" \
        -variable GoCommand -value $postmanCommand -anchor w
    pack .input.options.text .input.options.maxflow .input.options.mincflow \
        .input.options.feasible .input.options.minccirc .input.options.postman \
        -side top -fill x
    pack .input.options -side top -anchor w -before .input.frame \
        -padx 10m -pady 5m
    
    label .input.frame.sourceText -text "Source Node:" -anchor w
    grid .input.frame.sourceText -in .input.frame \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    entry .input.frame.source -textvariable goblinSource -bg white -width 5
    grid .input.frame.source -in .input.frame \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    
    label .input.frame.targetText -text "Target Node:" -anchor w
    grid .input.frame.targetText -in .input.frame \
        -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    entry .input.frame.target -textvariable goblinTarget -bg white -width 5
    grid .input.frame.target -in .input.frame \
        -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m

    grid rowconfig    .input.frame 0 -weight 1 -minsize 0
    grid columnconfig .input.frame 0 -weight 1 -minsize 0

    bind .input.frame.source <Return> {focus .input.frame.target}
    bind .input.frame.target <Return> {eval $GoCommand}
    
    focus .input.frame.source
}

proc TopSort {} {
    global ThisGraph LastCommand goblinNodeColours goblinNodeLabels
    set LastCommand "$ThisGraph topsort"
    set goblinNodeColours 0
    set goblinNodeLabels 4
    CallSolver "Topological Order" $LastCommand
}

proc BalancedNetworkFlows {} {
    global ThisGraph LastCommand GoCommand goblinSource
    set goblinSource [$ThisGraph source]

    set maxFlowCommand {
        if {[QualifiedNode $goblinSource]} {
            $ThisGraph set source $goblinSource
            set LastCommand "$ThisGraph maxbalflow $goblinSource"
            CallSolver "Maximum Balanced $goblinSource-Flow" $LastCommand
        }
    }
    
    set minCFlowCommand {
        if {[QualifiedNode $goblinSource]} {
            $ThisGraph set source $goblinSource
            set LastCommand "$ThisGraph mincbalflow $goblinSource"
            CallSolver "Min-Cost Balanced $goblinSource-Flow" $LastCommand
        }
    }
    
    set GoCommand $maxFlowCommand
    
    DisplayInputDialog "Balanced Network Flow Problems"
    
    frame .input.options
    label .input.options.text -text "Subgraph Characteristics:" -anchor w
    radiobutton .input.options.maxflow -text "Maximum st-Flow" \
        -variable GoCommand -value $maxFlowCommand -anchor w
    radiobutton .input.options.mincflow -text "Minimum Cost st-Flow" \
        -variable GoCommand -value $minCFlowCommand -anchor w
    pack .input.options.text .input.options.maxflow .input.options.mincflow \
        -side top -fill x
    pack .input.options -side top -anchor w -before .input.frame \
        -padx 10m -pady 5m
    
    label .input.frame.sourceText -text "Source Node:" -anchor w
    grid .input.frame.sourceText -in .input.frame \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    entry .input.frame.source -textvariable goblinSource -bg white -width 5
    grid .input.frame.source -in .input.frame \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news -padx 1m -pady 2m
    
    grid rowconfig    .input.frame 0 -weight 1 -minsize 0
    grid columnconfig .input.frame 0 -weight 1 -minsize 0

    bind .input.frame.source <Return> {eval $GoCommand}
    
    focus .input.frame.source
}

proc StartOrStop {} {
    global goblinSignalHalt Toolbar2 LastCommand
    if {$goblinSignalHalt==2} {
        CallSolver "Optimization" $LastCommand
    } else {
        set goblinSignalHalt 1
        $Toolbar2.solve configure -image stopped_solver
    }
}

set LastCommand ""

proc SetOptLevel {} {
    global GoblinTclPath
    source [file join $GoblinTclPath optlevel.tk]
}

proc SetMethodOptions {} {
    global GoblinTclPath
    source [file join $GoblinTclPath methopt.tk]
}

proc SetDataOptions {} {
    global GoblinTclPath
    source [file join $GoblinTclPath dataopt.tk]
}

proc SetTracingOptions {} {
    global GoblinTclPath
    source [file join $GoblinTclPath traceopt.tk]
}

proc SetLoggingOptions {} {
    global GoblinTclPath
    source [file join $GoblinTclPath logopt.tk]
}

bind . <Control-c> {StartOrStop}
bind . <Control-l> {source [file join $GoblinTclPath logging.tk]}
bind . <Control-M> {SetMethodOptions}
bind . <Control-O> {SetOptLevel}
bind . <Control-S> {SetDataOptions}
bind . <Control-T> {SetTracingOptions}
bind . <Control-L> {SetLoggingOptions}



# Info Menu

menu .mbar.info.menu
.mbar.info.menu add command -label "Problem Statistics..." \
    -command {source [file join $GoblinTclPath statistics.tk]}
.mbar.info.menu add command -label "About GOBLET..." \
    -command AboutGOBLET
.mbar.info.menu add command -label "About GOBLIN..." \
    -command AboutGOBLIN
.mbar.info.menu add command -label "Licence Agreement..." \
    -command ShowLGPL

proc AboutGOBLET {} {
    global GoblinVersion

    destroy .about
    toplevel .about
    wm title .about "GOBLET Info"
    wm resizable .about 0 0

    global ThisGraph FileName
    frame .about.frame
    pack .about.frame -side top -fill x -padx 10m -pady 5m
    message .about.frame.msg1 -width 200 -anchor w \
        -text "GOBLET $GoblinVersion"
    message .about.frame.msg2 -width 270 -anchor w \
        -text "Tcl/Tk based Graph Editor and Browser, User Interface of the GOBLIN Graph Library"
    message .about.frame.msg3 -width 250 -anchor w \
        -text "Written by Dr. Christian Fremuth-Paeger, University of Augsburg, Germany"
    message .about.frame.msg4 -width 220 -anchor w \
        -text "(c)    February 2001-February 2002"
    pack .about.frame.msg1 .about.frame.msg2 .about.frame.msg3 .about.frame.msg4 -side top -fill x -pady 1m
}

proc AboutGOBLIN {} {
    global GoblinVersion

    destroy .about
    toplevel .about
    wm title .about "GOBLIN Info"
    wm resizable .about 0 0

    global FileName
    frame .about.frame
    pack .about.frame -side top -fill x -padx 10m -pady 5m
    message .about.frame.msg1 -width 200 -anchor w \
        -text "GOBLIN $GoblinVersion" 
    message .about.frame.msg2 -width 270 -anchor w \
        -text "A C++ Class Library for Graph Optimization and Network Programming Problems" 
    message .about.frame.msg3 -width 250 -anchor w \
        -text "Written by Dr. Christian Fremuth-Paeger, University of Augsburg, Germany"
    message .about.frame.msg4 -width 200 -anchor w \
        -text "(c)    1998-2002"
    pack .about.frame.msg1 .about.frame.msg2 .about.frame.msg3 .about.frame.msg4 -side top -fill x -pady 1m
}



# GOBLET Iconbar

frame .iconbar
pack .iconbar -side top -fill x

set Toolbar1 .iconbar.tbar1
set Toolbar2 .iconbar.tbar2
set NavigationBar .iconbar.nbar
set EditorBar .iconbar.ebar

proc MakeBalloon {label wdName} {
    destroy .balloon
    toplevel .balloon
    wm geometry .balloon \
        100x20+[expr [winfo rootx $wdName]+32]+[expr [winfo rooty $wdName]+40]
    label .balloon.text -text $label -bg yellow -relief solid -anchor w
    pack .balloon.text -fill both

    append wdSize [winfo reqwidth .balloon.text] x [winfo reqheight .balloon.text]
    wm geometry .balloon \
        $wdSize+[expr [winfo rootx $wdName]+32]+[expr [winfo rooty $wdName]+40]
    wm overrideredirect .balloon 1
}

proc MakeBalloon2 {label wdName} {
    destroy .balloon
    toplevel .balloon
    wm geometry .balloon \
        100x20+[expr [winfo rootx $wdName]+32]+[expr [winfo rooty $wdName]+40]
    label .balloon.text -text $label -bg yellow -relief solid -anchor w
    pack .balloon.text -fill both

    append wdSize [winfo reqwidth .balloon.text] x [winfo reqheight .balloon.text]
    wm geometry .balloon \
        $wdSize+[expr [winfo rootx $wdName]+10]+[expr [winfo rooty $wdName]-30]
    wm overrideredirect .balloon 1
}

proc MakeHelp {label} {
    global StatusInfo
    set StatusInfo $label
}

proc DestroyBalloon {} {
    destroy .balloon
}

image create photo tool_open -file [file join $GoblinTclPath folder.gif]
image create photo tool_save -file [file join $GoblinTclPath floppy.gif]
image create photo tool_print -file [file join $GoblinTclPath printer.gif]
image create photo tool_log -file [file join $GoblinTclPath book.gif]
image create photo tool_restart -file [file join $GoblinTclPath reset.gif]

proc MakeToolbar1 {} {
    global GoblinTclPath Toolbar1 ThisGraph

    destroy $Toolbar1

    frame $Toolbar1
    pack $Toolbar1 -side left -padx 2m -fill x

    button $Toolbar1.open -image tool_open -relief flat -command SaveAndOpen
    bind $Toolbar1.open <Enter> {MakeBalloon "open..." $Toolbar1.open}
    bind $Toolbar1.open <Leave> {DestroyBalloon}

    button $Toolbar1.save -image tool_save -relief flat -command SaveFile
    bind $Toolbar1.save <Enter> {MakeBalloon "save graph" $Toolbar1.save}
    bind $Toolbar1.save <Leave> {DestroyBalloon}

    button $Toolbar1.print -image tool_print -relief flat -command PrintLayout2
    bind $Toolbar1.print <Enter> {MakeBalloon "print layout" $Toolbar1.print}
    bind $Toolbar1.print <Leave> {DestroyBalloon}

    button $Toolbar1.log -image tool_log -relief flat -command {
        source [file join $GoblinTclPath logging.tk]
    }
    bind $Toolbar1.log <Enter> {MakeBalloon "view log" $Toolbar1.log}
    bind $Toolbar1.log <Leave> {DestroyBalloon}

    button $Toolbar1.restart -image tool_restart -relief flat \
        -command RestartEngine
    bind $Toolbar1.restart <Enter> {MakeBalloon "restart engine" $Toolbar1.restart}
    bind $Toolbar1.restart <Leave> {DestroyBalloon}

    pack $Toolbar1.open $Toolbar1.save $Toolbar1.print $Toolbar1.log \
        $Toolbar1.restart -side left
}

image create photo display -file [file join $GoblinTclPath binocs.gif]
image create photo keep -file [file join $GoblinTclPath camera.gif]
image create photo tool_edit -file [file join $GoblinTclPath hammer.gif]
image create photo start_solver -file [file join $GoblinTclPath rlight.gif]
image create photo running_solver -file [file join $GoblinTclPath glight.gif]
image create photo stopped_solver -file [file join $GoblinTclPath ylight.gif]

proc MakeToolbar2 {} {
    global GoblinTclPath Toolbar2 ThisGraph

    destroy $Toolbar2
    
    frame $Toolbar2
    pack $Toolbar2 -side left -padx 10m -fill x

    button $Toolbar2.display -image display -relief flat -command InitBrowser
    bind $Toolbar2.display <Enter> {
        global Mode
        if {$Mode=="display graph"} {
            MakeBalloon "display trace objects" $Toolbar2.display
        } else {
            MakeBalloon "display graph" $Toolbar2.display
        }
    }
    bind $Toolbar2.display <Leave> {DestroyBalloon}

    button $Toolbar2.keep -image keep -relief flat -command DisplayNewLayout
    bind $Toolbar2.keep <Enter> {MakeBalloon "trace graph" $Toolbar2.keep}
    bind $Toolbar2.keep <Leave> {DestroyBalloon}
 
    button $Toolbar2.edit -image tool_edit -relief flat -command MoveNodes
    bind $Toolbar2.edit <Enter> {MakeBalloon "edit graph" $Toolbar2.edit}
    bind $Toolbar2.edit <Leave> {DestroyBalloon}

    button $Toolbar2.solve -image start_solver -relief flat -command StartOrStop
    bind $Toolbar2.solve <Enter> {MakeBalloon "restart/stop solver" $Toolbar2.solve}
    bind $Toolbar2.solve <Leave> {DestroyBalloon}

    pack $Toolbar2.display $Toolbar2.keep $Toolbar2.edit $Toolbar2.solve \
       -side left
}

image create photo nav_first -file [file join $GoblinTclPath first.gif]
image create photo nav_prev -file [file join $GoblinTclPath prev.gif]
image create photo nav_minus -file [file join $GoblinTclPath minus.gif]
image create photo nav_next -file [file join $GoblinTclPath next.gif]
image create photo nav_plus -file [file join $GoblinTclPath plus.gif]
image create photo nav_last -file [file join $GoblinTclPath last.gif]

proc MakeNavigationBar {} {
    global FileCounter goblinTraceCounter NavigationBar EditorBar
    global Mode StatusInfo ThisGraph GoblinTclPath
    
    destroy $NavigationBar
    destroy $EditorBar
    
    if {![string equal $Mode "trace object"]} return

    frame $NavigationBar -relief raised
    pack $NavigationBar -side left -padx 2m

    button $NavigationBar.first -image nav_first -relief flat -command { \
        if {$FileCounter > 1} {
            InitCanvasRegion
            set FileCounter 1
            TraceObject
        }
    }    
    bind $NavigationBar.first <Enter> {MakeBalloon "first trace file" $NavigationBar.first}
    bind $NavigationBar.first <Leave> {DestroyBalloon}
        
    button $NavigationBar.prev -image nav_prev -relief flat -command { \
        if {$FileCounter > 1} {
            InitCanvasRegion
            set FileCounter [expr {$FileCounter-1}]
            TraceObject
        }
    }    
    bind $NavigationBar.prev <Enter> {MakeBalloon "step back" $NavigationBar.prev}
    bind $NavigationBar.prev <Leave> {DestroyBalloon}
        
    button $NavigationBar.m10 -image nav_minus -relief flat -command { \
        if {$FileCounter > 10} {
            InitCanvasRegion
            set FileCounter [expr {$FileCounter-10}]
            TraceObject
        }
    }    
    bind $NavigationBar.m10 <Enter> {MakeBalloon "big step back" $NavigationBar.m10}
    bind $NavigationBar.m10 <Leave> {DestroyBalloon}
        
    button $NavigationBar.next -image nav_next -relief flat -command { \
        if {$FileCounter < $goblinTraceCounter} {
            InitCanvasRegion
            set FileCounter [expr {$FileCounter+1}]
            TraceObject
        }
    }    
    bind $NavigationBar.next <Enter> {MakeBalloon "step" $NavigationBar.next}
    bind $NavigationBar.next <Leave> {DestroyBalloon}
        
    button $NavigationBar.p10 -image nav_plus -relief flat -command { \
        if {$FileCounter < [expr {$goblinTraceCounter-9}]} {
            InitCanvasRegion
            set FileCounter [expr {$FileCounter+10}]
            TraceObject
        }
    }    
    bind $NavigationBar.p10 <Enter> {MakeBalloon "big step" $NavigationBar.p10}
    bind $NavigationBar.p10 <Leave> {DestroyBalloon}

    button $NavigationBar.last -image nav_last -relief flat -command { \
        if {$FileCounter < $goblinTraceCounter} {
            InitCanvasRegion
            set FileCounter $goblinTraceCounter
            TraceObject
        }
    }    
    bind $NavigationBar.last <Enter> {MakeBalloon "last trace file" $NavigationBar.last}
    bind $NavigationBar.last <Leave> {DestroyBalloon}

    pack $NavigationBar.first $NavigationBar.m10 $NavigationBar.prev \
        $NavigationBar.next $NavigationBar.p10 $NavigationBar.last -side left
}

image create photo new_node -file [file join $GoblinTclPath newnode.gif]
image create photo new_arc -file [file join $GoblinTclPath newarc.gif]
image create photo edit_label -file [file join $GoblinTclPath label.gif]
image create photo move_node -file [file join $GoblinTclPath move.gif]
image create photo redirect -file [file join $GoblinTclPath redirect.gif]
image create photo delete -file [file join $GoblinTclPath delete.gif]
image create photo predecessors -file [file join $GoblinTclPath pred.gif]

proc MakeEditorBar {} {
    global NavigationBar EditorBar Mode GoblinTclPath
    
    destroy $NavigationBar
    destroy $EditorBar
    
    frame $EditorBar -relief raised
    pack $EditorBar -side left -padx 2m

    button $EditorBar.newNode -image new_node -relief flat -command {AddNodes}
    bind $EditorBar.newNode <Enter> {MakeBalloon "insert nodes" $EditorBar.newNode}
    bind $EditorBar.newNode <Leave> {DestroyBalloon}

    button $EditorBar.newArc -image new_arc -relief flat -command {InsertArcs}
    bind $EditorBar.newArc <Enter> {MakeBalloon "insert arcs" $EditorBar.newArc}
    bind $EditorBar.newArc <Leave> {DestroyBalloon}

    button $EditorBar.editLabel -image edit_label -relief flat -command {EditLabels}
    bind $EditorBar.editLabel <Enter> {MakeBalloon "edit labels" $EditorBar.editLabel}
    bind $EditorBar.editLabel <Leave> {DestroyBalloon}

    button $EditorBar.moveNode -image move_node -relief flat -command {MoveNodes}
    bind $EditorBar.moveNode <Enter> {MakeBalloon "move nodes" $EditorBar.moveNode}
    bind $EditorBar.moveNode <Leave> {DestroyBalloon}

    button $EditorBar.redirect -image redirect -relief flat -command {RedirectArcs}
    bind $EditorBar.redirect <Enter> {MakeBalloon "redirect arcs" $EditorBar.redirect}
    bind $EditorBar.redirect <Leave> {DestroyBalloon}

    button $EditorBar.delete -image delete -relief flat -command {DeleteObjects}
    bind $EditorBar.delete <Enter> {MakeBalloon "delete objects" $EditorBar.delete}
    bind $EditorBar.delete <Leave> {DestroyBalloon}

    button $EditorBar.pred -image predecessors -relief flat -command {SetPredecessors}
    bind $EditorBar.pred <Enter> {MakeBalloon "set predecessors" $EditorBar.pred}
    bind $EditorBar.pred <Leave> {DestroyBalloon}

    pack $EditorBar.newNode $EditorBar.newArc $EditorBar.editLabel \
        $EditorBar.moveNode $EditorBar.redirect $EditorBar.delete \
        $EditorBar.pred -side left
}


# GOBLET Canvas Region

proc InitCanvasRegion {} {
    global w c xscroll yscroll savedMaxSize
    
    set w .fcanvas
    destroy $w
    frame $w
    pack $w -side top -after .infobar -fill both -expand yes -padx 1m -pady 1m

    set c $w.canvas
    set xscroll $w.xscroll
    set yscroll $w.yscroll
    canvas $c -scrollregion {0c 0c 30c 24c} -bg ivory \
	    -relief sunken -borderwidth 2 \
	    -xscrollcommand "$xscroll set" \
	    -yscrollcommand "$yscroll set"

    scrollbar $yscroll -command "$c yview" -width 3.5m
    scrollbar $xscroll -orient horiz -command "$c xview" -width 3.5m

    grid $c -in $w \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid $yscroll \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news
    grid $xscroll \
        -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid rowconfig    $w 0 -weight 1 -minsize 0
    grid columnconfig $w 0 -weight 1 -minsize 0
}



# GOBLET Status line

frame .infobar
pack .infobar -side bottom -fill x

label .infobar.opMode -textvariable Mode -relief sunken -width 16 -padx 1m \
    -font -*-courier-medium-r-normal--*-120-*-*-p-*-*-* -anchor w
bind .infobar.opMode <Enter> {MakeBalloon2 "operating mode" .infobar.opMode}
bind .infobar.opMode <Leave> {DestroyBalloon}

# label .infobar.usage -textvariable Mode -relief sunken -width 10 -padx 1m \
#     -font -*-courier-medium-r-normal--*-120-*-*-p-*-*-* -anchor w
# bind .infobar.usage <Enter> {MakeBalloon2 "memory usage" .infobar.usage}
# bind .infobar.usage <Leave> {DestroyBalloon}

label .infobar.times -textvariable TimeInfo -relief sunken -width 16 -padx 1m \
    -font -*-courier-medium-r-normal--*-120-*-*-p-*-*-* -anchor w
bind .infobar.times <Enter> {MakeBalloon2 "computation times" .infobar.times}
bind .infobar.times <Leave> {DestroyBalloon}

label .infobar.current -textvariable StatusInfo -relief sunken -width 150 -padx 1m \
    -font -*-courier-medium-r-normal--*-120-*-*-p-*-*-* -anchor w
bind .infobar.current <Enter> {MakeBalloon2 "status info" .infobar.current}
bind .infobar.current <Leave> {DestroyBalloon}

pack .infobar.opMode -padx 1m -side left
pack .infobar.times -padx 1m -side right
# pack .infobar.usage -padx 1m -side right
pack .infobar.current -padx 1m -side left



# LGPL Licence Window

proc ShowLGPL {} {
    global GoblinTclPath LGPL
    set LGPL .lgpl
    destroy $LGPL
    toplevel $LGPL
    wm title $LGPL "GOBLIN Licence Agreement"
    
     
    set LGPLButtons $LGPL.buttons
    frame $LGPLButtons
        button $LGPLButtons.done -text Done \
            -command {destroy $LGPL}

        pack $LGPLButtons.done -fill x -pady 1m
    
    pack $LGPLButtons -side bottom -padx 3m -pady 3m

    set LGPLView $LGPL.view
    frame $LGPLView
    pack $LGPLView -side top -fill both -expand yes -padx 1m -pady 1m

    set LGPLText $LGPLView.text
    set LGPLXScroll $LGPLView.xscroll
    set LGPLYScroll $LGPLView.yscroll
    text $LGPLText -bg ivory \
	    -relief sunken -borderwidth 2 \
	    -xscrollcommand "$LGPLXScroll set" \
	    -yscrollcommand "$LGPLYScroll set"

    scrollbar $LGPLXScroll -orient horiz -command "$LGPLText xview"
    scrollbar $LGPLYScroll -command "$LGPLText yview"

    grid $LGPLText -in $LGPLView \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid $LGPLXScroll \
        -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid $LGPLYScroll \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news
    grid rowconfig    $LGPLView 0 -weight 1 -minsize 0
    grid columnconfig $LGPLView 0 -weight 1 -minsize 0
    
    $LGPLText delete 1.0 end
    set LGPLStream [open [file join $GoblinTclPath LGPL]]
    while {![eof $LGPLStream]} {
        $LGPLText insert end [read $LGPLStream 1000]
    }
}
    


# Conversions of Canvas Coordinates and Goblin Coordinates

set Zoom 0.07
set Grid 2

proc CanvasCX {cx} {
    global goblinXShift goblinXZoom Zoom

    return [expr {$cx*$goblinXZoom*$Zoom+$goblinXShift*$Zoom}];
}


proc CanvasCY {cy} {
    global goblinYShift goblinYZoom Zoom

    return [expr {$cy*$goblinYZoom*$Zoom+$goblinYShift*$Zoom}];
}


proc GoblinCX {cx} {
    global goblinXShift goblinXZoom Zoom Grid

    return [expr {round(($cx-$goblinXShift*$Zoom)/($goblinXZoom+0.00001)/$Zoom/$Grid)*$Grid}];
}


proc GoblinCY {cy} {
    global goblinYShift goblinYZoom Zoom Grid

    return [expr {round(($cy-$goblinYShift*$Zoom)/($goblinYZoom+0.00001)/$Zoom/$Grid)*$Grid}];
}


proc GridCX {cx} {
    return [CanvasCX [GoblinCX $cx]];
}


proc GridCY {cy} {
    return [CanvasCY [GoblinCY $cy]];
}


proc CurrentCX {cx} {
    global xscroll
    return [GridCX [expr {$cx+[MaxCX]*[lindex [$xscroll get] 0]}]]
}


proc CurrentCY {cy} {
    global yscroll
    return [GridCY [expr {$cy+[MaxCY]*[lindex [$yscroll get] 0]}]]
}


proc MaxCX {} {
    global ThisGraph goblinXShift Zoom

    return [expr {[CanvasCX [$ThisGraph max cx]]+$goblinXShift*$Zoom}];
}


proc MaxCY {} {
    global ThisGraph goblinYShift Zoom

    return [expr {[CanvasCY [$ThisGraph max cy]]+$goblinYShift*$Zoom}];
}



# Placement of Canvas Nodes

proc DrawNode {v nodeType cx cy} {
    global c IncIn IncOut NodeIndex RevNodeIndex goblinNodeSize Zoom

    if {[string equal $nodeType "real"]} {
        set ratio [expr {$goblinNodeSize*$Zoom}]
    } else {set ratio 4}
    
    set node [$c create oval \
        [expr {$cx-$ratio}] [expr {$cy-$ratio}] \
        [expr {$cx+$ratio}] [expr {$cy+$ratio}] \
        -outline black -fill grey -tags node]
    set IncIn($v) {}
    set IncOut($v) {}
    set NodeIndex($node) $v
    set RevNodeIndex($v) $node
}


proc RedrawNode {v nodeType} {
    global c ThisGraph RevNodeIndex goblinNodeSize Zoom

    if {[string equal $nodeType "real"]} {
        set ratio [expr {$goblinNodeSize*$Zoom}]
    } else {set ratio 4}
    
    set Node $RevNodeIndex($v)
    $c coords $Node \
        [expr {[CanvasCX [$ThisGraph node $v cx]]-$ratio}] \
        [expr {[CanvasCY [$ThisGraph node $v cy]]-$ratio}] \
        [expr {[CanvasCX [$ThisGraph node $v cx]]+$ratio}] \
        [expr {[CanvasCY [$ThisGraph node $v cy]]+$ratio}]
}


proc DropNode {v cx cy} {
    global ThisGraph c
    
    set x0 [GoblinCX $cx]
    set y0 [GoblinCY $cy]
    
    if {($x0<0)} {
        for {set u 0} {$u<[expr {[$ThisGraph #nodes]+[$ThisGraph #artificial]}]} {incr u} {
            $ThisGraph node $u set cx [expr {[$ThisGraph node $u cx]-$x0}]
        }
        $ThisGraph node $v set cx 0
    } else {$ThisGraph node $v set cx $x0}

    if {($y0<0)} {
        for {set u 0} {$u<[expr {[$ThisGraph #nodes]+[$ThisGraph #artificial]}]} {incr u} {
            $ThisGraph node $u set cy [expr {[$ThisGraph node $u cy]-$y0}]
        }
        $ThisGraph node $v set cy 0
    } else {$ThisGraph node $v set cy $y0}
    
    RedrawGraph
}


# Placement of Canvas Arcs

proc DrawArc {a} {
    global ThisGraph c IncIn IncOut Mode \
        ArcIndex RevArcIndex HandleIndex RevHandleIndex thisCoords
    
    set u [$ThisGraph arc [expr {2*$a}] tail]
    set v [$ThisGraph arc [expr {2*$a}] head]
    set w [$ThisGraph arc [expr {2*$a}] align]
    
    if {$u==$v && [string equal $w "*"]} {return}

    # Draw Handle
    
    if {[string equal $w "*"]} {
        set cx [expr {([$ThisGraph node $u cx]+[$ThisGraph node $v cx])/2}]
        set cy [expr {([$ThisGraph node $u cy]+[$ThisGraph node $v cy])/2}]
    } else {
        set cx [$ThisGraph node $w cx]
        set cy [$ThisGraph node $w cy]
    }
    
    set handle [$c create rectangle \
        [expr {[CanvasCX $cx]-4}] [expr {[CanvasCY $cy]-4}] \
        [expr {[CanvasCX $cx]+4}] [expr {[CanvasCY $cy]+4}] \
        -outline black -fill black -tags handle]

    
    # Compute Canvas Coordinates
    
    if {$w!="*"} {set w [$ThisGraph node $w interpolate]}
        
    set thisCoords [list \
        [CanvasCX [$ThisGraph node $u cx]] \
        [CanvasCY [$ThisGraph node $u cy]]]
            
    while {$w!="*"} {
        DrawNode $w artifical \
            [CanvasCX [$ThisGraph node $w cx]] \
            [CanvasCY [$ThisGraph node $w cy]]
        lappend thisCoords \
            [CanvasCX [$ThisGraph node $w cx]] \
            [CanvasCY [$ThisGraph node $w cy]]
        set w [$ThisGraph node $w interpolate]
    }
    
    lappend thisCoords \
        [CanvasCX [$ThisGraph node $v cx]] \
        [CanvasCY [$ThisGraph node $v cy]]

    AlignThisCoords 0 2
    AlignThisCoords [expr {[llength $thisCoords]-2}] [expr {[llength $thisCoords]-4}]
    

    # Draw Arc
    
    global goblinArcStyle
    set lineCommand "$c create line $thisCoords"
    set widthOption "-width 2"
    set smoothOption ""
    if {$goblinArcStyle == 1} {set smoothOption "-smooth on"}
    set dirOption ""
    if {[$ThisGraph arc [expr {2*$a}] orientation]} {set dirOption "-arrow last"}

    # Handle predecessor arcs
    
    set fillOption ""
    if {[string equal $Mode "set predecessors"]} {
        if {[$ThisGraph node $v predecessor]==[expr 2*$a]} {
            set widthOption "-width 5"
	    set fillOption "-fill purple"
	    set dirOption "-arrow last"
        }
        if {[$ThisGraph node $u predecessor]==[expr 2*$a+1]} {
            set widthOption "-width 5"
            set fillOption "-fill purple"
            set dirOption "-arrow first"
        }
    }
    
    set Arc [eval $lineCommand $widthOption $smoothOption $fillOption $dirOption]

    # Set Indices
    
    $c lower $Arc
    lappend IncIn($v) $Arc
    lappend IncOut($u) $Arc
    set ArcIndex($Arc) $a
    set RevArcIndex($a) $Arc
    
    set RevHandleIndex($handle) $a
    set HandleIndex($a) $handle
}

proc RedrawArc {a} {
    global ThisGraph c RevArcIndex HandleIndex thisCoords
    
    set u [$ThisGraph arc [expr {2*$a}] tail]
    set v [$ThisGraph arc [expr {2*$a}] head]
    set w [$ThisGraph arc [expr {2*$a}] align]
    
    if {$u==$v && [string equal $w "*"]} {return}
    

    # Draw Handle
    
    if {[string equal $w "*"]} {
        set cx [expr {([$ThisGraph node $u cx]+[$ThisGraph node $v cx])/2}]
        set cy [expr {([$ThisGraph node $u cy]+[$ThisGraph node $v cy])/2}]
    } else {
        set cx [$ThisGraph node $w cx]
        set cy [$ThisGraph node $w cy]
    }
    
    $c coords $HandleIndex($a) \
        [expr {[CanvasCX $cx]-4}] [expr {[CanvasCY $cy]-4}] \
        [expr {[CanvasCX $cx]+4}] [expr {[CanvasCY $cy]+4}]

    
    # Compute Canvas Coordinates
    
    if {$w!="*"} {set w [$ThisGraph node $w interpolate]}
        
    set thisCoords [list \
        [CanvasCX [$ThisGraph node $u cx]] \
        [CanvasCY [$ThisGraph node $u cy]]]
            
    while {$w!="*"} {
        RedrawNode $w artifical
        lappend thisCoords \
            [CanvasCX [$ThisGraph node $w cx]] \
            [CanvasCY [$ThisGraph node $w cy]]
        set w [$ThisGraph node $w interpolate]
    }
    
    lappend thisCoords \
        [CanvasCX [$ThisGraph node $v cx]] \
        [CanvasCY [$ThisGraph node $v cy]]

    AlignThisCoords 0 2
    AlignThisCoords [expr {[llength $thisCoords]-2}] [expr {[llength $thisCoords]-4}]
    

    # Draw Arc
    
    eval $c coords $RevArcIndex($a) $thisCoords
    if {[$ThisGraph arc [expr {2*$a}] orientation]} {
        $c itemconfigure $RevArcIndex($a) -arrow last
    } else {
        $c itemconfigure $RevArcIndex($a) -arrow none
    }
}

proc AlignThisCoords {indexHead indexPred} {
    global thisCoords goblinNodeSize Zoom
    
    set xPred [lindex $thisCoords $indexPred]
    set yPred [lindex $thisCoords [expr {$indexPred+1}]]
    set xHead [lindex $thisCoords $indexHead]
    set yHead [lindex $thisCoords [expr {$indexHead+1}]]
    set dx [expr {$xHead-$xPred}]
    set dy [expr {$yHead-$yPred}]
    set norm [expr {sqrt($dx*$dx+$dy*$dy)}]
    
    if {$norm==0} {return}
    
    set newX [expr {$xHead-$dx/$norm*$goblinNodeSize*$Zoom}]
    set newY [expr {$yHead-$dy/$norm*$goblinNodeSize*$Zoom}]
        
    set thisCoords [lreplace $thisCoords $indexHead [expr {$indexHead+1}] \
        $newX $newY
    ]
}


# Initialize Canvas with Graph in GOBLIN Library

proc DrawGraph {} {
    global ThisGraph c
    
    $c configure -scrollregion [list 0 0 [MaxCX] [MaxCY]]

    for {set v 0} {$v<[$ThisGraph #nodes]} {incr v} {
        DrawNode $v real \
            [CanvasCX [$ThisGraph node $v cx]] \
            [CanvasCY [$ThisGraph node $v cy]]
    }
    
    if {[$ThisGraph is sparse]} {
        for {set a 0} {$a<[$ThisGraph #arcs]} {incr a} {DrawArc $a}
    } else {
            for {set v 0} {$v<[$ThisGraph #nodes]} {incr v} {
                set thisPred [$ThisGraph node $v predecessor]
		if {$thisPred!="*"} {DrawArc [expr $thisPred/2]}
            }
    }
}

proc RedrawGraph {} {
    global ThisGraph c
    
    $c configure -scrollregion [list 0 0 [MaxCX] [MaxCY]]

    for {set v 0} {$v<[$ThisGraph #nodes]} {incr v} {RedrawNode $v real}
    
    for {set a 0} {[$ThisGraph is sparse] && $a<[$ThisGraph #arcs]} {incr a} {
        RedrawArc $a
    }
}



# Editor Event Bindings

proc InitEditor {} {
    global ThisGraph currentNode currentArc StatusInfo GoblinTclPath Unchanged

    MakeEditorBar
    InitCanvasRegion

    set currentNode ""
    set currentArc ""
    set StatusInfo ""
    
    global c NodeIndex RevHandleIndex

    $c bind node <Any-Enter> {
        set thisObj [$c find withtag current]
        $c itemconfigure current -fill black
        set currentNode $NodeIndex($thisObj)
        set StatusInfo "node index $currentNode"
    }

    $c bind handle <Any-Enter> {
        set thisObj [$c find withtag current]
        $c itemconfigure current -fill grey
        set currentArc $RevHandleIndex($thisObj)
        set StatusInfo "arc index $currentArc"
    }

    $c bind node <Any-Leave> {
        set thisObj [$c find withtag current]
        $c itemconfigure current -fill grey
        set currentNode ""
        set StatusInfo ""
    }
    
    $c bind handle <Any-Leave> {
        set thisObj [$c find withtag current]
        $c itemconfigure current -fill black
        set currentArc ""
        set StatusInfo ""
    }
    
    global Mode ThisNode ThisArc StartNode EndNode ThisCoords HandleIndex

    set ThisNode ""
    set ThisArc ""
    set StartNode ""
    set EndNode ""

    bind $c <Button-1> {
        if {[string equal $Mode "move nodes"]} {
            set ThisNode $currentNode
            if {$currentArc!="" && [$ThisGraph arc [expr {2*$currentArc}] align]!="*"} {
                set ThisArc $currentArc}
        }
    
        if {[string equal $Mode "change labels"]} {
            if {$currentNode!="" && $currentNode<[$ThisGraph #nodes]} {
                source [file join $GoblinTclPath nodeattrib.tk]}
            if {$currentArc!=""} {
                source [file join $GoblinTclPath arcattrib.tk]}
        }
    
        if {[string equal $Mode "redirect arcs"]} {
            if {$currentArc!=""} {
                $ThisGraph arc [expr {2*$currentArc}] flip
                RedrawArc $currentArc
                PropagateModifications
            }
        }

        if {[string equal $Mode "insert nodes"]} {
            if {$currentNode == ""} {
                set v [$ThisGraph node insert]
                PropagateModifications

                DrawNode $v real [CurrentCX %x] [CurrentCY %y]
                DropNode $v [CurrentCX %x] [CurrentCY %y]
            }
        }
    
        if {[string equal $Mode "set predecessors"]} {
            if {$EndNode == ""} {
                if {$currentNode != "" && $currentNode<[$ThisGraph #nodes]} {
                    set EndNode $currentNode

                    MakeHelp "(L) set predecessor node/arc  (C) dismiss"
                }
            } else {
                set thisPred ""
                if {$currentNode!="" && $currentNode<[$ThisGraph #nodes]} {
                    set StartNode $currentNode
                    set thisPred [$ThisGraph adjacency $StartNode $EndNode]
                }

                if {$currentArc!=""} {
                    set thisPred [expr 2*$currentArc]
		    if {[$ThisGraph arc $thisPred head]!=$EndNode} {
                        incr thisPred
                    }
                    set StartNode [$ThisGraph arc $thisPred tail]
                }

                if {$thisPred!="" && [$ThisGraph arc $thisPred head]==$EndNode} {
                    $ThisGraph node $EndNode set predecessor $thisPred
                    PropagateModifications
                    set EndNode ""
                    MakeHelp "(L) select node"
                    InitEditor
                }
            }
        }
    
        if {[string equal $Mode "insert arcs"]} {
            if {$StartNode == ""} {
                if {$currentNode != "" && $currentNode<[$ThisGraph #nodes]} {
                    set StartNode $currentNode

                    set ThisCoords [list \
                        [CanvasCX [$ThisGraph node $StartNode cx]] \
                        [CanvasCY [$ThisGraph node $StartNode cy]] \
                        [CurrentCX %x] [CurrentCY %y]]
                    set ThisArc [$c create line $ThisCoords]
                    $c lower $ThisArc
                    MakeHelp "(L) select end node/place bend  (C) cancel"
                }
            } else {
                set EndNode [$c find withtag current]

                if {$EndNode != "" && \
                        [info exists NodeIndex($EndNode)]==1 && \
                        $NodeIndex($EndNode)<[$ThisGraph #nodes] \
                    } {
                    set u $StartNode
                    set v $NodeIndex($EndNode)
                    $c delete $ThisArc
            
                    set a [$ThisGraph arc insert $u $v]
                    set thisLength [llength $ThisCoords]
                    if {$thisLength>4} {
                        set goblinCoords ""
                        for {set i 0} {$i < $thisLength} {incr i} {
                            lappend goblinCoords [GoblinCX [lindex $ThisCoords $i]]
                        }

                        $ThisGraph arc [expr {2*$a}] set align \
                            [lindex $goblinCoords 0] [lindex $goblinCoords 1]
                        eval $ThisGraph arc [expr {2*$a}] interpolate \
                            [lrange $goblinCoords 2 [expr {$thisLength-3}]]

                        set ThisNode [$ThisGraph arc [expr {2*$a}] align]
                        MakeHelp "(L) align label"
                    } else {
                        set ThisNode ""
                        MakeHelp "(L) align label  (R) automatic alignment"
                    }
                    DrawArc $a
                    set ThisArc $a
                    set Mode "align label"

                    PropagateModifications
                    set StartNode ""
                    set EndNode ""
                } else {
                    set ThisCoords \
                        [lappend ThisCoords \
                            [CurrentCX %x] \
                            [CurrentCY %y] \
                        ]
                }
            }
        }
    
        if {[string equal $Mode "align label"] && $currentNode == ""} {
            if {$ThisNode == ""} {
                $ThisGraph arc [expr {2*$ThisArc}] set align \
                    [GoblinCX %x] [GoblinCX %y]
            } else {
                $ThisGraph node $ThisNode set cx [GoblinCX %x]
                $ThisGraph node $ThisNode set cy [GoblinCY %y]
            }
            set Mode "insert arcs"
            MakeHelp "left: select start node"
            set ThisNode ""
            set ThisArc ""
        }
        
        if {[string equal $Mode "delete objects"]} {
            if {$currentNode != "" && ![$ThisGraph is bipartite]} {
                $ThisGraph node $currentNode delete
                PropagateModifications
                InitEditor
            }
            if {$currentArc != ""} {
                $ThisGraph arc [expr {2*$currentArc}] delete
                PropagateModifications
                InitEditor
            }
        }
    }

    bind $c <B1-Motion> {
        if {[string equal $Mode "move nodes"] || [string equal $Mode "insert nodes"]} {
            if {$ThisNode != ""} {
                DropNode $ThisNode [CurrentCX %x] [CurrentCY %y]
            }
            if {$ThisArc != ""} {
                DropNode [$ThisGraph arc [expr {2*$ThisArc}] align] \
                    [CurrentCX %x] [CurrentCY %y]
            }
        }
    }

    bind $c <Motion> {
        if {[string equal $Mode "insert arcs"]} {
            if {$StartNode != ""} {
                set thisLength [llength $ThisCoords]
                set thiscx [CurrentCX %x]
                set thiscy [CurrentCY %y]
                
                if {$goblinArcStyle==2} {
                    set prevcx [lindex $ThisCoords [expr {$thisLength-4}]]
                    set prevcy [lindex $ThisCoords [expr {$thisLength-3}]]

                    if {$thiscx > $prevcx} {
                        set diffcx [expr {$thiscx-$prevcx}]
                    } else {
                        set diffcx [expr {$prevcx-$thiscx}]
                    }
                    if {$thiscy > $prevcy} {
                        set diffcy [expr {$thiscy-$prevcy}]
                    } else {
                        set diffcy [expr {$prevcy-$thiscy}]
                    }
                    if {$diffcx>$diffcy} {set thiscy $prevcy}
                    if {$diffcx<$diffcy} {set thiscx $prevcx}
                }
                
                set ThisCoords \
                    [lreplace $ThisCoords \
                        [expr {$thisLength-2}] \
                        [expr {$thisLength-1}] \
                        $thiscx $thiscy \
                    ]
                eval $c coords $ThisArc $ThisCoords
            }
        }
        
        if {[string equal $Mode "align label"]} {
            $c coords $HandleIndex($ThisArc) \
                [expr {[CurrentCX %x]-4}] [expr {[CurrentCY %y]-4}] \
                [expr {[CurrentCX %x]+4}] [expr {[CurrentCY %y]+4}]
        }
        
    }

    bind $c <ButtonRelease-1> {
        if {[string equal $Mode "move nodes"] || [string equal $Mode "insert nodes"]} {
            if {$ThisNode != ""} {
                set ThisNode ""
                PropagateModifications
            }
            if {$ThisArc != ""} {
                set v [$ThisGraph arc [expr {2*$ThisArc}] align]
                $ThisGraph node $v set cx [GoblinCX %x]
                $ThisGraph node $v set cy [GoblinCY %y]
                set ThisArc ""
                PropagateModifications
            }
        }
    }

    bind $c <Button-3> {
        if {[string equal $Mode "insert arcs"]} {
            if {$ThisArc != ""} {
                $c delete $ThisArc
                set StartNode ""
                set ThisArc ""
                MakeHelp "(L) select start node"
            }
        }
        
        if {[string equal $Mode "redirect arcs"]} {
            if {$currentArc!="" && ![$ThisGraph is undirected] \
                 && ![$ThisGraph is directed]} {
                $ThisGraph arc [expr {2*$currentArc}] set orientation \
                    [expr {1-[$ThisGraph arc [expr {2*$currentArc}] orientation]}]
                RedrawArc $currentArc
                PropagateModifications
            }
        }

        if {[string equal $Mode "align label"] && $ThisNode==""} {
            $c delete $HandleIndex($ThisArc)
            $c delete $RevArcIndex($ThisArc)
            DrawArc $ThisArc
            set ThisNode ""
            set ThisArc ""
            set Mode "insert arcs"
            MakeHelp "(L) select start node"
        }
    
        if {[string equal $Mode "set predecessors"]} {
            if {$EndNode != ""} {
                $ThisGraph node $EndNode set predecessor "*"
                PropagateModifications
                set EndNode ""
                MakeHelp "(L) select node"
                InitEditor
            }
        }
    }

    DrawGraph
}



# GOBLET Initialization

wm geometry . 730x520
wm minsize  . 730 520

set ThisGraph GOB1

set Filter [pwd]
set TraceDir [file join $env(HOME) goblet.trace]
file mkdir $TraceDir

set FileName "unnamed"
set OrigFileName "unnamed"
wm title . "GOBLET: [file tail $FileName]"

goblin mixed graph $ThisGraph
set Mode "insert nodes"
MakeMenus
InitCanvasRegion
InitDisplay
set Unchanged 1
set FileCounter 1

if {$argc != 0} {
    if {[file extension [lindex $argv 0]]==".$goblinExtension"} {
        set OrigFileName [file rootname [lindex $argv 0]]
    } else {
        set OrigFileName [lindex $argv 0]
    }
    if {![file exists $OrigFileName.$goblinExtension]} {
        toplevel .input
        wm title .input "GOBLET Prompt"
        wm resizable .input 0 0
    
        message .input.msg -width 8c -anchor w \
            -text "The file \"$OrigFileName\" does not exist!"
        pack .input.msg -padx 5m -pady 5m -side top -anchor w
    
        frame .input.buttons
        pack .input.buttons -padx 5m -pady 2m -side bottom

        button .input.buttons.start -text "Create" -command { \
            wm title . "GOBLET: [file tail $OrigFileName]"
            destroy .input
        }

        button .input.buttons.exit -text "Exit" -command { \
            destroy .input
            exit 0
        }    
    
        pack .input.buttons.start .input.buttons.exit \
            -side left -fill x -padx 3m
            
        grab set .input
        raise .input .
    } else {
        cd [file dirname $OrigFileName]
        set Filter [pwd]
        set OrigFileName [file join $Filter [file tail $OrigFileName]]
        OpenFile
    }
} else {
    set Filter [pwd]
}
