# by wiebe @ QuakeNet

# rating for user, team, whole chan ?
# show in absolute and relative values ?
# new day starts at 4 (= 04:00) ?

# file to save stats
set rating(file) "rating.txt"

# at which hour should a new day start? 2 digit format! so 04 for 4 AM for example
set rating(newday) "04"



#create channel flag
setudef flag rating



#catch any channel message
bind pubm -|- "% *" rating:pubm

proc rating:pubm { nick uhost handle chan text } {
  if { ![channel get $chan rating] } { return 0 }
  global ratingdb
  set now [clock seconds]
  if { [matchattr $handle -|fvlomn $chan] && ![matchattr $handle b] } {

# handle
    if { [info exists ratingdb($chan,$handle)] } {
      set info $ratingdb($chan,$handle)
      set timestamp [lindex [split $info] 0]
      set count [lindex [split $info] 1]
      set rest [join [lrange [split $info] 2 end]]
      if { ![string equal $timestamp ""] && ![string equal $count ""] } {
        set diff [expr $now - $timestamp]
        if { $diff < "600" } { set count [expr $count + $diff] } else { set count [expr $count + 120] }
        set ratingdb($chan,$handle) "$now $count $rest"
      } else { set ratingdb($chan,$handle) "$now 120" }
    } else { set ratingdb($chan,$handle) "$now 120" } 

# team
    if { [info exists ratingdb($chan,team)] } {
      set info $ratingdb($chan,team)
      set timestamp [lindex [split $info] 0]
      set count [lindex [split $info] 1]
      set rest [join [lrange [split $info] 2 end]]
      if { ![string equal $timestamp ""] && ![string equal $count ""] } {
        set diff [expr $now - $timestamp]
        if { $diff < "600" } { set count [expr $count + $diff] } else { set count [expr $count + 120] }
        set ratingdb($chan,team) "$now $count $rest"
      } else { set ratingdb($chan,team) "$now 120" }
    } else { set ratingdb($chan,team) "$now 120" } 

  }

# whole chan
  if { [info exists ratingdb($chan,$chan)] } {
    set info $ratingdb($chan,$chan)
    set timestamp [lindex [split $info] 0]
    set count [lindex [split $info] 1]
    set rest [join [lrange [split $info] 2 end]]
    if { ![string equal $timestamp ""] && ![string equal $count ""] } {
      set diff [expr $now - $timestamp]
      if { $diff < "600" } { set count [expr $count + $diff] } else { set count [expr $count + 120] }
      set ratingdb($chan,$chan) "$now $count $rest"
    } else { set ratingdb($chan,$chan) "$now 120" }
  } else { set ratingdb($chan,$chan) "$now 120" } 

}



#load
proc rating:load { } {
  global rating ratingdb
  if { [info exists ratingdb] } { unset ratingdb }
  if { ![info exists rating(file)] } { return 0 }
  set file $rating(file)
  if { ![file exists $file] } { return 0 }
  set filesocket [open $file r]
  set data [read $filesocket]
  close $filesocket
  foreach line [lrange [split $data \n] 1 end] {
# chan handle data..
    if { ![string equal $line ""] } {
      set chan [lindex [split $line] 0]
      set handle [lindex [split $line] 1]
      set info [join [lrange [split $line] 2 end]]
      if { [validchan $chan] && ![string equal $info ""] } {
        if { [validuser $handle] || [validchan $handle] || [string equal $handle team] } {
          set ratingdb($chan,$handle) $info
        }
      }
    }
  }
  set lasttimestamp [lindex [split $data \n] 0]
  if { ![info exists rating(newday)] } { set newday 04 } else { set newday $rating(newday) }
  if { ![string equal [string length $newday] 2] } { set newday 04 }
  if { $newday < "0" || $newday > "24" } { set newday 04 }
  set newday [clock scan ${newday}:00]
  if { $lasttimestamp < $newday } { rating:newday }
  return 0
}



