namespace eval ifacetk {
    variable options

    custom::defgroup IFace \
	[::msgcat::mc "Options for main interface."] \
	-group Tkabbur -tag "Main Interface"

    custom::defvar options(use_tabbar) 1 \
	[::msgcat::mc \
	     "Use Tabbed Interface (you need to restart)."] \
	-group IFace -type boolean

    custom::defvar options(tabs_side) top \
	[::msgcat::mc "Side where to place tabs in tabbed mode."] \
	-group IFace -type options \
	-values [list top    [::msgcat::mc "Top"] \
		      bottom [::msgcat::mc "Bottom"] \
		      left   [::msgcat::mc "Left"] \
		      right  [::msgcat::mc "Right"]] \
	-command [namespace current]::configure_tabs

    custom::defvar options(tab_minwidth) 90 \
	[::msgcat::mc "Minimum width of tab buttons in tabbed mode."] \
	-group IFace -type integer \
	-command [namespace current]::configure_tabs

    custom::defvar options(tab_maxwidth) 120 \
	[::msgcat::mc "Maximum width of tab buttons in tabbed mode."] \
	-group IFace -type integer \
	-command [namespace current]::configure_tabs

    custom::defvar options(show_toolbar) 1 \
	[::msgcat::mc "Show Toolbar."] \
	-group IFace -type boolean \
	-command [namespace current]::switch_toolbar

    custom::defvar options(show_presencebar) 1 \
	[::msgcat::mc "Show presence bar."] \
	-group IFace -type boolean \
	-command [namespace current]::switch_presencebar

    custom::defvar options(show_statusbar) 1 \
	[::msgcat::mc "Show status bar."] \
	-group IFace -type boolean \
	-command [namespace current]::switch_statusbar

#    if {!$XLFDFonts} {
	custom::defvar options(font) default_font \
	    [::msgcat::mc "Font to use in chat windows."] \
    -group IFace -type font \
	    -command [list [namespace current]::switch_font font Chat]

	custom::defvar options(roster_font) default_font \
	    [::msgcat::mc "Font to use in roster windows."] \
 	    -group IFace -type font \
	   -command [list [namespace current]::switch_font roster_font Roster]
#      }
    custom::defvar options(raise_new_tab) 1 \
	[::msgcat::mc "Raise new tab."] \
	-group IFace -type boolean

    custom::defvar options(message_numbers_in_tabs) 1 \
	[::msgcat::mc "Show number of unread messages in tab titles."] \
	-group IFace -type boolean

    custom::defvar options(only_personal_messages_in_window_title) 0 \
	[::msgcat::mc "Show only the number of personal unread messages\
		       in window title."] \
	-group IFace -type boolean

    custom::defvar options(update_title_delay) 600 \
	[::msgcat::mc "Delay between getting focus and updating window or tab title in milliseconds."] \
	-group IFace -type integer

    custom::defvar options(show_tearoffs) 1 \
	[::msgcat::mc "Show menu tearoffs when possible."] \
	-group IFace -type boolean

    custom::defvar options(closebuttonaction) close \
	[::msgcat::mc "What action does the close button."] \
	-group IFace -type options \
	-values [list \
		     close    [::msgcat::mc "Close Tkabbur"] \
		     nothing  [::msgcat::mc "Do nothing"] \
		     minimize [::msgcat::mc "Minimize"] \
		     iconize  [::msgcat::mc "Iconize"] \
		     systray  [::msgcat::mc "Minimize to systray (if systray\
					     icon is enabled, otherwise do nothing)"] \
		    ]

    custom::defvar mainwindowstate normal \
	[::msgcat::mc "Stored main window state (normal or zoomed)"] \
	-type string -group Hidden

    custom::defvar status_history [list] \
	    [::msgcat::mc "History of availability status messages"] \
	    -type list \
	    -group Hidden

    custom::defvar options(max_status_history) 10 \
	    [::msgcat::mc "Maximum number of status messages to keep.\
		    If the history size reaches this threshold,\
		    the oldest message will be deleted automatically\
		    when a new one is recorded."] \
	    -type integer -group IFace


    proc isource {file} {
	set dir [file dirname [info script]]
	source [file join $dir $file]
    }

    isource ilogin.tcl
    isource iroster.tcl
    isource systray.tcl
    
    variable after_focused_id ""

    variable number_msg
    variable personal_msg

    namespace export raise_win add_win tab_set_updated
}

source [file join [file dirname [info script]] buttonbar.tcl]

proc ifacetk::configure_tabs {args} {
    variable options
    global usetabbar
    variable tabs

    if {$usetabbar} {
	if {[string is integer -strict $options(tab_minwidth)] && \
		$options(tab_minwidth) >= 0} {
	    set minwidth $options(tab_minwidth)
	} else {
	    set minwidth 90
	}
	if {[string is integer -strict $options(tab_maxwidth)] && \
		$options(tab_maxwidth) >= 0} {
	    set maxwidth $options(tab_maxwidth)
	} else {
	    set maxwidth 90
	}

	switch -- $options(tabs_side) {
	    bottom {
		set row 2
		set col 1
		set orient horizontal
	    }
	    left {
		set row 1
		set col 0
		set orient vertical
	    }
	    right {
		set row 1
		set col 2
		set orient vertical
	    }
	    default {
		set row 0
		set col 1
		set orient horizontal
	    }
	}
	grid .nb -row $row -column $col -sticky nswe -in $tabs
	.nb configure -minwidth $minwidth -maxwidth $maxwidth -orient $orient
    }
}

proc ifacetk::save_mainwindowstate {w} {
    variable mainwindowstate

    if {![cequal $w .]} return

    set state [wm state .]
    if {$state != $mainwindowstate} {
	set mainwindowstate $state
    }
}

hook::add map_window_hook [namespace current]::ifacetk::save_mainwindowstate

option add *errorForeground red widgetDefault

wm protocol . WM_SAVE_YOURSELF session_checkpoint

wm protocol . WM_DELETE_WINDOW \
   [list [namespace current]::ifacetk::wm_delete_window]

proc ifacetk::wm_delete_window {} {
    variable options

    hook::run protocol_wm_delete_window_hook $options(closebuttonaction)
}

proc ifacetk::closebuttonproc {action} { 
    variable options

    switch -- $action {
        nothing {}
        minimize {
	    wm iconify .
        }
	iconize {
	    wm iconify .
	    wm state . withdrawn
	}
        close -
	default {
	    quit
        }
    }
}

hook::add protocol_wm_delete_window_hook \
    [namespace current]::ifacetk::closebuttonproc

set xselection ""

proc EncodeTextSelection {txt offset len} {
    set elided ""
    if {[lcontain [$txt tag names] emphasized] && [$txt tag cget emphasized -elide]} {
	set elided emphasized
    } elseif {[lcontain [$txt tag names] nonemphasized] && [$txt tag cget nonemphasized -elide]} {
	set elided nonemphasized
    }
    if {[cequal $elided ""]} {
	set ::xselection [eval $txt get [$txt tag ranges sel]]
    } else {
	lassign [$txt tag ranges sel] selstart selstop
	set sel $selstart
	set ::xselection ""
	while {![cequal [set range [$txt tag nextrange $elided $sel $selstop]] ""]} {
	    append ::xselection [$txt get $sel [lindex $range 0]]
	    set sel [lindex $range 1]
	}
	append ::xselection [$txt get $sel $selstop]
    }
    encoding convertto [crange $::xselection $offset [expr $offset + $len - 1]]
}

