#!/usr/bin/wish -f
# Copyright (c) 1997 Andrew G. Morgan <morgan@physics.ucla.edu>
# Copyright (c) 1997 The Regents of the University of California

set local_file "/etc/niceuser.conf"
set cluster_file "/cluster/niceuser.conf"

#
# Defaults
#

wm title . "Global Nicer"

set ypos [expr [winfo screenheight .] /2 - 90 ]
set xpos [expr [winfo screenwidth .] /2 - 120 ]
wm geometry . "+$xpos+$ypos"

set nice_bitmap ""
set list_was_changed 0
set new_choice ""
set nice_list ""
set nice_file $local_file
if {[catch {set fd [open "$nice_file" r]}] == 1} {
    set nice_file $cluster_file
} else {
    close $fd
}

######################################################################
#    FIRST THE PROCEEDURES USED IN THE MAIN PARTS OF THIS SCRIPT     #
######################################################################

#
# The message dialog
#

proc bad_attempt {message} {
    global nice_bitmap

    tk_dialog .bad_attempt "Notice" $message $nice_bitmap 0 "OK"
}

proc load_user_list {} {
    global nice_file nice_list

    set nice_list ""
    if {[catch {set fd [open "$nice_file" r]}] != 1} {
	while {[gets $fd s] != -1} {
	    set nice_list "$nice_list $s"
	}
	close $fd
    }
}

#
# Clean up
#

proc clean_up {retval} {
    global name fname bash

    if {[string compare $name $fname] != 0} {
	exec $bash -c "/bin/rm -f $fname"
    }
    exit $retval
}

proc FillList {} {
    global nice_list

    .middle.nice_list delete 0 end
    foreach s $nice_list {
	regsub -all "\:.*$" $s "" name
	regsub -all "^.*\:" $s "" nice
	.middle.nice_list insert end [ format "%-20s %s" $name $nice ]
    }
    
}

set new_choice ""

proc EditBox { old_entry } {
    global list_was_changed new_choice

    set new_choice ""

    regsub -all "\:.*$" $old_entry "" name
    regsub -all "^.*\:" $old_entry "" nice

    toplevel .ebox
    wm title .ebox "Edit User"
    wm group .ebox .

    frame .ebox.user

    label .ebox.user.label -text "User:"
    entry .ebox.user.name -width 20
    .ebox.user.name insert end "$name"

    label .ebox.user.clabel -text "Nice:"
    entry .ebox.user.nice -width 2
    .ebox.user.nice insert end "$nice"

    grid .ebox.user.label .ebox.user.name -sticky w
    grid .ebox.user.clabel .ebox.user.nice -sticky w

    frame .ebox.b
    button .ebox.b.ok -text "OK" -command {
	global new_choice

	set xx [string trim [.ebox.user.name get]]
	set yy [string trim [.ebox.user.nice get]]
	destroy .ebox

	set new_choice "$xx\:$yy"
    }
    button .ebox.b.cancel -text "Cancel" -command {
	global new_choice

	destroy .ebox
	set new_choice ""
    }

    pack .ebox.b.ok .ebox.b.cancel -side left
    pack .ebox.user .ebox.b

    tkwait variable new_choice
    return "$new_choice"
}

proc state_usage {} {
    bad_attempt "\
Sorry, you need to supply a username and a nice value.

For example,   User: smith   Nice: 7"
}

proc sanitize { pair } {
    if {[string match "* *" $pair] != 0} {
	state_usage
	return ""
    }

    return "$pair"
}

proc EditUser {} {
    global nice_list list_was_changed
    set chosen [ .middle.nice_list curselection ]

    if {[string compare "$chosen" ""] != 0} {
# we have a user to edit...
	set old_entry [ lindex $nice_list $chosen ]
	set new_entry [ EditBox $old_entry ]
	set new_entry [ sanitize "$new_entry" ]

	if {[string compare "" $new_entry] != 0} {
	    if {[string compare "$old_entry" "$new_entry"] != 0} {
		global nice_list

		set new_list ""
		foreach s $nice_list {
		    if {[string compare "$s" "$old_entry"] != 0} {
			set new_list "$new_list $s"
		    } else {
			set new_list "$new_list $new_entry"
		    }
		}
		set nice_list "$new_list"
		set list_was_changed 1
		FillList
	    }
	}
    }
}

