# $Id: ejabberd.tcl 1722 2009-03-13 17:03:35Z sergei $

package require msgcat

namespace eval ejabberd {
    ::msgcat::mcload [file join [file dirname [info script]] msgs]

    if {![::plugins::is_registered ejabberd]} {
	::plugins::register ejabberd \
			    -namespace [namespace current] \
			    -source [info script] \
			    -description [::msgcat::mc "Whether the Ejabberd plugin is loaded."] \
			    -loadcommand [namespace code load] \
			    -unloadcommand [namespace code unload]
	return
    }

    custom::defvar ejabberd_server_list {} \
	[::msgcat::mc "List of ejabberd servers."] \
	-group Hidden
}

proc ejabberd::load {} {
    variable NS_ECONFIGURE
    variable data

    set data(windows) {}

    set NS_ECONFIGURE "http://ejabberd.jabberstudio.org/protocol/configure"

    hook::add finload_hook [namespace current]::setup_menu

    disco::browser::register_feature_handler $NS_ECONFIGURE \
		[namespace current]::open_win \
		-desc [list * [::msgcat::mc "Administrate ejabberd"]]

    setup_menu
}

proc ejabberd::unload {} {
    variable NS_ECONFIGURE
    variable data

    disco::browser::unregister_feature_handler $NS_ECONFIGURE

    catch {
        set m [.mainframe getmenu admin]
	set idx [$m index [::msgcat::mc "Administrate ejabberd..."]]
        $m delete $idx
    }

    catch { destroy .ejabberdserver }

    foreach w $data(windows) {
	destroy_win $w
    }

    hook::remove finload_hook [namespace current]::setup_menu

    catch {unset data}
    catch {unset NS_ECONFIGURE}
}

proc ejabberd::setup_menu {} {
    catch {
        set m [.mainframe getmenu admin]

        $m add command -label [::msgcat::mc "Administrate ejabberd..."] \
	    -command [namespace current]::ask_server_dialog
    }
}

proc ejabberd::ask_server_dialog {} {
    global ejabberd_server
    global ejabberd_xlib
    variable ejabberd_server_list

    set gw .ejabberdserver
    catch { destroy $gw }

    if {[llength [connections]] == 0} return

    set ejabberd_xlib [connection_jid [lindex [connections] 0]]

    Dialog $gw -title [::msgcat::mc "ejabberd server"] -separator 1 -anchor e \
	    -default 0 -cancel 1

    set gf [$gw getframe]
    grid columnconfigure $gf 1 -weight 1

    if {[llength $ejabberd_server_list]} {
	set ejabberd_server [lindex $ejabberd_server_list 0]
    }

    label $gf.ljid -text [::msgcat::mc "Server JID:"]
    ComboBox $gf.jid \
	     -textvariable ejabberd_server \
	     -values $ejabberd_server_list \
	     -width 35

    grid $gf.ljid -row 0 -column 0 -sticky e
    grid $gf.jid  -row 0 -column 1 -sticky ew

    if {[llength [connections]] > 1} {
	foreach c [connections] {
	    lappend connections [connection_jid $c]
	}
	set ejabberd_xlib [lindex $connections 0]

	label $gf.lxlib -text [::msgcat::mc "Connection:"]
	ComboBox $gf.xlib \
		 -textvariable ejabberd_xlib \
		 -values $connections \
		 -editable 0

	grid $gf.lxlib -row 1 -column 0 -sticky e
	grid $gf.xlib  -row 1 -column 1 -sticky ew
    }

    $gw add -text [::msgcat::mc "Administrate"] -command "[namespace current]::administrate $gw"
    $gw add -text [::msgcat::mc "Cancel"] -command "destroy $gw"

    $gw draw $gf.jid
}

proc ejabberd::administrate {gw} {
    global ejabberd_server
    global ejabberd_xlib
    variable ejabberd_server_list

    destroy $gw

    set ejabberd_server_list \
	[update_combo_list $ejabberd_server_list $ejabberd_server 10]

    foreach c [connections] {
	if {[connection_jid $c] == $ejabberd_xlib} {
	    set xlib $c
	}
    }

    if {![info exists xlib]} return

    open_win $xlib $ejabberd_server
}

