# classl editor
#  Copyright (C) 1992-2000 Michigan State University
#
#  The CAPA system is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation; either version 2 of the
#  License, or (at your option) any later version.
#
#  The CAPA system is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public
#  License along with the CAPA system; see the file COPYING.  If not,
#  write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
#  Boston, MA 02111-1307, USA.
#
#  As a special exception, you have permission to link this program
#  with the TtH/TtM library and distribute executables, as long as you
#  follow the requirements of the GNU GPL in regard to all of the
#  software in the executable aside from TtH/TtM.

###########################################################
# createClasslEditor
###########################################################
###########################################################
###########################################################
proc createClasslEditor { classlFile } {
    global gUniqueNumber gWindowMenu gWindow gTitle gClassl gFile \
	    gClosed

    set error [ catch {set fileId [open $classlFile "r"]}]
    if { $error } { 
	displayError "Unable to open a $classlFile."
	return
    }
    close $fileId

    set num [incr gUniqueNumber]

    set gFile($num) $classlFile

    set classlWin [toplevel .classlwindow$num]
    $gWindowMenu add command -label "Classl $classlFile" \
	    -command "capaRaise $classlWin"
    wm title $classlWin  "Classl $classlFile"

    set menuFrame [frame $classlWin.menu -borderwidth 3 -relief raised]
    set infoFrame [frame $classlWin.infoFrame]
    set actionFrame [frame $classlWin.actionFrame]
    set windowFrame [frame $classlWin.windowFrame]
    pack $menuFrame $infoFrame $actionFrame $windowFrame
    pack configure $windowFrame -expand 1 -fill both
    pack configure $menuFrame -fill x -anchor w

#menu
    menubutton $menuFrame.file -text File -menu $menuFrame.file.m
    menubutton $menuFrame.edit -text Copy -menu $menuFrame.edit.m
    pack $menuFrame.file  $menuFrame.edit -side left
    
    set fileMenu [ menu $menuFrame.file.m ]
    set editMenu [ menu $menuFrame.edit.m ]

    $fileMenu add command -label Open -accelerator "Alt+o" \
	    -command "specifyClass createClasslEditor"
    bind $classlWin <Alt-o> "specifyClass createClasslEditor"
    $fileMenu add command -label Save -command "saveClassl $num 0" \
	    -accelerator "Alt+s"
    bind $classlWin <Alt-s> "saveClassl $num 0"
    $fileMenu add command -label "Save As" -command "saveClassl $num 1" \
	    -accelerator "Alt+S"
    bind $classlWin <Alt-Shift-s> "saveClassl $num 1" 
    $fileMenu add command -label Print -command "printClassl $num"
    $fileMenu add command -label Close -command "closeClassl $num" \
	    -accelerator "Alt+w"
    bind $classlWin <Alt-w> "closeClassl $num"
    
    $editMenu add command -label "Copy StudentNum" -command "classlCopy $num stunum" \
	-accelerator "Alt+c"
    bind $classlWin <Alt-c> "classlCopy $num stunum"
    $editMenu add command -label "Copy Name" -command "classlCopy $num name" \
	-accelerator "Alt+n"
    bind $classlWin <Alt-n> "classlCopy $num name"
    $editMenu add command -label "Copy Email" -command "classlCopy $num email" \
	-accelerator "Alt+e"
    bind $classlWin <Alt-e> "classlCopy $num email"

#info
#action
    button $actionFrame.add -text "Add" -command "classlAdd $num"
    button $actionFrame.edit -text "Edit" -command "classlEdit $num"
    button $actionFrame.save -text "Save" -command "saveClassl $num 1"
    button $actionFrame.delete -text "Delete" -command "classlDelete $num"
    button $actionFrame.section -text "Change Section" -command "classlSectionChange $num"
    button $actionFrame.sort -text "Sort" -command "classlSort $num"
    button $actionFrame.print -text "Print" -command "classlPrint $num"
    button $actionFrame.find -text "Find" -command "classlFind $num"
    button $actionFrame.merge -text "Merge" -command "classlMerge $num"
    pack $actionFrame.add $actionFrame.edit $actionFrame.save $actionFrame.delete \
	$actionFrame.section $actionFrame.sort $actionFrame.print $actionFrame.find \
	$actionFrame.merge -side left

#window
    set leftFrame [frame $windowFrame.left]
    set rightFrame [frame $windowFrame.right]
    pack $leftFrame $rightFrame -side left
    pack configure $leftFrame -expand 1 -fill both
    pack configure $rightFrame -fill y 

#FIXME need to set the title width based on the widest occuring element in
#the listbox
    scrollbar $rightFrame.scroll -orient v -command "$leftFrame.classl yview"
    pack $rightFrame.scroll -fill y -expand 1 -pady 20

    set gTitle($num) [format "%-100s" "Class  Section  StuNum  Name                                E-mail"]
    entry $leftFrame.title -textvariable gTitle($num) -width 80 \
	    -state disabled -xscrollcommand "$leftFrame.scroll set"
    set gClassl($num) [ listbox $leftFrame.classl -width 80 -height 30 \
	    -xscrollcommand "$leftFrame.scroll set" \
	    -yscrollcommand "$rightFrame.scroll set" \
            -exportselection 0]
    scrollbar $leftFrame.scroll -orient h -command \
	    "scrolltwo {$leftFrame.classl xview} {$leftFrame.title  xview}"
    pack $leftFrame.title $leftFrame.classl $leftFrame.scroll -side top
    pack configure $leftFrame.title $leftFrame.scroll -fill x
    pack configure $leftFrame.classl -fill both -expand 1

    set fileId [open $classlFile "r"]
    while { 1 } {
	set aline [gets $fileId]
	if { [eof $fileId ] } { break }
	$gClassl($num) insert end [format "%-100s" $aline]
    }
    set gClassl($num.changed) 0
    set gClassl($num.changedlast) 0
    set gClosed($num) 0
    Centre_Dialog $classlWin default
    trace variable gClassl($num.changed) w updateClasslStatus
}

