#---------------------------------------------------------------
# The file utilities
#---------------------------------------------------------------

#---------------------------------------------------------------
# Procedure: filepopup
#  Calls mkopensave
#---------------------------------------------------------------
proc filepopup {} {
    mkopensave .file "KP File Load" "KP File Load"
}

set filename ""

#---------------------------------------------------------------
# Procedure: loadfile {filename}
#  Loads file.
#  If $filenames ends with ".gz" or ".Z", calls gzip for decompression.
#---------------------------------------------------------------
proc loadfile {filename} {
    global filtertext
    if [regexp {\.(gz|Z)$} "$filename"] {
	set f [open "|gzip -d -c $filename"]
    } else {
	set f [open "$filename"]
    }
    settext [read $f]
    set filtertext "off"
}

#-----------------------------------------------------------
# Procedure: mkopensave {new title iconName}
#  Create the window displaying user directories and files to
#  allow the users to select files to save and open
#
#  Arguments;
#  new -        Path name to use for the new top-level window
#  title -      Title of new window
#  iconname -   Icon name of new window
#-----------------------------------------------------------


proc mkopensave {new title iconName} {
    toplevel $new
    relative . $new 100 0
    wm title $new "$title"
    wm iconname $new "$iconName"

    # Set up all the frames 
    frame $new.dirlist -relief flat -borderwidth 1  
    frame $new.dirlist.left -relief flat -borderwidth 1
    frame $new.filelist -relief flat -borderwidth 1
    frame $new.filelist.left -relief flat -borderwidth 1
    frame $new.bottom -relief flat -borderwidth 1
    frame $new.button -relief flat -borderwidth 1
    frame $new.but -relief flat -borderwidth 1
    frame $new.but.default -relief sunken -borderwidth 1
    
    # Set up all labels
    label $new.dirlist.label -text "Directories "
    label $new.filelist.label -text "Files "
    label $new.bottom.label -text "Selection"
    
    
    # The entry is used to display the selected filename
    entry $new.bottom.entry -relief sunken
    
    
    # Set up all listboxes
    
    listbox $new.dirlist.list -yscrollcommand "$new.dirlist.yscroll set" \
	    -xscrollcommand "$new.dirlist.xscroll set"  -relief sunken \
	    -width 30 -height 15 -selectmode browse
    listbox $new.filelist.list -yscrollcommand "$new.filelist.yscroll set" \
	    -xscrollcommand "$new.filelist.xscroll set" -relief sunken \
	    -width 20 -height 15 -selectmode browse
    
    # Set up all scrollbars
    scrollbar $new.dirlist.yscroll -orient vertical \
	    -command "$new.dirlist.list yview"
    scrollbar $new.dirlist.xscroll -orient horizontal \
	    -command "$new.dirlist.list xview"
    scrollbar $new.filelist.yscroll -orient vertical \
	    -command "$new.filelist.list yview"
    scrollbar $new.filelist.xscroll -orient horizontal \
	    -command "$new.filelist.list xview"
    
    # These two occupy the lower-right corner so that two scrollbars
    #  don't meet
    set scrollwidth [option get $new.dirlist.xscroll "width" "Width"]
    set scrollheight [expr $scrollwidth + 4]
    frame $new.dirlist.dummy -width "${scrollwidth}" -height "${scrollheight}"
    frame $new.filelist.dummy -width "${scrollwidth}" -height "${scrollheight}"

    # Set up all buttons
    button $new.but.default.ok -text "OK" -relief raised\
	    -width 7  -command "file_ok $new"
    button $new.but.cancel -text "Cancel" -relief raised\
	    -width 7 -command "destroy $new"

    # Set up the layout of the frames
    pack $new.button -side bottom -fill x
    pack $new.bottom -side bottom -fill x
    pack $new.dirlist -side left -padx 4
    pack $new.filelist -side right -padx 4

    # Set up the directory listbox and label 
    pack $new.dirlist.label -side top -anchor w
    pack $new.dirlist.xscroll -in $new.dirlist.left -side bottom -fill x
    pack $new.dirlist.list -in $new.dirlist.left -pady 4
    pack $new.dirlist.left -side left
    pack $new.dirlist.dummy -side bottom
    pack $new.dirlist.yscroll -side right -pady 6 -padx 4 -fill y

    # Set up the file listbox and label
    pack $new.filelist.label -side top -anchor w
    pack $new.filelist.xscroll -in $new.filelist.left -side bottom -fill x
    pack $new.filelist.list -in $new.filelist.left -pady 4
    pack $new.filelist.left -side left -anchor n
    pack $new.filelist.dummy -side bottom
    pack $new.filelist.yscroll -side right -pady 6 -padx 4 -fill y

    pack $new.bottom.label -in $new.bottom -side top -anchor w
    pack $new.bottom.entry -in $new.bottom -side top -fill x -ipady 4

    # Set up the buttons 
    pack $new.but -in $new.button -anchor c -pady 8
    pack $new.but.default  -side left -padx 50 -pady 4
    pack $new.but.cancel -side left -padx 50 -pady 4 -ipady 2
    pack $new.but.default.ok -side left -padx 4 -pady 4 -ipady 2

    # Insert the directory and file names in the listboxes
    initBoxes $new 
    # Bindings for shortcuts in place of ok and
    # cancel buttons
    bind $new.bottom.entry <Return> "fileenter $new"
    bind $new.bottom.entry <Escape> "destroy $new"

    grab set $new
    focus $new.bottom.entry
}

