#!/usr/bin/perl -w

sub read_status($$$) {
    my($file, $status, $total) = @_;
    $total->{'proofs'} = 0;
    $total->{'unprovable'} = 0;
    $total->{'proved'} = 0;
    $total->{'unfinished'} = 0;
    $total->{'untried'} = 0;
    $total->{'timeout'} = {};
    my $current_theory;

    open(STATUS, $file) || die "Cannot open $file";

    while(<STATUS>) {
	if( /^$/ || /^    Theory totals:/) {
	    $current_theory = undef;
	    next;
	}
	if(/^ Proof summary for theory ([A-Za-z0-9_?]*)$/ ){
	    $current_theory = $1;
	    next;
	}
	if(
	   /^    ([A-Za-z0-9_?]*)\.*(proved|unfinished|untried)[^]]*]\(\s*(\S*)\s*s\)$/
	   ){
            defined($current_theory) || die "Lemma $1 outside any theory";
	    # if(defined($status->{$1})) {
	    # 	my @keys = keys(%{$status->{$1}});
	    # 	print "lemma $1 appears in $current_theory and ",
	    # 	$keys[0], "\n";
	    # }
	    if(defined($total->{'timeout'}->{$1}) && 
	       $total->{'timeout'}->{$1} == 0){
		$status->{$1}->{$current_theory} = ["timeout", $3];
		$total->{'timeout'}->{$1} = 1;
		#print STDERR "timeout $current_theory.$1\n";
	    }
	    else {
		$status->{$1}->{$current_theory} = [$2, $3];
	    }
	    $total->{'proofs'}++;
	    if($1 =~ /unprovable/) {
		$total->{'unprovable'}++;
	    } else {
		$total->{$2}++;
	    }
	    next;
	}
	if(/Grand Totals:/) {
	    next;
	}
	if(/^Summary: ([0-9]*) proofs, ([0-9]*) timeout, ([0-9]*) unprovable, ([0-9]*) proved, ([0-9]*) failed, ([0-9]*) without proof$/) {
	    if( $total->{'proofs'} != $1 ||
		scalar(keys(%{$total->{'timeout'}})) != $2 ||
		$total->{'unprovable'} != $3 ||
		$total->{'proved'} != $4 ||
		$total->{'unfinished'} != $5 ||
		$total->{'untried'} != $6 ||
		$1 != $3 + $4 + $5 + $6)
	    {
		$timeout_len = scalar(keys(%{$total->{'timeout'}}));
		print "proof count error in $file:\n",
		"  proofs:     $1 \t(counted $total->{'proofs'})\n",
		"  timeout:    $2 \t(counted $timeout_len)\n",
		"  unprovable: $3 \t(counted $total->{'unprovable'})\n",
		"  proved:     $4 \t(counted $total->{'proved'})\n",
		"  unfinished: $5 \t(counted $total->{'unfinished'}",
		$timeout_len ? " including $timeout_len timeouts" : "",
		")\n",
		"  untried:    $6 \t(counted $total->{'untried'})\n\n";
	    }
	    next;
	};
        if(/timeout .* prove ([A-Za-z0-9_?]*)/){
	    $total->{'timeout'}->{$1} = 0;
	    next;
	}
        print "Unexpected line in $file\n", $_; 
        die "status parse error";
    }
}

# print "New\n\n";
read_status("Validate/timed-status", \%new, \%ntotal);
# print "\n\nOld\n\n";
read_status("Validate/timed-status-old", \%old, \%ototal);

# foreach $theory (sort keys(%new)) {
#     print "Theory $theory\n";
#     foreach $lemma (sort keys(%{$new{$theory}})) {
#         my($status, $time) = @{$new{$theory}{$lemma}};
# 	print "  $status \t$time\t$lemma\n"
#     }
# }

# sub deep_copy($$) {
#     my ($src, $target) = @_;
#     foreach $l (keys %$src) {
# 	foreach $t (keys %{$src->{$l}}) {
# 	    $target->{$l}->{$t} = $src->{$l}->{$t};
# 	}
#     }
# }
#
# deep_copy(\%new, \%added);
# deep_copy(\%old, \%deleted);


sub sort_lemma($$$) {
    # $oldstat and $newstat have one of the following values:
    # - undefined // lemma does not exist
    # - timeout
    # - proved
    # - unfinished
    # - untried
    my ($name, $oldstat, $newstat) = @_;
    #print STDERR "TIMEOUT $name\n" if $newstat eq "timeout";
    if(defined($oldstat) && defined($newstat) && $oldstat eq $newstat) {
	if($newstat eq "timeout") {
	    push @timeout, $name;
	}
	elsif($newstat ne "proved") {
	    push @stays_broken, $name;
	}
    }
    elsif(! defined($newstat)) {
	return;
    }
    elsif(defined($oldstat)) {
	if($newstat eq "proved") {
	    push @fixed, $name;
	}
	elsif($newstat eq "timeout") {
	    push @timeout, $name;
	}
	elsif($oldstat eq "proved") {
	    push @broken, $name;
	}
	else {
	    push @stays_broken, $name;
	}
    }
    else { # undefined($oldstat)
	if($newstat eq "proved") {
	    push @new_proved, $name;
	}
	elsif($newstat eq "timeout") {
	    push @timeout, $name;
	}
	else {
	    push @new_broken, $name;
	}
    }
}


