#----------------------------------------------------------
# This is a tk shell for AGNI.
# This program enables you to interactively build a distributed
# system using AGNI.
# 
# The AGNI Project - DISTRIBUTED SCRIPTING FOR THE PEOPLE!
# National Institute of Standards and Technology.
# Gaithersburg, Maryland.
#
# Author : M.Ranganathan.
#
#----------------------------------------------------------

proc check_error { error_string } {
  if { [string first ETCL_Error $error_string] == -1 } {
	return 0
  } else {
	return 1
  }
}

if { $tcl_platform(platform) == "unix" } {
  append auto_path " $env(AGNI_HOME)/applications/support"
} else {
  set AGNI_HOME [file attrib $env(AGNI_HOME) -shortname]
  append auto_path " $AGNI_HOME/applications/support"
}

catch {
  package require balloon
  package require getopt
} error_string

if { [string first "can" $error_string] != -1 } {
     tk_messageBox -icon error -type ok  -message  $error_string
     exit
}

catch {
  if { $tcl_platform(platform) != "unix" } {
     load "$AGNI_HOME/lib/etcl.dll"
  } else {
     load $env(AGNI_HOME)/lib/libetcl.so Etcl
  }
} error_string

catch {
  unset env(AGNI_LOCAL)
} foo

if { [string first "couldn't load file" $error_string] != -1 } {
     tk_messageBox -icon error -type ok  -message  $error_string
     exit
}

#----------------------------------------------------------------------
# The following global variables are used to track the state of
# the gui and the system.
# max_objs - number of boxes on the screen.
# avail_objs - number of available oject locations.
# open_streamlist currently open list of streams.
# sarray - mapping from stream name to the index of the object array.
# stream_objs - an array that holds one rectangular screen object per open
#		stream and place holder rectangles for streams that are not
#		open.
# name_label - is the label that pops up whenver the cursor slides over an
#	       open MStream.
# synch_flag - synchronous flag for append.
#-----------------------------------------------------------------------

set open_streamlist {}

# Generate a cascade menu containing a list of agents and attach the given
# command to each item in the list

proc gen_agent_list { w sname cmd } {
     set agents [list_agents $sname]
     $w delete 0 end
     foreach agent $agents {
          $w add command -label "Agent $agent" -command \
			"$cmd $sname $agent"
     }
}

# Generate a cascade menu containing a list of locations and attach the
# given command to each item in the list.

proc gen_active_locations { w sname cmd } {
     set count 0
     $w delete 0 end
     set locations [get_active_locations]
     set hosts [get_active_hosts]
     foreach loc $locations {
	set host [lindex $hosts $count]
	$w add command -label "$loc ($host)" -command \
			"$cmd $sname $loc"
	incr count
     }

}

proc popup_name { stream_name } {
     global name_label
     catch {
        stream_location $stream_name
     } location
     if { [check_error $location] != 0 } {
          tk_messageBox -icon error -type ok  -message  $location
	  StreamClose $stream_name ""
     } else {
       .name_frame.label configure -text "$stream_name currently at $location"
     }
}

proc popdown_name {} {
     .name_frame.label configure -text " "
}

# set up a balloon for the appropriate button
proc menu_help { but item text } {
     global help_tips
     set help_tips($but,$item) $text
}

proc button_help { but text } {
     global help_tips
     set help_tips($but) $text
}

proc StreamAppend { streamname } {
     global synch_flag$streamname
     set w .append_dialog$streamname.frame
     # Extract the text string from the text widget.
     set text_attrib [$w.text dump -text 1.0 end]
     for { set i 1} { $i < [llength $text_attrib] } { incr i 3 } {
	set text_string [append text_string [lindex $text_attrib $i]]
     }
     set synch_flag synch_flag$streamname
     # extract the synchronous button.
     set flagval [set $synch_flag]
     if { $flagval == "" } {
       catch {
	  set retval [stream_append $streamname $text_string -synchronous]
       } error_string
       if { [check_error $error_string] != 0 } {
          tk_messageBox -icon error -type ok  -message  $error_string
       }
     } else {
       catch {
	  stream_append $streamname $text_string 
       } error_string
       if { [check_error $error_string] != 0  } {
          tk_messageBox -icon error -type ok  -message  $error_string
       }
     }

}

