package Plagger::Plugin::Filter::Diff;

use strict;
use base qw( Plagger::Plugin );

use Plagger::Cache;

use Algorithm::Diff qw( traverse_sequences );

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'plugin.init'        => \&initialize,
        'update.entry.fixup' => \&filter,
    );
}

sub initialize {
    my($self, $context) = @_;

    my $params = {
        base    => $self->conf->{path} || File::Spec->catfile(Plagger->context->cache->{base}, 'Filter-Diff'),
        expires => $self->conf->{expires},
    };

    $self->{cache} = Plagger::Cache->new($params);
}

sub filter {
    my($self, $context, $args) = @_;

    my $entry = $args->{entry};

    my $prev_cache = $self->{cache}->get($entry->permalink) || {};
    my $prev = (ref $prev_cache eq 'HASH') ? $prev_cache : { body => $prev_cache };
    my $body_new = $entry->body ? $entry->body->utf8 : undef;
    my $lastmod_new = $entry->date || Plagger::Date->now;

    my $body_diffed = '';
    if ($prev->{body}) {
        Plagger->context->log( debug => "previous entry data found (".$prev->{modified_on}.")" );

        my @lines = split /^/, $body_new;
        my @lines_prev = split /^/, $prev->{body};

        traverse_sequences(\@lines_prev, \@lines,
            {
                DISCARD_B => sub {
                    Plagger->context->log( debug => "new line: $lines[$_[1]]" );
                    $body_diffed .= $lines[$_[1]];
                }
            }
        );
        $body_diffed =~ s/(?:^\s+|\s+$)//g;
        $entry->body($body_diffed);
        $entry->date($lastmod_new) unless $entry->date;
    }
    else {
        $entry->body('') unless $self->conf->{store_on_firsttime};
    }

    if (!$prev->{modified_on} || ($body_diffed ne '' && ($prev->{modified_on} < $lastmod_new))) {
        Plagger->context->log( debug => "Save entry data: ".$entry->permalink );
        $self->{cache}->set($entry->permalink, { body => $body_new, diff => $entry->body, modified_on => $lastmod_new });
    }
    else {
        Plagger->context->log( debug => "use previous diff data.");
        $entry->body($prev->{diff});
        $entry->date($prev->{modified_on});
    }
}

1;
__END__

=head1 NAME

Plagger::Plugin::Filter::Diff - Take a difference of the entry body.

=head1 SYNOPSIS

- module: Filter::Diff

=head1 DESCRIPTION

Take a difference of the entry body.

=head1 CONFIG

=over 4

=item store_on_firsttime

=item path

path to a cache directory for diff.

=item expires

expires of diff cache.

=back

=head1 AUTHOR

Mayuki Sawatari

=head1 SEE ALSO

L<Plagger>

=cut
