#!/usr/bin/perl -w

# Source: @RPM_PACKAGE_VERSION@-@RPM_PACKAGE_RELEASE@

BEGIN {
        select(STDERR); $|=1; select(STDOUT);
        unshift(@INC,($ENV{'POPHOME'}||'@POPHOME@').'/lib')
			unless $ENV{'KUNDE_NO_PERLPATH'};
      }

use utf8;
use strict;
use warnings;
use Umlaut qw(textmodus);

use Cf qw($ACCHOST $ACCUSER $ACCPASS $ACCDB);
use Dbase qw();
use Dbase::Help qw(:readonly DoFn Do DoSel);
use Dbase::Globals qw(get_kunde list_descr find_descr add_acct find_dienst);

sub Usage() {
	my $vers = '@RPM_PACKAGE_VERSION@-@RPM_PACKAGE_RELEASE@';

	textmodus(\*STDERR);
    die <<END;
Usage: $0 -- vergleicht Accounting
          -a     berücksichtige nur accountete Ziele
          -k XX  nur dieser Kunde
          -K     alle Kunden einzeln
          -f/-F  erhöhe/verringere Einzelaccounting
          -g/-G  erhöhe/verringere Datenbank-Accounting
          -e     füge Korrekturdatensätze ins Datenbank-Accounting ein
          -i     ignoriere vorherige Korrekturen
          -p     Fortschritt en detail anzeigen
          -t     analysiere die Testdaten
          -v     reporte wenn kein Problem
          -V     Ziele einzeln auflisten
          JJJJMM für diesen Monat
          Tag... nur diese Tage (mehrere können angegeben werden)

Summiert Accountingdaten in DB und Einzelaccounting, vergleicht, und
korrigiert (GEFAHR). -fFgGe erzwingt -VK.

Version: $vers
END
  exit 1;
}

use Getopt::Std;
use vars qw( $opt_h $opt_k $opt_e $opt_f $opt_F $opt_g $opt_G $opt_v $opt_V $opt_p $opt_a $opt_i $opt_K $opt_t);
getopts("aefFgGik:KptvVh") or Usage;
Usage if $opt_h;
Usage if $opt_f and $opt_G;
Usage if $opt_F and $opt_g;
Usage if $opt_e and $opt_F;
Usage if $opt_e and $opt_g;
Usage if $opt_e and $opt_V;
Usage unless @ARGV;

my $monat = shift;

#$opt_v=2 if $opt_V;
$opt_a=2 if $opt_e;
$opt_i=2 if $opt_e;
$opt_V=2 if $opt_f or $opt_F or $opt_g or $opt_G;
$opt_K=2 if $opt_e or $opt_f or $opt_F or $opt_g or $opt_G;

my $edb = Dbase->new(
    DATAHOST=>$ACCHOST,
    DATAHOST2=>$ACCHOST,
    DATAUSER=>$ACCUSER,
    DATAPASS=>$ACCPASS,
    DBDATABASE=>$ACCDB);

my $nz = find_descr( ziel   => noris     => 1 );
my $lz = find_descr( ziel   => lokal     => 1 );
my $kz = find_descr( ziel   => korrektur => 1 );
my $qq = find_descr( quelle => ( my $tab = $opt_t ? 'test' : 'netflow' ), 1 );
my $di = find_dienst("ip");