# set up a scrolling text widget to append to an open stream.
proc StreamAppendDialog { streamname } {
        global synch_flag$streamname
        global asynch_flag$streamname
        set synch_flag$streamname   1
        set asynch_flag$streamname {}
	toplevel .append_dialog$streamname
	set toplev .append_dialog$streamname
        wm title $toplev "Send Message to $streamname"
        set w [frame $toplev.frame]
	label $w.label -text "Enter text to send to $streamname"
	text $w.text -width 50 -height 10

	radiobutton $w.synch_flag  				\
		-command "set synch_flag$streamname {}; 
			  set asynch_flag$streamname 1  " 	\
		-variable synch_flag$streamname -text "Synch"

	radiobutton $w.asynch_flag  				\
		-command "set asynch_flag$streamname  {};	
			  set synch_flag$streamname 1   " 	\
	 	-variable asynch_flag$streamname -text "Asynch"

        button $w.ok -command "StreamAppend $streamname "  \
			-text OK -background green
        button $w.cancel -command "destroy $toplev"	   \
			-text Done -background red
	grid $w.label -row 0 -column 0 -sticky ew
        grid $w.text -row 1 -column 0 -stick ew
        grid $w.synch_flag -row 2 -column 0 -sticky  w
        grid $w.asynch_flag -row 2 -column 1 -sticky  w
        grid $w.ok -row 3 -column 0  -sticky  w
        grid $w.cancel -row 3 -column 1  -sticky w
	pack $w
}

# Get stuff from the GUI and register an agent with the stream.

proc RegisterAgent  {streamname}  {

     set w .register_agent$streamname
     set text_attrib [$w.text dump -text 1.0 end]
     for { set i 1} { $i < [llength $text_attrib] } { incr i 3 } {
	set agent_script [append agent_script [lindex $text_attrib $i]]
     }
     set argv [$w.argframe.argv get]
     catch {
        register_agent $streamname $argv $agent_script
     } error_string
     if { [check_error $error_string] != 0 } {
          tk_messageBox -icon error -type ok  -message  $error_string
     }
     destroy $w
}

# Set up a scrolling text widget with prompts to register an agent
proc RegisterAgentDialog { streamname } {
     toplevel .register_agent$streamname
     set toplev .register_agent$streamname
     label $toplev.label1 -text "Enter Argument to send to Agent"
     frame $toplev.argframe
     label $toplev.argframe.arglabel -text "argv"
     entry $toplev.argframe.argv -width 80 
     wm title $toplev "Register an Agent for $streamname"
     text $toplev.text -width 80  -height 30 \
	  -yscroll "$toplev.yscroll set"
     scrollbar $toplev.yscroll -command  "$toplev.text yview"
     label $toplev.label2 -text "Enter Agent Script:"
     $toplev.text insert 0.0 "
# Uncomment and add code to the handlers you want.

# on_stream_append {
# Message consumption handler.
# Be careful to return something on synchronous append !
#   return OK
# }

# on_stream_relocation {
#    Handler to execute on agent relocation.
# }

# on_stream_failure {
#   Handler to execute on failure of location where stream resides.
# }
   
# on_agent_exit {
#  finalizer.
# }

     "
     frame $toplev.buttons
     button $toplev.buttons.ok -text "OK" -background green \
		-command "RegisterAgent $streamname"
     button $toplev.buttons.cancel -text "CANCEL" -background red \
		-command "destroy $toplev"
     pack $toplev.label1
     pack $toplev.argframe 
     pack $toplev.argframe.arglabel $toplev.argframe.argv -side left -ipadx 5
     pack $toplev.yscroll -side right -fill y
     pack $toplev.label2
     pack $toplev.text
     pack $toplev.buttons -side bottom -fill x -pady 2m
     pack $toplev.buttons.ok $toplev.buttons.cancel -side left \
		-ipadx 10 -expand 1

}