proc ejabberd::open_win {xlib jid args} {
    variable data

    set w [win_id ejabberd $xlib:$jid]
    if {[winfo exists $w]} {
	raise_win $w
	return
    }

    lappend data(windows) $w

    set title [::msgcat::mc "%s administration" $jid]
    add_win $w -title $title \
	       -tabtitle $jid \
	       -class Ejabberd \
	       -raise 1

    set nb [NoteBook $w.nb]
    pack $nb -fill both -expand yes

    # Binding $nb, not $w to avoid multiple calls if $w is a toplevel
    bind $nb <Destroy> [list [namespace current]::cleanup $xlib $jid $w]

    foreach {page title} \
	[list main   [::msgcat::mc "Main"] \
	      nodes  [::msgcat::mc "Nodes"] \
	      reg    [::msgcat::mc "Registration"] \
	      access [::msgcat::mc "Access"] \
	      last   [::msgcat::mc "Last Activity"]] {
	set f [$nb insert end $page -text $title]

	fill_page_$page $f $xlib $jid
    }
    $nb raise main
}

proc ejabberd::cleanup {xlib jid w} {
    variable data

    catch {unset data($xlib,$jid,total_users)}
    catch {unset data($xlib,$jid,online_users)}
    catch {unset data($xlib,$jid,running_nodes)}
    catch {unset data($xlib,$jid,stopped_nodes)}
    catch {unset data($xlib,$jid,outgoing_s2s)}
    catch {unset data($xlib,$jid,welcome_subj)}
    catch {unset data($xlib,$jid,welcome_body)}
    catch {unset data($xlib,$jid,reg_watchers)}
    catch {unset data($xlib,$jid,acls)}
    catch {unset data($xlib,$jid,access_rules)}
    catch {unset data($xlib,$jid,last)}
    catch {unset data($xlib,$jid,last_int)}

    set idx [lsearch -exact $data(windows) $w]
    if {$idx >= 0} {
	set data(windows) [lreplace $data(windows) $idx $idx]
    }
}

proc ejabberd::add_grid_record {xlib jid info name desc row} {
    label $info.l$name -text $desc
    label $info.v$name -textvariable [namespace current]::data($xlib,$jid,$name)
    grid $info.l$name -row $row -column 0 -sticky e
    grid $info.v$name -row $row -column 1 -sticky w
}

proc ejabberd::add_grid_edit {xlib jid info name desc row} {
    label $info.l$name -text $desc
    entry $info.v$name -textvariable [namespace current]::data($xlib,$jid,$name)
    grid $info.l$name -row $row -column 0 -sticky e
    grid $info.v$name -row $row -column 1 -sticky we
}

proc ejabberd::add_grid_text {xlib jid info name desc row} {
    label $info.l$name -text $desc
    set sw [ScrolledWindow $info.s$name -scrollbar vertical]
    text $info.v$name -height 6 -wrap word
    $sw setwidget $info.v$name
    grid $info.l$name -row $row -column 0 -sticky e
    grid $info.s$name -row $row -column 1 -sticky we
}

proc ejabberd::fill_page_main {f xlib jid} {
    variable data

    set info [frame $f.info]
    pack $info -side top -anchor w -fill both

    grid columnconfigure $info 1 -weight 2

    add_grid_record $xlib $jid $info total_users   [::msgcat::mc "Registered users:"] 0
    add_grid_record $xlib $jid $info online_users  [::msgcat::mc "Online users:"]     1
    add_grid_record $xlib $jid $info running_nodes [::msgcat::mc "Running nodes:"]    2
    add_grid_record $xlib $jid $info stopped_nodes [::msgcat::mc "Stopped nodes:"]    3
    add_grid_record $xlib $jid $info outgoing_s2s  [::msgcat::mc "Outgoing S2S:"]     4

    set reload \
	[button $f.reload -text [::msgcat::mc "Reload"] \
	     -command [list [namespace current]::reload_page_main $f $xlib $jid]]
    pack $reload -side bottom -anchor e
    reload_page_main $f $xlib $jid
}

proc ejabberd::reload_page_main {f xlib jid} {
    variable NS_ECONFIGURE

    ::xmpp::sendIQ $xlib get \
	-query [::xmpp::xml::create info \
			-xmlns $NS_ECONFIGURE] \
	-to $jid \
	-command [list [namespace current]::parse_main_info $f $xlib $jid]
}

