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

package Zeromin2::App::vthread;

use strict;
use Img0ch::Thread::Virtual qw();

sub load_setting {
    my ($zApp) = @_;
    $zApp->privilege( 'can_remove_thread', 1 )
        or return $zApp->return_value(1);

    my $iBBS      = $zApp->bbs();
    my $key       = $zApp->key();
    my $iKernel   = $iBBS->get_kernel();
    my $iTVirtual = Img0ch::Thread::Virtual->new( $iBBS, $key );
    my $encoding  = $iKernel->get_encoding(1);

    my $max_length        = $iTVirtual->get_setting_string_max_length();
    my @setting_int_keys  = $iTVirtual->get_setting_integer_keys();
    my @setting_str_keys  = $iTVirtual->get_setting_string_keys();
    my @setting_hstr_keys = $iTVirtual->get_setting_hidden_string_keys();
    my @setting_bool_keys = $iTVirtual->get_setting_boolean_keys();
    my @all_keys          = (
        @setting_int_keys,  @setting_str_keys,
        @setting_hstr_keys, @setting_bool_keys
    );

    $zApp->add_template_param(
        {   BBS_TITLE => $iKernel->get_encoded_str(
                $iBBS->get_setting_instance()->get('BBS_TITLE'), 'utf8',
                $encoding
            ),
            SettingStringLengthMax => $max_length,
            Subject                => $iKernel->get_encoded_str(
                $iBBS->get_subject_instance()->get($key)->[0], 'utf8',
                $encoding,
            ),
            (   map {
                    (   $_ => $iKernel->get_encoded_str(
                            $iTVirtual->get_setting($_), 'utf8',
                            $encoding
                        )
                        )
                    } @all_keys
            ),
        }
    );
    return $zApp->return_value(0);
}

sub save_setting {
    my ($zApp) = @_;
    $zApp->check_csrf() or return $zApp->return_value(1);
    $zApp->privilege( 'can_remove_thread', 1 )
        or return $zApp->return_value(1);

    my $iBBS      = $zApp->bbs();
    my $key       = $zApp->key();
    my $iRequest  = $zApp->request();
    my $iSetting  = $iBBS->get_setting_instance();
    my $iKernel   = $iBBS->get_kernel();
    my $iTVirtual = Img0ch::Thread::Virtual->new( $iBBS, $key );
    my $encoding  = $iKernel->get_encoding(1);

    my $max_length        = $iTVirtual->get_setting_string_max_length();
    my @setting_int_keys  = $iTVirtual->get_setting_integer_keys();
    my @setting_str_keys  = $iTVirtual->get_setting_string_keys();
    my @setting_hstr_keys = $iTVirtual->get_setting_hidden_string_keys();
    my @setting_bool_keys = $iTVirtual->get_setting_boolean_keys();

    for my $setting_key (@setting_int_keys) {
        my $value   = $iRequest->param_int($setting_key);
        my $default = $iSetting->get_int($setting_key);
        $value > $default and $value = $default;
        $iTVirtual->set_setting( $setting_key,
            $value || $iTVirtual->get_setting_int($setting_key) );
    }
    for my $setting_key ( @setting_str_keys, @setting_hstr_keys ) {
        my $value = $iRequest->param($setting_key);
        my $len   = length $value;
        $iTVirtual->set_setting( $setting_key,
            ( $len and $len <= $max_length )
            ? $iKernel->get_encoded_str( $value, undef, 'utf8' )
            : $iTVirtual->get_setting($setting_key) );
    }
    for my $setting_key (@setting_bool_keys) {
        my $value = $iRequest->param($setting_key);
        $iTVirtual->set_setting( $setting_key, $value );
    }

    $iTVirtual->save();
    $zApp->add_template_param( { Done_vthread_save_setting => 1 } );
    $zApp->logger(
        1,
        'MODIFIED VIRTUAL THREAD SETTING: %s/%s',
        [ $iBBS->get_name(), $key ],
    );

    return load_setting($zApp);
}