# Move a stream to a new location.
proc StreamMove {streamname loc} {
     catch {
        set newloc [stream_move $streamname $loc]
     } error_string
     if { [check_error $error_string] != 0 } {
         tk_messageBox -icon error -type ok  -message  $error_string
     }
}

proc KillAgent { streamname agent} {
	set answer [tk_messageBox -message 				 \
	      "Killing an agent removes all its handlers. Proceed?"      \
	      -type yesno -icon warning]
	if { $answer == "yes" } {
	   catch {
	       kill_agent $streamname $agent
	   } error_string
           if { [check_error $error_string] != 0 } {
              tk_messageBox -icon error -type ok  -message  $error_string
	   }
        }

}

proc GetAgentCode { streamname agent } {
        # Get the agent code and display it in a scrollable text widget.
        toplevel .gac_$streamname$agent
        set toplev .gac_$streamname$agent
        wm title $toplev "Agent Code for $streamname Agent $agent"
	set code [get_agent_code $streamname $agent]
        text $toplev.text -width 80  -height 20 \
	  -yscroll "$toplev.yscroll set" 	\
	  -xscroll "$toplev.xscroll set"
        $toplev.text insert 0.0 $code
        scrollbar $toplev.yscroll -command  "$toplev.text yview"
        scrollbar $toplev.xscroll -command  "$toplev.text xview" \
		-orient horizontal
        button $toplev.ok -command "destroy $toplev" -text "OK" \
		-background green
        grid $toplev.text -row 0 -column 0
        grid $toplev.yscroll -row 0 -column 1 -sticky ns
        grid $toplev.xscroll -row 1 -column 0 -sticky ew
        grid $toplev.ok -row 2 -column 0
}

# Destroy the stream and remove its representation from the canvas.
	

proc StreamDestroy { stream_name w } {
     global open_streamlist
     global sarray
     global stream_objs
     global avail_objs
  
     set answer [tk_messageBox -message 			      \
	      "Destroying a stream removes all its Agents. Proceed?"  \
	      -type yesno -icon warning]
     if { $answer == "no" } {
	 return
     }
     catch {
	 stream_destroy $stream_name
     } error_string
     if { [check_error $error_string] != 0 } {
           tk_messageBox -icon error -type ok  -message  $error_string
           return
     }
     set index [lsearch -exact $open_streamlist $stream_name]
     if { $index == -1 } {
         tk_messageBox -icon error -type ok  \
		-message  "Internal Error!"
         exit
     }
     # call etcl to close stream here 
     set open_streamlist [lreplace $open_streamlist $index $index]
     set oid $sarray($stream_name)
     .canvas_frame.c itemconfigure $stream_objs($oid) -fill ""
     .canvas_frame.c bind  $stream_objs($oid) <Button-1>  ""
     .canvas_frame.c bind  $stream_objs($oid) <Enter>  ""
     .canvas_frame.c bind  $stream_objs($oid) <Leave>  ""
     set avail_objs($oid) 1
     destroy $w
}

proc get_stream_list {} {
  set streams [list_streams]
  set stream_list {}
  for { set i 0 } { $i < [llength $streams] } { incr i 2 } {
	lappend stream_list [lindex $streams $i]
  }
  return $stream_list
}

# Close an open stream - get rid of its bindings so we can no longer
# invoke operations on it from the shell.
proc StreamClose { stream_name w} {
     global open_streamlist
     global sarray
     global stream_objs
     global avail_objs
     global op_inprogress
     global sarray
  
     set index [lsearch -exact $open_streamlist $stream_name]
     if { $index == -1 } {
        tk_messageBox -icon error -type ok  \
		-message  "Internal Error!"
         exit
     }
     # call etcl to close stream here 
     set open_streamlist [lreplace $open_streamlist $index $index]
     set oid $sarray($stream_name)
     set avail_objs($oid) 1
     set op_inprogress($stream_name) 0
     # Destroy the menu 
     if { $w != "" }  {
       destroy $w
     }
     # Update the canvas and re-do bindings.
     .canvas_frame.c itemconfigure $stream_objs($oid) -fill ""
     .canvas_frame.c bind  $stream_objs($oid) <Button-1>  ""
     .canvas_frame.c bind  $stream_objs($oid) <Enter>  ""
     .canvas_frame.c bind  $stream_objs($oid) <Leave>  ""
     
}

