#/*
# *  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: File.pm 1181 2007-09-25 14:02:09Z hikarin $
#

package Img0ch::App::Search::File;

use strict;

sub new {
    my ( $iClass, $iKernel, @args ) = @_;
    bless {
        __bbs     => undef,
        __config  => $iKernel->get_config(),
        __kernel  => $iKernel,
        __resno   => 0,
        __request => Img0ch::Request->new(@args),
        __setting => undef,
    }, $iClass;
}

sub run {
    my ($iApp) = @_;
    $iApp->init() or return $iApp->redirect_error('init');

    my ( $result, $iTemplate, $ctype, $body );
    if ( my $word = $iApp->{__word} ) {
        ( $result, $iTemplate, $ctype, $body ) = $iApp->search($word);
    }
    else {
        ( $result, $iTemplate, $ctype, $body ) = $iApp->render();
    }

    $result or return $iApp->redirect_error();
    my $iRequest = $iApp->{__request};
    $iRequest->send_http_header( $ctype || 'text/html' );
    $iTemplate ? $iTemplate->flush() : $iRequest->print($body);
    return 1;
}

sub init {
    my ($iApp) = @_;
    my $iRequest = $iApp->{__request};
    $iRequest->init( $iApp->{__config} );

    my $bbs  = $iRequest->bbs();
    my $word = $iRequest->param('word');
    if ( my $path_info = $iRequest->path_info() ) {
        $path_info =~ s{\A/}{}xms;
        my @path = split '/', $path_info, 2;
        ( $path[0] || 'test' ) =~ /([\w\-]+)/xms;
        $bbs  = $1;
        $word = $path[1];
    }

    require Img0ch::BBS;
    my $iBBS = Img0ch::BBS->new( $iApp->{__kernel}, { bbs => $bbs, } );
    if ( !$iBBS->get_id() ) {
        $iApp->{__error} = 'INVALID_POST';
        return 0;
    }

    $iApp->{__bbs}     = $iBBS;
    $iApp->{__setting} = $iBBS->get_setting_instance();
    $iApp->{__upload}  = $iBBS->get_upload_instance(0);
    $iApp->{__word}    = $word;

    return 1;
}

sub search {
    my ( $iApp, $word ) = @_;
    my $iKernel = $iApp->{__kernel};

    require Data::Page::Navigation;
    $word = $iKernel->get_encoded_str($word);

    my $result = $iApp->{__upload}->get_tags($word);
    my ( $seen_b, $seen_s, $seen_u, $stack, $template_tags )
        = ( {}, {}, {}, [], {} );

    for my $file (@$result) {
        my ( $bbs, $key, $resno ) = @{$file};
        my $iBBS = $seen_b->{$bbs}
            ||= Img0ch::BBS->new( $iKernel, { bbs => $bbs } );
        my $iUpload = $seen_u->{$bbs} ||= $iBBS->get_upload_instance($key);
        my $iSubject = $seen_s->{$bbs};
        $iUpload->set_key($key);
        !$iSubject or $seen_s->{$bbs} = $iBBS->get_subject_instance();

        my ( $subject, $res ) = @{ $iSubject->get($key) };
        my ( $extension, $w, $h, $hash ) = @{ $iUpload->get($resno) };
        $extension or next;

        my ( $tw, $th ) = ( 0, 0 );
        my $thumb = $iUpload->get_thumbnail_size( $resno, \$tw, \$th );
        my $tp = $thumb ? $iUpload->url( "t${resno}", $extension ) : '';
        push @{$stack},
            {
            extension => $extension,
            width     => $w,
            width2    => $tw,
            height    => $h,
            height2   => $th,
            hash      => $hash,
            key       => $key,
            res       => $res,
            resno     => $resno,
            subject   => $subject,
            thumbnail => $thumb,
            thumbpath => $tp,
            url       => $iUpload->url( $resno, $extension ),
            },
            ;
    }

    my $iRequest      = $iApp->{__request};
    my $offset        = $iRequest->param_int('offset') || 1;
    my $item_per_page = $iRequest->param_int('entries') || 5;
    my $page  = Data::Page->new( scalar @$stack, $item_per_page, $offset );
    my $pages = [];
    map { push @$pages, { num => $_ } }
        $page->pages_in_navigation(
        $iApp->{__config}->get_int('search.pages_in_navigation') || 15 );

    %{$template_tags} = (
        Current        => $page->current_page(),
        Item           => $page->entries_per_page(),
        Next           => $page->next_page(),
        Pages          => $pages,
        Prev           => $page->previous_page(),
        Result         => [ $page->splice($stack) ],
        Total          => $page->total_entries(),
        Word           => $word,
        WordURLEscaped => $iRequest->escape_uri($word),
    );
    return $iApp->render($template_tags);
}