proc ejabberd::parse_main_info {f xlib jid status xml} {
    variable data

    if {![string equal $status ok]} {
	return
    }

    ::xmpp::xml::split $xml tag xmlns attrs cdata subels

    set data($xlib,$jid,total_users)   [::xmpp::xml::getAttr $attrs registered-users]
    set data($xlib,$jid,online_users)  [::xmpp::xml::getAttr $attrs online-users]
    set data($xlib,$jid,running_nodes) [::xmpp::xml::getAttr $attrs running-nodes]
    set data($xlib,$jid,stopped_nodes) [::xmpp::xml::getAttr $attrs stopped-nodes]
    set data($xlib,$jid,outgoing_s2s)  [::xmpp::xml::getAttr $attrs outgoing-s2s-servers]
}


proc ejabberd::fill_page_nodes {f xlib jid} {
}

proc ejabberd::fill_page_reg {f xlib jid} {
    variable data

    set info [frame $f.info]
    pack $info -side top -anchor w -fill both

    grid columnconfigure $info 1 -weight 2

    add_grid_edit $xlib $jid $info welcome_subj [::msgcat::mc "Welcome message subject:"] 0
    add_grid_text $xlib $jid $info welcome_body [::msgcat::mc "Welcome message body:"]    1
    add_grid_text $xlib $jid $info reg_watchers [::msgcat::mc "Registration watchers:"]   2


    #set set_b [button $f.set -text [::msgcat::mc "Set"]]
    #pack $set_b -side right -anchor se
    set reload \
	[button $f.reload -text [::msgcat::mc "Reload"] \
	     -command [list [namespace current]::reload_page_reg $f $xlib $jid]]
    pack $reload -side right -anchor se
    reload_page_reg $f $xlib $jid
}

proc ejabberd::reload_page_reg {f xlib jid} {
    variable NS_ECONFIGURE

    ::xmpp::sendIQ $xlib get \
	-query [::xmpp::xml::create welcome-message \
			-xmlns $NS_ECONFIGURE] \
	-to $jid \
	-command [list [namespace current]::parse_welcome_message $f $xlib $jid]

    ::xmpp::sendIQ $xlib get \
	-query [::xmpp::xml::create registration-watchers \
			-xmlns $NS_ECONFIGURE] \
	-to $jid \
	-command [list [namespace current]::parse_registration_watchers $f $xlib $jid]
}

proc ejabberd::parse_welcome_message {f xlib jid status xml} {
    variable data

    set wsubj $f.info.vwelcome_subj
    set wbody $f.info.vwelcome_body

    if {![winfo exists $wsubj]} {
	return
    }

    if {![string equal $status ok]} {
	return
    }

    ::xmpp::xml::split $xml tag xmlns attrs cdata subels

    set subj ""
    set body ""

    foreach subel $subels {
	::xmpp::xml::split $xml stag sxmlns sattrs scdata ssubels

	switch -- $stag {
	    subject {set subj $scdata}
	    body {set body $scdata}
	}
    }

    set data($xlib,$jid,welcome_subj) $subj
    set data($xlib,$jid,welcome_body) $body
    $wbody delete 0.0 end
    $wbody insert 0.0 $body
}

proc ejabberd::parse_registration_watchers {f xlib jid status xml} {
    variable data

    set wwatchers $f.info.vreg_watchers

    if {![winfo exists $wwatchers]} {
	return
    }

    if {![string equal $status ok]} {
	return
    }

    ::xmpp::xml::split $xml tag xmlns attrs cdata subels

    set jids {}

    foreach subel $subels {
	::xmpp::xml::split $xml stag sxmlns sattrs scdata ssubels

	switch -- $tag1 {
	    jid {lappend jids $scdata}
	}
    }

    set data($xlib,$jid,reg_watchers) $jids
    $wwatchers delete 0.0 end
    $wwatchers insert 0.0 [join $jids \n]
}

proc ejabberd::fill_page_access {f xlib jid} {
    variable data

    set info [frame $f.info]
    pack $info -side top -anchor w -fill both

    grid columnconfigure $info 1 -weight 2

    add_grid_text $xlib $jid $info acls         [::msgcat::mc "ACLs:"]         0
    add_grid_text $xlib $jid $info access_rules [::msgcat::mc "Access rules:"] 1


    #set set_b [button $f.set -text [::msgcat::mc "Set"]]
    #pack $set_b -side right -anchor se
    set reload \
	[button $f.reload -text [::msgcat::mc "Reload"] \
	     -command [list [namespace current]::reload_page_access $f $xlib $jid]]
    pack $reload -side right -anchor se

    reload_page_access $f $xlib $jid
}