# Open an existing stream

proc open_stream { stream_name } {
    global open_streamlist
    global sarray
    global stream_objs
    global avail_objs
    global max_objs
    global help_tips
    global op_inprogress

    # find a box in our GUI to assign.
    set found 0
    for { set index 0 } { $index < $max_objs } { incr index } {
	if { $avail_objs($index) == 1} {  
           set found 1
	   break
        }
    }

    # If we already have an open stream handle then return.
    if { [lsearch -exact $open_streamlist $stream_name] != -1 } {
        tk_messageBox -icon info -type ok  \
		-message  "The stream is already open!"
	return 
    }

    # Call AGNI to open the stream
    catch {
       stream_open $stream_name
    } error_string
    if { [check_error $error_string] != 0 } {
        tk_messageBox -icon info -type ok  \
		-message  $error_string
	return 
    } 
    set op_inprogress($stream_name) 0
    if {$found == 1} {
       set avail_objs($index) 0
    } else {
        tk_messageBox -icon error -type ok  \
		-message  "Cant open any more streams - GUI is full"
        return
    }
    lappend open_streamlist $stream_name
    set sarray($stream_name) $index
    .canvas_frame.c bind $stream_objs($index)  <Button-1> \
	"operations_menu $stream_name"
    .canvas_frame.c bind $stream_objs($index)  <Enter> \
	"popup_name $stream_name"
    .canvas_frame.c bind $stream_objs($index)  <Leave> \
	"popdown_name"
    .canvas_frame.c itemconfigure $stream_objs($index) -fill red

}

# Make a button state active 

proc ActivateButton { sname toplev } {
     global op_inprogress
     global stream_objs
     global sarray
     set op_inprogress($sname) 0
     set index $sarray($sname)
     .canvas_frame.c itemconfigure $stream_objs($index) -fill red
     destroy $toplev
}

# Setup the operations menu for individual streams.
proc operations_menu { sname } {
     global op_inprogress
     global sarray
     global stream_objs
     if { $op_inprogress($sname) == 1 } {
	 return
     }
     set op_inprogress($sname) 1
     set index $sarray($sname)
     .canvas_frame.c itemconfigure $stream_objs($index) -fill blue
     toplevel .opmenu_frame$sname
     set toplev .opmenu_frame$sname
     wm title $toplev "Operations"
     frame $toplev.frame -width 15
     set w $toplev.frame
     label  $w.label -text "Operation to perform on $sname"
     button $w.done  -text "DONE" -background green \
		-command "ActivateButton $sname $toplev"
     button $w.register_agent -text "Register Agent" \
		-command "RegisterAgentDialog $sname"
     button_help $w.register_agent "Register an Agent for $sname"
     button $w.stream_close -text "Close" \
		-command "StreamClose $sname $toplev"
     button_help $w.close "Close $sname in this program."
     button $w.stream_destroy -text "Destroy" \
		-command "StreamDestroy $sname $toplev"
     button_help $w.stream_destroy "Destroy MStream $sname and all its Agents "
     button $w.stream_append -text "Send Message" \
		-command "StreamAppendDialog $sname"
     button_help $w.stream_append "Send a message to MStream $sname"
     menubutton $w.stream_move \
	-text "Move" -menu $w.stream_move.locations  -relief raised
     button_help $w.stream_move "Move $sname to a new location"
     set move_menu [menu $w.stream_move.locations -tearoff 0 	\
		-postcommand "gen_active_locations  		\
			$w.stream_move.locations $sname StreamMove" ]
     menubutton $w.kill_agent -text "Kill Agent" \
		-menu  $w.kill_agent.agent_list  -relief raised
     set kill_menu  [menu $w.kill_agent.agent_list -tearoff 0 		\
                -postcommand "gen_agent_list $w.kill_agent.agent_list   \
				$sname KillAgent" ]
     menubutton $w.get_agent_code -text "View Agent Code" \
		-menu  $w.get_agent_code.agent_list  -relief raised
     set view_menu  [menu $w.get_agent_code.agent_list -tearoff 0 	\
         -postcommand "gen_agent_list $w.get_agent_code.agent_list 	\
			$sname GetAgentCode" ]
     set i 0
     foreach item [list  $w $w.label $w.stream_append $w.register_agent  \
		   $w.stream_close $w.stream_destroy $w.get_agent_code \
	           $w.kill_agent $w.stream_move] {
          grid $item  -row $i -column 0 -sticky ew
	  incr i
     }
     grid $w.done -row $i -column 0 -ipadx 10 -sticky ew
}

