#by wiebe @ QuakeNet

#public !peak and !netpeak command
#checks for network peak with the LUSERS command

#set here the file and path to save peak info
set peaksave(file) "peak.txt"


#peak pub
#bind pub -|- !peak peak:pub

proc peak:pub { nick uhost handle chan text } {
  set result [peak:peak $chan]
  if { ![string equal $result 0] } {
    puthelp "PRIVMSG $chan :$result"
  }
}



#peak msg
#bind msg fvlomn|fvlomn peak peak:msg

proc peak:msg { nick uhost handle text } {
  set chan [lindex [split $text] 0]
  set result [peak:peak $chan]
  if { [string equal $chan ""] } {
    lappend output "Usage: peak <channel>"
  } elseif { ![validchan $chan] || ![matchattr $handle fvlomn|fvlomn $chan] } {
    lappend output "No access or unknown channel $chan"
  } elseif { ![string equal $result 0] } {
    lappend output $result
  }
  if { [catch {set x [cnotice $nick $output]} error] || !$x } {
    foreach t $output { puthelp "NOTICE $nick :$t" }
  }
  return 1
}



#peak dcc
bind dcc - peak peak:dcc

proc peak:dcc { handle idx text } {
  set chan [lindex [split $text] 0]
  set result [peak:peak $chan]
  if { [string equal $chan ""] } {
    putidx $idx "Usage: peak <channel>"
  } elseif { ![validchan $chan] || ![matchattr $handle fvlomn|fvlomn $chan] } {
    putidx $idx "No access or unknown channel $chan"
  } elseif { ![string equal $result 0] } {
    putidx $idx $result
  }
  return 1
}



#returns peak info
proc peak:peak { chan } {
  if { ![validchan $chan] } { return 0 }
  set chan [string tolower $chan]
  global peaksave
  if { [info exists peaksave(peak,$chan)] } {
    set peak [lindex [split $peaksave(peak,$chan)] 0]
  } else {
    set peak 0
  }
  set users [llength [chanlist $chan]]
  if { $users > $peak } {
    global botnick botname
    set time [getchanjoin $botnick $chan]
    set peaksave(peak,$chan) "$users $time $botname"
    peak:save
  }
  set peak [lindex [split $peaksave(peak,$chan)] 0]
  set peak [peak:comma $peak]
  set time [lindex [split $peaksave(peak,$chan)] 1]
  set pnick [lindex [split $peaksave(peak,$chan)] 2]
  set pnick "[lindex [split $pnick !] 0] ([lindex [split $pnick !] 1])"
  set ago [peak:ts $time]
  set time [ctime $time]
  set result "Channel peak for $chan is $peak, set by $pnick on $time ($ago ago)"
  return $result
}



#netpeak pub
#bind pub -|- !netpeak peak:netpeak:pub

proc peak:netpeak:pub { nick uhost handle chan text } {
  set result [peak:netpeak]
  if { ![string equal $result 0] } {
    puthelp "PRIVMSG $chan :$result"
  }
  return 1
}



#netpeak pub
#bind msg fvlomn|fvlomn netpeak peak:netpeak:msg

proc peak:netpeak:msg { nick uhost handle text } {
  lappend output [peak:netpeak]
  if { [string equal $output 0] } { return 1 }
  if { [catch {set x [cnotice $nick $output]} error] || !$x } {
    foreach t $output { puthelp "NOTICE $nick :$t" }
  }
  return 1
}



#netpeak dcc
bind dcc - netpeak peak:netpeak:dcc

proc peak:netpeak:dcc { handle idx text } {
  set result [peak:netpeak]
  if { ![string equal $result 0] } {
    putidx $idx "$result"
  }
  return 1
}



#returns netpeak info
proc peak:netpeak { } {
  global peaksave
  if { ![info exists peaksave(peak,lusers)] } {
    return 0
  } else {
    set peak $peaksave(peak,lusers)
    set lusers [lindex [split $peak] 0]
    set lusers [peak:comma $lusers]
    set users [lindex [split $peak] 1]
    set users [peak:comma $users]
    set invisible [lindex [split $peak] 2]
    set invisible [peak:comma $invisible]
    set time [lindex [split $peak] 3]
    set now [clock seconds]
    set checktime [lindex [split $peak] 4]
    set checktime [peak:ts $checktime]
    set checklusers [lindex [split $peak] 5]
    set checklusers [peak:comma $checklusers]
    set ago [peak:ts $time]
    set time [ctime $time]
    return "Highest known network peak is $lusers ($users users and $invisible invisible) on $time ($ago ago). Last check performed $checktime ago, found $checklusers users online."
  }
}



#join
bind join -|- * peak:join

