#!/usr/bin/perl

use strict;
use warnings;

use Getopt::Long;
use File::Spec;
use LWP::Simple;

my $vers = 'v.0.2';

my ( $outdir, $needhelp, $alltbl, $sesstbl, $forday, $check_updates );

GetOptions ("out-dir=s"     => \$outdir,
	    "day=s"         => \$forday,
            "update"        => \$check_updates,
            "help"          => \$needhelp
	) or die("Error in command line arguments\n");

my $binkdconf = shift @ARGV;

    help() if defined $needhelp;
    help() unless defined $binkdconf;

my (%char,$binkdlog,%addr,%list,%sessFrom,%sessTo,%addrR,%addrS,$nodes,%tab,
	$startperiod,$endperiod);


sub help
{
	$0 =~ /([^\/\\]+)$/;
	my $src = $1;
	print   "Creates stat files from the binkd.log file.\n".
		"Usage: $src [options] binkd_config_file_name\n".
		"~~~~~~ \n".
		"  Binkd config MUST be defined!\n".
		"  Options:\n".
		"    --out-dir[|-o]     - directory name where create stat files. Optional.\n".
		"                         Default is current dir.\n".
		"    --day[|-d]         - date to create stat for. Format dd.mm, dd-mm or dd/mm.\n".
		"                         Default is from the start of log file till the end.\n".
		"    --update[|-u]      - Automatic update. Optional. By default, it\n".
		"                         checks for a new version and downloads the\n".
		"                         update to a new file.\n";
	exit;
}


sub update()
{
    my ( $ver_s, $upd, $of );

    $0 =~ /(.*[\\\/])[^\\\/]+$/;
    my $curpath = $1;
    $curpath = '' unless defined $curpath;
    my $url = 'http://brorabbit.g0x.ru/files/perl/';

    $ver_s = get($url . 'bls.v');
    if (defined ($ver_s) ) {
	if ( $vers lt $ver_s ) {

	    if ( $check_updates ) {
		$of = "${curpath}bls.pl";
		print "bls.pl will be updated to $ver_s\!\n";
#		writelog(" \*\*\* Updating bls.pl to $ver_s\!\n");
	    } else {
		$of = "${curpath}bls_${ver_s}.pl";
		print "You should update to $ver_s\!\n";
#		writelog(" \*\*\* You should update to $ver_s\! Update filename is \'bls_${ver_s}.pl\'.\n");
	    }

	    $upd = get( $url . 'bls.pl' );
	    print STDERR "Can't get update.\n" &&
		return unless defined $upd;
	    if ( open ( OF, ">$of") ) {
		binmode(OF);
		print( OF $upd );
		close(OF);
		chmod 0755, $of if $^O eq 'linux';
		print "$of saved.\n\n";
	    } else {
		print STDERR "Can't open $of ($!).\n";
	    }
	} else {
	    print "You have actual version.\n";
	}
    } else {
	print STDERR "Can't connect to $url\n";
    }
}


sub setvar
{
	my @monthes = ( undef, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
			'Aug', 'Sep', 'Oct', 'Nov', 'Dec' );
	my ($mm,$dd);

	$char{0}=" ";
	$char{1}="°";
	$char{2}="±";
	$char{3}="²";
	$char{4}="Û";

	$outdir = '.' unless defined( $outdir );
	$alltbl = File::Spec->catfile($outdir, "graph866.txt");
	$sesstbl = File::Spec->catfile($outdir, "sesstbl.txt");

	if ( defined($forday) ) {
		if ( $forday =~ /^(\d{1,2})[\.\-\/](\d{1,2})$/ ) {
			($mm,$dd) = ($2,$1);
			$mm = sprintf("%d ",$mm);
			$forday = sprintf("%02d ",$dd) . $monthes[$mm];
		} else {
			undef $forday;
		}
#		print "$forday\n";
	}
}


