####################################################
# by wiebe @ QuakeNet
#
####################################################

setudef flag rating

####################################################
# rating:help:pubm
####################################################
bind pubm vlomn|vlomn "% ${botnet-nick} help rating" rating:help:pubm
proc rating:help:pubm { n u h c t } {
  if {[matchattr $h bkZ]} { return 0 }
  lappend o "rating: usage rating \[<chan>\] \[<N>|all\]"
  lappend o "rating: shows rating for top N users (default 10) or all users for current or the given channel over the last 8 days, includes rating for channel staff and channel as a whole."
  if {[info procs cnotice] == ""} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "rating: " } }
  putloglev c $c "help: $n $u $h $c rating"
  return 1
}


####################################################
# rating:help:msg
####################################################
bind msgm vlomn|vlomn "help rating" rating:help:msgm
proc rating:help:msgm { n u h t } {
  if {[matchattr $h bkZ]} { return 0 }
  lappend o "rating: usage rating <chan> \[<N>|all\]"
  lappend o "rating: shows rating for top N users (default 10) or all users for the given channel over the last 8 days, includes rating for channel staff and channel as a whole."
  if {[info procs cnotice] == ""} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "rating: " } }
  putcmdlog "($n!$u) !$h! help rating"
  return 1
}


####################################################
# rating:pubm
####################################################
bind pubm vlomn|vlomn "% ${botnet-nick} rating" rating:pubm
bind pubm vlomn|vlomn "% ${botnet-nick} rating *" rating:pubm
proc rating:pubm { n u h c t } {
  if {![validchan $c]} { return 0 }
  if {[matchattr $h bkZ]} { return 0 }
  set t [join [lrange [split $t] 2 end]]
  set o [rating:out $h $t $c]
  if {[info procs cnotice] == ""} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "rating: " } }
  putloglev c $c "rating: $n $u $h $c $t"
  return 1
}


####################################################
# rating:msg
####################################################
bind msg vlomn|vlomn rating rating:msg
proc rating:msg { n u h t } {
  if {[matchattr $h bkZ]} { return 0 }
  set o [rating:out $h $t]
  if {[info procs cnotice] == ""} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "rating: " } }
  return 1
}


####################################################
# rating:dcc
####################################################
bind dcc -|- rating rating:dcc
proc rating:dcc { h i t } {
  if {![valididx $i]} { return 0 }
  set c [lindex [split [console $i]] 0]
  if {![validchan $c]} { set c "" }
  set o [rating:out $h $t $c]
  lappend o "rating: usage rating \[<chan>\] \[<N>|all\]"
  lappend o "rating: shows rating for top N users (default 10) or all users for the given channel over the last 8 days, includes rating for channel staff and channel as a whole."
  foreach l $o { putidx $i $l }
  return 1
}