#---------------------------------------------------------------
# Procedure: fileenter {w}
#  Called when the user hits <return> in entry
#---------------------------------------------------------------
proc fileenter {w} {
    press $w.but.default.ok "file_ok $w"
}

#----------------------------------------
# Insert directores to directory listbox
#----------------------------------------

proc initBoxes {w} {
    global filepath

    # Insert the list of the directories and files
    finddir $filepath $w
    findfiles $filepath $w
    
    displaydir $w $filepath

    # Set the first directory as default;
    # bind the commands for this new window
    $w.dirlist.list selection clear 0 [$w.dirlist.list size]
    $w.dirlist.list selection set 0
    listBindings $w
}

#-------------------------------------------------
# Display the directory in the directory entry box
#------------------------------------------------

proc displaydir {w path} {
    $w.bottom.entry delete 0 end
    $w.bottom.entry insert 0 "$path/"
}

#---------------------------------------------------
# Set the bindings for directory and file listboxes
#---------------------------------------------------

proc listBindings {w} {

    # temp is a global variable used to hold the name of this
    # particular window name because inside bind, the local variable
    # of w is not recognized
    global temp

    set temp $w
    bind $w.dirlist.list <Button-1> "dirselect $w mouse %y"
    bind $w.filelist.list <Button-1> "fileselect $w mouse %y"
    bind $w.filelist.list <B1-Motion> "fileselect $w mouse %y"
    bind $temp.bottom.entry <Up> "fileselect $w cursor -1"
    bind $temp.bottom.entry <Down> "fileselect $w cursor +1"
    bind $w.dirlist.list <Double-1> "filedoubleclick dirselect $w %y"
    bind $w.filelist.list <Double-1> "filedoubleclick fileselect $w %y"
    set temp 
}

#---------------------------------------------------------------
# Procedure: filedoubleclick {c w y}
#---------------------------------------------------------------
proc filedoubleclick {c w y} {
    press $w.but.default.ok "$c $w mouse $y; file_ok $w"
}

#---------------------------------------------------------------
# Procedure: fileselect {w event y}
#  Handles a buttonpress or drag in file list
#  Arguments:
#   w - top level widget for this box
#   event - either "mouse" or "cursor"
#   y - the y coordinate for mouse event, +1 or -1 for arrow keys
#---------------------------------------------------------------

proc fileselect {w event y} {
    global filepath filename
    set list $w.filelist.list
    switch $event {
	"mouse" {
	    $list selection clear 0 [$list size]
	    $list selection set [$list nearest $y]
	}
	"cursor" {
	    set current [$list curselection]
	    $list selection clear 0 [$list size]
	    if {"$current" == ""} {
		$list selection set 0
	    } else {
		$list selection set [expr $current $y]
	    }
	}
    }
    set filename [selection get]
    $w.bottom.entry delete 0 end
    $w.bottom.entry insert 0 "$filepath/$filename"
    set filename "$filepath/$filename"
}

#---------------------------------------------------------------
# Procedure: dirselect {w event y}
#  Handles a buttonpress or drag in directory list
#  Arguments:
#   w - top level widget for this box
#   event - either "mouse" or "cursor"
#   y - the y coordinate for mouse event, +1 or -1 for arrow keys
#---------------------------------------------------------------
proc dirselect {w event y} {
    global temp filepath
    set list $w.dirlist.list
    switch $event {
	"mouse" {
	    $list selection clear 0 [$list size]
	    $list selection set [$list nearest $y]
	}
    }
    $temp.bottom.entry delete 0 end
    $temp.bottom.entry insert 0 [selection get]
}

