#/*
# *  Copyright 2007-2008 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: Error.pm 1661 2008-03-09 23:53:39Z hikarin $
#

package Img0ch::Error;

use strict;

sub new {
    my ( $iClass, $iObject, $key, $ip_int ) = @_;
    my $class = ref $iObject || '';
    my ( $iKernel, $bbs, $common );

    if ( $class eq 'Img0ch::BBS' ) {
        $iKernel = $iObject->get_kernel();
        $bbs     = $iObject->get_name() || 'test';
        $common  = $iObject->get_common_repos();
    }
    elsif ( $class eq 'Img0ch::Kernel' or $class eq 'Img0ch::Maple' ) {
        $iKernel = $iObject;
        $bbs     = 'test';
        $common  = $iKernel->get_repos( $iKernel->get_repos_path('common') );
    }
    else {
        Img0ch::Kernel->throw_exception(
            'Img0ch::BBS or Img0ch::Maple(Img0ch::Kernel) not given');
    }

    my $date = time();
    my $repos_path
        = Img0ch::Maple::create_repository_subdirs( $date, 'error', $iKernel,
        1 );
    my $iRepos = $iKernel->get_repos_nocache($repos_path);

    bless {
        _bbs    => $bbs,
        __cache => '',
        __date  => $date,
        __error => $common,
        __ip    => $ip_int,
        _kernel => $iKernel,
        __key   => ( $key || '0' ),
        _rs     => $iRepos,
    }, $iClass;
}

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

sub get {
    my ( $iError, $key ) = @_;
    my $cache = $iError->{__cache} || '';
    $cache and return $cache;

    my $iKernel = $iError->{_kernel};
    my $iConfig = $iKernel->get_config();
    my $path    = $iConfig->get('SystemPath') . '/error.txt';
    my $fh      = $iKernel->get_read_file_handle($path);
    while ( my $line = <$fh> ) {
        chomp $line;
        my ( $errid, $errmsg ) = ( split '<>', $line )[ 0, 2 ];
        if ( $key eq $errid ) {
            $iError->{__cache} = $key;
            return $errmsg;
        }
    }
    close $fh or $iKernel->throw_io_exception($path);

    return '';
}

sub add {
    my ($iError) = @_;
    my $cache = $iError->{__cache};
    my %stop_to_add = map { ( $_ => 1 ) }
        qw(DENY_POSTING_ASCII_ONLY INVALID_POST POST_WITH_NGWORD TOO_LONG_MESSAGE);

    if (    $cache
        and !exists $stop_to_add{$cache}
        and my $ip_int = $iError->{__ip} )
    {
        my $iRepos = $iError->{_rs};
        my $bbs    = $iError->{_bbs};
        my $key    = $iError->{__key};
        my $date   = $iError->{__date};
        my $mil    = int( rand(99999) );
        my $prefix = "I:L:E.${bbs}.${key}.${date}.${mil}";
        $iRepos->set( "${prefix}.error", $cache );
        $iRepos->set( "${prefix}.ip", join( '.', unpack( 'C*', $ip_int ) ) );
        $iRepos->save();
        return 1;
    }

    return 0;
}

*record = \&add;

1;
__END__

=head1 NAME

Img0ch::Error - エラー処理を行うクラス

=head1 SYNOPSYS

  use Img0ch::Error

  my $iError = Img0ch::Error->new($iBBS, $key, $ip);

  # INVALID_POSTのメッセージを取り出す
  my $errstr = $iError->get('INVALID_POST');
  # エラー記録を行う
  my $true_or_false = $iError->record();

=head1 DESCRIPTION

1つのエラー処理を1つのオブジェクトとするクラスです。

=head2 new

=over 4

=item Arguments

$iBBS(Img0ch::BBS) or $iKernel(Img0ch::Kernel), $key?, $ip?

=item Return Value

$iError (Img0ch::Error itself)

=back

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

=head2 load

=over 4

=item Arguments

none

=item Return Value

1

=back

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

=head2 get

=over 4

=item Arguments

$key

=item Return Value

$message

=back

I<$key>に対応付けるエラーメッセージを返します。
存在しない場合はナルストリングを返します。

=head2 record

=over 4

=item Arguments

none

=item Return Value

1(succeeded) or 0

=back

get()で呼び出された情報からエラー記録を行います。
get()を呼び出されていない場合は0を返します。

=head1 AUTHOR

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

=cut
