#  Postilion software and its included text and images
#  Copyright (C) 1998, 1999, 2000 Nic Bernstein
#
#  The full text of the legal notices is contained in the file called
#  COPYING, included with this distribution.
#
#  This program 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.
# 
#  This program 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 this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


# CreateAddressWin --
#
# Create a hierachical browser widget to use for alias manipulation
#
# Arguments:

proc CreateAddressWin {} {
    global option t b address composeHeaderList composeAdrHdrList defaultFont \
	aliasMod tk_version activeCompose

    if ![string length $activeCompose] {
	set activeCompose dummy
    }
    upvar #0 $activeCompose mh
    set id .address
    upvar #0 $id win
    set win(type) address
    set mypad 8
    set win(mypad) $mypad
    
    # If a hierwin of this type already exists, exit, otherwise build one
    if [winfo exists $id] {
	wm deiconify $id
	raise $id
	return
    }
    toplevel $id -class Postilion
    $id configure
    wm withdraw $id
    Place $id address
    wm group $id .
    wm protocol $id WM_DELETE_WINDOW "AddrWinDestroy $id"
    wm title $id $t(addrbook)
    wm iconname $id $t(addrbook)
    BuildHierarchyWindow $id
    # Create path entry
    frame $id.fPE -bd 1 -relief flat
    label $id.path_label -relief flat
    label $id.path_begin -bd 2 -relief sunken -anchor w

    pack $id.fPE -fill x -padx $mypad -pady 4
    pack $id.path_label -in $id.fPE -side left
    pack $id.path_begin -in $id.fPE -side left -fill x \
	-padx 1 -pady 1 -ipady 2 -expand 1

    SetIcon $id addrwin
    Place $id address
    upvar #0 $id hd
    set hd(win_type) address
    set hd(list) $id.fLBs.1.lb
    set b($hd(list)) alias_chooser
    set hd(booklist) $id.fLBs.0.lb
    set b($hd(booklist)) show_adrbook_menu
    set hd(pathlabel) $id.path_label
    set hd(entry) $id.path_begin
    set b($hd(entry)) alias_content
    set hd(search) ""
    set hd(booklabel) $id.labbox.0.text
    set b($hd(booklabel)) clear_addr
    set hd(addlabel) $id.labbox.1.text
    set hd(mode) book
    set hd(w) $id
    set hd(hdrlist) {}

    # Set some global defaults, for now...
    set mypad 8

    #
    # ---- create action buttons
    #
    set w $id.buttons
    frame $w
    pack $w -padx $mypad -pady 5 -side top -fill x

    set w $id.buttons.top
    frame $w
    pack $w -side top -fill x

    button $w.delete -bd 2 -relief raised -text $t(delete)
    set hd(delete) $w.delete

    button $w.new -bd 2 -relief raised -text $t(new)
    set hd(new) $w.new

    button $w.edit -bd 2 -relief raised -text $t(edit)
    set hd(edit) $w.edit

    menubutton $w.move -text $t(move_to) -state disabled \
	-menu $w.move.m -indicatoron 1 -relief raised
    set hd(move) $w.move
    set b($hd(move)) move_alias

    menu $w.move.m
    set hd(movemenu) $w.move.m

    pack $w.delete $w.new $w.edit $w.move -side left -padx 5 -pady 5 -ipadx 5 \
	-fill x -expand yes

    set w $id.buttons.bot
    frame $w
    pack $w -side bottom -fill x
    
    # Add buttons for To:, Cc: etc.
    foreach header [string tolower $option(compose_headers)] {
	if {-1 != [lsearch $composeAdrHdrList $header]} {
	    button $w.${header} -text $t($header): -width 10 \
		-state disabled \
		-activebackground [lindex $option(color_set) 0]
	    if ![string compare $header to] {
		if {$tk_version < 8.0} {
		    $w.$header config -indicatoron yes -width 8
		} else {
		    $w.$header config -default active -width 8
		}
	    }
	    pack $w.$header -side left -padx 5 -pady 5 -ipadx 5 \
		-fill x -expand yes
	    lappend hd(hdrlist) $w.$header
	}
    }

    # Populate first listbox
    AddrUpdateBooklist $id
    $hd(booklabel) configure -text $t(addrbooks)
    $hd(pathlabel) configure -text $t(address):

    # Do bindings
    bind $w <FocusIn> "ConfigMainMenu $id"
    bind $hd(booklabel) <ButtonRelease-1> "AddrSwMode $id"
    bind $hd(booklist) <ButtonRelease-1> "AddressesPopulate $id"
    bind $hd(booklist) <3> "AddrPostMenu %X %Y %W \[%W index @%x,%y\]; break"
    bind $id <Key-Up> "AddressChooserMoveSel $id up"
    bind $id <Key-Left> "AddressChooserMoveSel $id up"
    bind $id <Key-Right> "AddressChooserMoveSel $id down"
    bind $id <Key-Down> "AddressChooserMoveSel $id down"
    bind $id <Key-Return> "MakeSelect $id to 0; AddrWinDestroy $id"
#    bind $id <M> break
    catch {bind $id <M1> break}
    catch {bind $id <M2> break}
    catch {bind $id <M3> break}
    catch {bind $id <M4> break}
    catch {bind $id <M5> break}
    bind $id <Key-space> "MakeSelect $id to 0"
    bind $id <Control-c> "AddrWinDestroy $id"
    bind $id <Key-Escape> "AddrWinDestroy $id"
    bind $id <Key> "AliasChooserSearch $id %A"

    # Configure buttons
    $hd(new) configure -state normal -command "AddrbookAdd"
    set b($hd(new)) add_addrbook
    $hd(delete) configure -state disabled
    $hd(edit) configure -state disabled
    $hd(move) configure -state disabled

    # Create the floating menus
    set menu $id.bookmenu
    menu $menu -tearoff 0
    $menu add command -label $t(new)... -command "AddrbookAdd"
    set b($menu,[$menu index end]) add_addrbook
    $menu add command -label $t(delete) -command "AddrbookDeleteDone ${id} 1"
    set b($menu,[$menu index end]) delete_addrbook
    $menu add command -label $t(set_default)
    set b($menu,[$menu index end]) set_default_addrbook
    $menu add cascade -label $t(import) -menu $menu.imp
    set b($menu,[$menu index end]) import_aliases_from_pgm
    set hd(bookmenu) $menu

    set menu $id.bookmenu.imp
    menu $menu -tearoff 0
    $menu add command -label mail -command "AddrbookImport mail"
    $menu add command -label elm -command "AddrbookImport elm"
    $menu add command -label pine -command "AddrbookImport pine"

    # Set up traces
    trace variable option(use_system_aliases) w "AddrUpdateBooklist $id"
    trace variable option(addrbooks) w "AddrUpdateBooklist $id"
    trace variable aliasMod w "AddressesPopulate $id"

    wm deiconify $id
    Size $id address
    return $id
}

