#/*
# *  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: Archive.pm 486 2007-04-13 14:34:30Z hikarin $
#

package Zeromin::Archive;

use strict;
use base qw(Img0ch::Archive);

sub new {
    my ( $zClass, $zBBS ) = @_;
    my $iBBS = $zBBS->can('parent') ? $zBBS->parent() : $zBBS;
    my $zArchive = $zClass->SUPER::new($iBBS);

    $zArchive->{__bbs}   = $iBBS;
    $zArchive->{__key}   = 0;
    $zArchive->{__cache} = undef;
    $zArchive;
}

sub set_key { $_[0]->{__key} = $_[1]; return }

sub create {
    my ( $zArchive, $key ) = @_;
    my $iBBS = $zArchive->{__bbs};

    require Img0ch::Pool::Thread;
    $key ||= $zArchive->{__key};
    my $iPool = Img0ch::Pool::Thread->new( $iBBS, $key );
    $iPool->load();
    my $res     = $iPool->count() || return 0;
    my $iKernel = $zArchive->{__bbs}->get_kernel();
    my $iConfig = $iKernel->get_config();

    if ( !$iConfig->get('DynamicArchive') ) {
        my $subject = $iPool->subject();
        my $path    = $zArchive->path($key);
        my $html    = join '/', $path, $key . '.html';
        my $dat     = join '/', $path, $key . '.dat';

        if ( !-d $path ) {
            require File::Path;
            File::Path::mkpath($path) or $iKernel->throw_io_exception($path);
        }

        local ( $!, *FH );
        open *FH, ">${dat}"    ## no critic
            or $iKernel->throw_io_exception($dat);
        my $count = $iPool->count();
        my $stack = [];
        for ( my $i = 1; $i <= $count; $i++ ) {
            my $res     = $iPool->get($i);
            my $first   = $i == 1 ? 1 : 0;
            my $name    = $res->[0];
            my $mail    = $res->[1];
            my $id      = $res->[3];
            my $date    = $id ? ( join ' ', $res->[2], $id ) : $res->[2];
            my $comment = $res->[4];
            print {*FH} $name, '<>', $mail, '<>', $date, '<>', $comment, '<>',
                ( $first ? $subject : '' ), "\n"
                or $iKernel->throw_io_exception($dat);
            $comment =~ s{
                (ftp|https?)://
                ([A-Za-z0-9\-\.]+)/?
                ([-_.!~*'()a-zA-Z0-9;/?:\@\&=+\$,%#]*)/?
                }{<a href="$1://$2/$3">$1://$2/$3</a>}gxms;
            $comment =~ s{&gt;&gt;(\d+)(-)?(\d+)?}
                {<a href="#r$1">>>$1$2$3</a>}gxms;
            $comment =~ s{>>([\d\+\-,]+)}{&gt;&gt;$1}gxms;
            push @$stack,
                {
                isFirst => $first,
                index   => $i,
                resno   => $i,
                name    => $name,
                mail    => $mail,
                date    => $date,
                text    => $comment,
                };
        }
        close *FH or $iKernel->throw_io_exception($dat);

        require Img0ch::Setting;
        require Img0ch::Template;
        my $iSetting  = Img0ch::Setting->new($iBBS);
        my $iTemplate = Img0ch::Template->new(
            $iBBS,
            {   file    => 'archive',
                setting => $iSetting,
            }
        );
        $iTemplate->param(
            {   Subject => $subject,
                ZThread => $stack,
                Thread  => $stack,
                Date    => _format_date(time()),
            }
        );
        $iTemplate->save($html);
        $zArchive->set( $key, $res, $subject );
        $zArchive->_plugin( 'zeromin.archive.thread', $key );
    }

    return 1;
}

sub remove {
    my ( $zArchive, $key ) = @_;
    my $iRepos = $zArchive->{_repos};
    my $bbs    = $zArchive->{_bbs};

    $key ||= $zArchive->{__key};
    my $res = $iRepos->remove("I:A.${bbs}.${key}.res");

    if ($res) {
        my $iKernel = $zArchive->{_kernel};
        my $path    = $zArchive->path($key);
        my $html    = join '/', $path, $key . '.html';
        my $dat     = join '/', $path, $key . '.dat';
        if ( -w $dat ) {
            unlink $dat or $iKernel->throw_io_exception($dat);
        }
        if ( -w $html ) {
            unlink $html or $iKernel->throw_io_exception($html);
        }
        $iRepos->remove("I:A.${bbs}.${key}.subject");
        $zArchive->save();
        $zArchive->{_count}--;
        $zArchive->_plugin( 'zeromin.remove.archive', $key );
        return 1;
    }
    return 0;
}

sub update {
    my ($zArchive) = @_;
    my $iBBS       = $zArchive->{__bbs};
    my $iKernel    = $zArchive->{_kernel};
    my $path       = $iBBS->path('kako');

    -d $path or return 0;
    local ( $!, *DH );
    opendir *DH, $path or $iKernel->throw_io_exception($path);
    my @file = readdir *DH;
    closedir *DH or $iKernel->throw_io_exception($path);

    require Img0ch::Metadata;
    require Img0ch::Setting;
    require Img0ch::Template;
    my $banner   = Img0ch::Metadata->new($iBBS)->main_banner();
    my $title    = Img0ch::Setting->new($iBBS)->get('BBS_TITLE');
    my $found    = [];
    my $tmplargv = { file => 'archive_index' };
    for my $token (@file) {
        next if $token !~ /\A\d+\z/xms;
        my $_path = join '/', $path, $token;
        -d $_path or next;
        my $iTemplate = Img0ch::Template->new( $iBBS, $tmplargv );
        $zArchive->_update( $iTemplate, $token, $path, $title, \$banner );
        push @$found, { token => $token };
    }

    my $iTemplate = Img0ch::Template->new( $iBBS, $tmplargv );
    $iTemplate->param(
        {   Banner    => $banner,
            BBS_TITLE => $title,
            IsToken1  => 1,
            Tokens    => $found,
        }
    );
    $iTemplate->save("${path}/index.html");
    return 1;
}

sub path {
    my ( $zArchive, $key ) = @_;
    my $path = $zArchive->{__bbs}->path('kako');

    return $key
        ? join( '/', $path, ( substr $key, 0, 4 ), ( substr $key, 0, 5 ) )
        : $path;
}

sub to_array_with_page {
    my ( $zArchive, $item_per_page, $offset ) = @_;

    require Data::Page;
    my $entries = $zArchive->to_array();
    my $page = Data::Page->new( scalar @$entries, $item_per_page, $offset );
    return ( [ $page->splice($entries) ], $page );
}

sub _update {
    my ( $zArchive, $iTemplate, $token1, $dir, $title, $banner ) = @_;
    my $cache = $zArchive->{__cache} ||= $zArchive->to_array();
    my $found = [];
    my $min   = sprintf '%04d000000', $token1;
    my $max   = sprintf '%04d000000', $token1 + 1;
    for my $key ( @{$cache} ) {
        if ( $key > $min and $key <= $max ) {
            push @$found, $key;
        }
    }

    my $stack = [];
    for my $key ( @{$found} ) {
        my ( $subject, $res ) = @{$zArchive->get($key)};
        push @$stack,
            {
            token2  => substr( $key, 0, 5 ),
            key     => $key,
            date    => _format_date($key),
            subject => $subject,
            };
    }

    $iTemplate->param(
        {   Archives  => $stack,
            Banner    => $$banner,
            BBS_TITLE => $title,
            token1    => $token1,
            IsToken2  => 1,
        }
    );
    $iTemplate->save("${dir}/${token1}/index.html");
    return 1;
}

sub _format_date {
    my ($time) = @_;
    my @d = localtime($time);
    $d[5] += 1900;
    $d[4] += 1;
    return sprintf '%02d/%02d/%02d %02d:%02d:%02d', $d[5], $d[4], $d[3],
        $d[2], $d[1], $d[0];
}

sub _plugin {
    my ( $zArchive, $at, $key ) = @_;
    require Zeromin::Plugin;
    my $iBBS    = $zArchive->{__bbs};
    my $zPlugin = Zeromin::Plugin->new($iBBS);
    $zPlugin->do( $at, $zArchive, [ $iBBS, $key ] );
    return;
}

1;
__END__