###########################################################
# closeClassl
###########################################################
###########################################################
###########################################################
proc closeClassl { num { mustClose 0 } } {
    global gWindowMenu gWindow gTitle gClassl gFile gClosed

    if { ![winfo exists $gClassl($num)] } { return }

    if { $gClosed($num) } { return }
    if { $gClassl($num.changed) == 1 } {
        if { [askToSave "Do you wish to save $gFile($num)?" "saveClassl $num" ] == "Cancel" && ( ! $mustClose ) } { return }
    }

    if { ( ! $mustClose ) && ( [makeSure "Are you sure you wish to stop editing
$gFile($num)?"] == "Cancel" ) } {
        return
    }
    set gClosed($num) 1
    destroy [winfo toplevel $gClassl($num)]
    removeWindowEntry "Classl $gFile($num)"
}

###########################################################
# saveClassl
###########################################################
###########################################################
###########################################################
proc saveClassl { num {saveAs 0}} {
    global gFile gClassl

    if { ![winfo exists $gClassl($num)] } { return }
    if { $saveAs } {
	set file [tk_getSaveFile -title "Enter name to Save As" \
		      -initialdir [file dirname "$gFile($num)"]]
	if {$file == "" } { return }
	set gFile($num) $file
    }
    set fileId [open "$gFile($num)" "w"]
    foreach line [$gClassl($num) get 0 end] { puts $fileId $line }
    close $fileId
    set gClassl($num.changed) 0
}

###########################################################
# classlSectionChange
###########################################################
###########################################################
###########################################################
proc classlSectionChange { num } {
    global gFile gClassl gWindowMenu
    
    if { [set which [$gClassl($num) curselection]] == "" } {
	displayMessage "Select a student first"
	return
    }
    if { [winfo exists .classlsection$num] } {
	capaRaise .classlsection$num
	return
    }
    set sectionChange [toplevel .classlsection$num]
    $gWindowMenu add command -label "Section Change" \
	    -command "capaRaise $sectionChange"
    wm title $sectionChange [file dirname $sectionChange]

    set infoFrame [frame $sectionChange.info]
    set entryFrame [frame $sectionChange.entry]
    set buttonFrame [frame $sectionChange.button]
    pack $infoFrame $entryFrame $buttonFrame -side top
    
    label $infoFrame.label -text "Enter New Section Number"
    pack $infoFrame.label

    label $entryFrame.label -text "Section:"
    entry $entryFrame.section -textvariable gClassl($num.section) -width 3 \
	-validate key -validatecommand "limitEntry %W 3 number %P"
    pack $entryFrame.label $entryFrame.section -side left

    set gClassl($num.done) 0
    button $buttonFrame.change -text "Change" -command "set gClassl($num.done) 1"
    button $buttonFrame.cancel -text "Cancel" -command "set gClassl($num.done) 0"
    pack $buttonFrame.change $buttonFrame.cancel -side left

    Centre_Dialog $sectionChange default
    update

    focus $sectionChange
    capaGrab $sectionChange
    vwait gClassl($num.done)
    capaGrab release $sectionChange
    
    if { $gClassl($num.done) } {
	set record [$gClassl($num) get $which]
	set record "[string range $record 0 9][format %03d $gClassl($num.section)][string range $record 13 end]"
	$gClassl($num) delete $which
	$gClassl($num) insert $which $record
	set gClassl($num.changed) 1
    }

    destroy $sectionChange
}

###########################################################
# classlSort
###########################################################
###########################################################
###########################################################
proc classlSort { num } {
    global gFile gClassl gWindowMenu
    if { [winfo exists .classlsort$num] } {
	capaRaise .classlsort$num
	return
    }

    set sortClassl [toplevel .classlsort$num]
    $gWindowMenu add command -label "Sort Classl" \
	    -command "capaRaise $sortClassl"
    wm title $sortClassl [file dirname $sortClassl]

    set infoFrame [frame $sortClassl.info]
    set buttonFrame [frame $sortClassl.button]
    pack $infoFrame $buttonFrame -side top
    
    label $infoFrame.label -text "How would you like the classl sorted?"
    pack $infoFrame.label
    
    set gClassl($num.done) 0
    button $buttonFrame.section -text "Sort By Section" \
	-command "set gClassl($num.done) Section"
    button $buttonFrame.name    -text "Sort By Name" \
	-command "set gClassl($num.done) Name"
    button $buttonFrame.cancel  -text "Cancel" -command "set gClassl($num.done) 0"
    pack $buttonFrame.section $buttonFrame.name $buttonFrame.cancel -side left

    Centre_Dialog $sortClassl default
    update

    focus $sortClassl
    capaGrab $sortClassl
    vwait gClassl($num.done)
    capaGrab release $sortClassl
    
    if { $gClassl($num.done) != 0 } {
	sortClassl$gClassl($num.done) $num
	set gClassl($num.changed) 1
    }
    destroy $sortClassl
}

###########################################################
# classlCompare
###########################################################
###########################################################
###########################################################
proc classlCompare { field1 field2 val1 val2 } {
    switch $field1 {
	section {
	    set a [string range $val1 10 12]
	    set b [string range $val2 10 12]
	}
	name {
	    set a " [string range $val1 24 55]"
	    set b " [string range $val2 24 55]"
	}
    }
    switch $field2 {
	name {
	    append a " [string range $val1 24 55]"
	    append b " [string range $val2 24 55]"
	}
	default {}
    }
    return [string compare $a $b]
}

###########################################################
# sortClasslSection
###########################################################
###########################################################
###########################################################
proc sortClasslSection { num } {
    global gClassl
    set allitems [$gClassl($num) get 0 end]
    set newitems [lsort -command "classlCompare section name" $allitems]
    $gClassl($num) delete 0 end
    eval "$gClassl($num) insert end $newitems"
}

###########################################################
# sortClasslName
###########################################################
###########################################################
###########################################################
proc sortClasslName { num } {
    global gClassl
    set allitems [$gClassl($num) get 0 end]
    set newitems [lsort -command "classlCompare name {}" $allitems]
    $gClassl($num) delete 0 end
    eval "$gClassl($num) insert end $newitems"
}
 
###########################################################
# makeClasslEntryEditor 
###########################################################
###########################################################
###########################################################
proc makeClasslEntryEditor { num window title buttonname } {
    global gClassl gWindowMenu

    if { [winfo exists $window] } {
	capaRaise $window
	return 1
    }

    set add [toplevel $window]
    $gWindowMenu add command -label "$title" -command "capaRaise $add"
    wm title $add "$title"

    set infoFrame [frame $add.info]
    set buttonFrame [frame $add.button]
    pack $infoFrame $buttonFrame -side top -anchor w

    set classFrame [frame $infoFrame.class]
    set sectionFrame [frame $infoFrame.section]
    set stuFrame [frame $infoFrame.stu]
    set nameFrame [frame $infoFrame.name]
    set emailFrame [frame $infoFrame.email]
    pack $classFrame $sectionFrame $stuFrame $nameFrame $emailFrame -side top -anchor w

    label $classFrame.label -text "Class Name" -width 20
    entry $classFrame.entry -textvariable gClassl($num.editclass) -width 9 \
	-validate key -validatecommand "limitEntry %W 9 any %P"
    pack $classFrame.label $classFrame.entry -side left

    label $sectionFrame.label -text "Section" -width 20
    entry $sectionFrame.entry -textvariable gClassl($num.editsection) -width 3 \
	-validate key -validatecommand "limitEntry %W 3 number %P"
    pack $sectionFrame.label $sectionFrame.entry -side left

    label $stuFrame.label -text "Student Number" -width 20
    entry $stuFrame.entry -textvariable gClassl($num.editstu) -width 9 \
	-validate key -validatecommand "limitEntry %W 9 any %P"
    pack $stuFrame.label $stuFrame.entry -side left

    label $nameFrame.label -text "Name(Last, First MI)" -width 20
    entry $nameFrame.entry -textvariable gClassl($num.editname) -width 30 \
	-validate key -validatecommand "limitEntry %W 30 any %P"
    pack $nameFrame.label $nameFrame.entry -side left

    label $emailFrame.label -text "Email" -width 20
    entry $emailFrame.entry -textvariable gClassl($num.editemail) -width 40 \
	-validate key -validatecommand "limitEntry %W 40 any %P"
    pack $emailFrame.label $emailFrame.entry -side left

    button $buttonFrame.add -text $buttonname -command "set gClassl($num.done) 1"
    button $buttonFrame.cancel -text Cancel -command "set gClassl($num.done) 0"
    pack $buttonFrame.add $buttonFrame.cancel -side left

    bind $add <Return> "set gClassl($num.done) 1"

    Centre_Dialog $add default
    update

    focus $add
    capaGrab $add
    return 0
}

###########################################################
# classlDelete
###########################################################
###########################################################
###########################################################
proc classlDelete { num } {
    global gClassl gWindowMenu

    if { [set which [$gClassl($num) curselection]] == "" } {
	displayMessage "Select a student first"
	return
    } 
    $gClassl($num) delete $which
    set gClassl($num.changed) 1
}

###########################################################
# classlEdit
###########################################################
###########################################################
###########################################################
proc classlEdit { num } {
    global gClassl gWindowMenu

    if { [set which [$gClassl($num) curselection]] == "" } {
	displayMessage "Select a student first"
	return
    } 
    set record [$gClassl($num) get $which]
    
    set gClassl($num.editclass) [string trimright [string range $record 0 8]]
    set gClassl($num.editsection) [string trimright [string range $record 10 12]]
    set gClassl($num.editstu) [string trimright [string range $record 14 22]]
    set gClassl($num.editname) [string trimright [string range $record 24 53]]
    set gClassl($num.editemail) [string trimright [string range $record 60 99]]

    if { [makeClasslEntryEditor $num ".classledit$num" "Editing Student" "Done"] } { return }

    vwait gClassl($num.done)
    capaGrab release .classledit$num
    destroy .classledit$num
    if { $gClassl($num.done) } {
	set gClassl($num.editsection) [string trimleft $gClassl($num.editsection) "0"]
	set record [format "%-9s %03d %-9s %-30s      %-40s" $gClassl($num.editclass) \
		   $gClassl($num.editsection) $gClassl($num.editstu) \
		   $gClassl($num.editname) $gClassl($num.editemail)]
	$gClassl($num) delete $which
	$gClassl($num) insert $which $record
	set gClassl($num.changed) 1
    }
}

###########################################################
# findStuNumClassl 
###########################################################
###########################################################
###########################################################
proc findStuNumClassl { num newstunum } {
    global gClassl 
    
    set max [$gClassl($num) index end]
    for {set i 0} {$i < $max} {incr i} {
	set teststunum [string range [$gClassl($num) get $i] 14 22]
	if { [regexp -nocase $newstunum $teststunum] } { return $i }
    }
    return -1
}

###########################################################
# classlAdd
###########################################################
###########################################################
###########################################################
proc classlAdd { num } {
    global gClassl gWindowMenu

    set gClassl($num.editclass) ""
    set gClassl($num.editsection) ""
    set gClassl($num.editstu) ""
    set gClassl($num.editname) ""
    set gClassl($num.editemail) ""

    if { [makeClasslEntryEditor $num ".classladd$num" "Adding a Student" "Add"] } { 
	return 
    }
    vwait gClassl($num.done)
    capaGrab release .classladd$num
    destroy .classladd$num
    
    if { $gClassl($num.done) } {
	if { [set which [findStuNumClassl $num $gClassl($num.editstu)]] > -1 } {
	    if { "Cancel" == [makeSure "Found a duplicate student \n [$gClassl($num) get $which] \n Replace this one?"] } {
		set gClassl($num.done) 0
		displayMessage "Student was not added."
	    } else {
		$gClassl($num) delete $which
	    }
	}
    }
    if { $gClassl($num.done) } {
	set gClassl($num.editsection) [string trimleft $gClassl($num.editsection) "0"]
	set a [format "%-9s %03d %-9s %-30s      %-40s" $gClassl($num.editclass) \
		   $gClassl($num.editsection) $gClassl($num.editstu) \
		   $gClassl($num.editname) $gClassl($num.editemail)]
	$gClassl($num) insert 0 $a
	set gClassl($num.changed) 1
    }
}

###########################################################
# classlPrint
###########################################################
###########################################################
###########################################################
proc classlPrint { num } {
    global gClassl gWindowMenu gFile

    if { [set which [$gClassl($num) curselection]] == "" } {
	displayMessage "Select a student first"
	return
    } 
    if { $gClassl($num.changed) == 1 } {
        if {[askToSave "Do you wish to save $gFile($num)?" "saveClassl $num"]=="Yes"} { 
	    saveClassl $num
	}
    }
    set record [$gClassl($num) get $which]
    set stunum [string range $record 14 22]

    if { [winfo exists .capaprint$num] } {
	capaRaise .capaprint$num
	return 1
    }

    set print [toplevel .capaprint$num]
    $gWindowMenu add command -label "Printing a Student" -command "capaRaise $print"
    wm title $print "Printing a Student"

    set infoFrame [frame $print.info]
    set dataFrame [frame $print.data]
    set buttonFrame [frame $print.button]
    pack $infoFrame $dataFrame $buttonFrame -side top -anchor w

    label $infoFrame.label -text "Print For Student $stunum"
    pack $infoFrame.label

    set setFrame [frame $dataFrame.set]
    set printerFrame [frame $dataFrame.printer]
    pack $setFrame $printerFrame -side top -anchor w

    label $setFrame.label -text "Set" -width 13
    entry $setFrame.set -textvariable gClassl($num.printset) -width 2 \
		-validate key -validatecommand "limitEntry %W 9 any %P"
    pack $setFrame.label $setFrame.set -side left

    label $printerFrame.label -text "Printer Name" -width 13
    entry $printerFrame.printer -textvariable gClassl($num.printername) -width 20 
    pack $printerFrame.label $printerFrame.printer -side left

    button $buttonFrame.print -text "Print" -command "set gClassl($num.done) 1"
    button $buttonFrame.cancel -text "Cancel" -command "set gClassl($num.done) 0"
    pack $buttonFrame.print $buttonFrame.cancel -side left

    bind $print <Return> "set gClassl($num.done) 1"

    Centre_Dialog $print default
    update

    focus $print
    capaGrab $print
    vwait gClassl($num.done)
    capaGrab release $print

    if { $gClassl($num.done) } {
	global gCapaConfig
	parseCapaConfig $num [file dirname $gFile($num)]
	if {[catch {printStudent $num $stunum $gClassl($num.printset) $gClassl($num.printername)} error ]} {
	    displayError "Unable to print  $stunum"
	}
	foreach name [array names gCapaConfig "$num.*"] {
	    unset gCapaConfig($name)
	}
    }
    destroy $print
}

###########################################################
# printStudent
###########################################################
###########################################################
###########################################################
proc printStudent { num stunum printset printername } {
    global gCapaConfig gFile
    set command "$gCapaConfig($num.qzparse_command) -c [file dirname $gFile($num)] \
                     -set $printset -stu $stunum"
    eval "exec $command"
    set tex_file [file join [file dirname $gFile($num)] TeX $stunum.tex]
    set command "$gCapaConfig($num.latex_command) $tex_file"
    removeStatus $num
    #if { "Yes" != [makeSure "Planning on running LaTeX, Continue?"] } { return }
    displayStatus "Running LaTeX" message $num
    set directory [pwd]
    cd [file join [file dirname $gFile($num)] TeX]
    eval "exec $command"
    cd $directory
    set dvi_file [file join [file dirname $gFile($num)] TeX $stunum.dvi]
    set ps_file [file join [file dirname $gFile($num)] TeX $stunum.ps]
    set command "$gCapaConfig($num.dvips_command) $dvi_file -o $ps_file >& /dev/null"
    removeStatus $num
    #if { "Yes" != [makeSure "Planning on running dvips, Continue?"] } { return }
    displayStatus "Running dvips" message $num
    eval "exec $command"
    removeStatus $num
    #if { "Cancel" == [set lprcmd [getLprCommand $ps_file $num]] } { return }
    if { [catch { eval "exec lpr -P$printername $ps_file" } errors ] } {
	displayError "An error occurred while printing: $errors"
    }
}

###########################################################
# updateClasslStatus
###########################################################
###########################################################
###########################################################
proc updateClasslStatus { name1 name2 op } {
    global gClassl gWindowMenu

    set num [lindex [split $name2 .] 0]
    if { $gClassl($num.changed) != $gClassl($num.changedlast)} {
	set gClassl($num.changedlast) $gClassl($num.changed)
	global gFile
	if { ![winfo exists $gClassl($num)] } { return }
	if { $gClassl($num.changed) } {
	    catch {removeWindowEntry "Classl $gFile($num)*"}
	    wm title [winfo toplevel $gClassl($num)] "Classl $gFile($num) (Modified)"
	    $gWindowMenu add command -label "Classl $gFile($num) (Modified)" -command \
		"capaRaise $gClassl($num)"
	} else {
	    catch {removeWindowEntry "Classl $gFile($num)*"}
	    wm title [winfo toplevel $gClassl($num)] "Classl $gFile($num)"
	    $gWindowMenu add command -label "Classl $gFile($num)" -command \
		"capaRaise $gClassl($num)"
	}
    }
}

###########################################################
# classlCopy
###########################################################
###########################################################
###########################################################
proc classlCopy { num field } {
    global gClassl
    
    if { ![winfo exists $gClassl($num)] } { return }
    if { [set which [$gClassl($num) curselection]] == "" } {
	displayMessage "Select a student first"
	return
    }
    set entry [$gClassl($num) get $which]
    set text ""
    switch $field {
	stunum { set text [string trimright [string range $entry 14 22]] }
	name { set text [string trimright [string range $entry 24 53]] }
	email { set text [string trimright [string range $entry 60 99]] }
    }
    if { $text != "" } {
	set gClassl($num.selection) $text
	selection own $gClassl($num)
	selection handle $gClassl($num) "classlPaste $num"
	selection handle -selection CLIPBOARD $gClassl($num) "classlPaste $num"
	clipboard clear -displayof $gClassl($num)
	clipboard append -displayof $gClassl($num) -- $text
    }
}

###########################################################
# classlPaste
###########################################################
###########################################################
###########################################################
proc classlPaste { num start length } {
    global gClassl
    return [string range $gClassl($num.selection) $start [expr $start + $length]]
}

###########################################################
# classlFind
###########################################################
###########################################################
###########################################################
proc classlFind { num } {
    global gClassl gWindowMenu

    if { [winfo exists .classlfind$num] } {
	capaRaise .classlfind$num
	return
    }
    set classlFind [toplevel .classlfind$num]
    $gWindowMenu add command -label "Find in Classl" \
	    -command "capaRaise $classlFind"
    wm title $classlFind "Find"

    set infoFrame [frame $classlFind.info]
    set entryFrame [frame $classlFind.entry]
    set buttonFrame [frame $classlFind.button]
    pack $infoFrame $entryFrame $buttonFrame -side top -anchor w

    set nameFrame [frame $entryFrame.name]
    set stunumFrame [frame $entryFrame.stunum]
    set emailFrame [frame $entryFrame.email]
    pack $nameFrame $stunumFrame $emailFrame -side top -anchor w

    label $nameFrame.label -text "Name" -width 14 -anchor w
    entry $nameFrame.name -textvariable gClassl($num.findname) -width 30 \
	-validate key -validatecommand "limitEntry %W 30 any %P"
    frame $nameFrame.spacer -width 80
    button $nameFrame.go -text "Find" -command "classlDoFind $num name"
    pack $nameFrame.label $nameFrame.name $nameFrame.spacer $nameFrame.go \
	-side left -anchor w

    label $stunumFrame.label -text "Student Number" -width 14 -anchor w
    entry $stunumFrame.stunum -textvariable gClassl($num.findstunum) -width 9 \
	-validate key -validatecommand "limitEntry %W 9 any %P"
    frame $stunumFrame.spacer -width 248
    button $stunumFrame.go -text "Find" -command "classlDoFind $num stunum"
    pack $stunumFrame.label $stunumFrame.stunum $stunumFrame.spacer \
	$stunumFrame.go -side left -anchor w

    label $emailFrame.label -text "Email" -width 14 -anchor w
    entry $emailFrame.email -textvariable gClassl($num.findemail) -width 40 \
	-validate key -validatecommand "limitEntry %W 40 any %P"
    button $emailFrame.go -text "Find" -command "classlDoFind $num email"
    pack $emailFrame.label $emailFrame.email $emailFrame.go -side left -anchor w

    button $buttonFrame.close -text "Close" -command "destroy $classlFind"
    pack $buttonFrame.close

    Centre_Dialog $classlFind default
}

###########################################################
# classlDoFind
###########################################################
###########################################################
###########################################################
proc classlDoFind { num type } {
    global gClassl 

    if {![winfo exists $gClassl($num)]} {return}
    if { [set which [$gClassl($num) curselection]] == "" } { 
	set which 0 
    } else {
	incr which
    }
    set max [$gClassl($num) index end]
    for {set i 0} { $i < ($max)} {incr i} {
	set current [expr ($i+$which)%$max]
	set entry [$gClassl($num) get $current]
	switch $type {
	    name { set tmp [string range [$gClassl($num) get $current] 24 53] }
	    stunum { set tmp [string range [$gClassl($num) get $current] 14 22] }
	    email { set tmp [string range [$gClassl($num) get $current] 60 99] }
	}
	if { [regexp -nocase $gClassl($num.find$type) $tmp] } {
	    $gClassl($num) selection clear 0 end
	    $gClassl($num) selection set $current
	    $gClassl($num) see $current
	    return
	}
    }
    displayMessage "Not Found"
}

###########################################################
# classlMerge
###########################################################
###########################################################
###########################################################
proc classlMerge { num } {
    global gClassl 

    set filename [tk_getOpenFile -title "Select a File to merge in"]

    if { $filename == "" } { return }
    set fileId [open $filename "r"]
    set maxlines [lindex [exec wc -l $filename] 0]
    set linenum 0
    set newentries 0
    displayStatus "Merging $filename" both $num
    set aline [gets $fileId]
    while {![eof $fileId]} {
	incr linenum
	set found 0
	set stunum [string range $aline 14 22]
	set max [$gClassl($num) index end]
	for {set i 0} { $i < ($max)} {incr i} {
	    set tmp [string range [$gClassl($num) get $i] 14 22]
	    if { [regexp -nocase $stunum $tmp] } { 
		set found 1
		break 
	    }
	}
	if { !$found } { 
	    incr newentries
	    $gClassl($num) insert end $aline 
	}
	updateStatusBar [expr $linenum/double($maxlines)] $num
	set aline [gets $fileId]
    }    
    removeStatus $num
    if { $newentries != 0 } { 
	$gClassl($num) see $max 
	$gClassl($num) selection set $max
    }
    displayMessage "Added $newentries students."
}
