#/*
# *  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: Oekaki.pm 363 2007-03-16 15:11:10Z hikarin $
#

package Img0ch::Compat::App::Oekaki;

use strict;
use base qw(Img0ch::App::Note);

sub create_animation {
    my ( $iApp, $id ) = @_;
    my ( $key, $magic, $resno, $width, $height, $url );
    my $iRequest  = $iApp->request();
    my $iTemplate = $iApp->{__parent}->{animate}->($iApp);

    if (    $key = $iRequest->key()
        and $resno = $iRequest->param_int('resno') )
    {
        my $iBBS    = $iApp->bbs();
        my $iKernel = $iApp->kernel;
        my $iUpload = Img0ch::Upload->new( $iBBS, $key );
        if ( -r $iUpload->path( $resno, 'pch' ) ) {
            $url = $iUpload->url( $resno, 'pch' );
            $magic = 'P';
        }
        else {
            $url = $iUpload->url( $resno, 'spch' );
            $magic = 'S';
        }
        $iTemplate->param(
            {   AnimationFile    => $url,
                PaintBBSAsViewer => ( $magic eq 'P' ? 1 : 0 )
            }
        );
    }
    return $iTemplate;
}

sub load_pch {
    my ($iApp) = @_;
    my $iRequest = $iApp->request();
    $iRequest->init( $iApp->config() );

    my ( $file, $pch );
    if (    my $key = $iRequest->key()
        and my $resno = $iRequest->param_int('resno') )
    {
        my $iBBS     = $iApp->bbs();
        my $iKernel  = $iApp->kernel();
        my $iUpload  = Img0ch::Upload->new( $iBBS, $key );
        my $pch_file = $iUpload->path( $resno, 'pch' );
        if ( !-r $pch_file ) {
            $pch_file = $iUpload->path( $resno, 'spch' );
            if ( !-r $pch_file ) {
                return ( undef, 'application/octet-stream', \$pch );
            }
        }
        local ( *FH, $! );
        open *FH, $pch_file    ## no critic
            or $iKernel->throw_io_exception($pch_file);
        $pch = do { local $/; <FH> };
        close *FH or $iKernel->throw_io_exception($pch_file);
        return ( undef, 'application/octet-stream', \$pch );
    }
    return $iApp->{__parent}->{pch}->($iApp);
}

sub create_confirm_password {
    my ( $iApp, $key, $resno ) = @_;
    my $iRequest = $iApp->request();
    $key   ||= $iRequest->key();
    $resno ||= $iRequest->param_int('resno');

    my $iTemplate = $iApp->{__parent}->{confirm}->( $iApp, $key, $resno );
    if ( my $input = $iRequest->param('editpass') ) {
        require Img0ch::Thread;
        my $iThread = Img0ch::Thread->new( $iApp->bbs(), $key );
        $iThread->load();
        my $res       = $iThread->get($resno);
        my $trip_mark = $iApp->config()->get('multibyte.TRUE_TRIP')
            || pack( 'C*', ( 0x81, 0x9f ) );
        my $trip_column = $iApp->setting()->get_int('BBS_TRIP_COLUMN') || 10;
        $input = '#' . $input;
        $iApp->trip( \$input, $trip_column, $trip_mark );

        if ( index( $res->[0], $input ) >= 0 ) {
            $iTemplate
                = $iApp->{__parent}->{canvas}->( $iApp, $resno, 1, $input );
            return $iTemplate;
        }
        $iTemplate->param( { Failed => 1 } );
    }

    $iTemplate->param( { Compatible => 1 } );
    return $iTemplate;
}

sub search_drafts {
    my ( $iApp, $noCanvas ) = @_;
    my $iRequest = $iApp->request();
    my $key      = $iRequest->key();
    my $resno    = $iRequest->param_int('resno');
    if ( $key and $resno ) {
        my $iTemplate = $iApp->create_confirm_password( $key, $resno );
        return $iTemplate;
    }

    my $iConfig = $iApp->config();
    my $code    = $iApp->get_crypt();
    my $path    = $iConfig->get('OekakiTempPath')
        || $iConfig->get('BBSPath') . '/test/oekaki/';
    my $file = $iApp->search_from_directory( $path, $code );

    require Img0ch::Plugin::Module::Draft;
    my $iDraft = Img0ch::Plugin::Module::Draft->new( $iApp->kernel() );
    my $now    = $iRequest->now();
    my $ip     = $iRequest->ip();
    if ( keys %$file ) {
        require Img0ch::Upload;
        my $iKernel   = $iApp->kernel();
        my $spch      = $file->{spch};
        my $animation = $spch || $file->{pch};
        my $image     = $file->{jpg} || $file->{png};
        my $magic     = $spch ? 'S' : 'P';
        my ( $width, $height ) = Img0ch::Upload->get_dimensions($image);
        $iDraft->set_ip($ip);
        $iDraft->set_image( $iApp->slurp_binary($image) );
        $iDraft->set_image_type( $iApp->{__image_type} );
        $iDraft->set_animation( $iApp->slurp_binary($animation) );
        $iDraft->set_ellapse(0);
        $iDraft->set_last_modified($now);
        $iDraft->set_width($width);
        $iDraft->set_height($height);
        $iDraft->set_edit_pass('');
        $iDraft->set_applet_magic($magic);
        unlink $animation or $iKernel->throw_io_exception($animation);
        unlink $image     or $iKernel->throw_io_exception($image);
        $image =~ s{/([\w\+\-\=\_\.]+)\z}{/t_$1}xms;

        if ( -r $image ) {
            unlink $image or $iKernel->throw_io_exception($image);
        }
    }

    $iDraft->save();
    $iApp->{__parent}->{continue}->($iApp);
}

sub search_from_directory {
    my ( $iApp, $path, $code ) = @_;
    my $iKernel = $iApp->kernel();
    my $result  = {};
    local ( *DH, $! );

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

    require File::Spec;
    for my $found ( grep /\A$code.*?\.(?:jpg|png|s?pch)\z/xms, @file ) {
        my ( undef, $extension ) = split '\.', $found;
        $result->{$extension} = File::Spec->catfile( $path, $found );
    }
    return $result;
}

sub get_crypt {
    my ($iApp) = @_;
    my @IP = $iApp->request()->ip() =~ /\A(\d+)\.(\d+)\.(\d+)\.(\d+)\z/xms;
    my $IP1 = sprintf '%03d%03d', $IP[0], $IP[1];
    my $IP2 = sprintf '%03d%03d', $IP[2], $IP[3];
    my $code = substr( crypt( $IP1, 'Au' ), -6 )
        . substr( crypt( $IP2, 'Ag' ), -6 );
    $code =~ tr{./}{__};    # /
    $code;
}

sub slurp_binary {
    my ( $iApp, $path ) = @_;
    my $iKernel = $iApp->kernel();
    local ( *FH, $! );

    open *FH, "<${path}"    ## no critic
        or $iKernel->throw_io_exception($path);
    binmode *FH;
    my $buffer = do { local $/ = undef; <FH> };
    close *FH or $iKernel->throw_io_exception($path);
    return \$buffer;
}

sub available_methods {
    my ( $iApp, $methods ) = @_;
    $iApp->{__parent} = {};
    %{ $iApp->{__parent} } = %$methods;
    %$methods = (
        %$methods,
        animate       => \&create_animation,
        animation     => \&create_animation,
        canvas        => \&create_canvas,
        continue      => \&search_drafts,
        create_canvas => \&create_canvas,
        pch           => \&load_pch,
        picture       => \&create_confirm_password,
    );
    return $methods;
}

1;
__END__