proc peak:join { nick uhost handle chan } {
  if { ![validchan $chan] } { return 0 }
  if { [isbotnick $nick] } { return 0 }
  global peaksave
  set chan [string tolower $chan]
  if { [info exists peaksave(peak,$chan)] } { set peak [lindex [split $peaksave(peak,$chan)] 0] } else { set peak 0 }
  set users [llength [chanlist $chan]]
  if { $users >= $peak } {
    set mask $nick!$uhost
    set time [clock seconds]
    set peaksave(peak,$chan) "$users $time $mask"
    peak:save
  }
}



#raw
bind raw -|- "315" peak:raw
bind raw -|- "251" peak:raw

proc peak:raw { server raw rest } {
  if { [string equal $raw 315] } {
    global peaksave
    set chan [string tolower [lindex [split $rest] 1]]
    if { [validchan $chan] && [botonchan $chan] } {
      if { [info exists peaksave(peak,$chan)] } { set peak [lindex [split $peaksave(peak,$chan)] 0] } else { set peak 0 }
      set users [llength [chanlist $chan]]
      if { $users > $peak } {
        global botnick botname
        set time [getchanjoin $botnick $chan]
        set peaksave(peak,$chan) "$users $time $botname"
        peak:save
      }
    }
  } elseif { [string equal $raw 251] } {
    global peaksave
    set lusers 0
    incr lusers [lindex [split $rest] 3]
    incr lusers [lindex [split $rest] 6]
    set users [lindex [split $rest] 3]
    set invisible [lindex [split $rest] 6]
    set time [clock seconds]
    if { ![info exists peaksave(peak,lusers)] } {
      set peaksave(peak,lusers) "$lusers $users $invisible $time $time $lusers"
    } elseif { $lusers > [lindex [split $peaksave(peak,lusers)] 0] } {
      set peaksave(peak,lusers) "$lusers $users $invisible $time $time $lusers"
    } else {
      set peaksave(peak,lusers) "[join [lrange [split $peaksave(peak,lusers)] 0 3]] $time $lusers"
    }
    peak:save
  }
  return 0
}



#save
proc peak:save { } {
  global peaksave
  set file $peaksave(file)
  set fs [open "$file" w]
  foreach name [array names peaksave] {
    if { [string match -nocase peak,* $name] } {
      set chan [lindex [split $name ,] 1]
      if { [validchan $chan] || [string equal $chan lusers] } {
        puts $fs "$chan $peaksave($name)"
      }
    }
  }
  close $fs
}



#load
proc peak:load { } {
  global peaksave
  set file $peaksave(file)
  foreach name [array names peaksave] {
    if { [string match -nocase peak,* $name] } {
      unset peaksave($name)
    }
  }
  if { ![file exists $file] } { return 0 }
  set fs [open "$file" r]
  set data [read $fs]
  close $fs
  foreach line [split $data \n] {
    if { ![string equal $line ""] } {
      set chan [lindex [split $line] 0]
      if { [validchan $chan] || [string equal $chan lusers] } {
        set rest [join [lrange [split $line] 1 end]]
        set peaksave(peak,$chan) "$rest"
      }
    }
  }
}



#load the info on start / rehash
peak:load



#init
bind evnt -|- init-server peak:connect

proc peak:connect { type } {
  peak:load
}



#lusers
bind time - "* * * * *" peak:time

proc peak:time { mi ho da mo ye } {
  global peaksave server
  if { [string equal $server ""] } { return 0 }
  if { ![info exists peaksave(peak,lusers)] } {
    puthelp "LUSERS"
    return 0
  }
  set peak $peaksave(peak,lusers)
  set lusers [lindex [split $peak] 0]
  set time [lindex [split $peak] 3]
  set checktime [lindex [split $peak] 4]
  set checklusers [lindex [split $peak] 5]
  set now [clock seconds]
  set ago [expr $now - $checktime]
  if { $ago > "300" } {
    puthelp "LUSERS"
  } elseif { [expr $checklusers / $lusers * 100] >= "99.99" } {
    puthelp "LUSERS"
  }
}



#give timestamp, returns duration since/to in Xy Xw Xd Xh Xm Xs format
proc peak:ts { ts } {
  if { ![string is digit $ts] } { return 0 }
  if { $ts > [unixtime] } {
    set ts [duration [expr $ts - [unixtime]]]
  } else {
    set ts [duration [expr [unixtime] - $ts]]
  }
  set ts [string map [list " seconds" "s" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " second" "s" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " minutes" "m" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " minute" "m" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " hours" "h" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " hour" "h" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " days" "d" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " day" "d" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " weeks" "w" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " week" "w" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " years" "y" "search" "replace" "search" "replace"] $ts]
  set ts [string map [list " year" "y" "search" "replace" "search" "replace"] $ts]
  return [join [lrange [split $ts] 0 1]]
}


#convert a number to 123,456,789 etc
proc peak:comma { number } {
  set x 2
  set y 0
  set r ""
  while { ![string equal [string range $number end-$x end-$y] ""] } {
    set r [linsert $r 0 [string range $number end-$x end-$y]]
    incr x 3
    incr y 3
  }
  set number [join $r ,]
  return $number
}

