#!/usr/bin/env perl -l

#
# http://www.tbray.org/ongoing/When/200x/2007/09/20/Wide-Finder
#

#
# Rather than Erlang (as was in here before) this is more based on the
# Scala version of this code at
# http://www.martin-probst.com/2007/09/24/wide-finder-in-scala/
#

#
# requires the data at http://www.tbray.org/tmp/o10k.ap
#

$|++;

sub main {
    die 'no file' unless -e 'ex/tbray.data';
    Slurp->new( filename => 'ex/tbray.data' );
    POE::Kernel->run();
}

{

    package Slurp;
    use MooseX::POE;
    use IO::File;
    has filename => (
        isa => 'Str',
        is  => 'ro',
    );

    has count => (
        isa     => 'HashRef',
        is      => 'rw',
        default => sub { {} },
    );

    my $file;

    sub START {
        $file ||= IO::File->new( $_[0]->filename, 'r' );
        shift->yield('loop');
    }

    event loop => sub {
        my ($self) = @_;
        if ( not eof $file ) {
            my @chunk;
            push @chunk, <$file> for ( 0 .. 1 );
            Count->new->yield( 'loop', \@chunk );
            return;
        }
        $self->yield('tally');
    };

    event inc => sub {
        my $chunk = $_[ARG0];
        my $count = $_[0]->count;
        for ( keys %$chunk ) {
            $count->{$_} += $chunk->{$_};
        }
        $_[0]->count($count);
    };

    event tally => sub {
        my $count = $_[OBJECT]->count;
        print "$count->{$_}: $_"
          for sort { $count->{$b} <=> $count->{$a} } keys %$count;
    };

}

{

    package Count;
    use MooseX::POE;

    event loop => sub {
        my ( $self, $sender, $chunk ) = @_[ OBJECT, SENDER, ARG0 ];
        my $count = {};
        for my $line (@$chunk) {
            $count->{$1}++
              if $line =~
              qr|GET /ongoing/When/\d\d\dx/(\d\d\d\d/\d\d/\d\d/[^ .]+)|o;
        }
        POE::Kernel->post( $sender => 'inc', $count );
        POE::Kernel->post( $sender => 'loop' );
    };

}

main();