proc EncodeEntrySelection {txt offset len} {
    if [$txt selection present] {
	set idx1 [$txt index sel.first]	
	set idx2 [$txt index sel.last]
	set ::xselection [string range [$txt get] $idx1 $idx2]
	encoding convertto \
	    [crange $::xselection $offset [expr $offset + $len - 1]]
    } else {
	set ::xselection ""
    }
}

if {[cequal $tcl_platform(platform) unix]} {
    proc ::tk::GetSelection {w {sel PRIMARY}} {
        if {![catch {selection get -displayof $w \
			-selection $sel -type UTF8_STRING} txt]} {
	    return $txt
	} elseif {![catch {selection get -displayof $w -selection $sel} txt]} {
	    if {[selection own] == ""} {
		return [encoding convertfrom $txt]
	    } else {
		return $::xselection
	    }
	} else {
	    return -code error "could not find default selection"
	}
    }

    bind Text  <Map> { selection handle %W "EncodeTextSelection %W" }
    bind Entry <Map> { selection handle %W "EncodeEntrySelection %W" }
    
    if {[info tclversion] < 8.4} {
	bind Text <ButtonRelease-2> {
	    if {![catch {::tk::GetSelection %W} sel]} {
		%W insert current $sel
	    }
	}
	bind Entry <ButtonRelease-2> {
	    if {![catch {::tk::GetSelection %W} sel]} {
		%W insert insert $sel
	    }
	}
    }
}
###############################################################################

proc ifacetk::load_descmenu {} {
    global descmenu

    set descmenu \
	[list "&Tkabbur" {} tkabbur $ifacetk::options(show_tearoffs) \
	     [list \
		  [list cascad [::msgcat::mc "Presence"] {} presence $ifacetk::options(show_tearoffs) \
		       [list \
			    [list command [::msgcat::mc "Available"] {} {} {} \
				 -command {set userstatus available}] \
			    [list command [::msgcat::mc "Free to chat"] {} {} {} \
				 -command {set userstatus chat}] \
			    [list command [::msgcat::mc "Away"] {} {} {} \
				 -command {set userstatus away}] \
			    [list command [::msgcat::mc "Extended away"] {} {} {} \
				 -command {set userstatus xa}] \
			    [list command [::msgcat::mc "Do not disturb"] {} {} {} \
			    	-command {set userstatus xa}]]] \
		  [list command [::msgcat::mc "Log in..."] {} {} {Ctrl l} \
		       -command [list [namespace current]::login_dialog]] \
		  [list command [::msgcat::mc "Log out"] {} {} {Ctrl j} \
		       -command [list [namespace current]::logout_dialog]] \
		  [list command [::msgcat::mc "Register an account..."] {} {} {} \
		       -command [list [namespace current]::reg_profile_do]] \
		  {separator} \
		  [list command [::msgcat::mc "Change password..."] {} {} {} \
		       -command {change_password_dialog}] \
		  [list command [::msgcat::mc "Edit my info..."] {} {} {} \
		  	-command {ifacetk::edit_info_dialog}] \
		  [list cascad [::msgcat::mc "Privacy rules"] {} privacy $ifacetk::options(show_tearoffs) \
		       [list \
			    [list checkbutton [::msgcat::mc "Activate lists at startup"] {} {} {} \
				 -variable privacy::options(activate_at_startup)] \
			    [list command [string trim [::msgcat::mc "Edit invisible list "]] {} {} {} \
				 -command {ifacetk::privacy_edit_special_list invisible}] \
			    [list command [string trim [::msgcat::mc "Edit ignore list "]] {} {} {} \
				 -command {ifacetk::privacy_edit_special_list ignore}] \
			    [list command [string trim [::msgcat::mc "Edit conference list "]] {} {} {} \
				 -command {ifacetk::privacy_edit_special_list conference}] \
			    [list checkbutton [::msgcat::mc "Accept messages from roster users only"] {} {} {} \
				 -variable privacy::accept_from_roster_only \
				 -command privacy::on_accept_from_roster_only_change] \
			    {separator} \
			    [list command [::msgcat::mc "Manually edit rules"] {} {} {} \
				 -command {ifacetk::privacy_request_lists}]]] \
		  {separator} \
		  [list cascad [::msgcat::mc "View"] {} {} $ifacetk::options(show_tearoffs) \
		   [list \
		     [list checkbutton [::msgcat::mc "Toolbar"] \
			  {} {} {} \
			  -variable [namespace current]::options(show_toolbar)] \
		     [list checkbutton [::msgcat::mc "Presence bar"] \
			  {} {} {} \
			  -variable [namespace current]::options(show_presencebar)] \
		     [list checkbutton [::msgcat::mc "Status bar"] \
			  {} {} {} \
			  -variable [namespace current]::options(show_statusbar)] \
		  ]] \
		  [list cascad [::msgcat::mc "Roster"] {} roster $ifacetk::options(show_tearoffs) \
		   [list \
		    [list checkbutton [::msgcat::mc "Show online users only"] \
			 {} {} {} \
			 -variable [namespace current]::roster::show_only_online] \
		    [list checkbutton [::msgcat::mc "Show own resources"] {} {} {} \
			 -variable [namespace current]::roster::options(show_own_resources)] \
		    [list cascad [::msgcat::mc "Export roster..."] \
			 export_roster export_roster 0 {}] \
		    [list cascad [::msgcat::mc "Import roster..."] \
			 import_roster import_roster 0 {}] \
		    [list command [::msgcat::mc "Add group by regexp on JIDs..."] {} {} {} \
			 -command [namespace current]::roster::add_group_by_jid_regexp_dialog] \
		  ]] \
		  [list cascad [::msgcat::mc "Chats"] {} chats $ifacetk::options(show_tearoffs) \
		   [list \
		    [list checkbutton [::msgcat::mc "Smart autoscroll"] {} {} {} \
			 -variable chat::options(smart_scroll)] \
		    [list checkbutton [::msgcat::mc "Stop autoscroll"] {} {} {} \
			 -variable chat::options(stop_scroll)] \
		    [list checkbutton [::msgcat::mc "Emphasize"] {} {} {} \
			 -variable plugins::stylecodes::options(emphasize)] \
		    [list checkbutton [::msgcat::mc "Show emoticons"] {} {} {} \
			 -variable plugins::emoticons::options(show_emoticons)] \
		    {separator} \
		  ]] \
		  {separator} \
		  [list command [::msgcat::mc "Customize"] {} {} {} \
		       -command {custom::open_window Tkabbur}] \
		  {separator} \
		  [list command [::msgcat::mc "Profile on"] {} {} {} -command {
		      profile -commands -eval on
		  }] \
		  [list command [::msgcat::mc "Profile report"] {} {} {} -command {
		      profile off profil
		      profrep profil real profresults
		  }] \
		  {separator} \
		  [list command [::msgcat::mc "Quit"] {} {} {} \
		       -command {quit}] \
		 ] \
	     [::msgcat::mc "&Services"] {} services $ifacetk::options(show_tearoffs) \
	     [list \
		  [list command [::msgcat::mc "Add user to roster..."] {} {} {} \
		       -command {message::send_subscribe_dialog ""}] \
		  {separator} \
		  [list command [::msgcat::mc "Send message..."] {} {} {} \
		       -command {message::send_dialog}] \
		  [list command [::msgcat::mc "Open chat..."] {} {} {} \
		       -command {chat::open_chat_dialog}] \
		  [list command [::msgcat::mc "Join group..."] {} {} {}\
		       -command {join_group_dialog}] \
		  [list command [::msgcat::mc "Show user or service info..."] {} {} {} \
		       -command {userinfo::show_info_dialog}] \
		  {separator} \
		  [list command [::msgcat::mc "Service Discovery"] {} {} {} \
		       -command {ifacetk::discovery_dialog}] \
		  {separator} \
		  [list command [::msgcat::mc "Message archive"] {} {} {} \
		       -command {message_archive::show_archive}] \
          [list cascad [::msgcat::mc "Plugins"] {} plugins $ifacetk::options(show_tearoffs) \
	        ] \
		  {separator} \
		  [list cascad [::msgcat::mc "Admin tools"] {} admin $ifacetk::options(show_tearoffs) \
		       [list \
			    [list command [::msgcat::mc "Send broadcast message..."] {} {} {} \
				 -command {ifacetk::send_announce_message announce/online}] \
			    [list command [::msgcat::mc "Send message of the day..."] {} {} {} \
				 -command {ifacetk::send_announce_message announce/motd}] \
			    [list command [::msgcat::mc "Update message of the day..."] {} {} {} \
				 -command {ifacetk::send_announce_message announce/motd/update}] \
			    [list command [::msgcat::mc "Delete message of the day"] {} {} {} \
				 -command {ifacetk::send_announce_message announce/motd/delete}] \
		        {separator} \
               ]] \
		 ] \
	     [::msgcat::mc "&Help"] {} {} $ifacetk::options(show_tearoffs) \
	     [list \
		  [list command [::msgcat::mc "Quick help"] {} {} {} \
		       -command ifacetk::quick_help_window] \
		  [list command [::msgcat::mc "About"] {} {} {} \
		       -command ifacetk::about_window] \
		 ] \
	    ]
    
    if {![info exists ::enable_profiling] || !$::enable_profiling || \
	    ([clength [info commands profile]] == 0)} {
	set tmpmenu {}
	set eatP 0
	foreach menu [lindex $descmenu 4] {
	    if {[::msgcat::mc "Profile on"] == [lindex $menu 1] || \
		    [::msgcat::mc "Profile report"] == [lindex $menu 1]} {
		set eatP 1
	    } elseif {$eatP} {
		set eatP 0
	    } else {
		lappend tmpmenu $menu
	    }
	}
	set descmenu [lreplace $descmenu 4 4 $tmpmenu]
    }
    
    set descmenu [menuload $descmenu]
}

