#!/usr/bin/perl
#
# avg-pkg-build-time: display average build times of packages
# Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
#
# $Id: avg-pkg-build-time 537 2006-04-03 17:41:28Z rleigh $
#

package conf;
use Sbuild::Conf;
package main;

die "No avg-time database defined\n" if !$conf::avg_time_db;

use strict;
use GDBM_File;
use File::Basename;

my $do_space = 0;
my $delmode = 0;
my $dumpmode = 0;
my $addmode = 0;
my $topmode = 0;
my $open_mode = GDBM_READER;
my $db_file = $conf::avg_time_db;

if (basename($0) =~ /space$/) {
	$do_space = 1;
	$db_file = $conf::avg_space_db;
}

while( @ARGV && $ARGV[0] =~ /^-/ ) {
	$_ = shift @ARGV;
	if (/^(-s|--space)$/) {
		$do_space = 1;
		$db_file = $conf::avg_space_db;
	}
	elsif (/^--delete$/) {
		$delmode = 1;
		$open_mode = GDBM_WRCREAT;
	}
	elsif (/^--dump$/) {
		$dumpmode = 1;
	}
	elsif (/^(-a|--add)$/) {
		$addmode = 1;
		$open_mode = GDBM_WRCREAT;
	}
	elsif (/^(-t|--top)$/) {
		$topmode = 1;
	}
	elsif (/^(-f|--dbfile)$/) {
		die "-f need argument\n" if !@ARGV;
		$db_file = shift @ARGV;
	}
}

my %db;
tie %db, 'GDBM_File', $db_file, $open_mode, 0664
	or die "Can't open db\n";

die "No packages given for --delete.\n" if $delmode && !@ARGV;

if ($addmode) {
	die "Args for --add must be package and a build time\n"
		if @ARGV != 2 || $ARGV[1] !~ /^[\d.:]+$/;
	my($pkg,$t) = @ARGV;

	if (!$do_space) {
		if ($t =~ /:/) {
			my @a = split( ':', $t );
			my $x;
			for( $t = 0; $x = shift @a; ) {
				$t = ($t * 60) + $x;
			}
		}
	}
	
	if (exists $db{$pkg}) {
		if (!$do_space) {
			my @times = split( /\s+/, $db{$pkg} );
			push( @times, $t );
			my $sum = 0;
			foreach (@times[1..$#times]) { $sum += $_; }
			$times[0] = $sum / (@times-1);
			$db{$pkg} = join( ' ', @times );
		}
		else {
			my $keepvals = 4;
			my @values = split( /\s+/, $db{$pkg} );
			shift @values;
			unshift( @values, $t );
			pop @values if @values > $keepvals;
			my ($sum, $n, $weight, $i) = (0, 0, scalar(@values));
			for( $i = 0; $i < @values; ++$i) {
				$sum += $values[$i] * $weight;
				$n += $weight;
			}
			unshift( @values, $sum/$n );
			$db{$pkg} = join( ' ', @values );
		}
	}
	else {
		$db{$pkg} = "$t $t";
	}
}
else {
	my $pkg;
	my @pkgs = sort sortfunc (@ARGV ? @ARGV : keys %db);
	foreach $pkg (@pkgs) {
		if (exists $db{$pkg}) {
			if ($delmode) {
				delete $db{$pkg};
				print "$pkg: deleted\n";
			}
			elsif ($dumpmode) {
				print "$pkg: $db{$pkg}\n";
			}
			else {
				if (!$do_space) {
					my @times = split( /\s+/, $db{$pkg} );
					my $t = $times[0];
					my($sum, $sumq) = (0, 0);
					foreach (@times[1..$#times]) {
						$sum += $_;
						$sumq += $_*$_;
					}
					my $sigma;
					$sigma = (@times <= 2) ? 0 :
						sqrt( ($sumq - $sum*$sum/(@times-1))/(@times-2) );
					printf "%s%02d:%02d:%02d (%d %s, sigma %02d:%02d:%02d)\n",
						   align($pkg), int($t/3600), int(($t%3600)/60),
						   int($t%60), @times-1, (@times == 2) ? "entry" : "entries", 
				           int($sigma/3600), int(($sigma%3600)/60), int($sigma%60);
				}
				else {
					my @values = split( /\s+/, $db{$pkg} );
					printf "%s%6dk (%dk latest)\n",
						   align($pkg), $values[0], $values[1];
				}
			}
		}
		else {
			print "$pkg: unknown\n";
		}
	}
}

untie %db;
exit 0;

sub align {
	my $str = shift;
	
	$str .= ":";
	my $l = length($str);
	$str .= "\t" if $l < 24;
	$str .= "\t" if $l < 16;
	$str .= "\t" if $l < 8;
	return $str;
}

sub sortfunc {
	if ($topmode) {
		my $tima = (split( /\s+/, $db{$a} ))[0];
		my $timb = (split( /\s+/, $db{$b} ))[0];
		return $timb <=> $tima;
	}
	else {
		return $a cmp $b;
	}
}
