#/*
# *  Copyright 2007 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: Log.pm 591 2007-05-08 14:20:41Z hikarin $
#

package Img0ch::Log;

use strict;

sub new {
    my ( $iClass, $iBBS, $key ) = @_;
    my $iKernel = $iBBS->get_kernel();

    my ( undef, undef, undef, $day, $month, $year ) = localtime($key);
    $year  += 1900;
    $month += 1;

    my $repos = $iBBS->get_repos_path( $year, $month, $day, $key, 'log' );
    my $repos_dir = $repos;
    $repos_dir =~ s{/log\..*\z}{}xms;
    if ( !-d $repos_dir ) {
        require File::Path;
        File::Path::mkpath($repos_dir)
            or $iKernel->throw_io_exception($repos_dir);
    }

    bless {
        _bbs  => $iBBS->get_name(),
        _key  => $key,
        __log => [],
        _rs   => $iKernel->get_repos_nocache($repos),
    }, $iClass;
}

sub load { $_[0]->{_rs}->load(); return 1 }

sub save {
    my ($iLog) = @_;
    my $logs   = $iLog->{__log};
    my $iRepos = $iLog->{_rs};
    my ( $bbs, $key ) = ( $iLog->{_bbs}, $iLog->{_key} );
    my $prefix_top = "I:L.${bbs}.${key}";

    for my $log (@$logs) {
        my $resno   = $log->[0];
        my $content = $log->[1];
        my $prefix  = join '.', $prefix_top, $resno;
        my ( $date, $ip, $serial, $agent )
            = ( $content->[0], $content->[1], $content->[2], $content->[3] );
        $ip = join '.', unpack( 'C*', $ip );
        $iRepos->set( "${prefix}.date",   $date );
        $iRepos->set( "${prefix}.ip",     $ip );
        $iRepos->set( "${prefix}.serial", $serial );
        $iRepos->set_binary( "${prefix}.agent", $agent );
    }

    @{ $iLog->{__log} } = ();
    $iRepos->save();
    1;
}

sub get {
    my ( $iLog, $resno ) = @_;
    my $iRepos = $iLog->{_rs};
    my ( $bbs, $key ) = ( $iLog->{_bbs}, $iLog->{_key} );

    $resno = Img0ch::Kernel::intval($resno);
    my $prefix = "I:L.${bbs}.${key}.${resno}";
    my $date   = $iRepos->get("${prefix}.date");
    if ($date) {
        my $ip     = $iRepos->get("${prefix}.ip");
        my $serial = $iRepos->get("${prefix}.serial");
        my $agent  = $iRepos->get_binary("${prefix}.agent");
        $ip = pack 'C*', split( '\.', $ip );
        return [
            $date,   $ip,
            $serial, Img0ch::Kernel::escape_html_entities($agent),
        ];
    }

    return [ 0, '', '', '' ];
}

sub set {
    my ( $iLog, $resno, $log ) = @_;
    my $iRepos = $iLog->{_rs};
    my ( $bbs, $key ) = ( $iLog->{_bbs}, $iLog->{_key} );

    $resno = Img0ch::Kernel::intval($resno);
    my $prefix = "I:L.${bbs}.${key}.${resno}";
    my $ip = join '.', unpack( 'C*', $log->[1] );
    $iRepos->set( "${prefix}.date",   $log->[0] );
    $iRepos->set( "${prefix}.ip",     $ip );
    $iRepos->set( "${prefix}.serial", $log->[2] );
    $iRepos->set_binary( "${prefix}.agent", $log->[3] );
    return;
}

sub add {
    my ( $iLog, $resno, $log ) = @_;
    push @{ $iLog->{__log} }, [ $resno, $log ];
    return;
}

sub remove {
    my ( $iLog, $resno ) = @_;
    my $iRepos = $iLog->{_rs};
    my ( $bbs, $key ) = ( $iLog->{_bbs}, $iLog->{_key} );

    $resno = Img0ch::Kernel::intval($resno);
    my $prefix = "I:L.${bbs}.${key}.${resno}";
    my $date   = $iRepos->remove("${prefix}.date");
    if ($date) {
        $iRepos->remove("${prefix}.ip");
        $iRepos->remove("${prefix}.serial");
        $iRepos->remove("${prefix}.agent");
        return 1;
    }

    return 0;
}

1;
__END__

=head1 NAME

Img0ch::Log - 書き込み記録を管理するクラス

=head1 SYNOPSYS

  use Img0ch::Log

  my $iLog = Img0ch::Log->new( $iBBS, $key );
  $iLog->add( $resno, [ $date, $ip, $serial, $agent ] );
  $iLog->save();

  my ( $date, $ip, $serial, $agent ) = @{ $iLog->get($resno) };
  $iLog->remove($resno);
  $iLog->save();

=head1 DESCRIPTION

1つのスレッドの書き込み記録を1つのオブジェクトとするクラスです。

=head2 new

=over 4

=item Arguments

$iBBS (Img0ch::BBS), $key

=item Return Value

$iLog (Img0ch::Log itself)

=back

I<Img0ch::Log>のオブジェクトを作成します。

=head2 load

=over 4

=item Arguments

none

=item Return Value

1

=back

レポジトリを読み込みます。

=head2 save

=over 4

=item Arguments

none

=item Return Value

1

=back

add()で設定された内容をレポジトリに保存します。

=head2 get

=over 4

=item Arguments

$resno

=item Return Value

[ $date, $ip, $serial, $agent ]

=back

レス番号からログ情報の配列のリファレンスを返します。
$agentはHTML実体参照が行われた文字列で返します。

存在しない場合は$dateを0、それ以外の変数を
ナルストリングにした配列のリファレンスを返します。

=head2 set

=over 4

=item Arguments

$resno, [ $date, $ip, $serial, $agent ]

=item Return Value

none

=back

レス番号からログ情報を書き換えます。
実際に保存するにはsave()を呼び出す必要があります。

=head2 add

=over 4

=item Arguments

[ $date, $ip, $serial, $agent ]

=item Return Value

none

=back

ログ情報を追記します。実際に保存するにはsave()を呼び出す必要があります。

=head2 remove

=over 4

=item Arguments

$resno

=item Return Value

1(removed) or 0

=back

レス番号からログ情報を削除します。
ログ情報が存在しないレス番号が指定された場合0を返します。
実際に保存するにはsave()を呼び出す必要があります。

=head1 AUTHOR

hkrn E<lt>hikarin@users.sourceforge.jpE<gt>

=cut