proc ifacetk::privacy_edit_special_list {type} {
    global pesl_dialog
    set w .discovery
    if {[winfo exists $w]} {
	destroy $w
    }

    switch -- [llength [jlib::connections]] {
	0 {
	    return
	}
	1 {
	    privacy::edit_special_list $type
	    return
	}
    }
    set lnames {}
    foreach connid [jlib::connections] {
	lappend lnames $connid [jlib::connection_bare_jid $connid]
    }

    if {[CbDialog $w [::msgcat::mc "Edit $type list"] \
	    [list [::msgcat::mc "OK"] [list $w enddialog 0] \
		  [::msgcat::mc "Cancel"] [list $w enddialog 1]] \
	    pesl_dialog $lnames {} -modal local] != 0} {
	return
    }

    foreach connid [array names pesl_dialog] {
	if {[lcontain [jlib::connections] $connid] && $pesl_dialog($connid)} {
	    privacy::edit_special_list $type -connection $connid
	}
    }

}
proc ifacetk::privacy_request_lists {} {
    global prl_dialog
    set w .discovery
    if {[winfo exists $w]} {
	destroy $w
    }

    switch -- [llength [jlib::connections]] {
	0 {
	    return
	}
	1 {
	    privacy::request_lists
	    return
	}
    }
    set lnames {}
    foreach connid [jlib::connections] {
	lappend lnames $connid [jlib::connection_bare_jid $connid]
    }

    if {[CbDialog $w [::msgcat::mc "Manually edit rules"] \
	    [list [::msgcat::mc "OK"] [list $w enddialog 0] \
		  [::msgcat::mc "Cancel"] [list $w enddialog 1]] \
	    prl_dialog $lnames {} -modal local] != 0} {
	return
    }

    foreach connid [array names prl_dialog] {
	if {[lcontain [jlib::connections] $connid] && $prl_dialog($connid)} {
	    privacy::request_lists -connection $connid
	}
    }

}
proc ifacetk::edit_info_dialog {} {
    global ei_dialog
    set w .ei
    if {[winfo exists $w]} {
	destroy $w
    }

    switch -- [llength [jlib::connections]] {
	0 {
	    return
	}
	1 {
	    set connid [jlib::route ""]
	    userinfo::open [jlib::connection_bare_jid $connid] -editable 1 $connid
	    return
	}
    }
    set lnames {}
    foreach connid [jlib::connections] {
	lappend lnames $connid [jlib::connection_bare_jid $connid]
    }

    if {[CbDialog $w [::msgcat::mc "Edit my info..."] \
	    [list [::msgcat::mc "OK"] [list $w enddialog 0] \
		  [::msgcat::mc "Cancel"] [list $w enddialog 1]] \
	    ei_dialog $lnames {} -modal local] != 0} {
	return
    }
    foreach connid [array names ei_dialog] {
	if {$ei_dialog($connid)} {
	    set jid [jlib::connection_bare_jid $connid]
	    userinfo::open $jid -editable 1 -connection $connid
	}
    }
}
proc ifacetk::discovery_dialog {} {
    global dis_dialog
    set w .discovery
    if {[winfo exists $w]} {
	destroy $w
    }

    switch -- [llength [jlib::connections]] {
	0 {
	    return
	}
	1 {
	    disco::browser::open_win "" 
	    return
	}
    }
    set lnames {}
    foreach connid [jlib::connections] {
	lappend lnames $connid [jlib::connection_jid $connid]
    }

    if {[CbDialog $w [::msgcat::mc "Service Discovery"] \
	    [list [::msgcat::mc "OK"] [list $w enddialog 0] \
		  [::msgcat::mc "Cancel"] [list $w enddialog 1]] \
	    dis_dialog $lnames {} -modal local] != 0} {
	return
    }

    foreach connid [array names dis_dialog] {
	if {[lcontain [jlib::connections] $connid] && $dis_dialog($connid)} {
	    disco::browser::open_win "" -connection $connid
	}
    }

}


###############################################################################

proc ifacetk::get_conf {w option} {
    return [lindex [$w configure $option] 4]
}

###############################################################################

proc ifacetk::send_announce_message {resource} {
    if {[llength [jlib::connections]] == 0} return

    set server [jlib::connection_server [lindex [jlib::connections] 0]]

    if {$resource == "announce/motd/delete"} {
	message::send_msg "$server/$resource" -type normal
    } else {
	message::send_dialog -to "$server/$resource"
    }
}

###############################################################################

