#!/usr/local/bin/perl

$format = 'l';

if ($ARGV[0] =~ /^-/) {
    local $_ = shift;
    if ($_ =~ /^-f(.)$/) {
	$format = $1;
    } elsif ($_ eq '-l') {
	$format = 'l';
    } elsif ($_ eq '-u') {
	$unify = 1;
    }
}

sub get_rank ( % ) {
    my (%a) = @_;
    
    my (@k) = sort { $a{$b} <=> $a{$a} } keys %a;
    my (%r);

    my ($i, $j, $t);
    $i = j; $t = -1;
    for($j = 0; $j < @k; $j++) {
	if ($a{$k[$j]} != $t) {
	    $i = $j;
	}
	$t = $a{$k[$j]};
	$r{$k[$j]} = $i + 1;
    }
    return %r;
}

&read_unify_list($unify) if $unify;
$THRESHOLD = 1000000;

while(<>){
    if (/^[ 0-9]{3}[. ] (.+?) *([ 0-9]{4}[0-9])(\([ 0-9]\d.\d%\))?([< 0-9]{4}>)? ([ 0-9]{6}[0-9])(\([ 0-9]\d.\d%\))?([< 0-9]{4}>)? ([ 0-9]{2}\d.\d\d)([< 0-9]{4}[> ])?$/) {
	# input is a past output of this script
	$handle = $1;
	$totallines += $2;
	$lines{$handle} += $2;
	$bytes{$handle} += $5;
	$totalbytes += $5;
	next;
    }
    next unless m"^\([0-9][0-9]:[0-9][0-9]:[0-9][0-9]\)\[(.+?)\] ?(.*)";
    
    $handle = $1;
    $len = length($2);
    if ($unify) {
	$handle =~ s/[%@бєбў]..*$//;
    }
    $handle = $unify_list{$handle} || $handle;
    $handle =~ s/\033/\^\[/g;
    ++$totallines;
    ++$lines{$handle};
    $bytes{$handle} += $len;
    $totalbytes += $len;
}

@keys = keys %lines;

foreach $k (@keys) {
    $length{$k} = $bytes{$k} / $lines{$k};
    $lines_s{$k} = $lines{$k} - $bytes{$k}/$THRESHOLD;
    $bytes_s{$k} = $bytes{$k} + $lines{$k}/$THRESHOLD;
}

%monkeys_line = &get_rank(%lines_s);
%monkeys_bytes = &get_rank(%bytes_s);
%monkeys_target = map { ($lines{$_} * 200 >= $totallines) ? ($_, -$length{$_}) : () } @keys;
%monkeys_length = &get_rank(%monkeys_target);
foreach $k (@keys) {
    $monkeys_length{$k} ||= $monkeys_line{$k} + $THRESHOLD;
}


if ($format eq 'b') {
    *sortrank = *monkeys_bytes;
    $header = "rank name            lines   bytes        length\n";
    $delim  = "-------------------------------------------------\n";
    $entry  = "%4s %-16s%5d%.0s%.0s%8d%7s%.0s%7.2f%.0s\n";
    $formspec = "00100";
    $foot = "%-21s%5d%8d       %7.2f\n"
} elsif ($format eq 'B') {
    *sortrank = *monkeys_bytes;
    $formspec = "01101";
} elsif ($format eq 'm') {
    *sortrank = *monkeys_length;
    $formspec = "10000";
} elsif ($format eq 'M') {
    *sortrank = *monkeys_length;
    $formspec = "11010";
} elsif ($format eq 'L') {
    *sortrank = *monkeys_line;
    $formspec = "10011";
} else {
    *sortrank = *monkeys_line;
    $formspec = "10000";
}

@forms = split(//, $formspec);
$entry = ("%4s %-16s%5d"
	  . ($forms[0] ? "%7s" : "%.0s") # lines%
	  . ($forms[1] ? "%5s" : "%.0s") # lines-rank
	  . "%8d"
	  . ($forms[2] ? "%7s" : "%.0s") # bytes%
	  . ($forms[3] ? "%5s" : "%.0s") # bytes-rank
	  . "%7.2f"
	  . ($forms[4] ? "%5s" : "%.0s") # length-rank
	  . "\n");
{
    # create other line format
    $_ = sprintf($entry, 0, name, 1, 2, 3, 4, 5, 6, 7);
    s/    1/lines/; s/   0/rank/; s/    4/bytes/; s/  7.00/length/;
    s/[0-9.]/ /g; $header = $_; s/./-/g; $delim = "-".$_;
    $_ = $entry;
    s/%7s/       /g; s/%5s/     /g; s/%4s %-16s%5d/%-20s%6d/; s/%\.0s//g; $foot = $_;
}
print($header, $delim);
@monkeys= sort {$sortrank{$a} <=> $sortrank{$b}
	    || $a cmp $b} keys %lines;
foreach (@monkeys){
    printf ($entry,
	    &form($sortrank{$_}, "%s."), $_, 
	    $lines{$_}, &percent($lines{$_}, $totallines), "<$monkeys_line{$_}>",
	    $bytes{$_}, &percent($bytes{$_}, $totalbytes), "<$monkeys_bytes{$_}>", 
	    $length{$_}, &form($monkeys_length{$_},"<%s>"));
}
print($delim);
$monkeys = scalar @monkeys;
printf($foot, 
       "($monkeys monkeys)" ,
       $totallines, $totalbytes, $totalbytes/$totallines);
0;

sub form {
    my ($k, $f) = @_;
    return "" if ($k >= $THRESHOLD);
    return sprintf($f, $k);
}
sub percent {
    my ($a, $t) = @_;
    return sprintf("(%4.1f%%)", $a / $t * 100);
}