# AddrPostMenu
#
# Post a the menu for a given entry. The arguments are: the root window
# coordinates, the listbox, and the name of the address book
#
# Arguments:
# x, y   -	Position of pointer, this is where we will popup the menu
# listW  -	Name of the list widget the entry belongs to
# index  -	Name of the addressbook

proc AddrPostMenu { x y listW index } {
    global t option bookMod aliasBook

    set w [winfo toplevel $listW]
    upvar #0 $w hd

    set name [string trimright [$listW get $index] " ->"]
    set hd(book) $name
    set sysbook $t([lindex $option(system_aliases) 0])

    # Disable or enable menu choices
    if [string compare $name $sysbook] {
	if $aliasBook(writable,$name) {
	    $w.bookmenu entryconfigure 1 -state normal
	    $w.bookmenu entryconfigure 2 -state normal
	} else {
	    $w.bookmenu entryconfigure 1 -state disabled
	    $w.bookmenu entryconfigure 2 -state disabled
	}
    } else {
	$w.bookmenu entryconfigure 1 -state disabled
	$w.bookmenu entryconfigure 2 -state disabled
    }
    $w.bookmenu entryconfigure 3 -command {
	set option(default_book) $name
	set bookMod 1
    }

    # Post the menu
    bind $w.bookmenu <Unmap> "$listW selection clear $index"
    tk_popup $w.bookmenu $x $y
}

# AddrUpdateBooklist
#
# Update the list of known books for an alias window
#
# Arguments:
# handler - The handler of the address window