proc ifacetk::quick_help_window {} {
    set w .quick_help

    if {[winfo exists $w]} {
	destroy $w
    }

    Dialog $w -anchor e \
	      -separator yes \
	      -title [::msgcat::mc "Quick Help"] \
	      -side bottom \
	      -modal none \
	      -default 0 \
	      -cancel 0
    $w add -text [::msgcat::mc "Close"] -command [list destroy $w]

    set frame [$w getframe]
    set sw [ScrolledWindow $frame.sw]
    pack $sw -fill both -expand yes

    set t [text $frame.help -wrap none]

    set tabstop [font measure [get_conf $t -font] \
		      "    [::msgcat::mc {Middle mouse button}]      "]
    $t configure -tabs $tabstop

    $sw setwidget $t
    $t insert 0.0 \
"[::msgcat::mc {Main window:}]
    $::tk_modify-L\t[::msgcat::mc {Log in}]
    $::tk_modify-J\t[::msgcat::mc {Log out}]

[::msgcat::mc Tabs:]
    $::tk_modify-F4,
    [::msgcat::mc {Middle mouse button}]\t[::msgcat::mc {Close tab}]
    $::tk_modify-PgUp/Down\t[::msgcat::mc {Previous/Next tab}]
    $::tk_modify-Alt-PgUp/Down\t[::msgcat::mc {Move tab left/right}]
    Alt-\[1-9,0\]\t[::msgcat::mc {Switch to tab number 1-9,10}]
    $::tk_modify-R\t[::msgcat::mc {Hide/Show roster}]

[::msgcat::mc Common:]
    $::tk_modify-S\t[::msgcat::mc {Activate search panel}]

[::msgcat::mc Chats:]
    TAB\t[::msgcat::mc {Complete nickname or command}]
    $::tk_modify-Up/Down\t[::msgcat::mc {Previous/Next history message}]
    Alt-E\t[::msgcat::mc {Show palette of emoticons}]
    $::tk_modify-Z\t[::msgcat::mc {Undo}]
    $::tk_modify-Shift-Z\t[::msgcat::mc {Redo}]
    Alt-PgUp/Down\t[::msgcat::mc {Scroll chat window up/down}]
    [::msgcat::mc {Right mouse button}]\t[::msgcat::mc {Correct word}]

[::msgcat::mc Systray:]
    [::msgcat::mc {Left mouse button}]\t[::msgcat::mc {Show main window}]
    [::msgcat::mc {Middle mouse button}]\t[::msgcat::mc {Hide main window}]
    [::msgcat::mc {Right mouse button}]\t[::msgcat::mc {Popup menu}]"
    $t configure -state disabled

    $w draw
}