# Setup the initial canvas.

proc setup_canvas { cframe } {
    global open_streamlist
    global stream_objs
    global avail_objs
    global max_objs

    set w $cframe
    set c $w.c
    frame $w.grid
    scrollbar $w.hscroll -orient horiz -command "$c xview"
    scrollbar $w.vscroll -command "$c yview"
    canvas $c -relief sunken -borderwidth 2 \
	-scrollregion {0c 0c 50c 40c} \
	-xscrollcommand "$w.hscroll set" \
	-yscrollcommand "$w.vscroll set"
    pack $w.grid -expand yes -fill both -padx 1 -pady 1
    grid rowconfig    $w.grid 0 -weight 1 -minsize 0
    grid columnconfig $w.grid 0 -weight 1 -minsize 0
    grid $c -padx 1 -in $w.grid -pady 1 \
        -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid $w.vscroll -in $w.grid -padx 1 -pady 1 \
        -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news
    grid $w.hscroll -in $w.grid -padx 1 -pady 1 \
        -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
    set bg green
    set count 0
    for {set i 0} {$i < 20} {incr i} {
       set x [expr { 3*$i}]
       for {set j 0; set y 0} {$j < 20} {incr j; incr y 2} {
	      set objid [ $c create rect ${x}c ${y}c \
			      [expr $x+1]c [expr $y+1]c \
				-outline "" -fill "" -tags rect]
	      # keep track of the object ids for the rectangles.
	      set stream_objs($count) $objid
	      set avail_objs($count) 1
	      incr count
       }
    }
    set max_objs $count
}

# Create a stream and update the gui.

proc StreamCreate  {}  {
     global open_streamlist
     global sarray
     global avail_objs
     global stream_objs
     global max_objs
     global op_inprogress

     set w .create
     set text_attrib [$w.text dump -text 1.0 end]
     # set resctl_script "{"
     for { set i 1} { $i < [llength $text_attrib] } { incr i 3 } {
	set resctl_script [append resctl_script [lindex $text_attrib $i]]
     }
     # append resctl_script "}"
     set streamname [$w.stream_name get]
     set index [lsearch -exact $open_streamlist $streamname]
     if { $index != -1 } {
        tk_messageBox -icon error -type ok  \
		-message  "Stream $streamname exists!"
        destroy $w
        return

     }
     catch {
        stream_create $streamname -controller $resctl_script
     } error_string
     if { [check_error $error_string] != 0 } {
          tk_messageBox -icon error -type ok  -message  $error_string
          return
     }
     set op_inprogress($streamname) 0
     set found 0
     for { set index 0 } { $index < $max_objs } { incr index } {
	if { $avail_objs($index) == 1} {  
           set found 1
	   break
        }
     }
     if {$found == 1} {
       set avail_objs($index) 0
     } else {
        tk_messageBox -icon error -type ok  \
		-message  "Cant open any more streams - GUI is full"
        return
     }
     lappend open_streamlist $streamname
     set sarray($streamname) $index
     .canvas_frame.c bind $stream_objs($index)  <Button-1> \
	"operations_menu $streamname"
     .canvas_frame.c bind $stream_objs($index)  <Enter> \
	"popup_name $streamname"
     .canvas_frame.c bind $stream_objs($index)  <Leave> \
	"popdown_name"
     .canvas_frame.c itemconfigure $stream_objs($index) -fill red
      destroy $w
}

