# $Id: stats.tcl 1342 2007-12-31 14:15:42Z sergei $

namespace eval stats {}

set ::NS(stats) http://jabber.org/protocol/stats


proc stats::open_window {} {
    variable lastline
    variable f

    set w .stats

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


    add_win $w -title [::msgcat::mc "Statistics monitor"] \
	-tabtitle [::msgcat::mc "Statistics"] \
	-class Stats \
	-raise 1
	#-raisecmd [list focus $w.tree] \

    set sw [ScrolledWindow $w.sw]
    pack $sw -side top -fill both -expand yes
    set sf [ScrollableFrame $w.sf]
    $sw setwidget $sf

    set f [$sf getframe]

    set i 0
    foreach label [list [::msgcat::mc "JID"] \
			[::msgcat::mc "Node"] \
			[::msgcat::mc "Name "] \
			[::msgcat::mc "Value"] \
			[::msgcat::mc "Units"]] {
	set l [label $f.titlelabel$i -text $label]
	grid $l -row 0 -column $i -sticky w

	incr i
    }

    set i 7
    set l [label $f.titlelabel$i -text [::msgcat::mc "Timer"]]
    grid $l -row 0 -column $i -sticky w -columnspan 2

    set lastline 1
}

proc stats::add_line {jid node name} {
    variable data
    variable lastline
    variable f

    set n $lastline
    incr lastline

    set l [label $f.ljid$n -text $jid]
    grid $l -row $n -column 0 -sticky w

    set l [label $f.lnode$n -text $node]
    grid $l -row $n -column 1 -sticky w

    set l [label $f.lname$n -text $name]
    grid $l -row $n -column 2 -sticky w

    set l [label $f.lvalue$n \
	       -textvariable [namespace current]::data(value,$jid,$node,$name)]
    grid $l -row $n -column 3 -sticky e

    set l [label $f.lunits$n \
	       -textvariable [namespace current]::data(units,$jid,$node,$name)]
    grid $l -row $n -column 4 -sticky w

    set b [button $f.brequest$n -text [::msgcat::mc "Request"] \
	       -command [list [namespace current]::request_value \
			     $jid $node $name]]
    grid $b -row $n -column 5 -sticky w

    set b [button $f.bremove$n -text [::msgcat::mc "Remove"] \
	       -command [list [namespace current]::remove_line \
			     $n]]
    grid $b -row $n -column 6 -sticky w

    set s [Spinbox $f.spin$n 0 1000000000 1 \
		   [namespace current]::data(tmpperiod,$jid,$node,$name) \
		   -width 4]
    trace variable [namespace current]::data(tmpperiod,$jid,$node,$name) w \
	  [list [namespace current]::unset_timer $n $jid $node $name]
    grid $s -row $n -column 7 -sticky w

    catch {unset data(period,$jid,$node,$name)}

    set b [button $f.bsettimer$n -text [::msgcat::mc "Set"] \
	       -relief raised \
	       -command [list [namespace current]::toggle_timer \
			     $n $jid $node $name]]
    grid $b -row $n -column 8 -sticky w

}

proc stats::query_list {jid node args} {
    set vars [list xmlns $::NS(stats)]

    if {$node != ""} {
	lappend vars node $node
    }
    
    jlib::send_iq get [jlib::wrapper:createtag query \
			   -vars $vars] \
	-to $jid \
	-connection [jlib::route $jid] \
	-command [list [namespace current]::recv_query_list_result $jid $node]
}

proc stats::recv_query_list_result {jid node res child} {
    variable data

    if {![cequal $res OK]} {
	return
    }

    open_window

    jlib::wrapper:splitxml $child tag vars isempty chdata children

    foreach item $children {
	jlib::wrapper:splitxml $item tag1 vars1 isempty1 chdata1 children1

	if {$tag1 == "stat"} {
	    set name [jlib::wrapper:getattr $vars1 name]
	    #puts "$jid $node $name"
	    add_line $jid $node $name
	}
    }
}

proc stats::request_value {jid node name} {
    set vars [list xmlns $::NS(stats)]

    if {$node != ""} {
	lappend vars node $node
    }
    
    jlib::send_iq get [jlib::wrapper:createtag query \
			   -vars $vars \
			   -subtags [list [jlib::wrapper:createtag stat \
					       -vars [list name $name]]]] \
	-to $jid \
	-connection [jlib::route $jid] \
	-command [list [namespace current]::recv_values_result $jid $node]
}

proc stats::recv_values_result {jid node res child} {
    variable data

    if {![cequal $res OK]} {
	return
    }

    open_window

    jlib::wrapper:splitxml $child tag vars isempty chdata children

    foreach item $children {
	jlib::wrapper:splitxml $item tag1 vars1 isempty1 chdata1 children1

	if {$tag1 == "stat"} {
	    set name  [jlib::wrapper:getattr $vars1 name]
	    set value [jlib::wrapper:getattr $vars1 value]
	    set units [jlib::wrapper:getattr $vars1 units]

	    foreach subitem $children1 {
		jlib::wrapper:splitxml $subitem tag2 vars2 isempty2 \
		    chdata2 children2
		if {$tag2 == "error"} {
		    set error [error_to_string \
				   [list [jlib::wrapper:getattr $vars2 code] \
					$chdata2]]
		    break
		}
	    }

	    if {[info exists error]} {
		set data(value,$jid,$node,$name) $error
		set data(units,$jid,$node,$name) error
	    } else {
		set data(value,$jid,$node,$name) $value
		set data(units,$jid,$node,$name) $units
	    }
	}
    }
}


proc stats::remove_line {n} {
    variable f

    foreach slave [grid slaves $f -row $n] {
	destroy $slave
    }
}

proc stats::unset_timer {n jid node name args} {
    variable data
    variable f

    if {[info exists data(period,$jid,$node,$name)]} {
	unset data(period,$jid,$node,$name)
	$f.bsettimer$n configure -relief raised
    }
}

proc stats::toggle_timer {n jid node name} {
    variable data
    variable f

    if {![info exists data(period,$jid,$node,$name)]} {
	if {[string is integer -strict $data(tmpperiod,$jid,$node,$name)] && \
		$data(tmpperiod,$jid,$node,$name) > 0} {
	    set data(period,$jid,$node,$name) $data(tmpperiod,$jid,$node,$name)
	    $f.bsettimer$n configure -relief sunken

	    timer $n $jid $node $name
	}
    } else {
	unset data(period,$jid,$node,$name)
	$f.bsettimer$n configure -relief raised
    }
}

proc stats::timer {n jid node name} {
    variable data
    variable f

    if {![winfo exists $f.spin$n]} return

    request_value $jid $node $name

    if {![info exists data(period,$jid,$node,$name)]} return

    set p $data(period,$jid,$node,$name)

    after cancel \
	[list [namespace current]::timer $n $jid $node $name]
    if {$p > 0 && [winfo exists $f.spin$n]} {
	after [expr {$p * 1000}] \
	    [list [namespace current]::timer $n $jid $node $name]
    }
}



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

        $m add command -label [::msgcat::mc "Open statistics monitor"] \
	    -command [namespace current]::open_window
    }
}
hook::add finload_hook [namespace current]::stats::setup_menu

stats::setup_menu


hook::add postload_hook \
    [list disco::browser::register_feature_handler $::NS(stats) \
	 [namespace current]::stats::query_list -node 1 \
	  -desc [list * [::msgcat::mc "Service statistics"]]]