####################################################
# rating:out
####################################################
proc rating:out { h t {c ""} } {
  set t [split $t]; set d [lindex $t 0]
  if {$c == "" || [string match {[#&]*} $d]} { set c $d; set t [lrange $t 1 end] }
  set t [lindex $t 0]
  if {$t == ""} { set t 10 }
  if {![validchan $c] && [info procs whichchan] != ""} { set c [whichchan $h $c] }
  set d [rating:lower $c]
  if {$c == ""} {
    lappend o "rating: no channel specified"
    lappend o "rating: usage rating \[<chan>\] \[<N>|all\]"
  } elseif {![validchan $c] || ![matchattr $h vlomn|vlomn $c]} {
    lappend o "rating: no access or unknown channel $c"
    lappend o "rating: usage rating \[<chan>\] \[<N>|all\]"
  } elseif {![channel get $c rating]} {
    lappend o "rating: rating disabled for channel $c (-rating)"
  } elseif {![regexp {^\d+$} $t] && ![string equal -nocase $t all]} {
    lappend o "rating: invalid option $t - must be a number or all"
    lappend o "rating: usage rating \[<chan>\] \[<N>|all\]"
  } else {
    set m [clock seconds]
    for {set y 0} {$y < 8} {incr y} {
      lappend x [clock format [expr ($m - 21600) - ($y * 86400)] -format %m-%d]
      lappend z [clock format [expr ($m - 21600) - ($y * 86400)] -format "%a %d"]
    }
    global ratingdb
    set j 5; set k ""; set n ""; set v ""; set w ""; lappend g "$d,c,$d"; lappend g "$d,t"
    foreach u [userlist] {
      set v [string tolower $u]
      if {![matchattr $u -|Rfvlomn $c] || [matchattr $u bkZ]} { continue }
      lappend g "$d,u,$v"
      if {[string length $u] > $j} { set j [string length $u] }
    }
    set z "  # User[string repeat " " [expr $j - 4]]   Average   Total  [join $z "  "]"

    foreach u $g {
      if {![info exists ratingdb($u)]} {
        if {[string match "?*,u,?*" $u]} {
          set u [getuser [lindex [split $u ,] 2] HANDLE]
          if {[matchattr $u -|omn $c]} { set f o } elseif {[matchattr $u -|l $c]} { set f l
          } elseif {[matchattr $u -|v $c]} { set f v } elseif {[matchattr $u -|f $c]} { set f f
          } else { set f R }
          lappend n "$u $f"; continue
        }
        set ratingdb($u) ""
      }
# a = average, l = total, i= info, x = dates, z = day dd
      set i [lrange [split $ratingdb($u)] 1 end]; set b ""; set l 0
      foreach y $x {
        set p [lsearch -glob $i "$y-*"]
        if {$p != -1} {
          set p [lindex [split [lindex $i $p] -] 2]; incr l $p; set p [rating:duration $p]
        } else { set p - }
        set p "[string repeat " " [expr 6 - [string length $p]]]$p"
        lappend b $p
      }
      set a [rating:duration [expr $l / 8]]
      set a "[string repeat " " [expr 7 - [string length $a]]]$a"
      set m [rating:duration $l]
      set m "[string repeat " " [expr 6 - [string length $m]]]$m"
      if {[string match "?*,u,?*" $u]} {
        set u [lindex [split $u ,] 2]; set u [getuser $u HANDLE]
        if {[matchattr $u -|omn $c]} { set f o } elseif {[matchattr $u -|l $c]} { set f l
        } elseif {[matchattr $u -|v $c]} { set f v } elseif {[matchattr $u -|f $c]} { set f f
        } else { set f R }
        if {$l > 0} {
          set u "$u[string repeat " " [expr $j - [string length $u]]]"
          lappend k "$l $u $f $a  $m  [join $b "  "]"
        } else { lappend n "$u $f" }
      } elseif {$u == "$d,t"} {
        set u "STAFF[string repeat " " [expr $j - 5]]"
        set v "    $u   $a  $m  [join $b "  "]"
      } else {
        set u "CHAN[string repeat " " [expr $j - 4]]"
        set w "    $u   $a  $m  [join $b "  "]"
      }
    }
    set k [lsort -dictionary -decreasing $k]
    set n [join [lsort -dictionary $n] "   "]
    if {![string equal -nocase $t all]} { set k [lrange $k 0 [expr $t -1]] }
    lappend o $z; set q 1
    foreach e $k {
      set m "[string repeat " " [expr 3 - [string length $q]]]$q"
      lappend o "$m [join [lrange [split $e] 1 end]]"
      incr q
    }
    if {$v != ""} { lappend o $v }
    if {$w != ""} { lappend o $w }
    if {$n != ""} { lappend o "rating: users with no rating: $n" }
    if {![string equal -nocase $t all]} { set t "top $t" }
    lappend o "rating: end of list for $c ($t)"
  }
  return $o
}


####################################################
# rating:pubm
# scriptdb(chan,u,handle) ts 'mm dd count' 'mm dd count' etc
# scriptdb(chan,c,chan) ts count rest
# scriptdb(chan,t) ts count rest
####################################################
bind pubm -|- "% *" rating:pubm
proc rating:pubm { n u h c t } {
  if {![validchan $c]} { return 0 }
  if {![channel get $c rating]} { return 0 }
  if {[matchattr $h bkZ|k]} { return 0 }
  global ratingdb; set m [clock seconds]; set c [rating:lower $c]; set h [string tolower $h]
  lappend o "$c,c,$c"
  if {[validuser $h] && [matchattr $h -|Rfvlomn $c]} { lappend o "$c,u,$h"; lappend o "$c,t"  }
  set x [clock format [expr $m - 21600] -format %m-%d]
  foreach e $o {
    if {![info exists ratingdb($e)]} { set ratingdb($e) "$m $x-120"; continue }
    set p [lsearch -glob $ratingdb($e) "$x-*"]
    if {$p == -1} { set ratingdb($e) "$m $x-120 [join [lrange [split $ratingdb($e)] 1 end]]"; continue }
    if {$p != 1} { continue }
    set d [split $ratingdb($e)]; set s [lindex $d 0]; set f [split [lindex $d $p] -]
    set r [lindex $f 2]; set y [expr $m - $s]
    if {$y < 600} { set r [expr $r + $y] } else { set r [expr $r + 120] }
    set ratingdb($e) "$m $x-$r [join [lrange $d 2 14]]"
  }
}


####################################################
# rating:time
####################################################
bind time -|- "01 * * * *" rating:time; bind time -|- "31 * * * *" rating:time
proc rating:time { n h d m y } { rating:save z }


####################################################
# rating:save
####################################################
bind evnt -|- prerestart rating:save
proc rating:save { z } {
  global ratingdb
  if {[llength [array names ratingdb]] == 0} { return 0 }
  set f "ratingdb.txt"; set f [open $f w]
  if {[file exists $f]} {
    if {![file isfile $f]} { return 0 }
    if {![file writable $f]} { return 0 }
  }
  foreach n [lsort [array names ratingdb]] {
    set n [split $n ,]; set c [lindex $n 0]
    if {![validchan $c]} { continue }
    set t [lindex $n 1]; set h [lindex $n 2]; set n [join $n ,]
    if {$t == "c" && $c != $h} { unset ratingdb($n); continue }
    if {$t == "u" && ![validuser $h]} { unset ratingdb($n); continue }
    if {$t == "t" && $h != ""} { unset ratingdb($n); continue }
    puts $f "$n $ratingdb($n)"
  }
  close $f
}


####################################################
# rating:load
####################################################
bind evnt -|- userfile-loaded rating:load
proc rating:load { {z ""} } {
  rating:save z; global ratingdb; set f "ratingdb.txt"
  if {[info exists ratingdb]} { unset ratingdb }
  if {![file exists $f]} { return 0 }
  if {![file isfile $f]} { return 0 }
  if {![file readable $f]} { return 0 }
  set f [open "$f" r]; set d [read $f]; close $f
  foreach l [split $d \n] {
    if {$l == ""} { continue }
    set l [split $l]; set n [split [lindex $l 0] ,]; set c [lindex $n 0]
    if {![validchan $c]} { continue }
    set t [lindex $n 1]; set h [lindex $n 2]; set n [join $n ,]
    if {$t == "c" && $c != $h} { continue }
    if {$t == "u" && ![validuser $h]} { continue }
    if {$t == "t" && $h != ""} { continue }
    set ratingdb($n) "[join [lrange $l 1 end]]"
  }
}


####################################################
# rating:nkch
####################################################
bind nkch - * rating:nkch
proc rating:nkch { o n } {
  if {[string equal -nocase $o $n]} { return 0 }
  global ratingdb; set o [string tolower $o]; set n [string tolower $n]
  foreach c [channels] {
    set c [rating:lower $c]
    if {![info exists ratingdb($c,u,$o)]} { continue }
    set ratingdb($c,u,$n) $ratingdb($c,u,$o)
    unset ratingdb($c,u,$o)
  }
  return 0
}


####################################################
# rating:lower
####################################################
proc rating:lower { t } {
  global rfc-compliant
  if {[info exists rfc-compliant] && ${rfc-compliant} == 1} { set t [string map "\\{ \[ \\} \] ~ ^ \\\\ |" $t] }
  set t [string tolower $t]
  return $t
}


####################################################
# rating:duration
####################################################
proc rating:duration { t } {
  set o ""; set h [expr $t / 3600]; set m [expr int(fmod($t,3600) / 60)]
  if {$h > 0} { append o "${h}h" } else { set h "" }
  if {$m > 0} {
    if {[string length $m] == 1 && $h != ""} { set m "0$m" }
    append o "${m}m"
  }
  if {$o == ""} { return "0m" }
  return $o
}


set userflagdb(rating) {
  "rating.tcl: R=include user in rating"
}


set scriptdb(rating) {
  "keeps track of channel activity, provides rating command. activity of users with any of 'R f v l o m n' channel flags is tracked."
}