# Ask the user for information in order to create a stream.
proc StreamCreateDialog {} {
     toplevel .create
     wm title .create "Create a new MStream"
     set create_authscript 0
     label .create.label1 -text "Enter stream name to create: "
     entry .create.stream_name -width 80 
     text .create.text -width 80  -height 30 \
	  -yscroll ".create.yscroll set"
     scrollbar .create.yscroll -command  ".create.text yview"
     label .create.label2 -text "Enter Optional Stream Controller: "
     .create.text insert 0.0 "
# Uncomment and add code to the handlers you want.
#
# on_stream_append {
#    Message consumption handler.
#    argv contains the message appended.
#    schedule agents and run_scheduled_agents to get user registered 
#    agents to run as follows:
#   
#    foreach i \[list_agents\] {
#       schedule_agent \$i
#    }
#       run_scheduled_agents
# }
        
# on_stream_move {
#    Policy handler to verify reconfiguration.
#    argv contains the target location.
#    Return 0 to allow the move and 1 to disallow it.
#    return 0
# }
 
# on_stream_new_agent {
#    Handler to authenticate new agent registrations.
#    use  stream_sender_name and stream_sender_location to
#    query about the senders name and location.
#    return 0 to allow the agent addition and 1 to disallow it.
#    return 0
# }

# on_stream_move_fail {
#    Handler to run when relocation fails.
# }

# on_stream_relocation {
#    Handler for the relocation event.
#    Runs at the target location after the move completes.
#    schedule agents and run_scheduled_agents to get user registered 
#    agents to run as follows:
#   
#    foreach i \[list_agents\] {
#       schedule_agent \$i
#    }
#       run_scheduled_agents
# }

# on_stream_failure {
#    Handler to run at system controller on failure.
# }

# on_stream_open {
#    Handler to approve/disapprove opens.
#    Return 0 to approve the open and 1 to disapprove it.
#    return 0
# }

# on_stream_close {
#    Notification on stream close.
# }

# on_stream_agent_kill {
#    [lindex argv 0] contains stream name
#    [lindex argv 1] contains agent_id
# }

# post_process {
#    Post processing handler
#
#    Use get_move_targets and set_move_target to choose the relocation
#    target.
#
#    Use get_current_event to query the context for which 
#    post-processing has been invoked.
#   
# }
     "
     frame .create.buttons
     button .create.buttons.ok -text "OK" -background green \
		-command "StreamCreate"
     button .create.buttons.cancel -text "CANCEL" -background red \
		-command "destroy .create"
     pack .create.label1
     pack .create.stream_name
     pack .create.yscroll -side right -fill y
     pack .create.label2
     pack .create.text
     pack .create.buttons -side bottom -fill x -pady 2m
     pack .create.buttons.ok .create.buttons.cancel -side left \
		-ipadx 10 -expand 1

}

# Get the active locations 
proc get_active_locations {} {
   set peer_map [get_active_peer_map]
   set active_peers {}
   for { set i 0} { $i < [llength $peer_map] } { incr i 2 } {
	lappend active_peers [lindex $peer_map $i]
   }
   return $active_peers
}

# Get the active hosts 
proc get_active_hosts {} {
   set peer_map [get_active_peer_map]
   set active_peers {}
   for { set i 1} { $i < [llength $peer_map] } { incr i 2 } {
	lappend active_peers [lindex $peer_map $i]
   }
   return $active_peers
}

# Show the active locations in a list box
proc show_active_map {} {

}

# Show the peer map (active and inactive locations)
proc show_peer_map {} {
  toplevel .plist
  set w .plist
  wm title $w "Peer map"

}

# Open the selected stream
proc open_selected_stream {} {
	global lbox_name
        global stream_list
	set cursel [ $lbox_name curselection ]
        set stream_name [lindex $stream_list $cursel]
        open_stream $stream_name
}

