#/*
# *  Copyright 2007-2010 hkrn <hikarin@users.sourceforge.jp>
# *
# *  Licensed under the Apache License, Version 2.0 (the "License");
# *  you may not use this file except in compliance with the License.
# *  You may obtain a copy of the License at
# *
# *      http://www.apache.org/licenses/LICENSE-2.0
# *
# *  Unless required by applicable law or agreed to in writing, software
# *  distributed under the License is distributed on an "AS IS" BASIS,
# *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# *  See the License for the specific language governing permissions and
# *  limitations under the License.
# */
#
# $Id: NGWord.pm 1957 2010-01-23 11:18:01Z hikarin $
#

package Zeromin::Filter::NGWord;

use strict;
use base qw(Img0ch::Filter::NGWord);
use Digest::MD5 qw();

sub new {
    my ( $zClass, $iObject ) = @_;
    my $class = ref $iObject || '';
    my ( $zFNG, $iKernel );

    if ( $class eq 'Img0ch::BBS' ) {
        $zFNG             = $zClass->SUPER::new($iObject);
        $iKernel          = $iObject->get_kernel();
        $zFNG->{__bbs_id} = $iObject->get_id();
        $zFNG->{__kernel} = $iKernel;
    }
    elsif ( $class eq 'Img0ch::Kernel' or $class eq 'Img0ch::Maple' ) {
        require Img0ch::BBS;
        $iKernel = $iObject;
        my $iBBS = Img0ch::BBS->new( $iKernel, { id => 0 } );
        $zFNG             = $zClass->SUPER::new($iBBS);
        $zFNG->{__bbs_id} = 0;
        $zFNG->{__kernel} = $iKernel;
    }
    else {
        Img0ch::Kernel->throw_exception(
            'Img0ch::BBS or Img0ch::Maple not given');
    }

    my $bbs = $zFNG->{_bbs};
    $zFNG->{__buffer}   = [];
    $zFNG->{__encoding} = $iKernel->get_encoding(1);
    $zFNG;
}

sub load {1}

sub save {
    my ($zFNG)     = @_;
    my $iRepos     = $zFNG->{_rs};
    my $buffer     = $zFNG->{__buffer};
    my $bbs        = $zFNG->{_bbs};
    my $prefix_top = "I:F:N.${bbs}";

    for my $one (@$buffer) {
        my $word   = $one->[0];
        my $id     = Digest::MD5::md5_hex( $bbs, $word );
        my $prefix = "${prefix_top}.${id}";
        eval { $iRepos->set_binary( "${prefix}.regex", qr{$word} ); };
        if ($@) {
            $iRepos->set_binary( "${prefix}.regex", $word );
        }
        $iRepos->set_binary( "${prefix}.entry", $word );
        $iRepos->set( "${prefix}.utf8", 1 );
        $iRepos->set( "${prefix}.flag", $one->[1] );
        $iRepos->set_binary( "${prefix}.replace", $one->[2] );
        $iRepos->set( "${prefix}.apply", $one->[3] );
    }
    $iRepos->save();

    @{ $zFNG->{__buffer} } = ();
    return 1;
}

sub get {
    my ( $zFNG, $hash, $unijp, $encoding ) = @_;
    my $iRepos = $zFNG->{_rs};
    my ( $bbs, $id_b64, $id_hex );

    if ( my $word = $hash->{word} ) {
        $bbs = $hash->{bbs} || $zFNG->{_bbs};
        $id_hex = Digest::MD5::md5_hex( $bbs, $word );
    }
    else {
        $bbs    = $zFNG->{_bbs};
        $id_hex = $hash->{id};
    }

    if ( $iRepos->get_int("I:F:N.${bbs}.${id_hex}.flag") ) {
        my $prefix = "I:F:N.${bbs}.${id_hex}";
        my $entry  = $iRepos->get_binary("${prefix}.entry");
        my $to     = $iRepos->get_binary("${prefix}.replace");
        if ( $unijp and !$iRepos->get("${prefix}.utf8") ) {
            $entry = $unijp->set( $entry, 'sjis' )->get();
            $to    = $unijp->set( $to,    'sjis' )->get();
        }
        my $iBBS = Img0ch::BBS->new( $zFNG->{__kernel}, { bbs => $bbs } );
        {   id    => $id_hex,
            bbs   => $iBBS->get_id(),
            entry => $entry,
            regex => $iRepos->get_binary("${prefix}.regex"),
            type  => $iRepos->get_int("${prefix}.flag"),
            to    => $to,
            apply => ( $iRepos->get_int("${prefix}.apply") || 1 ),
        };
    }
    elsif ( $iRepos->get_int("I:F:N.${bbs}.${id_b64}.flag") ) {
        my $prefix = "I:F:N.${bbs}.${id_b64}";
        my $entry  = $iRepos->get_binary("${prefix}.entry");
        my $to     = $iRepos->get_binary("${prefix}.replace");
        if ( $unijp and !$iRepos->get("${prefix}.utf8") ) {
            $entry = $unijp->set( $entry, 'sjis' )->get();
            $to    = $unijp->set( $to,    'sjis' )->get();
        }
        my $iBBS = Img0ch::BBS->new( $zFNG->{__kernel}, { bbs => $bbs } );
        {   id    => $id_b64,
            bbs   => $iBBS->get_id(),
            entry => $entry,
            regex => $iRepos->get_binary("${prefix}.regex"),
            type  => $iRepos->get_int("${prefix}.flag"),
            to    => $to,
            apply => ( $iRepos->get_int("${prefix}.apply") || 1 ),
        };
    }
    else {
        {   id    => '',
            bbs   => undef,
            entry => '',
            regex => '',
            type  => 0,
            to    => '',
            apply => 1,
        };
    }
}