foreach $nl (keys %new) 
{
    my $new_occ = scalar(keys(%{$new{$nl}}));
    my $old_occ = scalar(keys(%{$old{$nl}}));
    if($new_occ == 1 && $old_occ == 1) {
	my ($nth, $nstat) = %{$new{$nl}};
	my ($oth, $ostat) = %{$old{$nl}};
	sort_lemma("$nth.$nl", $ostat->[0], $nstat->[0]);
    }
    else { # $new_occ != 1 || $old_occ != 1
	foreach $nth (keys(%{$new{$nl}})) {
	    sort_lemma("$nth.$nl", $old{$nl}{$nth}[0], $new{$nl}{$nth}[0]);
	}
    }
}

# validation summary again with colors
sub validation_summary($) {
    my ($with_color) = @_;

    print "Validation summary\n";
    print "[1;35m" if $with_color;
    print scalar(keys(%{$ntotal{'timeout'}}));
    print " timeout, ";
    print "[m" if $with_color;
    print "[1;31m" if $with_color;
    print scalar(@broken);
    print " broken, ";
    print "[m" if $with_color;
    print "[1;32m" if $with_color;
    print scalar(@fixed);
    print " fixed, ";
    print "[m" if $with_color;
    print "[1;32m" if $with_color;
    print scalar(@new_proved);
    print " new proved";

    # newline and 10 spaces for good indentation in ChangeLog files
    print "\n          ";
    print "[m" if $with_color;
    print "[31m" if $with_color;
    print scalar(@stays_broken);
    print " stay broken, ";
    print "[m" if $with_color;
    print "[31m" if $with_color;
    print scalar(@new_broken);
    print " new unfinished ";
    print "[m" if $with_color;
    print "\n\n";
}

# validation summary without colors
validation_summary(0);

if(scalar(@timeout) != 0) {
    print "Nonterminating proofs (aborted by timeout):\n    ",
        join( "\n    ", sort(@timeout)),
        "\n\n";
}

if(scalar(@broken) == 0) {
    print "Great! No lemma broke.\n\n";
}
else {
    print "Newly broken lemmas (that have been proved previously):\n    ",
        join( "\n    ", sort(@broken)),
        "\n\n";
}

if(scalar(@fixed) == 0) {
    print "No lemma was fixed.\n\n";
}
else {
    print "Fixed lemmas (proved now, unfinished/untried before):\n    ",
        join("\n    ", sort(@fixed)), "\n\n";
}


if(scalar(@new_broken) == 0) {
    print "No new unfinished/untried lemma.\n\n";
}
else {
    print "New unfinished/untried lemmas:\n    ",
    join( "\n    ", sort(@new_broken)), "\n\n";
}


if(scalar(@stays_broken) == 0) {
    print "No lemma stayed unfinished/untried\n\n";
}
else {
    print "Lemmas that stayed unfinished/untried:\n    ",
    join("\n    ", sort(@stays_broken)), "\n\n";
}


if(scalar(@new_proved) == 0) {
    print "No new proved lemmas\n\n";
}
else {
    print "New proven lemmas (that did not exist before):\n    ",
    join("\n    ", sort(@new_proved)), "\n\n";
}

print "old total: ",
    "$ototal{'proofs'} proofs, ",
    "$ototal{'unprovable'} unprovable, ",
    "[1;32m", "$ototal{'proved'} proved, ", "[m",
    "[1;31m", "$ototal{'unfinished'} failed, ", 
    "$ototal{'untried'} untried", "[m", 
    "\n";

print "new total: ",
    "$ntotal{'proofs'} proofs, ",
    "$ntotal{'unprovable'} unprovable, ",
    "[1;32m", "$ntotal{'proved'} proved, ", "[m",
    "[1;31m", "$ntotal{'unfinished'} failed, ", 
    "$ntotal{'untried'} untried", "[m", 
    "\n\n";

print "Total\t\tpreviously\tcurrently\n";
printf( "  proofs\t%10d\t%9d\n", $ototal{'proofs'}, $ntotal{'proofs'});
printf( "  unprovable\t%10d\t%9d\n", 
	$ototal{'unprovable'}, $ntotal{'unprovable'});
printf( "  [1;32mproved\t%10d\t%9d[m\n", 
	$ototal{'proved'}, $ntotal{'proved'});
printf( "  [1;35mtimeout\t%10d\t%9d[m\n", 
	scalar(keys(%{$ototal{'timeout'}})), 
	scalar(keys(%{$ntotal{'timeout'}})));
printf( "  [1;31mfailed\t%10d\t%9d[m\n", 
	$ototal{'unfinished'}, $ntotal{'unfinished'});
printf( "  [1;31muntried\t%10d\t%9d[m\n", 
	$ototal{'untried'}, $ntotal{'untried'});
print "\n";

# validation summary with colors
validation_summary(1);