#save
proc rating:save { } {
  global rating ratingdb
  if { ![info exists ratingdb] } { return 0 }
  if { ![info exists rating(file)] } { return 0 }
  set file $rating(file)
  set now [clock seconds]
  set fs [open $file w]
  puts $fs "$now"
  foreach name [lsort [array names ratingdb]] {
    set chan [lindex [split $name ,] 0]
    set handle [lindex [split $name ,] 1]
    set info $ratingdb($name)
    if { [validchan $chan] && ![string equal $info ""] } {
      if { [validuser $handle] || [validchan $handle] || [string equal $handle team] } {
        puts $fs "$chan $handle $info"
      }
    }
  }
  close $fs
  return 0
}



#time
bind time - "00 * * * *" rating:time
bind time - "15 * * * *" rating:time
bind time - "30 * * * *" rating:time
bind time - "45 * * * *" rating:time

proc rating:time { mi ho da mo ye } {
  global rating
  if { ![info exists rating(newday)] } { set newday 04 } else { set newday $rating(newday) }
  if { ![string equal [string length $newday] 2] } { set newday 04 }
  if { $newday < "0" || $newday > "24" } { set newday 04 }
  if { [string equal $ho $newday] && [string equal $mi 00] } { rating:newday }
  rating:save
}



#newday
proc rating:newday { } {
  putlog "a new day has begon!"
  global ratingdb
  foreach name [lsort [array names ratingdb]] {
    set ratingdb($name) "0 0 [join [lrange [split $ratingdb($name)] 1 6]]"
  }
}



#evnt
bind evnt - userfile-loaded rating:evnt

proc rating:evnt { type } {
  rating:save
  rating:load
}



#bind pub -|fvlomn !rating rating:pub

proc rating:pub { nick uhost handle chan text } {

  if { ![channel get $chan rating] } {
    lappend output "Ratings are not available, chan is set -rating."
  } else {

    set urating [rating:stats $chan $handle]
    set urating1 [lindex [split $urating] 0]
    set urating2 [lindex [split $urating] 1]
    set urating1d [join [lrange [split [duration $urating1]] 0 3]]
    set urating1d [rating:replace $urating1d]
    set urating2d [join [lrange [split [duration $urating2]] 0 3]]
    set urating2d [rating:replace $urating2d]

    set trating [rating:stats $chan team]
    set trating1 [lindex [split $trating] 0]
    set trating2 [lindex [split $trating] 1]
    set trating1d [join [lrange [split [duration $trating1]] 0 3]]
    set trating1d [rating:replace $trating1d]
    set trating2d [join [lrange [split [duration $trating2]] 0 3]]
    set trating2d [rating:replace $trating2d]

    set crating [rating:stats $chan $chan]
    set crating1 [lindex [split $crating] 0]
    set crating2 [lindex [split $crating] 1]
    set crating1d [join [lrange [split [duration $crating1]] 0 3]]
    set crating1d [rating:replace $crating1d]
    set crating2d [join [lrange [split [duration $crating2]] 0 3]]
    set crating2d [rating:replace $crating2d]

    lappend output "     rating_today    (rating_last_7_days)"
    lappend output "You: $urating1d    ($urating2d)"
    lappend output "Team: $trating1d     ($trating2d)"
    lappend output "Chan: $crating1d     ($trating2d)"
  }
  if { [catch {set x [cnotice $nick $output]} error] || !$x } {
    foreach t $output { puthelp "NOTICE $nick :$t" }
  }
}



#rating msg
#bind msg -|fvlomn rating rating:msg

proc rating:msg { nick uhost handle text } {
  set chan [lindex [split $text] 0]
  set output ""
  if { [string equal $chan ""] } {
    lappend output "usage: rating <channel>"
  } elseif { ![validchan $chan] || ![matchattr $handle -|fvlomn $chan] } {
    lappend output "$chan\017 is unknown or you have no access on it."
  } else {
    rating:pub $nick $uhost $handle $chan $text
  }
  if { [catch {set x [cnotice $nick $output]} error] || !$x } {
    foreach t $output { puthelp "NOTICE $nick :$t" }
  }
}



