#!/usr/bin/perl -T
use strict;
use re 'taint';
use Time::HiRes ();
use BerkeleyDB;

use vars qw(%keys %virus %types %history $avg_int $uptime);

$avg_int = 5*60;  # 5 minute interval

sub p1($$@) {
  my($k,$avg,@tot_k) = @_;
  printf("%-22s %6d %6.0f/h", $k, $keys{$k}, $avg*3600);
  for my $tot_k (@tot_k) {
    if ($keys{$tot_k} <= 0) {
      printf("    --- %%")
    } else {
      printf(" %6.1f %%", 100*$keys{$k}/$keys{$tot_k})
    }
    print " ($tot_k)";
  }
  print "\n";
}

sub p2($$$) {
  my($k,$avg,$tot_k) = @_;
  printf("%-22s %6d %6.0f/h %6.1f %% (%s)\n",
         $k, $virus{$k}, $avg*3600, 100*$virus{$k}/$keys{$tot_k}, $tot_k);
}

sub enqueue($$$$) {
  my($name,$now,$val,$hold_time) = @_;
  if (ref $history{$name} ne 'ARRAY') { $history{$name} = [] }
  my($oldest_useful);
  for my $j (0..$#{$history{$name}}) {
    if ($history{$name}->[$j][0] + $hold_time >= $now)
      { $oldest_useful = $j; last }
  }
  if (defined $oldest_useful) {
    @{$history{$name}} =
      @{$history{$name}}[$oldest_useful..$#{$history{$name}}];
  }
  push(@{$history{$name}}, [$now,$val]);
  my($average,$dv,$dt); my($n) = scalar(@{$history{$name}});
  my($oldest) = $history{$name}->[0];
  my($latest) = $history{$name}->[$n-1];
  $dt = $latest->[0] - $oldest->[0];  $dv = $latest->[1] - $oldest->[1];
  if ($n < 2 || $dt < $hold_time/2) {
    $dt = $uptime; $dv = $val;  # average since the start time
  }
  if ($dt > 0) { $average = $dv/$dt }
  ($average, $dv, $dt, $n);
}

# main prigram starts here
  my($env) = BerkeleyDB::Env->new(
    '-Home'=>'/var/amavis/db', '-Flags'=> DB_INIT_CDB | DB_INIT_MPOOL);
  defined $env or die "BDB no env: $BerkeleyDB::Error $!";
  my($db) = BerkeleyDB::Hash->new(
    '-Filename'=>'snmp.db', '-Flags'=>DB_RDONLY, '-Env'=>$env );
  defined $db or die "BDB no dbS 1: $BerkeleyDB::Error $!";

  my($stat,$key,$val);
  for (;;) {
    %keys = (); %virus = (); %types = ();
    print "\n";
    my($cursor) = $db->db_cursor;
    defined $cursor or die "BDB db_cursor error: $BerkeleyDB::Error";
    my($now) = Time::HiRes::time;
    while ( ($stat=$cursor->c_get($key,$val,DB_NEXT)) == 0 ) {
      if    ($key =~ /^virus\.byname\.(.*)\z/s) { $virus{$1} = $val }
      else { $keys{$key} = $val }
    }
    $stat==DB_NOTFOUND  or die "BDB c_get: $BerkeleyDB::Error $!";
    $cursor->c_close==0 or die "BDB c_close error: $BerkeleyDB::Error";
    for my $k (sort keys %keys) {
      if ($keys{$k} =~ /^C32 (.*)\z/) {
        $keys{$k} = $1;
      } elsif ($k eq 'sysUpTime' && $keys{$k} =~ /^INT (.*)\z/) {
        $uptime = $now - $1;
        my($ticks) = int($uptime*100);  my($t) = $ticks;
        my($hh)= $t % 100; $t = int($t/100);
        my($s) = $t % 60;  $t = int($t/60);
        my($m) = $t % 60;  $t = int($t/60);
        my($h) = $t % 24;  $t = int($t/24);
        my($d) = $t;
        printf("%-15s %s %s (%d days, %d:%02d:%02d.%02d)\n",
               $k,'Timeticks', $ticks, $d,$h,$m,$s,$hh);
        delete($keys{$k});
      } else {
        printf("%-15s %s\n", $k,$keys{$k});
        delete($keys{$k});
      }
    }
    for (sort keys %keys) {
      my($avg,$dv,$dt,$n) = enqueue($_, $now, $keys{$_}, $avg_int);
      if    (/^OpsDecTyp/)    {}  # later
      elsif (/^CacheHitsVirusMsgs$/)  { p1($_,$avg,'ContentVirusMsgs') }
      elsif (/^CacheHitsBannedMsgs$/) { p1($_,$avg,'ContentBannedMsgs') }
      elsif (/^CacheHitsSpamMsgs$/)   { p1($_,$avg,'ContentSpamMsgs') }
      elsif (/^Cache/)        { p1($_,$avg,'CacheAttempts') }
      elsif (/^Content/)      { p1($_,$avg,'InMsgs') }
      elsif (/^Quar/)         { p1($_,$avg,'QuarMsgs') }
      elsif (/^OpsSql/)       { p1($_,$avg,'InMsgsRecips') }
      elsif (/^(InMsgs|Ops)/) { p1($_,$avg,'InMsgs') }
      elsif (/^Out/)          { p1($_,$avg,'OutMsgs') }
      else                    { p1($_,$avg,undef) }
    }
    for (sort { $keys{$b} <=> $keys{$a} } grep {/^OpsDecTyp/} keys %keys) {
      my($avg,$dv,$dt,$n) = enqueue($_, $now, $keys{$_}, $avg_int);
      p1($_,$avg,'InMsgs');
    }
    for (keys %virus) { $virus{$_} = $1 if $virus{$_} =~ /^C32 (.*)\z/ }
    for (sort { $virus{$b} <=> $virus{$a} } keys %virus) {
      my($avg,$dv,$dt,$n) = enqueue($_, $now, $virus{$_}, $avg_int);
      p2($_,$avg,'ContentVirusMsgs');
    }
    sleep 10;
  }

END {
  $db->db_close==0 or die "BDB db_close error: $BerkeleyDB::Error $!";
}
