#!/usr/local/bin/perl5
use Data::Dumper;
use HTML::Entities;
use Date::Format;
use GD;

# cat data.txt | anim.pl
# gifsicle -l -d 4 -O2 frame*.gif > anim.gif

my %color;

sub
strip_html {
	$_ = decode_entities(shift);

	$_ =~ s/\<[^\>]+\>//g;
	return $_;
}

sub
extract_number {
	$_ = strip_html(shift);

	if (/([[:digit:]]+)/) {
		$i = int($1);
		if ($i > 0 && $i < 2001) {
			return int($1);
		}
	}
	return undef;
}

sub
detect_comments {
	$_ = shift;

	$_ =~ s/<BR>//g;	# hard returns
	$_ =~ s/\s+$//g;	# trailing whitespace
	$_ =~ s/^\s+//g;	# leading whitespace
	$_ =~ s/<\/*b>//g;	# Bold tag
	$_ =~ s/<\/*font.*>//g;	# Font tag
	$_ =~ s/\s*<img src=\/images\/smilies\/.*>\s*//g;       # smilies
	$_ =~ s/:\)//g;		# emoticons


	return grep(/[^[:digit:]]+/, $_) ? 1 : 0;
}

sub
rectangleAt {
	my $image = shift;
	my $x = shift;
	my $y = shift;
	my $w = shift;
	my $h = shift;
	my $color = shift;

	$image->rectangle($x, $y, $x + $w, $y + $h, $color);
}

sub
newGrid {
	my $frame = new GD::Image(901, 201);

	$color{white} = $frame->colorAllocate(255,255,255);
	$color{black} = $frame->colorAllocate(0,0,0);

	$color{1} = $frame->colorAllocate(0x1f, 0xff, 0x50);
	$color{2} = $frame->colorAllocate(0x1a, 0x9f, 0xff);
	$color{3} = $frame->colorAllocate(0xa5, 0x16, 0xff);
	$color{4} = $frame->colorAllocate(0xff, 0x11, 0x3e);
	$color{5} = $frame->colorAllocate(0xfd, 0xff, 0x0d);
	$color{6} = $frame->colorAllocate(0,0,0);

	#$frame->transparent($color{white});
	$frame->rectangle(0, 0, 900, 180, $color{black});

	# Grid
	for $x (1 .. 100) {
		$frame->line($x * 9, 0, $x * 9, 181, $color{black});
	}
	for $y (1 .. 20) {
		$frame->line(0, $y * 9, 900, $y * 9, $color{black});
	}

	# Progress bar bounding box.
	rectangleAt($frame, 497, 186, 402, 10, $color{black});

	return $frame;
}

sub
fillSquare {
	$image = shift;
	$square = shift;
	$color = shift;

	$y = int(($square - 1) / 100);
	$x = int(($square - 1)  % 100);

	$x1 = 1 + ($x * 9);
	$y1 = 1 + ($y * 9);
	$x2 = $x1 + 7;
	$y2 = $y1 + 7;
	$image->filledRectangle($x1, $y1, $x2, $y2, $color);
}

while (<>) {
	chop;
	($page, $post, $pdate, $edate, $poster, $plevel, $message) = split(/\t/);
	next if ($post == 0);	# Skip the OP.

	$number = extract_number($message);
	$comments = detect_comments($message);
	$edited = $edate != 0 ? 1 : 0;

	$hash{$poster}++;
	push @posts,
		{
			poster => $poster,
			page => int($page),
			post => int($post),
			level => $plevel,
			post_date => int($pdate),
			edit_date => int($edate),
			edited => $edited,
			comments => $comments,
			message => $message,
			number => $number
		};
}

foreach $post ( @posts ) {
	$post->{multiple} = ($hash{$post->{poster}} > 1) || 0;
}


$start = $posts[0]{post_date};
$last = $posts[$#posts]{post_date};
print "Start " . $start . "\n";
print "Last " . $last . "\n";

$count = 0;
$break = $start;
$frame = 0;
$frames_total = (($last - $start) / 300) + 1;

$fr = newGrid();
$string = sprintf("%s GMT, Frame %4d/%4d, Entries %4d(+%2d), Numbers %4d",
	scalar gmtime($break), $frame, $frames_total, 0, 0, 0);
print $string;
$fr->string(gdSmallFont, 1, 184, $string, $color{black});
open(FRAME, ">anim/frame00000.gif") || die;
binmode FRAME;
print FRAME $fr->gif; 
close FRAME;
undef $fr;

select STDOUT; $| = 1;

while ($break < $last) {
	$last_count = $count;
	$count = 0;
	$pick = 0;
	$frame++;
	$break += 300;
	@numbers = ();
	foreach $post ( @posts ) {
		last if ($post->{post_date} > $break);
		next if (!defined($post->{number}));
		$numbers[$post->{number}]++;
		$count++;
	}
	$fr = newGrid();

	for $i (1 .. 2000) {
		next if (!defined($numbers[$i]));

		$c = $numbers[$i];
		if ($c > 5) { $c = 6; }
		fillSquare($fr, $i, $color{$c});

		$pick++;
	}

	$hist[$count - $last_count]++;

	$string = sprintf("%s GMT, Frame %4d/%4d, Entries %4d(+%2d), Numbers %4d",
		scalar gmtime($break),
		$frame, $frames_total,
		$count, $count - $last_count, $pick);
	$fr->string(gdSmallFont, 1, 184, $string, $color{black});

	$x = (1 - (($last - $break) / ($last - $start))) * 400;
	$fr->filledRectangle(498, 187, 498 + $x, 195, $color{black});

	print "\r" . $string;

	$file = sprintf("anim/frame%05d.gif", $frame);
	open(FRAME, ">$file") || die;
	binmode FRAME;
	print FRAME $fr->gif; 
	close FRAME;
	undef $fr;
}
print "\n";
print Dumper(\@hist);