sub run($$$) {
	my($kunde,$tag,$ziel) = @_;
	print STDERR " "x70,"\r  kunde=$kunde tag=$tag ziel=$ziel\r" if $opt_p;

	my $asel = "SELECT SUM(bytes) FROM acct WHERE ";
	my @where = ("jjmm = $monat","quelle = $qq","dienst = $di");

	push(@where, "kunde = $kunde") if $kunde;
	push(@where, "tt = $tag") if $tag;
	if($ziel) {
		push(@where, "dest = $ziel");
	} elsif($opt_a) {
		push(@where, "dest != $nz");
		push(@where, "dest != $lz");
		push(@where, "dest != $kz") if $opt_i;
	}
	my $bytes = DoFn($asel.join(" AND ",@where))||0;

	my $bsel = "select sum(bytes) from $tab ";
	my $esel = "where ";
	if($tag) {
		$tag = "0$tag" if length($tag)==1;
		$esel .= "datum = $monat$tag";
	} else {
		$esel .= "(datum >= ${monat}01 and datum <= ${monat}31)";
	}
	$esel .= " and kunde = $kunde" if $kunde;
	if($ziel) {
		$esel .= " and ziel = $ziel";
	} elsif($opt_a) {
		$esel .= " and ziel != $nz and ziel != $lz";
	}
	my $ebytes = $edb->DoFn($bsel.$esel) || 0;

	print STDERR " "x70,"\r" if $opt_p;
	return if $bytes==0 and $ebytes==0;
	my $diff = $ebytes - $bytes;

	if(not $diff) {
		$kunde="*" unless $kunde;
		$ziel="*" unless $ziel;
		print "$kunde $tag $ziel $bytes\n" if $opt_v;
		return;
	}
	# opt_e   Ziel    Resultat
	#   n       n        raus (nix zu tun)
	#   n       j        weiter (fFgG)
	#   j       n        weiter (e)
	#   j       j        raus (geht nicht)
	if(not $kunde or not $tag or $opt_e and $ziel or not $opt_e and not $ziel) {
		$kunde="*" unless $kunde;
		$tag="*" unless $tag;
		if($ziel)  {
			print "$kunde $tag $ziel $bytes $ebytes -- DIFF $diff\n";
		} else {
			my $kdiff = DoFn($asel.join(" AND ",@where)." and dest = $kz")||0;
			print "$kunde $tag * $bytes $ebytes -- DIFF $diff . $kunde $tag $ziel";
			print " $opt_e" if defined $opt_e;
			print " k+$kdiff" if $kdiff;
			print "\n";
		}
		return;
	}
	if($opt_e and not $ziel) {
		my $kdiff = DoFn($asel.join(" AND ",@where)." and dest = $kz")||0;
		$diff -= $kdiff;
		if(! $diff) {
			print "$kunde $tag * $bytes k+$kdiff\n" if $opt_v;
			return;
		}
		if ($diff > 0) {
			print "$kunde $tag * $bytes $ebytes -- DIFF +$diff";
			print " (k+$kdiff)\n" if $kdiff;
			print "\n";
			add_acct($kunde,"ip","korrektur", $monat,$tag, $tab, $diff,1,0);
		} else {
			print "$kunde $tag * $bytes $ebytes -- DIFF $diff $kdiff\n";
		}
		return;
	}
	if($diff > 0 and $opt_f or $diff < 0 and $opt_F) { # Einzelaccounting
		my $cfk = $bytes/$ebytes;
		print "$kunde $tag $ziel $bytes $ebytes -- e $cfk\n";
		$edb->Do("update $tab set bytes = bytes * $cfk $esel");
		my $mq = $edb->DoFn("select quelle from $tab $esel order by bytes desc limit 1");
		my $ebytes = $edb->DoFn($bsel.$esel) || 0;
		$cfk=$bytes-$ebytes;
		if ($cfk) {
			print "$kunde $tag $ziel $bytes $ebytes -- e $cfk\n";
			$edb->Do("update $tab set bytes=bytes + $cfk $esel and quelle=$mq");
		}
		return;
	}
	if($diff > 0 and $opt_g or $diff < 0 and $opt_G) { # Sammelaccounting
		print "$kunde $tag $ziel $bytes $ebytes -- g+$diff\n";
		Do("UPDATE acct SET bytes=$bytes WHERE ".join(" AND ",@where));
		return;
	}
	print "$kunde $tag $ziel $bytes $ebytes -- DIFF $diff\n";
}


sub init_kunde() {
	if($opt_k) {
		my @k = split(/,/,$opt_k);
		return sub {
			while(1) {
				my $k = pop @k;
				return undef unless $k;
				my $kk = get_kunde($k);
				return $kk if $kk;
				warn "Kunde '$k' gibt es nicht!\n" unless $kk;
			}
		};
	} elsif($opt_K) {
		my $res = DoSel "select id from kunde order by id";
		return sub {
			my($r) = $res->nextrow;
			return $r;
		};
	} else {
		my $once = 0;
		return sub {
			return undef if $once++;
			return '';
		};
	}
}

my @av = @ARGV;
sub init_tag() {
	if(@ARGV) {
		my @av = @ARGV;
		return sub {
			shift @av;
		};
	} else {
		my @tag = (1..31);
		return sub {
			shift @tag;
		};
	}
}


sub init_ziel() {
	if($opt_V) {
		my @des;
		list_descr("ziel",0,"",sub {
			my($nam,$id,$bla,$inf) = @_;
			push(@des,$id) if $id != $kz or not $opt_i;
		});
		return sub {
			pop @des;
		};
	} else {
		my $once = 0;
		return sub {
			return undef if $once++;
			return '';
		};
	}
}

print "Kunde Tag Ziel Bytes Bytes_ext -- DIFF?\n";

my $kunde;
my $next_kunde = init_kunde();
while(defined($kunde = &$next_kunde())) {
	my $tag;
	my $next_tag = init_tag();
	while(defined($tag = &$next_tag())) {
		my $ziel;
		my $next_ziel = init_ziel();
		while(defined($ziel = &$next_ziel())) {
			run($kunde,$tag,$ziel);
		}
	}
}
