#! /usr/bin/env perl

# cvs blame inspired by Bonsai
# Author: Bernd Gehrmann <bernd@physik.hu-berlin.de>

=head1 NAME

cvsblame - Shows a blame-annotated representation of a CVS controlled file in Konqueror.

=head1 SYNOPSIS

cvsblame <filename>

=head1 DESCRIPTION

cvsblame opens Konqueror to display the output of cvs annotate of
a cvs controlled file. When the mouse is on a revision number shown
in the second column, a popup with the respective log message
appears. 

In the popup, a proper mailto: link to the author of a revision
can be created as follows: In your home directory, make a file
.cvsblame. In that file, enter for each repository you are working
with a line like

      accounts :pserver:gehrmab@cvs.kde.org:/home/kde /home/bernd/.kdeaccounts

where the accounts file contains a simple list of cvs usernames in
the first column and the respective mail address in the second.

=head1 BUGS

=over 4

=item Does not really work for filenames which are not in the current directory

=item Is a hack. Really.

=back 

=head1 AUTHOR

Bernd Gehrmann <bernd@physik.hu-berlin.de>

=cut

$file = $ARGV[0];
$outputfile = `kde-config --path tmp` || './#'; # if we put the file in the cwd, then we keep a '#' at the beggining to help CVS ignore it
($outputfile) = split(/:/,$outputfile);
chomp $outputfile;
$outputfile .= "cvsblame.$$.html";
$configfile = $ENV{HOME}. "/.cvsblame";
$rootfile = "`pwd`/CVS/Root";
$cvsroot = `cat "$rootfile"`;
chop $cvsroot;

#
# Look for a username -> mail address mapping
#

if (open(CONFIG, $configfile)) {
    while (<CONFIG>) {
	if (/accounts\s*([^\s]*)\s+([^\s]*)/) {
	    if ($1 eq $cvsroot) {
		$accountfile = $2;
            }
        }
    }
    close CONFIG;
}
if ($accountfile) {
    open(ACCOUNTS, $accountfile) || die "Account file not found: $accountfile";
    while (<ACCOUNTS>) {
        if (/([^\s]*)\s+([^\s].*[^\s])\s+([^\s]+)/) {
            $mail{$1} = "$2 &lt;$3&gt;";
        }
	elsif (/([^\s]*)\s+([^\s]*)/) {
	    $mail{$1} = $2;
        }
    }
}


#
# The real work, first the html header
#


open(OUTPUT, ">$outputfile");
print OUTPUT <<EOF;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Blame annotation for $file</title>
  </head>
  <script type="text/javascript">
    function hidelog(event) {
      var target = event.relatedTarget;
      while (target && target.id != "popup")
        target = target.offsetParent;
      if (target)
        return;
      target = event.target;
      while (target.id != "popup")
        target = target.offsetParent;
      target.style.visibility = "hidden";
    }
    function init() {
      document.getElementById("popup").addEventListener("mouseout", hidelog, false);
    }
    function poplog(target, rev) {
      var popup = document.getElementById("popup");
      var x = 120, y = 0;
      while (target && target != document)
      {
          x += target.offsetLeft;
          y += target.offsetTop;
          target = target.offsetParent;
      }
      popup.style.pixelLeft = x;
      popup.style.pixelTop = y;
      popup.innerHTML = rev;
      popup.style.visibility = "visible";
      return true;
    }
EOF

#
# Translate information from cvs log in javascript stuff
#

$revision = "";
open (LOG, "cvs log \"$file\"|");
while (<LOG>) {
      chop;
      $line = $_;
      if ($line =~ /^revision (.*)/) {
             $revision = $1;
             $revstr = "log$revision";
             $revstr =~ s/\./_/g;
      } elsif ($line =~ /date: ([^;]*);\s*author: ([^;]*);.*/) {
             $date = $1;
             $author = $2;
             if ($mail{$author}) {
		 $author = "<a href=\\\"mailto:$mail{$author}\\\">$author</a>";
             }
             $content = "<b>$revision</b>&nbsp;&nbsp;$author&nbsp;&nbsp;<b>$date<b>";
      } elsif ($line eq "----------------------------" && !($revision eq "")) {
             print OUTPUT "var $revstr = \"$content\";\n";
      } elsif ($line eq "=============================================================================" && !($revision eq "")) {
             print OUTPUT "var $revstr = \"$content\";\n";
      } else {
             $line =~ s/\"/\\\"/g;
	     $line =~ s/&/&amp;/g;
	     $line =~ s/</&lt;/g;
	     $line =~ s/>/&gt;/g;
             $content = "$content<br>$line";
      }
}
close LOG;

print OUTPUT <<EOF;
  </script>
  <style type="text/css">
        body {
            background: #eeeee0;
        }
        #popup {
            position: absolute;
            background: #ffcc99;
            border: 1px solid #80664D;
            padding: 2px;
         }
         a:link {
            text-decoration: none;
         }
         a:hover {
            text-decoration: underline;
         }
  </style>
  <body text="#000000" onload="init()">
    <h1>$file</h1>
    <table border=0 cellpadding=0 cellspacing=0 width="100%">
EOF

#
# Information from cvs annotate
#

$color = 1;
$lineno = 1;
$oldrevision = "";
$oldlineno = "";
$oldrevstr = "";
open (ANNOTATE, "cvs annotate \"$file\" 2>/dev/null|");
while (<ANNOTATE>) {
      chop;
      $line = $_;
      $revision = substr $line, 0, 13;
      $revision =~ s/\s//g;
      $author = substr $line, 14, 9;
      $author =~ s/\s//g;
      $date = substr $line, 23, 9;
      $content = substr $line, 35;
      $content =~ s/\&/&amp;/g;
      $content =~ s/\</&lt;/g;
      $content =~ s/\>/&gt;/g;
      $revstr = "log$revision";
      $revstr =~ s/\./_/g;
      if ($revision eq $oldrevision) {
	  if ($lineno == $oldlineno+20) {
	      $linkstr = "<span onmouseover=\"return poplog(this, $revstr)\"'>";
	      $linkendstr = "</span>";
              $revauthor = "$author $revision";
              $oldlineno = $lineno;
	  } else {
	      $linkstr = "";
	      $linkendstr = "";
	      $revauthor = "";
	  }
      } else {
          $color = ($color == 0)? 1 : 0;
          $linkstr = "<span onmouseover=\"return poplog(this, $revstr)\"'>";
	  $linkendstr = "</span>";
	  $revauthor = "$author $revision";
	  $oldlineno = $lineno;
	  $oldrevision = $revision;
      }
      print OUTPUT "<tr><td nowrap style=\"background: ", ($color==1)? "#EEEEE0" : "#FFFFCC", "\"><pre>";

      print OUTPUT sprintf '%-5i%s%-14s%s%s', $lineno, $linkstr, $revauthor,$linkendstr, $content;
      print OUTPUT "</pre></td></tr>\n";
      $lineno++;
}
close ANNOTATE;

# 
# Finally, the html footer
#

print OUTPUT <<EOF;
    </table>
    <div id="popup" style="visibility: hidden"></div>
  </body>
</html>
EOF

close OUTPUT;

system("kfmclient openProfile webbrowsing $outputfile");

exit 0;