sub all {
    my ( $zFNG, $unijp ) = @_;
    my $encoding     = $zFNG->{__encoding};
    my $prefix_regex = qr/\AI:F:N\.(?:.+?)\.(.+?)\.\w+\z/xms;
    my $ret          = [];
    my $id_table     = {};

    $zFNG->{_rs}->iterate(
        sub {
            my ( $key, $value, $id_table, $prefix_regex ) = @_;
            $key =~ /$prefix_regex/xms or return 0;
            my $id = $1;
            $id_table->{$id} = 1;
            return 0;
        },
        $id_table,
        $prefix_regex
    );

    for my $id ( keys %$id_table ) {
        push @$ret, $zFNG->get( { id => $id }, $unijp, $encoding );
    }
    $ret;
}

sub all_with_page {
    my ( $zFNG, $unijp, $item_per_page, $offset ) = @_;

    defined $Data::Page::VERSION or require Data::Page;
    my $entries = $zFNG->all($unijp);
    my $page = Data::Page->new( scalar @$entries, $item_per_page, $offset );
    return ( [ $page->splice($entries) ], $page );
}

sub all_in {
    my ( $zFNG, $unijp, $bbs ) = @_;
    my $data = $zFNG->all($unijp);
    $bbs ||= $zFNG->{__bbs_id};
    [ grep { $_->{bbs} == $bbs } grep { defined $_->{bbs} } @$data ];
}

sub all_in_with_page {
    my ( $zFNG, $unijp, $bbs, $item_per_page, $offset ) = @_;

    defined $Data::Page::VERSION or require Data::Page;
    my $entries = $zFNG->all_in( $unijp, $bbs );
    my $page = Data::Page->new( scalar @$entries, $item_per_page, $offset );
    return ( [ $page->splice($entries) ], $page );
}

sub add {
    my ( $zFNG, $word, $type, $to, $apply ) = @_;
    my $buffer = $zFNG->{__buffer};
    for my $one (@$buffer) {
        $one->[0] eq $word and return 0;
    }

    push @{ $zFNG->{__buffer} }, [ $word, $type, $to, $apply ];
    1;
}

sub set {
    my ( $zFNG, $id, $type, $to, $bbs, $apply ) = @_;
    my $iRepos      = $zFNG->{_rs};
    my $prev_bbs    = $zFNG->{_bbs};
    my $prev_prefix = "I:F:N.${prev_bbs}.${id}";

    $bbs ||= 'test';
    if ( my $word
        = $iRepos->decode_binary( $iRepos->remove("${prev_prefix}.entry") ) )
    {
        my $regex = $iRepos->decode_binary(
            $iRepos->remove("${prev_prefix}.regex") );
        my $prev_type = $iRepos->remove("${prev_prefix}.flag");
        my $prev_to   = $iRepos->decode_binary(
            $iRepos->remove("${prev_prefix}.replace") );
        my $prev_apply = $iRepos->remove("${prev_prefix}.apply");
        my $new        = Digest::MD5::md5_hex( $bbs, $word );
        my $pfx        = "I:F:N.${bbs}.${new}";
        $iRepos->set_binary( "${pfx}.entry", $word );
        $iRepos->set_binary( "${pfx}.regex", $regex );
        $iRepos->set( "${pfx}.flag",           ( $type  || $prev_type ) );
        $iRepos->set_binary( "${pfx}.replace", ( $to    || $prev_to ) );
        $iRepos->set( "${pfx}.apply",          ( $apply || $prev_apply ) );
        return 1;
    }

    return 0;
}

sub remove {
    my ( $zFNG, $id ) = @_;
    my $iRepos = $zFNG->{_rs};
    my $prefix = "I:F:N.$zFNG->{_bbs}.${id}";

    if ( $iRepos->remove("${prefix}.entry") ) {
        $iRepos->remove("${prefix}.regex");
        $iRepos->remove("${prefix}.flag");
        $iRepos->remove("${prefix}.replace");
        $iRepos->remove("${prefix}.apply");
        return 1;
    }
    return 0;
}

1;
__END__