sub load_access {
    my ($zApp) = @_;
    $zApp->privilege('can_enter_control_section')
        or return $zApp->return_value( 1, [] );

    my $iBBS      = $zApp->bbs();
    my $key       = $zApp->key();
    my $iKernel   = $iBBS->get_kernel();
    my $iTVirtual = Img0ch::Thread::Virtual->new( $iBBS, $key );
    my $encoding  = $iKernel->get_encoding(1);
    my $iConfig   = $iKernel->get_config();

    $zApp->add_template_param(
        {   BBS_TITLE => $iKernel->get_encoded_str(
                $iBBS->get_setting_instance()->get('BBS_TITLE'), 'utf8',
                $encoding
            ),
            DeniedHosts =>
                join( "\n", @{ $iTVirtual->get_denied_remote_host() } ),
            Subject => $iKernel->get_encoded_str(
                $iBBS->get_subject_instance()->get($key)->[0], 'utf8',
                $encoding,
            ),
        }
    );
    return $zApp->return_value(0);
}

sub save_access {
    my ($zApp) = @_;
    $zApp->check_csrf()                   or return $zApp->return_value(1);
    $zApp->privilege('can_add_access')    or return $zApp->return_value(1);
    $zApp->privilege('can_remove_access') or return $zApp->return_value(1);

    my $iBBS      = $zApp->bbs();
    my $key       = $zApp->key();
    my $iKernel   = $iBBS->get_kernel();
    my $iConfig   = $iKernel->get_config();
    my $iTVirtual = Img0ch::Thread::Virtual->new( $iBBS, $key );
    my $encoding  = $iKernel->get_encoding(1);
    my @denies    = split "\n", $zApp->request()->param('deny');

    map { $iTVirtual->remove_denial_remote_host($_) }
        @{ $iTVirtual->get_denied_remote_host() };
    map     { $iTVirtual->set_denial_remote_host($_) }
        map { trim($_) } @denies;                        ## no critic
    $iTVirtual->save();
    $zApp->add_template_param( { Done_vthread_save_access => 1 } );
    $zApp->logger(
        1,
        'MODIFIED VIRTUAL THREAD DENIED LIST: %s/%s',
        [ $iBBS->get_name(), $key ],
    );

    return load_access($zApp);
}

sub load_ngword {
    my ($zApp) = @_;
    $zApp->privilege('can_enter_control_section')
        or return $zApp->return_value( 1, [] );

    my $iBBS      = $zApp->bbs();
    my $key       = $zApp->key();
    my $iKernel   = $iBBS->get_kernel();
    my $iTVirtual = Img0ch::Thread::Virtual->new( $iBBS, $key );
    my $encoding  = $iKernel->get_encoding(1);

    my $iConfig = $iKernel->get_config();
    my $llimit  = $iConfig->get_int('vta.ngword_length_limit') || 50;
    my $climit  = $iConfig->get_int('vta.ngword_count_limit') || 100;

    $zApp->add_template_param(
        {   BBS_TITLE => $iKernel->get_encoded_str(
                $iBBS->get_setting_instance()->get('BBS_TITLE'), 'utf8',
                $encoding
            ),
            NGWords => join( "\n",
                map { $iKernel->get_encoded_str( $_, 'utf8', $encoding ) }
                    @{ $iTVirtual->get_ngwords() } ),
            NGWordLengthLimit => $llimit,
            NGWordCountLimit  => $climit,
            Subject           => $iKernel->get_encoded_str(
                $iBBS->get_subject_instance()->get($key)->[0], 'utf8',
                $encoding,
            ),
        }
    );
    return $zApp->return_value(0);
}

