# ejabberd.tcl --
#
#       Ejabebrd administration plugin.

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"]]

    disco::browser::register_feature_handler ejabberd:config \
                [list ::data::request_data ejabberd:config] -node 1 \
                -desc [list * [::msgcat::mc "Configure service"]]

    setup_menu
}

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

    disco::browser::unregister_feature_handler ejabberd:config
    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"] -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 [expr {$::tk_scale * 20}]
    set yscale [expr {$::tk_scale * 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]
}

# vim:ft=tcl:ts=8:sw=4:sts=4:et