sub readconf
{

    my $point="0";
    my ($zone, $net, $node,$_address, $domain, $password,$z,$n,$f,$p,$aa);

	unless (open (F, "<$binkdconf")) {
		printf( "Cannot open $binkdconf: $!\r");
		exit(1);
	}
	
	$nodes=0;
	while (defined(my $line = <F>)) {
		$line =~ s/	/ /g;
		$line =~ s/^ //g;
		next if $line =~ /^\#.*/i;
		
		if ( $line =~ /^[ ]*address[ ]+(\d+)\:(\d+)\/(\d+)\.*\d*\@.*/i && !defined ($node)) {
			($zone, $net, $node)=($1, $2, $3);
			next;
		}
		
		if ($line =~ /^[ ]*log[ ]+([^ ]+).*/i) {
			$binkdlog = $1;
			next;
		}

		if ( $line =~ /^[ ]*node[ ]+([^ ]+)[ ]+([^ ]+)[ ]+([^ ]+).*/i ) {
			($_address, $domain, $password) = ($1, $2, $3);

			$nodes++;

			if ($_address =~ /^(\d+)\:\d+.*/) {
				$z=$1;
			} else {
				$z=$zone;
			}
			if ($_address =~ /^\d+\:(\d+)\/.*/ || $_address =~ /^(\d+)\/.*/) {
				$n=$1;
			} else {
				$n=$net;
			}

			if ($_address =~ /.*\/(\d+)\..*/ || $_address =~ /.*\/(\d+)$/ || $_address =~ /^(\d+)\..*/ || $_address =~ /^(\d+)$/) {
				$f=$1;
			} else {
				$f=$node;
			}
			if ($_address =~ /.*\.(\d+)$/) {
				$p=$1;
			} else {
				$p=$point;
			}
			
			if ($p != 0) {
				$aa="$z\:$n\/$f\.$p";
			} else {
				$aa="$z\:$n\/$f";
			}
			
			$addr{$aa}{'def'}=1;
			$list{$nodes}=$aa;
			$sessFrom{$aa}=0;
			$sessTo{$aa}=0;
			$addrR{$aa}=0;
			$addrS{$aa}=0;
		}
	}
	
	close(F);
	print("Binkd log file not found in specified config!\n") && exit unless defined $binkdlog;
}


sub readbinkdlog
{
	my($direction,$day, $hour, $minsec,
		$address, $result, $sent, $rcvd);
	unless (open (F, "<$binkdlog")) {
		printf( "Cannot open $binkdlog: $!\r");
		exit();
	}

  while (defined(my $line = <F>)) {
	$line =~ s/\r?\n$//s;

	next unless $line =~ /^. (\d\d [a-z]{3}) (\d\d):(\d\d:\d\d) \[\d+\] done \((from|to) (\d+\:\d+\/\d+\.?\d*)\@[^,]+, ([^,]+), S\/R\: \d+\/\d+ \((\d+)\/(\d+) bytes\)\)$/i;
	($day, $hour, $minsec, $direction, $address, $result, $sent, $rcvd) = ($1, $2, $3, $4, $5, $6, $7, $8);
	if (defined($forday)) {
		next unless $day eq $forday;
	}
	
	if ( !defined($startperiod) ) {
		$startperiod="$day $hour:$minsec";
	}

	if ( $direction eq "from" ) {
		$sessFrom{$address}++;
	}
	if ( $direction eq "to" ) {
		$sessTo{$address}++;
	}
#	print "$address\n";
	if ( !defined( $addr{$address}{'def'} ) ) {
		$nodes++;
		$addr{$address}{'def'} = 1;
		$addrS{$address}=$sent;
		$addrR{$address}=$rcvd;
		$list{$nodes}=$address;
	} else {
		$addrS{$address}+=$sent;
		$addrR{$address}+=$rcvd;
        }
	if ( !defined($addr{$address}{$direction})) {
		$addr{$address}{$direction}=1;
	} else {
		$addr{$address}{$direction}++;
	}
	if ( !defined($tab{$address}{$hour}) ) {
		$tab{$address}{$hour}=1;
	} else {
		if ($tab{$address}{$hour} < 4) {
			$tab{$address}{$hour}++;
		}
	}
  }     
  $endperiod="$day $hour:$minsec";
  close(F);

}