sub save_ngword {
    my ($zApp) = @_;
    $zApp->check_csrf() or return $zApp->return_value(1);
    $zApp->privilege('can_edit_ngword') or return $zApp->return_value(1);

    my $iBBS      = $zApp->bbs();
    my $key       = $zApp->key();
    my $iKernel   = $iBBS->get_kernel();
    my $iConfig   = $iKernel->get_config();
    my $iTVirtual = Img0ch::Thread::Virtual->new( $iBBS, $key );
    my $encoding  = $iKernel->get_encoding(1);

    my $llimit = $iConfig->get_int('vta.ngword_length_limit') || 50;
    my $climit = $iConfig->get_int('vta.ngword_count_limit')  || 100;
    my @ngwords = split "\n", $zApp->request()->param('ngword');

    if ( @ngwords <= $climit ) {
        map { $iTVirtual->remove_ngword($_) } @{ $iTVirtual->get_ngwords() };
        map { $iTVirtual->set_ngword($_) }
            map  { $iKernel->get_encoded_str( $_, $encoding, 'utf8' ) }
            grep { length($_) <= $llimit }
            map { trim($_) } @ngwords;    ## no critic
        $iTVirtual->save();
        $zApp->add_template_param( { Done_vthread_save_ngword => 1 } );
        $zApp->logger(
            1,
            'MODIFIED VIRTUAL THREAD NGWORDS: %s/%s',
            [ $iBBS->get_name(), $key ],
        );
    }
    else {
        return $zApp->return_value(2);
    }

    return load_ngword($zApp);
}

sub load_user {
    my ($zApp) = @_;
    $zApp->privilege( 'can_remove_thread', 1 )
        or return $zApp->return_value(1);

    my $iBBS      = $zApp->bbs();
    my $key       = $zApp->key();
    my $iKernel   = $iBBS->get_kernel();
    my $iTVirtual = Img0ch::Thread::Virtual->new( $iBBS, $key );
    my $encoding  = $iKernel->get_encoding(1);
    my $iConfig   = $iKernel->get_config();

    my $users          = $iTVirtual->get_users();
    my $priv_methods   = $iTVirtual->privilege_methods();
    my $is_admin       = $iTVirtual->administrator();
    my $all_privileges = $iTVirtual->all_privileges();
    my $users_value    = [ values %$users ];
    for my $user ( @{$users_value} ) {
        my $user_privilege = $user->{privilege};
        $user_privilege & $is_admin
            and $user_privilege = $all_privileges;
        $user->{name}
            = $iKernel->get_encoded_str( $user->{name}, 'utf8', $encoding );
        for my $priv_method ( @{$priv_methods} ) {
            my $value = $iTVirtual->$priv_method();
            $user_privilege & $value and $user->{$priv_method} = 1;
        }
    }

    $zApp->add_template_param(
        {   BBS_TITLE => $iKernel->get_encoded_str(
                $iBBS->get_setting_instance()->get('BBS_TITLE'), 'utf8',
                $encoding
            ),
            Users   => $users_value,
            Subject => $iKernel->get_encoded_str(
                $iBBS->get_subject_instance()->get($key)->[0], 'utf8',
                $encoding,
            ),
        }
    );
    return $zApp->return_value(0);
}

sub create_user {
    my ($zApp) = @_;
    $zApp->privilege( 'can_remove_thread', 1 )
        or return $zApp->return_value(1);

    my $iBBS     = $zApp->bbs();
    my $iKernel  = $iBBS->get_kernel();
    my $encoding = $iKernel->get_encoding(1);

    $zApp->add_template_param(
        {   BBS_TITLE => $iKernel->get_encoded_str(
                $iBBS->get_setting_instance()->get('BBS_TITLE'), 'utf8',
                $encoding
            ),
            Subject => $iKernel->get_encoded_str(
                $iBBS->get_subject_instance()->get( $zApp->key() )->[0],
                'utf8', $encoding,
            ),
        }
    );
    return $zApp->return_value(0);
}