sub render {
    my ( $iApp, $template_tags ) = @_;
    my $iBBS     = $iApp->{__bbs};
    my $iConfig  = $iApp->{__config};
    my $iRequest = $iApp->{__request};
    my $iUpload  = $iApp->{__upload};
    $template_tags ||= {};

    require HTML::TagCloud;
    my $level = $iConfig->get_int('tagcloud.level') || 24;
    my $max   = $iConfig->get_int('tagcloud.max')   || 50;
    my $cloud = HTML::TagCloud->new( levels => $level );
    my $tags = $iUpload->get_tag_count();
    my $uri
        = $iRequest->get_app_uri() . '/img0ch-sf.cgi/' . $iBBS->get_name();
    while ( my ( $name, $count ) = each %$tags ) {
        $cloud->add( $name, join( '/', $uri, $iRequest->escape_uri($name) ),
            $count );
    }

    my $stack = [];
    for my $tag ( $cloud->tags($max) ) {
        push @$stack,
            {
            count => $tag->{count},
            level => $tag->{level},
            name  => $tag->{name},
            url   => $tag->{url},
            };
    }
    $template_tags->{TagCloud} = $stack;

    my $iMeta     = $iBBS->get_metadata_instance();
    my $iTemplate = $iBBS->get_template_instance(
        {   file    => 'search_image',
            request => $iRequest,
            setting => $iApp->{__setting},
        }
    );
    $iTemplate->param(
        {   Banner        => $iMeta->main_banner(),
            META          => $iMeta->meta(),
            TagCloudHTML  => $cloud->html($max),
            TagCloudCSS   => $cloud->css(),
            TagCloudLevel => [ map {$_} ( 1 .. $level ) ],
            %$template_tags,
        }
    );

    return ( 1, $iTemplate, 'text/html', undef, );
}

sub redirect_error {
    my ($iApp)   = @_;
    my $iKernel  = $iApp->{__kernel};
    my $iRequest = $iApp->{__request};
    my $key      = $iRequest->key();
    my $ip       = $iRequest->ip_int();

    require Img0ch::Error;
    my $iError = Img0ch::Error->new( $iKernel, $key, $ip );
    my $error = $iApp->{__error} || 'INVALID_POST';
    my $long = $iError->get($error);
    $iError->record();

    if ( $iRequest->param('js') ) {
        $iRequest->send_http_header( 'text/javascript', 'UTF-8' );
        $iRequest->print(
            $iRequest->get_json( { ok => 0, error => $error } ) );
    }
    else {
        require Img0ch::Template;
        my $iTemplate = Img0ch::Template->new(
            ( $iApp->{__bbs} || $iKernel ),
            {   file    => ('error'),
                request => $iRequest,
                setting => $iApp->{__setting},
            }
        );
        $iTemplate->param(
            {   Banner       => '',
                Flag         => 0,
                LongErrorStr => $long,
            }
        );
        my $iConfig = $iApp->{__config};
        my $charset = $iConfig->get('DefaultCharset');
        $iRequest->send_http_header( 'text/html', $charset );
        $iTemplate->flush();
    }
    return 0;
}

1;
__END__