# generate a list box with the list of streams and open 
proc SelectAndOpenStream {}  {
  	global lbox_name
  	global stream_list
        set stream_list [get_stream_list]

        toplevel .slist
        set w .slist

        wm title $w "Pick a stream to open"
        label $w.msg -justify left -text \
		"Pick a MStream to open:"
        pack $w.msg -side top

  	frame $w.frame -borderwidth 5
  	# pack the frame in the top level window.
  	pack $w.frame -side top -expand yes -fill x
  	scrollbar $w.frame.yscroll -command  "$w.frame.list yview"
  	scrollbar $w.frame.xscroll -orient horizontal \
		-command $w.frame.list.xview
  	listbox $w.frame.list -selectmode single \
		-width 20 -height 10 -setgrid 1 \
    		-yscroll "$w.frame.yscroll set" \
		-xscroll "$w.frame.xscroll set"
  	set lbox_name $w.frame.list
  	foreach s $stream_list {
    		$w.frame.list insert end $s
  	}
  	grid $w.frame.list -row 0 -column 0 -rowspan 1 -sticky news
  	grid $w.frame.yscroll -row 0 -column 1 -columnspan 1 -sticky news
  	grid $w.frame.xscroll -row 1 -column 0 -columnspan 1 -sticky news
  	grid rowconfig $w.frame 0 -weight 1 -minsize 0
  	grid columnconfig $w.frame 0 -weight 1 -minsize 0
  	frame $w.buttons 
  	pack $w.buttons -side bottom -fill x -pady 2m
  	button $w.buttons.dismiss -text "CANCEL"  -command { 
			destroy .slist 
		     }
  	button $w.buttons.open    -text "OK" -command { 
					open_selected_stream
					destroy .slist
				}
  	pack $w.buttons.dismiss  -side left
  	pack $w.buttons.open  -side right
}

proc StartDaemonAndJoinSession {} {
	global env
	set session_name      [.session.session_frame.session_name get]
	set sitectl_script    [.session.sitectl_frame.sitectl_ent get]
        set sessionctl_script [.session.sysctl_frame.sysctl_ent get]
        if { $sitectl_script != ""  && $sessionctl_script != "" } {
	   exec  $env(AGNI_HOME)/bin/agnid -h $session_name    \
			-l $sitectl_script -s $sessionctl_script &
	} elseif { $sitectl_script != "" } {
	   exec  $env(AGNI_HOME)/bin/agnid -h $session_name    \
			-l $sitectl_script &
	} elseif { $sessionctl_script != "" } {
	   exec  $env(AGNI_HOME)/bin/agnid -h $session_name    \
			-s $sessionctl_script &
	} else {
	   exec  $env(AGNI_HOME)/bin/agnid -h $session_name   &
	}

	after 2000
	catch {
	  join_session $session_name
	} error_string
	if { [check_error $error_string] != 0 } {
          tk_messageBox -icon error -type ok  -message  $error_string
	} else {
	    .opframe.shell configure -state active
	    .opframe.leave_session configure -state active
	    .opframe.mb configure -state active
	    .opframe.join_session configure -state disabled
	    destroy .session
	    set fd [open "$env(HOME)/.agnirc" "w+"]
	    puts $fd "join_session $session_name " 
	    close $fd
	    label .name_frame.session_name -text "Session: $session_name" \
		-foreground red
	    pack .name_frame.session_name
	} 
	    
}

proc LeaveSession {} {
	global env
	global open_streamlist

        set answer [tk_messageBox -message 			      \
	   "Leaving the session will kill the AGNI daemon. Proceed?"  \
	    -type yesno -icon warning]
        if { $answer == "no" } {
	   return
        }
	leave_session 
	file delete "$env(HOME)/.agnirc"
        .opframe.shell configure -state disabled
        .opframe.leave_session configure -state disabled
        .opframe.mb configure -state disabled
	.opframe.join_session configure -state active
        destroy .name_frame.session_name
	foreach stream $open_streamlist {
	     StreamClose $stream ""
	}
	# Clean up the canvas.
}

proc FileDialog { w ent } {
	set types {
		{ "Tcl scripts" {.tcl .etcl}}
		{ "All files"	* }
	}
	set file [tk_getOpenFile -filetypes $types -parent $w]
	if [string compare $file ""] {
	   $ent delete 0 end
 	   $ent insert 0 $file
	   $ent xview end
        }

}