#---------------------------------------------------------------
# Find all the directories and put them in the directory listbox
#---------------------------------------------------------------

proc finddir {path w} {
    $w.dirlist.list delete 0 end
    set maxlen 0
    foreach i [exec ls -a $path] {
	if [file isdirectory "$path/$i"] {
	    $w.dirlist.list insert end "$path/$i"
	    if {[string length "$path/$i"] > $maxlen} {
		set maxlen [string length "$path/$i"]
	    }
	}
    }
    regexp -- {-width width Width ([0-9]+) [0-9]+$} [$w.dirlist.list configure -width] dummy width
    if {$maxlen > $width} {
	$w.dirlist.list xview [expr $maxlen - $width + 1]
    } else {
	# might have moved right before, so move it back
	$w.dirlist.list xview 0
    }
}

#---------------------------------------------------------------
# Find all the files and put them in the file listbox
#---------------------------------------------------------------

proc findfiles {path w} {
    $w.filelist.list delete 0 end
    foreach i [exec ls -a $path] {
	if [file isfile "$path/$i"] {
	    $w.filelist.list insert end "$i"
	}
    }
}

#----------------------------------------------------------------------
# Make sure the entry selected is valid
#----------------------------------------------------------------------

proc file_ok {w} {
    global filepath

    set selection [$w.bottom.entry get]
    if {[file isdirectory $selection] || \
            [file isdirectory $filepath/$selection]} {
	# Directory is selected, need to update the directory list
	# and file list
	if {[file isdirectory $filepath/$selection]} {
	    set selection $filepath/$selection
	}
	set origdir [pwd]
	cd $selection
	set filepath [pwd]
	cd $origdir
	findfiles $filepath $w
	finddir $filepath $w
	displaydir $w $filepath
	$w.dirlist.list selection clear 0 [$w.dirlist.list size]
	$w.dirlist.list selection set 0
    } elseif {[file isfile $filepath/$selection]} {
	# It is an existing file
	loadfile $filepath/$selection
	destroy $w
	#openFile 0 $filepath/$selection $w
    } elseif {[file isdirectory [file dirname $filepath/$selection]]} {
	# It is a non existing file
	openFile 1 $filepath/$selection $w
    } elseif {[file isfile $selection]} {
	# It is an existing file
	loadfile $selection
	destroy $w
	# openFile 0 $selection $w
    } elseif {[file isdirectory [file dirname $selection]] } {
	# It is a non existing file
	openFile $mode 1 $selection $w
    } else {
	dialog .d {Warning} {Invalid Directory or File name!} {} -1 OK
    }
    focus .entry
}

#---------------------------------------------------------------
# Procedure: dialog {w title text bitmap default args}
#---------------------------------------------------------------

proc dialog {w title text bitmap default args} {
    
    global button
    
    toplevel $w -class Dialog
    wm title $w $title
    wm iconname $w Dialog
    wm geometry $w +300+300
    
    frame $w.top -relief raised -bd 1
    pack $w.top -side top -fill both
    frame $w.bot -relief raised -bd 1
    pack $w.bot -side bottom -fill both
    frame $w.bot.default -relief sunken -bd 1
    
    message $w.top.msg -width 3i -text $text\
	    -font -Adobe-times-medium-r-normal--*-180* 
    pack $w.top.msg -side right -expand 1 -fill both\
	    -padx 5m -pady 5m
    if {$bitmap != ""} {
	label $w.top.bitmap -bitmap $bitmap
	pack $w.top.bitmap -side left -padx 5m -pady 5m
    }
    
    set i 0
    foreach but $args {
	button $w.bot.button$i -text $but -command "set button $i" -width 7
	if {$i == $default} {
	    pack $w.bot.default -side left -expand 1 -padx 5m -pady 2m
	    pack $w.bot.button$i -in $w.bot.default \
		    -side left -padx 3m -pady 3m -ipadx 2m -ipady 1m
	} else {
	    pack $w.bot.button$i -side left -expand 1\
		    -padx 5m -pady 5m -ipadx 2m -ipady 1m
	}
	incr i
    }
    
    if {$default >= 0} {
	bind $w <Return> "$w.bot.button$default flash; \
		set button $default"
    }
    
    set oldFocus [focus]
    grab $w
    focus $w
    tkwait variable button
    destroy $w
    focus $oldFocus
    return $button
}
