#!/data/koenneck/bin/wish
#-----------------------------------------------------------------------------
# A semi visual command line client for SICS
#
# Mark Koennnecke, December 1996
#----------------------------------------------------------------------------
lappend auto_path /data/koenneck/bin/tcl

#----------------------------------------------------------------------------
#                        Initialization Section 

set INI(DefUser) Spy
set INI(DefPasswd) 007
set INI(ServerPort) 2910
set INI(InterruptPort) 2913
set INI(box) localhost
set INI(usPasswd) Rosy
set INI(muPasswd) Diethelm
set INI(socket) stdout
set INI(status) stdout
set INI(maxinput) 10
set INI(startsleep) 5000

#---------------------------------------------------------------------------
#                      Menu Commands 
proc MenuExit { } {
  exit  
}
proc MenuUser { } {
  global INI
  SendCommand  [format "config Rights User %s" $INI(usPasswd)]
}
proc MenuManager { } {
  global INI
  SendCommand [format "config Rights Mugger %s" $INI(muPasswd)]
}
proc MenuConnect { } {
  StartConnection  
}
#--------------------------------------------------------------------------
#                 Commands used in bindings
proc TextInput {} {
  global INI
  set input [.input.entry get]
  SendCommand $input
  .input.libo.liste insert end $input
  if {[ .input.libo.liste size]  > $INI(maxinput) } {
     .input.libo.liste delete 0 
  }
  .input.libo.liste see end
  .input.entry delete 0 end
}
proc InputBack { } {
  set b [.input.entry index end]
  set b [expr {$b - 1}]
  .input.entry delete $b
}
proc InputSelect {} {
  global INI
  set input [.input.libo.liste get active]
  SendCommand  $input
}
proc ListEdit {} {
  global INI
  set input [.input.libo.liste get active]
  .input.entry insert 0 $input
} 
#---------------------------------------------------------------------------
#                         The Button Commands
proc ButtonHalt {} {
  global INI
  SendCommand "INT1712 3"
}
proc ButtonStop {} {
  global INI
  SendCommand "INT1712 2"
}
#----------------------------------------------------------------------------
#                       Create the Visuals
proc MakeWindow {} {
# a frame to hold all
# the menubar
  frame .mbar -relief raised -bd 2
  menubutton .mbar.file -text File -underline 0 \
             -menu .mbar.file.menu
  menubutton .mbar.con -text Connect -underline 0 \
             -menu .mbar.con.menu
  menubutton .mbar.rights -text Rights -underline 0 \
             -menu .mbar.rights.menu
  pack .mbar.file .mbar.con .mbar.rights -side left
# file pulldown
  menu .mbar.file.menu
  .mbar.file.menu add command -label "Exit" -command MenuExit
# connect menu
  menu .mbar.con.menu
  .mbar.con.menu add command -label "Topsi" -command MenuConnect
# Rights menu pulldown 
  menu .mbar.rights.menu 
  .mbar.rights.menu add command -label "Become User" -command \
   MenuUser
  .mbar.rights.menu add command -label "Become Manager" -command \
   MenuManager

# now the output from our SICS server
  frame .output 
  label .output.text -text "The Sics-Server's answers:"
  pack .output.text -side top
  listbox .output.liste -height 13 -width 70 \
          -yscrollcommand ".output.scroll set" 
  pack .output.liste -side left
  scrollbar .output.scroll -command ".output.liste yview"
  pack .output.scroll -side right -fill y

# the delimiter between output and input 
  frame .strich -relief flat -height 3m
  .strich configure -background red

# the input stuff
  frame .input
  label .input.head -text "Command History"
  pack .input.head -side top -fill x
  frame .input.libo
  listbox .input.libo.liste -height 5 -width 70 \
         -yscrollcommand ".input.libo.scroll set"
  pack .input.libo.liste -side left
#list box bindings
  bind .input.libo.liste <Double-Button-1> InputSelect
  bind .input.libo.liste <Double-Button-3> ListEdit

  scrollbar .input.libo.scroll -command ".input.libo.liste yview"
  pack .input.libo.scroll -side right -fill y
  pack .input.libo -after .input.head
  label .input.line -text "Type Command to Server"
  pack .input.line -after .input.libo -fill x
  entry .input.entry -width 70 -relief sunken 
  pack .input.entry -after .input.line
#entry bindings
  bind .input.entry <KeyPress-Return> TextInput
  bind .input.entry <Double-Button-1> TextInput
  bind .input.entry <KeyPress-Delete> InputBack
  bind .input.entry <Control-d> InputBack
#  bind .input.entry <Any-KeyPress> { puts "The Keysym is %K"}

# The lower button row
  frame .buttonrow
  button .buttonrow.stop -text "Stop"      -command ButtonStop
  button .buttonrow.halt -text "Emergency Halt" -command ButtonHalt
  button .buttonrow.exit -text "Exit"           -command MenuExit 
  label  .buttonrow.stat -background DarkSalmon -text "Disconnected "
  pack .buttonrow.stop .buttonrow.halt .buttonrow.stat \
       -side left -fill x
# the end
  pack configure .mbar -expand 1
  pack .mbar .output .strich .input  .buttonrow -side top -fill x
  wm title . "The SICS Visual Command Line Client"
}
#-----------------------------------------------------------------------------
#              Setting up the connection to the Server
proc StartConnection {} {
   global INI
   global lost
# start main connection
   set INI(socket) [socket $INI(box) $INI(ServerPort)]
   puts $INI(socket) [format "%s %s" $INI(DefUser) $INI(DefPasswd)]
   flush $INI(socket)
   fconfigure $INI(socket) -blocking 0
   fconfigure $INI(socket) -buffering none
   fileevent $INI(socket) readable GetData
   after $INI(startsleep)
# start status  connection
   set INI(status) [socket $INI(box) $INI(ServerPort)]
   puts $INI(status) [format "%s %s" $INI(DefUser) $INI(DefPasswd)]
   flush $INI(status)
   fconfigure $INI(status) -blocking 0
   fconfigure $INI(status) -buffering none
   fileevent $INI(status) readable GetStatus
   after $INI(startsleep)
   after 2000 SendStatRequest
}
#----------------------------------------------------------------------------
proc GetData { } {
   global INI
   global lost
   if { [eof $INI(socket)] } {
      PutOutput "Connection to server lost"
      .buttonrow.stat configure -text "Disconnected"
      after cancel SendStatRequest
      close $INI(socket)
      close $INI(status)
      return 
   } 
   set buf [read $INI(socket)]
   set buf [string trim $buf]
   set list [split $buf \n]
   foreach teil $list {
     set teil [string trimright $teil]
     if { [ string first status $teil] >= 0} {
       set l [ split $teil = ]
       .buttonrow.stat configure -text [lindex $l 1] 
     } else {
        PutOutput $teil
     }
   }
}
#----------------------------------------------------------------------------
proc GetStatus { } {
   global INI
   global lost
   if { [eof $INI(status)] } {
      PutOutput "Connection to server lost"
      .buttonrow.stat configure -text "Disconnected"
      after cancel SendStatRequest
      close $INI(status)
      close $INI(socket)
      return 
   } 
   set buf [read $INI(status)]
   set buf [string trim $buf]
   set list [split $buf \n]
   foreach teil $list {
     set teil [string trimright $teil]
     if { [ string first status $teil] >= 0} {
       set l [ split $teil = ]
       .buttonrow.stat configure -text [lindex $l 1] 
     } 
   }
}
#--------------------------------------------------------------------------
proc PutOutput { line } {
  .output.liste insert end $line
  .output.liste see end
}

proc SendCommand { text} {
  global INI
  global lost
  if { [eof $INI(socket)] } {
      PutOutput "Connection to server lost"
  }
  puts $INI(socket) $text
  flush $INI(socket)
}

proc SendStatRequest { } {
  global INI
  global lost
  if { [eof $INI(status)] } {
      PutOutput "Connection to server lost"
  }
  puts $INI(status) status
  flush $INI(status)
  after 2000 SendStatRequest
}

proc PutOutput { line } {
  .output.liste insert end $line
  .output.liste see end
}


#-----------------------------------------------------------------------------
#                    M A I N
set lost 0
MakeWindow
vwait lost