proc AddrUpdateBooklist {handler args} {
    global option aliasBook
    upvar #0 $handler hd

    # Clear the list and the move menu
    $hd(booklist) delete 0 end
    $hd(movemenu) delete 1 end

    # Populate the list
    foreach a $option(addrbooks) {
	set book [list [lindex $a 0] ->]
	$hd(booklist) insert end $book
    }

    # Add the system book if appropriate
    set sysbook [list [lindex $option(system_aliases) 0] ->]
    if {$option(use_system_aliases)} {
	$hd(booklist) insert end $sysbook
    } 

    # Populate the Move-to menu
    foreach book [array names aliasBook writable,*] {
	regsub writable, $book {} name
	if $aliasBook(writable,$name) {
	    $hd(movemenu) add command -label $name \
		-command "AliasMoveTo move $handler $name"
	}
    }	
}

# AddressesPopulate --
#
# Populate the addresses window
#
# Arguments:
# id - The handler of the address window

proc AddressesPopulate {id args} {
    global t b aliasBook activeCompose
    upvar #0 $id hd

    if ![string length $activeCompose] {
	set activeCompose dummy
    }

    # Get the current selection (if any)
    set item [$hd(booklist) curselection]
    if ![catch {set curbook [string trimright [$hd(booklist) get $item] " ->"]}] {
	$hd(addlabel) configure -text $curbook
	set hd(book) $curbook
    }

    # List all aliases
    RatAlias list alias

    # Clear the list
    $hd(list) delete 0 end
    set hd(aliasIds) ""

    # Populate the list
    foreach a [lsort [array names alias]] {
	set book [lindex $alias($a) 0]
	if ![string compare $hd(book) $book] {
	    lappend hd(aliasIds) $a
	    if [string length [lindex $alias($a) 1]] {
		$hd(list) insert end [lindex $alias($a) 1]
	    } else {
		$hd(list) insert end $a
	    }
	}
    }

    # Do the bindings
    bind $hd(list) <ButtonRelease-1> "PostAddrSel $id"

    # Set the action button states
    if $aliasBook(writable,$hd(book)) {
	$hd(delete) configure -state normal -command "AddrbookDeleteDone $id 1"
	set b($hd(delete)) delete_addrbook
	$hd(new) configure -state normal -command "AliasDetail $id new"
	set b($hd(new)) add_addrbook
    } else {
	$hd(delete) configure -state disabled
	if [info exists b($hd(delete))] {unset b($hd(delete))}
	$hd(new) configure -state disabled
	if [info exists b($hd(new))] {unset b($hd(new))}
    }
    $hd(edit) configure -state disabled
    $hd(move) configure -state disabled
    $hd(entry) configure -text ""
    foreach button $hd(hdrlist) {
	set header [lindex [split $button .] end]
	$button configure -text $t($header):-$t(list) -state normal \
	    -command "MakeSelect $id $header 1"
    }
}

# AddrSwMode --
#
# Change the mode of the Address widget to book
#
# Arguments:
# id - The handler of the address widget

proc AddrSwMode {id} {
    upvar #0 $id hd

    set hd(book) ""
    $hd(booklist) selection clear 0 end
    $hd(list) delete 0 end
    $hd(entry) configure -text {}
    $hd(addlabel) configure -text {}
    $hd(new) configure -state normal -command "AddrbookAdd"
    set b($hd(new)) add_addrbook
    $hd(edit) configure -state disabled
    if [info exists b($hd(edit))] {unset b($hd(edit))}
    $hd(delete) configure -state disabled
    if [info exists b($hd(delete))] {unset b($hd(delete))}
    $hd(move) configure -state disabled
    if [info exists b($hd(move))] {unset b($hd(move))}
    foreach button $hd(hdrlist) {
	$button configure -state disabled
    }
}

# PostAddrSel --
# 
# Effect the selection of a particular address from the list
#
# Arguments:
# id - The handler for the address widget