sub edit_user {
    my ($zApp) = @_;
    $zApp->privilege( 'can_remove_thread', 1 )
        or return $zApp->return_value(1);

    my $iBBS      = $zApp->bbs();
    my $key       = $zApp->key();
    my $iKernel   = $iBBS->get_kernel();
    my $encoding  = $iKernel->get_encoding(1);
    my $iTVirtual = Img0ch::Thread::Virtual->new( $iBBS, $key );
    my $user      = $iTVirtual->get_user( $zApp->request()->param('id') );

    my $user_privilege = $user->{privilege};
    $user_privilege & $iTVirtual->administrator()
        and $user_privilege = $iTVirtual->all_privileges();
    for my $priv_method ( @{ $iTVirtual->privilege_methods() } ) {
        my $value = $iTVirtual->$priv_method();
        $user_privilege & $value and $user->{$priv_method} = 1;
    }

    $zApp->add_template_param(
        {   %$user,
            BBS_TITLE => $iKernel->get_encoded_str(
                $iBBS->get_setting_instance()->get('BBS_TITLE'), 'utf8',
                $encoding
            ),
            Subject => $iKernel->get_encoded_str(
                $iBBS->get_subject_instance()->get( $zApp->key() )->[0],
                'utf8', $encoding,
            ),
            id => $user->{id},
            name =>
                $iKernel->get_encoded_str( $user->{name}, 'utf8', $encoding ),
        }
    );
    return $zApp->return_value(0);
}

sub save_user {
    my ($zApp) = @_;
    $zApp->check_csrf() or return $zApp->return_value(1);
    $zApp->privilege( 'can_remove_thread', 1 )
        or return $zApp->return_value(1);

    my $iBBS      = $zApp->bbs();
    my $key       = $zApp->key();
    my $iKernel   = $iBBS->get_kernel();
    my $encoding  = $iKernel->get_encoding(1);
    my $iRequest  = $zApp->request();
    my $iTVirtual = Img0ch::Thread::Virtual->new( $iBBS, $key );

    my $pass = $iRequest->param('pass');
    $pass or return $zApp->return_value(3);
    my $confirm = $iRequest->param('confirm');
    $confirm or return $zApp->return_value(4);
    $pass eq $confirm or return $zApp->return_value(5);

    my $privilege_value  = 0;
    my @privilege_values = $iRequest->param('privilege');
    map { $privilege_value += Img0ch::Kernel::intval($_) } @privilege_values;

    my $user = $iTVirtual->get_user( $iRequest->param('id') );
    if ( defined $user->{id} ) {
        my $name = $user->{name};
        $iTVirtual->set_user( $name, $pass, $privilege_value );
        $zApp->logger(
            1,
            'EDIT VIRTUAL THREAD USER '
                . '( name=%s; pass=%s; privilege=%d ): %s/%s',
            [   $iKernel->get_encoded_str( $name, 'utf8', $encoding ),
                $pass, $privilege_value, $iBBS->get_name(), $key
            ],
        );
    }
    else {
        my $name_utf8 = $iRequest->param('name');
        $name_utf8 or return $zApp->return_value(2);
        my $name = $iKernel->get_encoded_str( $name_utf8, $encoding, 'utf8' );
        $iTVirtual->exists_user($name) and return $zApp->return_value(6);
        $iTVirtual->set_user( $name, $pass, $privilege_value );
        $zApp->logger(
            1,
            'CREATE VIRTUAL THREAD USER '
                . '( name=%s; pass=%s; privilege=%d ): %s/%s',
            [ $name_utf8, $pass, $privilege_value, $iBBS->get_name(), $key ],
        );
    }
    $iTVirtual->save();

    return $zApp->return_value(0);
}

sub remove_user {
    my ($zApp) = @_;
    $zApp->check_csrf() or return $zApp->return_value(1);
    $zApp->privilege( 'can_remove_thread', 1 )
        or return $zApp->return_value(1);

    my $iBBS      = $zApp->bbs();
    my $bbs       = $iBBS->get_name();
    my $key       = $zApp->key();
    my $iTVirtual = Img0ch::Thread::Virtual->new( $iBBS, $key );
    my @param     = $zApp->request()->param('id');

    for my $id (@param) {
        $iTVirtual->remove_user($id);
        $zApp->logger(
            1,
            'REMOVED VIRTUAL THREAD USER: %s at %s/%s',
            [ $id, $bbs, $key ],
        );
    }
    $iTVirtual->save();

    return $zApp->return_value(0);
}

sub trim {
    my ($str) = @_;
    $str =~ tr/\n\r\t//d;
    return $str;
}

1;
__END__