sub qsortp
{
  my $n = 1;
  my $a = '0';
  my ( $nn, $z, $ne, $f, $p, $zn, $nen, $fn, $pn );
  until( $n == $nodes ) {
	$nn=$n+1;
	if ( $nn <= $nodes ) {


	$list{$n} =~ /(\d+)\:(\d+)\/(\d+)\.?(\d*)/;
	($z, $ne, $f, $p) = ($1, $2, $3, $4);
	if ($p !~ /\d+/) { $p = 0; }

	$list{$nn} =~ /(\d+)\:(\d+)\/(\d+)\.?(\d*)/;
	($zn, $nen, $fn, $pn) = ($1, $2, $3, $4);
	if ($pn !~ /\d+/) { $pn = 0; }

		if (($z <=> $zn || $ne <=> $nen || $f <=> $fn || $p <=> $pn) == 1) {
	       		$a = $list{$n};
			$list{$n}=$list{$nn};
			$list{$nn}=$a;
		}
        }
	$n++;
  }
  qsortp() if $a ne 0;
}



	setvar();
	update();
	readconf();
	readbinkdlog();
	print( "No log entryes for $forday.\n") && exit unless defined $startperiod;
	qsortp();

	unless (open (Fa, ">$alltbl")) {
		printf( "Cannot open $alltbl: $!\r");
		exit;
	}
	unless (open (Fss, ">$sesstbl")) {
		printf( "Cannot open $sesstbl: $!\r");
		exit;
	}

  my $n=1;
#  $r46n=0;
  my $totalSent=0;
  my $totalRcvd=0;
  my $totalSess=0;
  my ($h,$hh,$strout,$c);

#  print(Fr "CHRS: CP866 2\nRealName: Evil Robot\n\n * From $startperiod till $endperiod *\n\n                        0 1 2 3 4 5 6 7 8 9 1011121314151617181920212223\n");
  print(Fa "CHRS: CP866 2\nRealName: Evil Robot\n\n * From $startperiod till $endperiod *\n\n                        0 1 2 3 4 5 6 7 8 9 1011121314151617181920212223\n");
  print(Fss "CHRS: CP866 2\nRealName: Evil Robot\n\n * From $startperiod till $endperiod *\nÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n³     Node address       ³  Sent bytes  ³Received bytes³   In     Out  Sess. ³\nÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n");
  until( $n > $nodes ) {
	$h=0;
	$strout="³";

	$strout=$strout . sprintf("%-20s", $list{$n});
	until( $h == 24) {
		$hh=sprintf("%02d", $h);
		$a=$list{$n};
		if ( defined($tab{$a}{$hh})) {
		$c=$tab{$a}{$hh}; } else {
                $c=0;}
		$strout=$strout . "³$char{$c}";
		$h++;
	}
	$strout=$strout . "³\n";
# r46 table
#        if ( $list{$n} =~ /$2\:46[^\.]+\d+$/) {
#		$r46n++;
#		print(Fr sprintf("%3s", $r46n) . $strout);
#	}
# r46 table
	print(Fa sprintf("%3s", $n) . $strout);

	$sessFrom{$a} = 0 if !defined($sessFrom{$a});
	$sessTo{$a} = 0 if !defined($sessTo{$a});
	print(Fss "³" . sprintf("%3s", $n) . "³" . sprintf("%-20s", $a) . "³" . sprintf("%14s", $addrS{$a}) . "³" . sprintf("%14s", $addrR{$a}) . "³" . sprintf("%6s", $sessFrom{$a})  . "³" . sprintf("%6s", $sessTo{$a})  . "³"  . sprintf("%7s", $sessTo{$a} + $sessFrom{$a})  . "³" ."\n" );

	$totalSent+=$addrS{$a};
	$totalRcvd+=$addrR{$a};
	$totalSess+=$sessTo{$a} + $sessFrom{$a};

	$n++;
  }

#  print(Fr "\n\" \" - 0 sessions, ° - 1 session, ± - 2 sessions,\n² - 3 sessions, Û - 4 or more sessions.\n\n");
  print(Fa "\n\" \" - 0 sessions, ° - 1 session, ± - 2 sessions,\n² - 3 sessions, Û - 4 or more sessions.\n\n");
  print(Fss "ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n³                Total:  ³" . sprintf("%14s", $totalSent) ."³" . sprintf("%14s", $totalRcvd) ."³" . sprintf("%21s", $totalSess) ."³\n");

#  close(Fr);
  close(Fa);
  close(Fss);