# rating:stats chan handle/team/chan
proc rating:stats { chan text } {
  global ratingdb
  if { ![validchan $chan] } { return 0 }
  if { [validuser $text] || [validchan $text] || [string equal -nocase $text team] } {
    if { [info exists ratingdb($chan,$text)] } { set info $ratingdb($chan,$text) } else { set info "0 0 0" }
    set userday [lindex [split $info] 1]
    set x 0
    set useravg [join [lrange [split $info] 1 end]]
    set t 7
    foreach u [split $useravg] {
      if { ![string is digit $u] || [string equal $u ""] } { continue }
      incr x $u
    }
    set useravg $x
    return "$userday $useravg"
  }
}



#rating dcc
bind dcc - rating rating:dcc

proc rating:dcc { handle idx text } {
  set chan [lindex [split $text] 0]
  if { [string equal $chan ""] } {
    putidx $idx "rating <channel>"
  } elseif { ![validchan $chan] } {
    putidx $idx "invalid channel $chan"
    putidx $idx "rating <channel>"
  } elseif { ![matchattr $handle omn|fvlomn $chan] } {
    putidx $idx "sorry, you have no access to view rating for $chan"
  } elseif { ![channel get $chan rating] } {
    putidx $idx "rating is disabled for $chan"
  } else {
    putidx $idx "username rating_today (rating_last_7_days)"
    foreach user [lsort [userlist]] {
      if { [matchattr $user -|fvlomn $chan] && ![matchattr $user b] } {
        set urating [rating:stats $chan $user]
        set urating1 [lindex [split $urating] 0]
        set urating2 [lindex [split $urating] 1]
        set urating1d [join [lrange [split [duration $urating1]] 0 3]]
        set urating1d [rating:replace $urating1d]
        set urating2d [join [lrange [split [duration $urating2]] 0 3]]
        set urating2d [rating:replace $urating2d]

        putidx $idx "$user    $urating1d    ($urating2d)"
      }
    }
    putidx $idx "-------------------------------------"
    set trating [rating:stats $chan team]
    set trating1 [lindex [split $trating] 0]
    set trating2 [lindex [split $trating] 1]
    set trating1d [join [lrange [split [duration $trating1]] 0 3]]
    set trating1d [rating:replace $trating1d]
    set trating2d [join [lrange [split [duration $trating2]] 0 3]]
    set trating2d [rating:replace $trating2d]

    putidx $idx "Team    $trating1d    ($trating2d)"

    set crating [rating:stats $chan $chan]
    set crating1 [lindex [split $crating] 0]
    set crating2 [lindex [split $crating] 1]
    set crating1d [join [lrange [split [duration $crating1]] 0 3]]
    set crating1d [rating:replace $crating1d]
    set crating2d [join [lrange [split [duration $crating2]] 0 3]]
    set crating2d [rating:replace $crating2d]

    putidx $idx "Chan    $crating1d    ($crating2d)"
    putidx $idx "end of list for $chan"
  }
}



#replace
proc rating:replace { text } {
  set text [string map [list " years" "y" "search" "replace" "search" "replace"] $text]
  set text [string map [list " year" "y" "search" "replace" "search" "replace"] $text]
  set text [string map [list " weeks" "w" "search" "replace" "search" "replace"] $text]
  set text [string map [list " week" "w" "search" "replace" "search" "replace"] $text]
  set text [string map [list " days" "d" "search" "replace" "search" "replace"] $text]
  set text [string map [list " day" "d" "search" "replace" "search" "replace"] $text]
  set text [string map [list " hours" "h" "search" "replace" "search" "replace"] $text]
  set text [string map [list " hour" "h" "search" "replace" "search" "replace"] $text]
  set text [string map [list " minutes" "m" "search" "replace" "search" "replace"] $text]
  set text [string map [list " minute" "m" "search" "replace" "search" "replace"] $text]
  set text [string map [list " seconds" "s" "search" "replace" "search" "replace"] $text]
  set text [string map [list " second" "s" "search" "replace" "search" "replace"] $text]
  return $text
}