proc DeleteUser {} {
    set chosen [ .middle.nice_list curselection ]

    if {[string compare "$chosen" ""] != 0} {
	global nice_list list_was_changed
# we have a user to delete...

	set chosen_user [ lindex $nice_list $chosen ]
	set new_list ""
	foreach s $nice_list {
	    if {[string compare "$s" "$chosen_user"] != 0} {
		set new_list "$new_list $s"
	    }
	}
	set nice_list "$new_list"
	set list_was_changed 1
	FillList
    }
}

proc NewUser {} {
    global nice_list list_was_changed

    set old_entry "\:4"
    set new_entry [ EditBox $old_entry ]

    set new_entry [ sanitize "$new_entry" ]
    if {[string compare "" $new_entry] != 0} {

	regsub -all "\:.*$" $new_entry "" name
	if {[string compare "" $name] == 0} { state_usage ; return }
	regsub -all "^.*\:" $new_entry "" nice
	if {[string compare "" $nice] == 0} { state_usage ; return }

	if {[string compare "$old_entry" "$new_entry"] != 0} {
	    global nice_list
	    
	    set chosen [ .middle.nice_list curselection ]
	    if { [string compare "$chosen" "" ] == 0 } {
		set nice_list "$nice_list $new_entry"
	    } else {
		set chosen_user [ lindex $nice_list $chosen ]
		
		set new_list ""
		foreach s $nice_list {
		    if {[string compare "$s" "$chosen_user"] != 0} {
			set new_list "$new_list $s"
		    } else {
			set new_list "$new_list $new_entry $s"
		    }
		}
		set nice_list "$new_list"
	    }
	    set list_was_changed 1
	    FillList
	}
    }
}

#
# Menu choices
#

proc SaveChoices {} {
    global nice_list local_file list_was_changed

    if { "$list_was_changed" == 0 } { return }

    if {[catch {set fd [open "$local_file\-pre" w]}] != 1} {
	foreach s $nice_list {
	    puts $fd "$s"
	}
	close $fd
	exec /bin/bash -c "(/bin/mv $local_file\-pre $local_file 2>&1) >/dev/null &"
    }

    set list_was_changed 0
}

set done_now ""

proc want_to_save {} {
    global done_now

    toplevel .warn
    wm title .warn "* WARNING *"

    label .warn.think -text "Do you want to save your changes?"
    pack .warn.think

    frame .warn.b
    button .warn.b.save -text "Save & Quit" -command {
	global done_now

	SaveChoices
	set done_now "1"
    }
    button .warn.b.quit -text "Just Quit" -command { 
	global done_now
	set done_now "1" 
    }

    pack .warn.b.save .warn.b.quit -side left -fill x
    pack .warn.think .warn.b

    tkwait variable done_now
    destroy .warn
}

proc Quit {} {
    global list_was_changed

    if { "$list_was_changed" != 0 } {
	want_to_save
    }

    exit 0
}

#
# Here is the options menu
#

## output choices

######################################################################
#        THE MAIN PART OF THIS APPLICATION: THE MAIN WINDOW          #
######################################################################

# menu bar

frame .top 

menubutton .top.file -text "File"
menu .top.file.menu
.top.file config -menu .top.file.menu

.top.file.menu add command -label "Save" -command { SaveChoices }
.top.file.menu add command -label "Quit" -command { Quit }

pack .top.file

# list of known users

frame .middle

label .middle.title -font fixed -text "username      nicelevel    "
pack .middle.title -anchor w -side top

listbox .middle.nice_list -font fixed -yscrollcommand ".middle.sb set" -exportselection 0 -selectmode single
scrollbar .middle.sb -command ".middle.nice_list yview"
pack .middle.nice_list -side left -expand true -fill both
pack .middle.sb -side left -fill y

bind .middle.nice_list <Double-Button-1> {
    .middle.nice_list selection clear 0 end
    .middle.nice_list selection set [ .middle.nice_list nearest %y ]
    EditUser
}

# command options

frame .bottom

button .bottom.new -text "New" -command { NewUser }
button .bottom.edit -text "Edit" -command { EditUser }
button .bottom.delete -text "Delete" -command { DeleteUser }

pack .bottom.new .bottom.edit .bottom.delete -side left -padx 1m

# here are the defaults

pack .top -anchor w
pack .middle
pack .bottom

#
# Before we start...
#

load_user_list
FillList