proc ejabberd::reload_page_access {f xlib jid} {
    variable NS_ECONFIGURE

    ::xmpp::sendIQ $xlib get \
	-query [::xmpp::xml::create acls \
			-xmlns $NS_ECONFIGURE] \
	-to $jid \
	-command [list [namespace current]::parse_access acls $f $xlib $jid]

    ::xmpp::sendIQ $xlib get \
	-query [::xmpp::xml::create access \
			-xmlns $NS_ECONFIGURE] \
	-to $jid \
	-command [list [namespace current]::parse_access access_rules $f $xlib $jid]
}

proc ejabberd::parse_access {var f xlib jid status xml} {
    variable data

    set w $f.info.v$var

    if {![winfo exists $w]} {
	return
    }

    if {![string equal $status ok]} {
	return
    }

    ::xmpp::xml::split $xml tag xmlns attrs cdata subels

    set data($xlib,$jid,$var) $cdata
    $w delete 0.0 end
    $w insert 0.0 $cdata
}

proc ejabberd::fill_page_last {f xlib jid} {
    variable data

    set info [frame $f.info]
    pack $info -side top -anchor w -fill both -expand yes

    #grid columnconfigure $info 1 -weight 2

    #add_grid_text $xlib $jid $info acls         [::msgcat::mc "ACLs:"]         0
    #add_grid_text $xlib $jid $info access_rules [::msgcat::mc "Access rules:"] 1

    label $info.lplot \
	-text [::msgcat::mc \
		   "Number of users that used this service N days ago:"]
    pack $info.lplot -side top -anchor w

    set sw [ScrolledWindow $info.sw]
    pack $sw -side top -fill both -expand yes
    set plot [canvas $info.plot -background white]
    $sw setwidget $plot

    set data($xlib,$jid,last) {}
    set data($xlib,$jid,last_int) 0

    set integral \
	[checkbutton $f.integral -text [::msgcat::mc "Integral"] \
	     -variable [namespace current]::data($xlib,$jid,last_int) \
	     -command [list [namespace current]::redraw_last $f $xlib $jid]]
    pack $integral -side left -anchor se

    set reload \
	[button $f.reload -text [::msgcat::mc "Reload"] \
	     -command [list [namespace current]::reload_page_last $f $xlib $jid]]
    pack $reload -side right -anchor se
}

proc ejabberd::reload_page_last {f xlib jid} {
    variable NS_ECONFIGURE

    ::xmpp::sendIQ $xlib get \
	-query [::xmpp::xml::create last \
			-xmlns $NS_ECONFIGURE] \
	-to $jid \
	-command [list [namespace current]::parse_last $f $xlib $jid]
}

proc ejabberd::parse_last {f xlib jid status xml} {
    variable data

    set plot $f.info.plot

    if {![winfo exists $plot]} {
	return
    }

    if {![string equal $status ok]} {
	return
    }

    ::xmpp::xml::split $xml tag xmlns attrs cdata subels

    set data($xlib,$jid,last) $cdata

    redraw_last $f $xlib $jid
}

proc ejabberd::redraw_last {f xlib jid} {
    variable data

    set plot $f.info.plot

    set maxdays 0

    foreach t $data($xlib,$jid,last) {
	set days [expr {$t / (60*60*24)}]
	if {$days > $maxdays} {set maxdays $days}

	if {![info exists last($days)]} {
	    set last($days) 0
	}
	incr last($days)
    }

    set xscale 20
    set yscale 200

    $plot delete all

    set val 0

    for {set i 0} {$i <= $maxdays} {incr i} {
	if {[info exists last($i)]} {
	    set v $last($i)
	} else {
	    set v 0
	}

	if {$data($xlib,$jid,last_int)} {
	    incr val $v
	} else {
	    set val $v
	}

	set x1 [expr {$xscale * $i}]
	set x2 [expr {$xscale * ($i+1)}]
	set x [expr {($x1 + $x2)/2}]
	set y [expr {-$yscale * $val}]

	$plot create rectangle $x1 0 $x2 $y -fill red

	$plot create text $x 0 -text $i -anchor n
	$plot create text $x $y -text $val -anchor s
    }

    set bbox [$plot bbox all]

    set y1 [lindex $bbox 1]
    set y2 [lindex $bbox 3]
    set height [winfo height $plot]

    $plot scale all 0 0 1 [expr {0.9 * $height / (0.0 + $y2 - $y1)}]
    $plot configure -scrollregion [$plot bbox all]
}