proc ifacetk::about_window {} {
    global tkabber_version toolkit_version

    set w .about

    if {[winfo exists $w]} {
	destroy $w
    }

    Dialog $w -anchor e \
	      -separator yes \
	      -title [::msgcat::mc "About"] \
	      -image tkabber/logo \
	      -side bottom \
	      -modal none \
	      -default 0 \
	      -cancel 0
    $w add -text [::msgcat::mc "Close"] -command [list destroy $w]

    set frame [$w getframe]
    set m [message $frame.msg -text "
Tkabbur $tkabber_version ($toolkit_version)

Copyright \u00a9 2002-2008 [::msgcat::mc {Alexey Shchepin}]
\n[::msgcat::mc Authors:]
    [::msgcat::mc {Alexey Shchepin}]
    [::msgcat::mc {Marshall T. Rose}]
    [::msgcat::mc {Sergei Golovan}]
    [::msgcat::mc {Michail Litvak}]
    [::msgcat::mc {Tomasz Sieprawski}]
"]
    pack $m -side top -anchor w

    set t [text $frame.url -cursor [get_conf $frame.msg -cursor] \
			   -bg [get_conf $frame.msg -bg] \
			   -height 1 \
			   -width 25 \
			   -bd 0 \
			   -highlightthickness 0 \
			   -takefocus 0]
    ::richtext::config $t -using url
    ::richtext::render_message $t "  http://code.google.com/p/tkabbur" ""
    $t delete {end - 1 char}
    $t configure -state disabled

    pack $t -side top -anchor w -fill x

    $w draw
}

proc ifacetk::switch_font {font class args} {
    variable options

    set opts [lassign $options($font) family size]
    set args [list -family $family -size $size]
    set bold 0
    set italic 0
    set underline 0
    set overstrike 0
    foreach opt $opts {
	switch -- $opt {
	    bold { 
		lappend args -weight bold
		set bold 1
	    }
	    italic {
		lappend args -slant italic
		set italic 1
	    }
	    underline {
		lappend args -underline 1
		set underline 1
	    }
	    overstrike {
		lappend args -overstrike 1
		set overstrike 1
	    }
		
	}
    }
    if {!$bold} {
	lappend args -weight normal
    }
    if {!$italic} {
	lappend args -slant roman
    }
    if {!$underline} {
	lappend args -underline 0
    }
    if {!$overstrike} {
	lappend args -overstrike 0
    }

    eval redefine_fonts $class $args
    if {$class == "Roster"} {
	roster::redraw_after_idle

	foreach chatid [chat::opened] {
	    if {[chat::is_groupchat $chatid]} {
		chat::redraw_roster_after_idle $chatid
	    }
	}
    }
}

proc ifacetk::show_ssl_info {} {
    global ssl_certificate_fields

    if {[winfo exists .ssl_info]} {
	destroy .ssl_info
    }

    if {[lempty [set msg_list [ssl_info]]]} return

    Dialog .ssl_info -title [::msgcat::mc "SSL Info"] -separator 1 -anchor e \
	-default 0 -cancel 0 -modal none
    .ssl_info add -text [::msgcat::mc "Close"] -command "destroy .ssl_info"
    set fr [.ssl_info getframe]

    if {[llength $msg_list] == 2} {
	lassign $msg_list server msg
	set page [frame $fr.page]
	set title [format [::msgcat::mc "%s SSL Certificate Info"] $server]
	grid [label $page.title -text $title] -row 0 -column 0 -sticky ew
	grid [message $page.info -aspect 50000 -text $msg] \
	    -row 1 -column 0 -sticky ew
	pack $page -expand yes -fill both -padx 1m -pady 1m
    } else {
	set nb [NoteBook $fr.nb]
	pack $nb -expand yes -fill both -padx 0m -pady 0m

	set i 0
	foreach {server msg} $msg_list {
	    set page [$nb insert end page$i -text $server]
	    set title [format [::msgcat::mc "%s SSL Certificate Info"] $server]
	    grid [label $page.title -text $title] -row 0 -column 0 -sticky ew
	    grid [message $page.info -aspect 50000 -text $msg] \
		-row 1 -column 0 -sticky ew
	    incr i
	}
	$nb compute_size
	$nb raise page0
    }
    .ssl_info draw
}

proc ifacetk::update_ssl_ind {args} {
    global use_tls
    variable ssl_ind

    if {!$use_tls} return

    lassign [update_ssl_info] state fg balloon

    if {![cequal $fg warning]} {
	label .fake_label
	set fg [.fake_label cget -foreground]
	destroy .fake_label
    } else {
	set fg [option get $ssl_ind errorForeground Label]
    }
    $ssl_ind configure -state $state
    if {[cequal $state normal]} {
	$ssl_ind configure -foreground $fg
    }
    DynamicHelp::register $ssl_ind balloon $balloon
}

hook::add connected_hook [namespace current]::ifacetk::update_ssl_ind
hook::add disconnected_hook [namespace current]::ifacetk::update_ssl_ind

###############################################################################

proc ifacetk::add_toolbar_button {icon command helptext} {
    if {[catch {set bbox [.mainframe gettoolbar 0].bbox}] || \
	    ![winfo exists $bbox]} {
	return 0
    }
    $bbox add -image $icon \
	      -highlightthickness 0 \
	      -takefocus 0 \
	      -relief link \
	      -bd $::tk_borderwidth \
	      -padx 1 \
	      -pady 1 \
	      -command $command \
	      -helptext $helptext
    return [$bbox index end]
}

###############################################################################

proc ifacetk::set_toolbar_icon {index script args} {
    if {[catch {set bbox [.mainframe gettoolbar 0].bbox}] || \
	    ![winfo exists $bbox]} {
	return
    }
    set image [eval $script]
    $bbox itemconfigure $index -image $image
}

###############################################################################

proc ifacetk::online_icon {args} {
    if {$roster::show_only_online} {
	return toolbar/show-online
    } else {
	return toolbar/show-offline
    }
}

proc ifacetk::create_main_window {} {
    global usetabbar
    global user_status_list
    global use_tls
    global descmenu
    variable mf
    variable rw
    variable rosterwidth
    variable ssl_ind
    variable main_window_title
    variable options
    variable status_history

    set main_window_title "Tkabbur"
    wm title . $main_window_title
    wm iconname . $main_window_title
    wm group . .

    bind all <<PrevWindow>> {focus [Widget::focusPrev %W]}

    load_descmenu
    set mf [MainFrame .mainframe -menu $descmenu -textvariable status]
    unset descmenu

    if {$use_tls} {
	set ssl_ind [$mf addindicator -text "SSL" -state disabled]
	$ssl_ind configure -relief flat
	DynamicHelp::register $ssl_ind balloon [::msgcat::mc "Disconnected"]
	bind $ssl_ind <1> [namespace current]::show_ssl_info
    }

    pack $mf -expand yes -fill both

    bind $mf <Destroy> quit

    set bbox [ButtonBox [$mf addtoolbar].bbox -spacing 0 -padx 1 -pady 1]

    add_toolbar_button toolbar/add-user {message::send_subscribe_dialog ""} \
	[::msgcat::mc "Add new user..."]
    add_toolbar_button toolbar/disco {ifacetk::discovery_dialog} \
	[::msgcat::mc "Service Discovery"]
    add_toolbar_button toolbar/join-conference join_group_dialog \
	[::msgcat::mc "Join group..."]

    set idx [add_toolbar_button [ifacetk::online_icon] \
		 [namespace current]::roster::switch_only_online \
		 [::msgcat::mc "Toggle showing offline users"]]
    trace variable [namespace current]::roster::show_only_online w \
	[list [namespace current]::set_toolbar_icon $idx \
	      [namespace current]::online_icon]

    pack $bbox -side left -anchor w
    switch_toolbar

    if {$options(use_tabbar)} {
        set usetabbar 1
    } else {
        set usetabbar 0
    }

    set ww 0
    foreach {status str} $user_status_list {
	if {[string length $str] > $ww} {
	    set ww [string length $str]
	}
    }

    frame .presence
    menubutton .presence.button -menu .presence.button.menu -relief $::tk_relief \
	-textvariable userstatusdesc -direction above -width $ww

    disallow_presence_change ""
    set w .presence.status
    ComboBox $w -textvariable textstatus -values $status_history
    $w bind <Return> {set userstatus $userstatus}
    trace add variable ::userstatus write \
	[list [namespace current]::save_availability_status $w]
    $w bind <Button-3> [list [namespace current]::show_status_context_menu $w]
    bind [entry .presence.priority -textvariable userpriority -width $ww] \
    	<Return> {set userstatus $userstatus}
    if {$usetabbar} {
	pack .presence.button -side left
	pack .presence.status -side left -fill x -expand yes
	pack .presence.priority -side right -fill x
    } else {
	pack .presence.button -side top -anchor w
	pack .presence.status -side top -fill x -expand yes -anchor w
	pack .presence.priority -side right -fill x
    }
    grid .presence -row 3 -column 1 -sticky nswe -in [$mf getframe]

    if {[winfo exists [set m .presence.button.menu]]} {
	destroy $m
    }
    menu $m -tearoff $ifacetk::options(show_tearoffs)
    foreach {status str} $user_status_list {
		$m add command \
		       -label $str \
		       -command [list set userstatus $status]
    }

    switch_presencebar
    switch_statusbar

    set rosterwidth [option get . mainRosterWidth [winfo class .]]
    if {$rosterwidth == ""} {
	set rosterwidth [winfo pixels . 3c]
    }

    grid columnconfigure [$mf getframe] 1 -weight 1
    grid rowconfigure [$mf getframe] 1 -weight 1

    if {$usetabbar} {
	set pw [PanedWin [$mf getframe].pw -side bottom -pad 1 -width 4]
	grid $pw -row 1 -column 1 -sticky nswe
	set rw [PanedWinAdd $pw -minsize 0 -weight 0]
	set nw [PanedWinAdd $pw -minsize 32 -weight 1]

	variable tabs
	set tabs $nw

	roster::create .roster -width $rosterwidth -height 300 \
	    -popup [namespace current]::roster::popup_menu \
	    -grouppopup [namespace current]::roster::group_popup_menu \
	    -singleclick [namespace current]::roster::user_singleclick \
	    -doubleclick [namespace current]::roster::jid_doubleclick \
	    -draginitcmd [namespace current]::roster::draginitcmd \
	    -dropcmd [namespace current]::roster::dropcmd
	pack .roster -expand yes -fill both -side top -in $rw -anchor w

	grid columnconfigure $nw 1 -weight 1
	grid rowconfigure $nw 1 -weight 1

	ButtonBar .nb -orient horizontal \
		      -pady 1 \
		      -padx 4 \
		      -pages .pages

	configure_tabs

	frame $nw.fr -relief raised -bd 1
	grid $nw.fr -row 1 -column 1 -sticky nsew

	grid columnconfigure $nw.fr 0 -weight 1
	grid rowconfigure $nw.fr 0 -weight 1

	PagesManager .pages -width 400
	grid .pages -row 0 -column 0 -padx 2m -pady 2m -in $nw.fr -sticky nsew
	PanedWinConf $pw 0 -width $rosterwidth

	event add <<CollapseRoster>> <Control-Key-r>
	bind . <<CollapseRoster>>      [list [namespace current]::collapse_roster]
	bind . <Control-Prior>      [list [namespace current]::tab_move .nb -1]
	bind . <Control-Next>       [list [namespace current]::tab_move .nb 1]
	bind . <Control-Meta-Prior> [list [namespace current]::current_tab_move .nb -1]
	bind . <Control-Alt-Prior>  [list [namespace current]::current_tab_move .nb -1]
	bind . <Control-Meta-Next>  [list [namespace current]::current_tab_move .nb  1]
	bind . <Control-Alt-Next>   [list [namespace current]::current_tab_move .nb  1]
	bind . <Control-Key-F4> {
	    if {[.nb raise] != ""} {
		eval destroy [pack slaves [.nb getframe [.nb raise]]]
		.nb delete [.nb raise] 1
		ifacetk::tab_move .nb 0
	    }
	}

	for {set i 1} {$i < 10} {incr i} {
	    bind . <Meta-Key-$i> [list [namespace current]::tab_raise_by_number .nb $i]
	    bind . <Alt-Key-$i>  [list [namespace current]::tab_raise_by_number .nb $i]
	}
	bind . <Meta-Key-0> [list [namespace current]::tab_raise_by_number .nb 10]
	bind . <Alt-Key-0>  [list [namespace current]::tab_raise_by_number .nb 10]

	set m [menu .tabsmenu -tearoff 0]
	$m add command -label [::msgcat::mc "Close"] -accelerator $::tk_close \
	    -command {
		if {[.nb raise] != ""} {
		    eval destroy [pack slaves [.nb getframe $curmenutab]]
		    .nb delete $curmenutab 1
		    ifacetk::tab_move .nb 0
		}
	    }
	$m add separator
	$m add command -label [::msgcat::mc "Close other tabs"] \
	    -command {
		foreach tab [.nb pages] {
		    if {$tab != $curmenutab} {
			eval destroy [pack slaves [.nb getframe $tab]]
			.nb delete $tab 1
		    }
		}
		ifacetk::tab_move .nb 0
	    }
	$m add command -label [::msgcat::mc "Close all tabs"] \
	    -command {
		foreach tab [.nb pages] {
		    eval destroy [pack slaves [.nb getframe $tab]]
		    .nb delete $tab 1
		}
	    }

	.nb bindtabs <3> [list [namespace current]::tab_menu %X %Y]
	.nb bindtabs <2> [list [namespace current]::destroy_tab]
	.nb bindtabs <<ScrollUp>> [list [namespace current]::tab_move .nb -1]
	.nb bindtabs <<ScrollDown>> [list [namespace current]::tab_move .nb 1]

	#DragSite::register .nb.c -draginitcmd [namespace current]::draginitcmd
	#DropSite::register .nb.c -dropovercmd [namespace current]::dropovercmd \
	#    -dropcmd [namespace current]::dropcmd -droptypes {NoteBookPage}

	set geometry [option get . geometry [winfo class .]]
	if {$geometry == ""} {
	    set geometry 788x550
	}
    } else {
	roster::create .roster -width $rosterwidth -height 300 \
	    -popup [namespace current]::roster::popup_menu \
	    -grouppopup [namespace current]::roster::group_popup_menu \
	    -singleclick [namespace current]::roster::user_singleclick \
	    -doubleclick [namespace current]::roster::jid_doubleclick \
	    -draginitcmd [namespace current]::roster::draginitcmd \
	    -dropcmd [namespace current]::roster::dropcmd
	grid .roster -row 1 -column 1 -sticky nswe -in [$mf getframe]
	set geometry [option get . geometry [winfo class .]]
	if {$geometry == ""} {
	    set geometry 200x350
	}
    }

    bind . <Map> [list hook::run map_window_hook %W]

    wm geometry . $geometry

    define_alert_colors
    update idletasks
}

proc ifacetk::destroy_tab {page} {
    if {[.nb raise] != ""} {
	eval destroy [pack slaves [.nb getframe $page]]
	.nb delete $page 1
	ifacetk::tab_move .nb 0
    }
}

proc ifacetk::draginitcmd {target x y top} {
    set c .nb.c

    set tags [$c gettags current]
    if {[lcontain $tags page]} {
	# page name
	set data [string range [lindex $tags 1] 2 end]
	return [list NoteBookPage {move} $data]
    } else {
	return {}
    }
}

proc ifacetk::dropovercmd {target source event X Y op type data} {
    set c .nb.c

    set x [expr {$X-[winfo rootx $c]}]
    set y [expr {$Y-[winfo rooty $c]}]
    set xc [$c canvasx $x]
    set yc [$c canvasy $y]

    set tags [$c gettags [lindex [$c find closest $xc $yc] 0]]
    if {[lcontain $tags page]} {
	DropSite::setcursor based_arrow_down
	return 3
    } else {
	DropSite::setcursor dot
	return 2
    }
}

proc ifacetk::dropcmd {target source X Y op type data} {
    set c .nb.c

    set x [expr {$X-[winfo rootx $c]}]
    set y [expr {$Y-[winfo rooty $c]}]
    set xc [$c canvasx $x]
    set yc [$c canvasy $y]

    set tags [$c gettags [lindex [$c find closest $xc $yc] 0]]
    if {[lcontain $tags page]} {
	# page name
	set data1 [string range [lindex $tags 1] 2 end]
	.nb move $data [.nb index $data1]
    }
}

proc ifacetk::destroy_win {path} {
    global usetabbar

    if {$usetabbar} {
	set page [ifacetk::nbpage $path]
	eval destroy [pack slaves [.nb getframe $page]]
	.nb delete $page 1
	ifacetk::tab_move .nb 0
    } else {
	destroy $path
    }
}

hook::add finload_hook [namespace current]::ifacetk::create_main_window 1

proc ifacetk::allow_presence_change {connid} {
    .presence.button configure -state normal

    set m [.mainframe getmenu tkabbur]
    $m entryconfigure [$m index [::msgcat::mc "Presence"]] -state normal

}

proc ifacetk::disallow_presence_change {connid} {
    if {[llength [jlib::connections]] == 0} {
	.presence.button configure -state disabled

	set m [.mainframe getmenu tkabbur]
	$m entryconfigure [$m index [::msgcat::mc "Presence"]] -state disabled
    }
}

hook::add connected_hook [namespace current]::ifacetk::allow_presence_change
hook::add disconnected_hook [namespace current]::ifacetk::disallow_presence_change

proc ifacetk::on_open_chat_window {chatid type} {
    variable number_msg
    variable personal_msg

    set number_msg($chatid) 0
    set personal_msg($chatid) 0
}

proc ifacetk::on_close_chat_window {chatid} {
    variable number_msg
    variable personal_msg

    unset number_msg($chatid)
    unset personal_msg($chatid)
}

hook::add open_chat_pre_hook [namespace current]::ifacetk::on_open_chat_window
hook::add close_chat_post_hook [namespace current]::ifacetk::on_close_chat_window

proc ifacetk::nbpage {path} {
    return [crange [win_id tab $path] 1 end]
}

proc ifacetk::nbpath {page} {
    return [lindex [pack slaves [.nb getframe $page]] 0]
}

proc ifacetk::update_chat_title {chatid} {
    global usetabbar
    variable options
    variable number_msg
    variable personal_msg

    set cw [chat::winid $chatid]

    if {$usetabbar} {
	set tabtitle $chat::chats(tabtitlename,$chatid)
	if {$options(message_numbers_in_tabs) && ($number_msg($chatid) > 0)} {
	    append tabtitle " ($number_msg($chatid))"
	}
	.nb itemconfigure [nbpage $cw] -text $tabtitle
    } else {
	if {$personal_msg($chatid)} {
	    set star "*"
	} else {
	    set star ""
	}
	if {$options(only_personal_messages_in_window_title)} {
	    set messages $personal_msg($chatid)
	} else {
	    set messages $number_msg($chatid)
	}

	if {$messages > 0} {
	    set title "($messages$star) $chat::chats(titlename,$chatid)"
	} else {
	    set title $chat::chats(titlename,$chatid)
	}
	wm title $cw $title
	wm iconname $cw $title
    }
}

proc ifacetk::update_chat_titles {} {

    foreach chatid [chat::opened] {
	lassign [chat::window_titles $chatid] \
	    ::chat::chats(tabtitlename,$chatid) \
	    ::chat::chats(titlename,$chatid)
	ifacetk::update_chat_title $chatid
    }
}

proc ifacetk::update_main_window_title {} {
    global usetabbar
    variable main_window_title
    variable number_msg
    variable personal_msg
    variable options

    if {!$usetabbar} return

    set star ""
    set messages 0
    if {$options(only_personal_messages_in_window_title)} {
        set star "*"
        foreach chatid [chat::opened] {
            incr messages $personal_msg($chatid)
        }
    } else {
        foreach chatid [chat::opened] {
            incr messages $number_msg($chatid)
            if {$personal_msg($chatid) > 0} {
                set star "*"
            }
        }
    }
    if {$messages} {
	set title "($messages$star) $main_window_title"
    } else {
	set title $main_window_title
    }
    wm title . $title
    wm iconname . $title
}

proc ifacetk::chat_window_is_active {chatid} {
    global usetabbar

    set cw [chat::winid $chatid]
    set w [winfo toplevel $cw]
    set f [focus]
    if {($f != "") && ($w == [winfo toplevel $f]) && \
	    (!$usetabbar || ([.nb raise] == [nbpage $cw]))} {
	return 1
    } else {
	return 0
    }
}

proc ifacetk::add_number_of_messages_to_title {chatid from type body extras} {
    global usetabbar
    variable number_msg
    variable personal_msg

    if {![catch {::plugins::mucignore::is_ignored $connid $from $type} ignore] && \
	    $ignore != ""} {
	    return
    }

    foreach xelem $extras {
	jlib::wrapper:splitxml $xelem tag vars isempty chdata children
	# Don't add number to title if this 'empty' tag is present. It indicates
	# messages history in chat window.
	if {[cequal [jlib::wrapper:getattr $vars xmlns] tkabber:x:nolog]} {
	    return
	}
    }

    if {[chat_window_is_active $chatid]} return

    if {$from == ""} return

    if {$type == "chat"} {
	incr number_msg($chatid)
	incr personal_msg($chatid)
    } elseif {$type == "groupchat"} {
	set jid [chat::get_jid $chatid]
	set myjid [chat::our_jid $chatid]
	set mynick [chat::get_nick [chat::get_connid $chatid] $myjid $type]
	if {![cequal $jid $from] && ![cequal $myjid $from]} {
	    incr number_msg($chatid)
	}
	if {![cequal $jid $from] && ![cequal $myjid $from] && \
		[check_message $mynick $body]} {
	    incr personal_msg($chatid)
	}
    }
    update_chat_title $chatid
    update_main_window_title 
}

hook::add draw_message_hook [namespace current]::ifacetk::add_number_of_messages_to_title 18

proc ifacetk::set_main_window_title_on_connect {connid} {
    set_main_window_title_on_disconnect $connid
}

proc ifacetk::set_main_window_title_on_disconnect {connid} {
    variable main_window_title

    if {[llength [jlib::connections]] == 0} {
	set main_window_title "Tkabbur"
    } else {
        if {[llength [jlib::connections]] == 1} {
	    set main_window_title "Tkabbur - [jlib::connection_jid [lindex [jlib::connections] end]]"
	} else {
	    set main_window_title "Tkabbur - [llength [jlib::connections]]"
	}
    }
    wm title . $main_window_title
    wm iconname . $main_window_title
}

hook::add connected_hook \
    [namespace current]::ifacetk::set_main_window_title_on_connect
hook::add disconnected_hook \
    [namespace current]::ifacetk::set_main_window_title_on_disconnect

proc ifacetk::raise_win {path} {
    global usetabbar

    if {[winfo exists $path]} {
	if {$usetabbar} {
	    .nb raise [nbpage $path]
	}
    }
}


proc ifacetk::add_win {path args} {
    global usetabbar
    variable options

    set title ""
    set tabtitle ""
    set class ""
    set raisecmd ""
    set type ""
    set raise 0

    foreach {attr val} $args {
	switch -- $attr {
	    -title    {set title    $val}
	    -tabtitle {set tabtitle $val}
	    -class    {set class    $val}
	    -raisecmd {set raisecmd $val}
	    -raise    {set raise    $val}
	    -type     {set type     $val}
	    default   {error "Unknown option $attr"}
	}
    }

    if {$usetabbar} {
	set page [nbpage $path]
	set f [.nb insert end $page \
		   -text $tabtitle \
		   -raisecmd [list [namespace current]::tab_raise \
				   $path $raisecmd]]
	frame $path -class $class
	pack $path -expand yes -fill both -in $f
	#tkwait visibility $path
	set ::tabcolors($page) ""
	if {$raise || $options(raise_new_tab) || [llength [.nb pages]] == 1} {
	    after idle [list catch [list .nb raise $page]]
	}
    } else {
	toplevel $path -class $class -relief flat -bd 2m
	wm group $path .
	wm title $path $title
	wm iconname $path $title
	set geometry [option get $path ${type}geometry $class]
	if {$geometry != ""} {
	    wm geometry $path $geometry
	}
    }
}

bind Chat <FocusIn>  [list [namespace current]::ifacetk::get_focus %W]
bind Chat <FocusOut> [list [namespace current]::ifacetk::loose_focus %W]

proc ifacetk::tab_raise {path command} {
    tab_set_updated $path
    if {$command != ""} {
	eval $command
    }
}

proc ifacetk::get_focus {path} {
    if {![winfo exists $path]} return
    hook::run got_focus_hook $path
}

proc ifacetk::on_focus_got {path} {
    variable options
    variable after_focused_id

    if {$after_focused_id != ""} {
	after cancel $after_focused_id
    }
    set after_focused_id \
	[after $options(update_title_delay) \
	       [list [namespace current]::set_title $path]]
}
hook::add got_focus_hook [namespace current]::ifacetk::on_focus_got

proc ifacetk::set_title {path} {
    global usetabbar
    variable number_msg
    variable personal_msg

    if {![winfo exists $path]} return
    
    if {$usetabbar} {
	if {[set p [.nb raise]] != ""} {
	    tab_set_updated $p
	}
	update_main_window_title
    } else {
	if {[info exists chat::chat_id($path)]} {
	    set chatid $chat::chat_id($path)
	    set number_msg($chatid) 0
	    set personal_msg($chatid) 0
	    update_chat_title $chatid
	}
    }
}

proc ifacetk::loose_focus {path} {
    if {![winfo exists $path]} return
    hook::run lost_focus_hook $path
}

proc ifacetk::on_focus_lost {path} {
    variable after_focused_id

    if {$after_focused_id != ""} {
	after cancel $after_focused_id
	set after_focused_id ""
    }
    balloon::destroy
}
hook::add lost_focus_hook [namespace current]::ifacetk::on_focus_lost

proc ifacetk::tab_move {nb shift args} {
    set len [llength [$nb pages]]

    if {$len > 0} {
	set newidx [expr [$nb index [$nb raise]] + $shift]

	if {$newidx < 0} {
	    set newidx [expr $len - 1]
	} elseif {$newidx >= $len} {
	    set newidx 0
	}

	$nb see [lindex [$nb pages] $newidx]
	$nb raise [lindex [$nb pages] $newidx]
    }
}

proc ifacetk::current_tab_move {nb shift} {
    set len [llength [$nb pages]]

    if {$len > 0} {
	set newidx [expr [$nb index [$nb raise]] + $shift]

	if {$newidx < 0} {
	    set newidx [expr $len - 1]
	} elseif {$newidx >= $len} {
	    set newidx 0
	}

	$nb move [$nb raise] $newidx
	$nb see [$nb raise]
    }
}

proc ifacetk::tab_raise_by_number {nb num} {
    set pages [$nb pages]
    incr num -1
    set page [lindex $pages $num]
    if {$page != ""} {
	$nb raise $page
    }
}

proc ifacetk::define_alert_colors {} {
    global usetabbar
    global alert_colors

    if {$usetabbar} {
	option add *alertColor0 Black widgetDefault
	option add *alertColor1 DarkBlue widgetDefault
	option add *alertColor2 Blue widgetDefault
	option add *alertColor3 Red widgetDefault

	set alert_colors [list \
		[option get .nb alertColor0 ButtonBar] \
		[option get .nb alertColor1 ButtonBar] \
		[option get .nb alertColor2 ButtonBar] \
		[option get .nb alertColor3 ButtonBar]]
    }
}

array set ::alert_lvls {info 1 error 1 server 1 message 2 mesg_to_user 3}

proc ifacetk::tab_set_updated {path {updated 0} {level ""}} {
    global usetabbar
    global tabcolors
    global alert_lvls alert_colors
    variable number_msg
    variable personal_msg

    if {!$usetabbar} return

    set page [nbpage $path]
    if {[.nb index $page] < 0} {
	set page $path
	if {[.nb index $page] < 0} return
	set path [nbpath $page]
    }

    set st [wm state .]
    if {(![cequal $st normal] && ![cequal $st zoomed]) || \
	    ([cequal [focus -displayof .] ""])} {
	set backgroundP 1
    } else {
	set backgroundP 0
    }
    if {(!$updated) && $backgroundP} {
	return
    }

    if {$updated && \
	    (($page != [.nb raise]) && \
		[info exists alert_lvls($level)] || \
		$backgroundP)} {
	set lvlnum $alert_lvls($level)
    } else {
	set lvlnum 0
    }

    if {!$updated || $tabcolors($page) < $lvlnum} {
	set color [lindex $alert_colors $lvlnum]
	.nb itemconfigure $page -foreground $color -activeforeground $color
	set tabcolors($page) $lvlnum
	hook::run tab_set_updated $path $updated $level
    }
    if {[info exists chat::chat_id($path)]} {
	if {!$updated || ($lvlnum == 0)} {
	    set chatid $chat::chat_id($path)
	    set number_msg($chatid) 0
	    set personal_msg($chatid) 0
	    update_chat_title $chatid
	    update_main_window_title
	}
    }
}

proc ifacetk::tab_menu {x y page} {
    global curmenutab
    set curmenutab $page
    tk_popup .tabsmenu $x $y    
}

###############################################################################

proc ifacetk::collapse_roster {} {
    variable mf
    variable rosterwidth

    set pw [$mf getframe].pw
    set r [PanedWinConf $pw 0 -width]
    set n [PanedWinConf $pw 1 -width]

    if {$r > 0} {
	set rosterwidth $r
	PanedWinConf $pw 0 -width 0
	PanedWinConf $pw 1 -width [expr {$r + $n}]
    } else {
	PanedWinConf $pw 0 -width $rosterwidth
	PanedWinConf $pw 1 -width [expr {$r + $n - $rosterwidth}]
    }
}

###############################################################################

proc ifacetk::switch_toolbar {args} {
    variable options
    variable mf
    $mf showtoolbar 0 $options(show_toolbar)
}

proc ifacetk::switch_presencebar {args} {
    global usetabbar
    variable options
    variable mf

    if {[winfo exists .presence]} {
	if {$options(show_presencebar)} {
	    catch {
		grid .presence -row 3 -column 1 \
		    -sticky nswe -in [.mainframe getframe]
		.presence.status configure -takefocus 1
	    }
	} else {
	    grid forget .presence
	    .presence.status configure -takefocus 0
	    if {[focus] == ".presence.status"} {
	    focus [Widget::focusPrev .presence.status]
	    }
	}
    }
}

proc ifacetk::switch_statusbar {args} {
    variable options
    variable mf

    catch {
	if {$options(show_statusbar)} {
	    pack $mf.botf -side bottom -fill x -before [$mf getframe]
	} else {
	    pack forget $mf.botf
	}
    }
}

proc ifacetk::deiconify {} {
    global tcl_platform
    variable mainwindowstate

    if {[cequal $tcl_platform(platform) windows]} {
	if {[cequal $mainwindowstate zoomed]} {
	    wm state . zoomed
	}
    }
    update
    wm deiconify .
}

hook::add finload_hook [namespace current]::ifacetk::deiconify 100

proc ifacetk::save_availability_status {w args} {
    variable status_history
    variable options

    set avstatus [$w cget -text]
    if {$avstatus == ""} return

    set ix [$w getvalue]
    if {$ix >= 0} {
	set status_history [linsert [lreplace $status_history $ix $ix] end $avstatus]
    } elseif {[llength $status_history] < $options(max_status_history)} {
	lappend status_history $avstatus
    } else {
	set status_history [linsert [lrange $status_history 1 end] end $avstatus]
    }

    $w configure -values $status_history
}

proc ifacetk::show_status_context_menu w {
    set m $w.menu

    if {![winfo exists $m]} {
	menu $m -tearoff 0
	$m add command \
	    -label [::msgcat::mc "Clear history"] \
	    -command [list [namespace current]::clear_status_history $w]
    }

    tk_popup $m [winfo pointerx $w] [winfo pointery $w]
}

proc ifacetk::clear_status_history w {
    variable status_history

    set status_history [list]
    $w configure -values $status_history
}


proc client:errormsg {message} {
    if {[winfo exists .client_error]} {
	destroy .client_error
    }
    
    MessageDlg .client_error -aspect 50000 -icon error \
	-message $message -type user -buttons ok -default 0 -cancel 0
}

# This proc should be called by WM_SAVE_YOURSELF protocol callback.
# On Windows (and Tk >= 8.4.13) this means WM_QUERYENDSESSION (so we should quit),
# on Unix, an X session manager may call this repeatedly.
proc session_checkpoint {} {
    global tcl_platform
    ::hook::run save_yourself_hook
    if {$tcl_platform(platform) == "windows"} quit
}

# Trap SIGTERM to quit gracefully on Unix when Tclx is available:
if {$tcl_platform(platform) == "unix" 
    && ![catch {package require Tclx}]} {
    signal trap SIGTERM quit
}

# Import add_win tab_set_updated to the root namespace:
namespace import ::ifacetk::raise_win ::ifacetk::add_win ::ifacetk::tab_set_updated

# vim:ts=8:sw=4:sts=4:noet