proc JoinSession {} {
	toplevel .session
	set w .session
	wm title $w "Start daemon and join a session"
	label $w.msg -justify left -text \
"This will start your agni daemon and attempt to join a session.
A session is specified as a pair -  name (or IP address):port. 
Leave the name blank (specify only :port) if you are the session leader"
        set f0 [frame $w.session_frame]
	entry $f0.session_name -width 60
        label  $f0.label -text "Session: " -width 25
	pack $f0.label $f0.session_name -side left

        set f [frame $w.sitectl_frame]
	label $f.sitectl_label -text "Site Controller Script:" -width 25
        entry $f.sitectl_ent  -width 40
        button $f.sitectl_but -command "FileDialog $w $f.sitectl_ent" \
           -text "Browse..."
        pack $f.sitectl_label $f.sitectl_ent $f.sitectl_but -side left

        set f1 [frame $w.sysctl_frame]
	label $f1.sysctl_label -text "System Controller Script:" -width 25
        entry $f1.sysctl_ent  -width 40
        button $f1.sysctl_but -command "FileDialog $w $f1.sysctl_ent" \
           -text "Browse..."
        pack $f1.sysctl_label $f1.sysctl_ent $f1.sysctl_but -side left

	frame $w.buttons 
	button $w.buttons.ok -text "OK" -command "StartDaemonAndJoinSession" \
		-background green
	button $w.buttons.cancel -text "CANCEL" -command "destroy .session" \
		-background red
	pack $w.buttons.ok $w.buttons.cancel -side left -fill x -expand 1
	pack $w.msg $f0 $f $f1 $w.buttons 

}

proc Quit {} {
	leave_session
	exit
}

	

#-- HERE is the main script ----
wm title . "AGNI Distributed System builder"
frame .opframe -width 100 -height 30
init_balloons -delay 300

#--- edit menu items ------
menubutton .opframe.mb -text "Edit" -menu .opframe.mb.menu -relief raised
set m [menu .opframe.mb.menu -tearoff 0]
$m add command -label "Create Stream" -command { StreamCreateDialog }
menu_help $m 0 "Create a new MStream"
$m add command -label "Open Stream" -command { SelectAndOpenStream }
menu_help $m 1 "Open an existing MStream"
#--- Peers menu items ----
# menubutton .opframe.mb1 -text "Peers" -menu .opframe.mb1.menu
# set m1 [menu .opframe.mb1.menu -tearoff 0]
# $m1 add command -label "Peer Map" -command { show_peermap }
# menu_help $m1 0 "Map all peer identifiers"
# $m1 add command -label "Active Map" -command { show_active_map }
# menu_help $m1 1 "Show identity of active peers"
#--- Shell
if { $tcl_platform(platform) != "unix" } {
  set m [ button .opframe.shell -text "Shell" 			\
	-command "exec xterm -e $env(AGNI_HOME)/bin/etcl &" ]
} else {
  set m [ button .opframe.shell -text "Shell" 			\
	-command "exec $env(AGNI_HOME)/bin/etcl &" ]
}

button_help $m  "Start a text-mode shell to interact with AGNI"
#endif
#--- Leave Session
set m [ button .opframe.leave_session -text \
	"Leave Session"  -command "LeaveSession"]
menu_help $m 1 "Leave the current MStream Session. "
#--- Join Session
set m [button .opframe.join_session -text "Join Session" \
		-command "JoinSession"]
menu_help $m 1 "Join an MStream Session."
#--- Quit
button .opframe.quit -text "Quit" -command Quit
button_help .opframe.quit  "Exit this program"
#---- Streams menu
set i 0
foreach w [list .opframe.mb .opframe.join_session .opframe.leave_session \
		 .opframe.shell .opframe.quit ] {
     grid $w -row $i -column 0 -sticky ew
     incr i
}

.opframe.shell configure -state disabled
.opframe.leave_session configure -state disabled
.opframe.mb configure -state disabled

pack .opframe -side left
frame .canvas_frame
setup_canvas .canvas_frame
pack .canvas_frame
frame .name_frame -width 300 -height 10
pack .name_frame
set name_label [label .name_frame.label -text  " "]
pack $name_label