proc PostAddrSel {id} {
    global t b aliasBook activeCompose
    upvar #0 $id hd

    if ![string length $activeCompose] {
	set activeCompose dummy
    }
    if ![catch {set hd(current) [lindex $hd(aliasIds) [$hd(list) curselection]]}] {
	set address [lindex [RatAlias get $hd(current)] 2]
	$hd(entry) configure -text $address
	if $aliasBook(writable,$hd(book)) {
	    $hd(delete) configure -state normal \
		-command "AliasDelete $id"
	    set b($hd(delete)) delete_alias
	    $hd(edit) configure -state normal \
		-command "AliasDetail $id edit $hd(current)"
	    set b($hd(edit)) edit_alias
	    $hd(new) configure -state normal -command "AliasDetail $id new"
	    set b($hd(new)) new_alias
	    $hd(move) configure -state normal
	    set b($hd(move)) move_alias
	} else {
	    $hd(new) configure -state disabled
	    if [info exists b($hd(new))] {unset b($hd(new))}
	    $hd(edit) configure -state disabled
	    if [info exists b($hd(edit))] {unset b($hd(edit))}
	    $hd(delete) configure -state disabled
	    if [info exists b($hd(delete))] {unset b($hd(delete))}
	    $hd(move) configure -state disabled
	    if [info exists b($hd(move))] {unset b($hd(move))}
	}
        foreach button $hd(hdrlist) {
	    set header [lindex [split $button .] end]
	    $button configure -state normal -text $t($header): -width 10 \
		    -command "MakeSelect $id $header 0"
	}
    }
}

# MakeSelect --
#
# Make a compose window, if necessary, and insert the appropriate header ino it
#
# Arguments:
# id   - the id of the address window
# header - which header this is for
# list - 1 if this is a list insert, 0 for single address
proc MakeSelect {id header list} {
    global activeCompose option
    if { 0 == [string compare $activeCompose dummy]} {
	set activeCompose [Compose dummy]
	tkwait visibility .$activeCompose
    }

    if $list {
	ListSelect $activeCompose $id $header
    } else {
	AddressSelect $activeCompose $id $header
    }
}

# AddressChooserMoveSel --
#
# Move the selection in the chooser.
#
# Arguments:
# handler   - The handler which defines this selection window
# direction - Which direction we should move the selection.

proc AddressChooserMoveSel {handler direction} {
    upvar #0 $handler hd

    set cur [$hd(list) curselection]
    if ![catch {$hd(list) selection clear $cur}] {
	if [string compare up $direction] {
	    if {[incr cur] > [$hd(list) size]} {
		incr cur -1
	    }
	    if {[expr $cur/[$hd(list) size].0] >= [lindex [$hd(list) yview] 1]} {
		$hd(list) yview $cur
	    }
	} else {
	    if {$cur > 0} {
		incr cur -1
		if {[expr $cur/[$hd(list) size].0] < [lindex [$hd(list) yview] 0]} {
		    $hd(list) yview scroll -1 pages
		}
	    }
	}
	$hd(list) selection set $cur
	set hd(search) ""
	PostAddrSel $handler
    }
}

# ListSelect --
#
# Expand all names in an address book and insert into proper header field
#
# Arguments:
# handler        - The handler which controls this text widget
# id        - The window handle for the selection widget
# header    - Which header field this is for

proc ListSelect {handler id header} {
    upvar #0 $handler mh
    upvar #0 $id hd

    set w2 $mh(headerFrame).${header}_entry.t

    foreach selection $hd(aliasIds) {
	# if the alias is real...
	if [string length $selection] {
	    # add a comma if necessary
	    if [string length [string trim [$w2 get 1.0 end]]] {
		$w2 insert end ,
	    }
	    # add the new address
	    $w2 insert end $selection
	    update idletasks
	    ComposeHandleHE $w2 $mh(${header}_handler)
	}
    }
}

# AddrWinDestroy --
#
# Destroy address window and clean up
#
# Arguments:
# id - The handler for the address window

proc AddrWinDestroy {id} {
    global option aliasMod activeCompose quiting
    upvar #0 $id handler
    upvar #0 $activeCompose mh

    trace vdelete option(use_system_aliases) w "AddrUpdateBooklist $id"
    trace vdelete option(addrbooks) w "AddrUpdateBooklist $id"
    trace vdelete aliasMod w "AddressesPopulate $id"
    AliasSave
    RecordPos $id address
    destroy ${id}_icon
    destroy $id
    if !{$quiting} {
	ConfigMainMenu default
	if { [llength [winfo children .]] <=2 } {
	    Quit all
	}
    }
    unset handler
}
