# +========================================================================+
# || Copyright (C) 2009 Christian Kuelker                                 ||
# ||                                                                      ||
# || License: GNU General Public License - GNU GPL - version 2            ||
# ||          or (at your opinion) any later version                      ||
# +========================================================================+
#  ID:       $Id$
#  Revision: $Revision$
#  Head URL: $HeadURL$
#  Date:     $Date$
#  Source:   $Source$

package CipUX::CAT::Web::Module::BasicAssignment;

use warnings;
use strict;
use Data::Dumper;
use Log::Log4perl qw(get_logger :levels);
use base qw(CipUX::CAT::Web::Module);

{

    use version; our $VERSION = qv('3.4.0.3');
    use re 'taint';    # Keep data captured by parens tainted
    delete @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};    # Make %ENV safer

    # CONST
    Readonly::Scalar my $EMPTY_STRING => q{};

    # Add this, after debugging this module entity, or remove permanently
    #    task_access.cgi             (list problem, too long names)
    #    object_class_assignment.cgi (not a sharp instrument)
    Readonly::Array my @MODULE => qw(
        admin_class_assignment.cgi
        teacher_class_assignment.cgi
        student_class_assignment.cgi
        module_access.cgi
        class_role_assignment.cgi
        admin_role_assignment.cgi
        teacher_role_assignment.cgi
        student_role_assignment.cgi
    );

    # this can not be used every where, update all if you change:
    Readonly::Scalar my $DEFAULT_MODULE => 'student_class_assignment.cgi';
    Readonly::Scalar my $TEMPLATE       => 'basic_assignment';
    Readonly::Scalar my $FIRST_LETTER   => 'A';

    Readonly::Hash my %ENTITY => (
        'task_access'              => 'task',
        'object_class_assignment'  => 'class_share',
        'admin_class_assignment'   => 'class_share',
        'student_class_assignment' => 'class_share',
        'teacher_class_assignment' => 'class_share',
        'module_access'            => 'cat_module',
        'class_role_assignment'    => 'role_account',
        'admin_role_assignment'    => 'role_account',
        'teacher_role_assignment'  => 'role_account',
        'student_role_assignment'  => 'role_account',

    );

    Readonly::Hash my %ENTITY_TYPE => (
        'admin_class_assignment'   => 'share',
        'object_class_assignment'  => 'share',
        'student_class_assignment' => 'share',
        'teacher_class_assignment' => 'share',
        'module_access'            => 'module',
        'task_access'              => '',
        'class_role_assignment'    => 'account',
        'admin_role_assignment'    => 'account',
        'teacher_role_assignment'  => 'account',
        'student_role_assignment'  => 'account',
    );

    Readonly::Hash my %LIST_ALL_TASK => (
        'module_access'            => 'cipux_task_list_role_accounts',
        'task_access'              => 'cipux_task_list_cat_modules',
        'object_class_assignment'  => 'cipux_task_list_user_accounts',
        'student_class_assignment' => 'cipux_task_list_student_accounts',
        'teacher_class_assignment' => 'cipux_task_list_teacher_accounts',
        'admin_class_assignment'   => 'cipux_task_list_admin_accounts',
        'class_role_assignment'    => 'cipux_task_list_class_shares',
        'admin_role_assignment'    => 'cipux_task_list_admin_accounts',
        'teacher_role_assignment'  => 'cipux_task_list_teacher_accounts',
        'student_role_assignment'  => 'cipux_task_list_student_accounts',
    );
    Readonly::Hash my %FLUSH => (
        'module_access'            => 1,
        'task_access'              => 1,
        'object_class_assignment'  => 0,
        'student_class_assignment' => 0,
        'teacher_class_assignment' => 0,
        'admin_class_assignment'   => 0,
        'class_role_assignment'    => 1,
        'admin_role_assignment'    => 1,
        'teacher_role_assignment'  => 1,
        'student_role_assignment'  => 1,
    );

    # TODO: get this from task or object layer!
    Readonly::Hash my %TARGET_ATTR => (
        'module_access'            => 'cipuxMemberRid',
        'object_class_assignment'  => 'memberUid',
        'student_class_assignment' => 'memberUid',
        'teacher_class_assignment' => 'memberUid',
        'admin_class_assignment'   => 'memberUid',
        'class_role_assignment'    => 'memberUid',
        'admin_role_assignment'    => 'memberUid',
        'teacher_role_assignment'  => 'memberUid',
        'student_role_assignment'  => 'memberUid',
    );

    # OBJECT
    # used in BUILD/new to pass entity from Comtroller.pm
    my %name_of :
        ATTR( init_arg => 'name' :default('student_class_assignment') );

    # GLOBAL
    my $task_hr           = {};
    my $cipux_entity      = $EMPTY_STRING;
    my $cipux_entity_type = $EMPTY_STRING;
    my $letter            = $FIRST_LETTER;
    my $target_attr       = $EMPTY_STRING;

    # METHOD
    sub register {

        my $self = shift;

        my $c = __PACKAGE__;    # module class name
        foreach my $m (@MODULE) {
            $self->set_module_name_register( { class => $c, name => $m } );
            $self->task_cfg($m);
            my $c_ar = $self->module_cfg($m);
            $self->set_module_cfg_register( { cfg_ar => $c_ar, name => $m } );
        }

        return 1;
    }

    sub module_cfg : CUMULATIVE(BASE FIRST) {

        my $self   = shift;
        my $module = shift;

        # somtimes there is no object in self. Probably wrong usage
        # by cipux_cat_module client?
        my $name = $self;
        if ( defined $module ) { $name = $module; }
        $name =~ s{\.cgi}{}smx;
        my $trans_name = $name;
        $trans_name =~ s{_}{ }gmx;

        my %desc  = ( $name => 'Basic ' . $trans_name );
        my $ldesc = "This module let you make assignments to $trans_name.";
        my %ldesc = ( $name => $ldesc );
        my $module_hr = {};
        $module_hr->{cipuxName}        = $trans_name;
        $module_hr->{cipuxTemplateDir} = $TEMPLATE;
        $module_hr->{cipuxIcon}        = 'assignment.png';
        if ( $name eq 'module_access' ) {
            $module_hr->{cipuxIcon} = 'module.png';
            $ldesc{$name} .= 'by adding and removing roles';
            $ldesc{$name} .= ' you can decide who has access.';
        }
        elsif ( $name eq 'task_access' ) {
            $module_hr->{cipuxIcon} = 'module.png';
            $ldesc{$name} .= 'by adding and removing CAT modules';
            $ldesc{$name} .= ' you can decide who has access.';
        }
        $module_hr->{cipuxDescription}      = $ldesc{$name};
        $module_hr->{cipuxShortDescription} = $desc{$name};

        # save all tasks for ACL
        foreach my $t (qw(add_member remove_member list list_member list_all))
        {
            if (    defined $name
                and exists $task_hr->{$name}
                and defined $t
                and exists $task_hr->{$name}->{$t} )
            {
                push @{ $module_hr->{cipuxTask} }, $task_hr->{$name}->{$t};
            }
            else {
                push @{ $module_hr->{cipuxTask} }, 'NULL';
            }
        }

        return [$module_hr];
    }

    sub task_cfg {

        my $self   = shift;    # TODO: sometimes not blessed, why?
        my $module = shift;

        # 'add member'    : cipux_task_add_member_to_<ENTITY>
        # 'remove member' : cipux_task_remove_member_from_<ENTITY>
        # 'list'          : cipux_task_list_<ENTITY>s
        # 'list_member'   : cipux_task_list_members_of_<ENTITY>
        # 'list_all'      : cipux_task_list_user_accounts

        # module_access.cgi => module_access
        $module =~ s{\.cgi}{}smx;

        $target_attr = $TARGET_ATTR{$module};

        #       = cat_module
        #       = class_share
        $cipux_entity = $ENTITY{$module};

        #            = module
        #            = share
        $cipux_entity_type = $ENTITY_TYPE{$module};

        #     = _cat_module
        my $e = '_' . $ENTITY{$module};

        my $prefix = 'cipux_task_';

        # 'list'       : cipux_task_list_<ENTITY>s
        $task_hr->{$module}->{list} = $prefix . 'list' . $e . 's';

        # 'list_all'   : cipux_task_list_user_accounts
        $task_hr->{$module}->{list_all} = $LIST_ALL_TASK{$module};

        # 'list_member': cipux_task_list_members_of_<ENTITY>
        $task_hr->{$module}->{list_member} = $prefix . 'list_members_of' . $e;

        # 'add'        : cipux_task_add_member_to_<ENTITY>
        $task_hr->{$module}->{add_member} = $prefix . 'add_member_to' . $e;

        # 'remove'     : cipux_task_remove_member_from_<ENTITY>
        $task_hr->{$module}->{remove_member}
            = $prefix . 'remove_member_from' . $e;

        return;
    }

    sub module {

        my ( $self, $arg_r ) = @_;
        my $rpc
            = ( exists $arg_r->{rpc_obj} )
            ? $arg_r->{rpc_obj}
            : $self->perr('rpc_obj');
        my $cgi
            = ( exists $arg_r->{cgi_obj} )
            ? $arg_r->{cgi_obj}
            : $self->perr('cgi_obj');
        my $lh
            = ( exists $arg_r->{lh_obj} )
            ? $arg_r->{lh_obj}
            : $self->perr('lh_obj');
        my $c_hr
            = ( exists $arg_r->{c_hr} )
            ? $arg_r->{c_hr}
            : $self->perr('c_hr');

        my $l = get_logger(__PACKAGE__);

        my $module = $name_of{ ident $self};
        $module =~ s{\.cgi}{}smx;
        $l->debug("module [$module]");

        my $modulecgi = $module . '.cgi';
        $l->debug("modulecgi [$modulecgi]");

        $target_attr = $TARGET_ATTR{$module};
        $l->debug("target_attr [$target_attr]");
        $cipux_entity = $ENTITY{$module};
        $l->debug("cipux_entity [$cipux_entity]");
        $cipux_entity_type = $ENTITY_TYPE{$module};
        $l->debug("cipux_entity type [$cipux_entity_type]");

        $l->debug('initialize forms');

        # initialize forms after ticket is known
        # form have to be defined first
        my $form = $self->_form(
            {
                page    => 'index',
                mode    => 'overview',
                rpc_obj => $rpc,
                lh_obj  => $lh,
                c_hr    => $c_hr,
                module  => $module,
            }
        );

        # | submitted
        # submitted values have to be checked second

        # read CGI values after form is defined (before redefined)
        my $mode
            = ( defined $form->field('mode') )
            ? $form->field('mode')
            : 'overview';
        $l->debug("read mode as [$mode]");

        $letter = ( defined $form->field('letter') )
            ? $letter
            = $form->field('letter')
            : $letter;

        $form->field(
            name  => 'letter',
            type  => 'hidden',
            value => "$letter",
            force => 1
        );
        $l->debug("letter $letter");

        my @object = $form->field( name => 'obj', cgi_value => 1 );
        my $oid    = $form->field( name => 'oid', cgi_value => 1 );

        my $flush_needed = 0;

        # submitted
        if ( $form->submitted ) {

            # ACTION: ADMIT
            if (   $form->submitted eq $lh->maketext('admit')
                && $form->validate )
            {
                $l->debug('action really admit (member)');
                foreach my $o (@object) {

                    my $p_hr = { object => $oid, value => $o };
                    $l->debug("object ID [$oid]");
                    $l->debug("value [$o]");

                    my $a_hr = $rpc->xmlrpc(
                        {
                            cmd      => $task_hr->{$module}->{add_member},
                            param_hr => $p_hr
                        }
                    );

                    if ( $a_hr->{status} eq 'TRUE' ) {

                        my $m = $lh->maketext(
                            'The object %s has been added to %s.');
                        $flush_needed = 1;

                    }
                    else {

                        # not able to set password
                        $self->wwarn( { number => '0-999-0023-999' } );
                    }

                }
            }

            # ACTION: DISMISS
            elsif ($form->submitted eq $lh->maketext('dismiss')
                && $form->validate )
            {
                $l->debug('action really dissmiss (member)');
                foreach my $o (@object) {

                    my $p_hr = { object => $oid, value => $o };
                    $l->debug("object ID [$oid]");
                    my $a_hr = $rpc->xmlrpc(
                        {
                            cmd      => $task_hr->{$module}->{remove_member},
                            param_hr => $p_hr
                        }
                    );

                    if ( $a_hr->{status} eq 'TRUE' ) {

                        $flush_needed = 1;
                        my $msg = $lh->maketext(
                            'Object %s has been removed from course %s.');
                    }
                    else {

                        $self->wwarn( { number => '0-999-0023-999' } );
                    }

                }
            }

            # LISTING: MEMBER (LIST)
            elsif ( $form->submitted eq $lh->maketext('list member') ) {
                $l->debug('list pushed');

                # no_gid_given
                my $oid = $form->field('oid')
                    || die 'No object Id (OID) given!';

                #           nextmode  list OID  Members
                $form = $self->_form(
                    {
                        page    => 'group',
                        mode    => 'list',
                        list    => 1,
                        oid     => $oid,
                        rpc_obj => $rpc,
                        lh_obj  => $lh,
                        c_hr    => $c_hr,
                        module  => $module,
                    }
                );
            }

            # LISTING: NON MEMBER (ADMIT)
            elsif ( $form->submitted eq $lh->maketext('admit member') ) {

                $l->debug('admit pushed');

                # no_gid_given
                my $oid = $form->field('oid')
                    || die 'No object ID (OID) given!';
                $l->debug("oid [$oid]");

                $form = $self->_form(
                    {
                        page    => 'group',
                        mode    => 'admit',
                        list    => 0,
                        oid     => $oid,
                        rpc_obj => $rpc,
                        lh_obj  => $lh,
                        c_hr    => $c_hr,
                        module  => $module,
                    }
                );
            }

            # LISTING: MEMBER (DISMISS,REMOVE)
            elsif ( $form->submitted eq $lh->maketext('dismiss member') ) {

                $l->debug('dismiss pushed');

                # no_gid_given
                my $oid = $form->field('oid')
                    || die 'No object ID (OID) given!';

                $form = $self->_form(
                    {
                        page    => 'group',
                        mode    => 'dismiss',
                        list    => 0,
                        oid     => $oid,
                        rpc_obj => $rpc,
                        lh_obj  => $lh,
                        c_hr    => $c_hr,
                        module  => $module,
                    }
                );
            }

            # INDEX
            else {
                $l->debug('OK pressed. go to index');
                $form = $self->_form(
                    {
                        page    => 'index',
                        mode    => 'overview',
                        rpc_obj => $rpc,
                        lh_obj  => $lh,
                        c_hr    => $c_hr,
                        module  => $module,
                    }
                );
            }
        }
        else {
            $l->debug('new page. go to index');
            $form = $self->_form(
                {
                    page    => 'index',
                    mode    => 'overview',
                    rpc_obj => $rpc,
                    lh_obj  => $lh,
                    c_hr    => $c_hr,
                    module  => $module,
                }
            );
        }

        if ( $FLUSH{$module} and $flush_needed ) {
            my $a_hr = $rpc->xmlrpc(
                {
                    cmd      => 'rpc_intern',
                    param_hr => { subcmd => 'flush', },
                }
            );

        }

        my $path = "tpl/$c_hr->{cat_theme}";

        return {
            cookie_hr => {},
            layout    => "$path/basic_assignment/layout.html",
            layout_ar => [
                { begin_html => 1, },
                {
                    body_ar => [ $lh->maketext('Basic Group Administration') ]
                },
                { formbuilder_hr => { form => $form, } },
                {
                    footer_hr =>
                        { show_index_back => 1, show_script_back => 0 },
                },
                { end_html => 1, },
            ],
        };

    }

    sub _form {

        # This function needs to be called before the query of CGI can return
        # values. The need to define the form in the first step is because the
        # object reference must be defined to evaluate if the form was
        # submitted.
        #
        # Therefore the definition (and redefinition) of fields must be the
        # least possible, because if a field is defined before the value is
        # queried the value is lost.
        #
        # The redefinition and definition of new fiels should be done just
        # before rendering the form.
        #
        # With FormBuilder it make not much sence to have more than one
        # form, because the object is global and the submitted query can
        # NOT distinguish well between different form objects.
        #

        my ( $self, $arg_r ) = @_;
        my $page
            = (     exists $arg_r->{page}
                and defined $arg_r->{page}
                and $arg_r->{page} )
            ? $self->l( $arg_r->{page} )
            : $self->perr('page');    # curr mode: list, create
        my $mode
            = ( exists $arg_r->{mode} and defined $arg_r->{mode} )
            ? $self->l( $arg_r->{mode} )
            : $self->perr('mode');  # next mode: {overview|list|admit|dismiss}
        my $list
            = ( exists $arg_r->{list} and defined $arg_r->{list} )
            ? $self->l( $arg_r->{list} )
            : 1;                    # 1 = list | 0 = {admit|dismiss}
        my $oid
            = ( exists $arg_r->{oid} and defined $arg_r->{oid} )
            ? $self->l( $arg_r->{oid} )
            : undef;
        my $rpc
            = ( exists $arg_r->{rpc_obj} )
            ? $arg_r->{rpc_obj}
            : $self->perr('rpc_obj');
        my $lh
            = ( exists $arg_r->{lh_obj} )
            ? $arg_r->{lh_obj}
            : $self->perr('lh_obj');
        my $c_hr
            = ( exists $arg_r->{c_hr} )
            ? $arg_r->{c_hr}
            : $self->perr('c_hr');
        my $module
            = ( exists $arg_r->{module} and defined $arg_r->{module} )
            ? $self->l( $arg_r->{module} )
            : $self->perr('module');

        my $l = get_logger(__PACKAGE__);
        $l->debug("mode [$mode]");
        $l->debug("page [$page]");

        my $path = "tpl/$c_hr->{cat_theme}";
        $l->debug("path [$path]");

        my $module_tr = $module;
        $module_tr =~ s{_}{ }gmx;

        my $form = CGI::FormBuilder->new(
            method => 'post',
            fields => [qw/oid/],

            #    validate   => {id => 'NAME'},
            #    require    => 'id',
            #],
            #params => $cgi,

            debug      => 0,
            keepextra  => 1,
            table      => 0,
            reset      => 0,
            sticky     => 0,
            stylesheet => "$path/form.css",
            template   => {
                type     => 'TT2',
                template => "$path/$TEMPLATE/$page.html",
                variable => 'form',
                data     => {
                    CIPUX_MODALITY    => $module,
                    CIPUX_MODALITY_TR => $module_tr,
                    SHOW_DEBUG        => 0,
                    TEMPLATE          => $TEMPLATE,
                    ICON              => 'assignment.png',
                    CIPUX_ENTITY_TYPE => $cipux_entity_type,
                    CIPUX_ENTITY      => $cipux_entity,
                    MODE              => $mode,
                    lh                => $lh,
                }
            },
        );
        my $member_ar = $EMPTY_STRING;
        $l->debug("mode eq [$mode]");
        if ( $mode eq 'overview' ) {
            $l->debug(' _form is overview');
            $form->submit(
                [
                    $lh->maketext('list member'),
                    $lh->maketext('admit member'),
                    $lh->maketext('dismiss member'),
                ]
            );

            my $a_hr = $rpc->xmlrpc(
                {
                    cmd      => $task_hr->{$module}->{list},
                    param_hr => {}
                }
            );

            my @course = sort keys %{ $a_hr->{cmdres_r} };

            $form->field(
                name    => 'group',
                options => \@course,
                force   => 1
            );
        }
        elsif ( $mode eq 'list' ) {
            $l->debug("go mode eq [$mode]");
            $form->submit( [ $lh->maketext('OK') ] );
            $form->field(
                name  => 'oid',
                value => "$oid",
                type  => 'static',
                force => 1
            );

            my $p_hr = { object => $oid };
            $l->debug('will exec cmd ['
                    . $task_hr->{$module}->{list_member}
                    . ']' );
            $l->debug("object ID [$oid]");
            $l->debug("rpc_obj [$rpc]");
            my $a_hr = $rpc->xmlrpc(
                {
                    cmd      => $task_hr->{$module}->{list_member},
                    param_hr => $p_hr
                }
            );
            $l->debug( 'rpc answer_hr ',
                { filter => \&Dumper, value => $a_hr } );
            $l->debug('evaluate answer');

            # 'cmdres_r' => {
            #    'index.cgi' => {
            #        'cipuxMemberRid' => [
            #            'admins'
            #        ],

            my @member
                = ref( $a_hr->{cmdres_r}->{$oid}->{$target_attr} ) eq 'ARRAY'
                ? sort @{ $a_hr->{cmdres_r}->{$oid}->{$target_attr} }
                : ();

            $l->debug( 'found [' . scalar @member . '] member' );
            foreach my $member (@member) {
                $l->debug("member [$member]");
            }

            $form->field(
                name    => 'obj',
                options => \@member,
                force   => 1
            );

            $form->field(
                name     => 'object',
                options  => \@member,
                force    => 1,
                multiple => 1
            );

    #my $cmd = 'cipux_task_retrieve_all_user_account_lastname_firstname_role';
            my $cmd = $LIST_ALL_TASK{$module};

         # TODO, code for old return value and parameter return_tpl_data => 1,
            my $return_tpl_data = {};

            $a_hr = $rpc->xmlrpc(
                {
                    cmd      => $cmd,
                    param_hr => $p_hr
                }
            );

            $form->tmpl_param( data => $return_tpl_data );
            $form->tmpl_param( test => 'hallo' );

        }
        elsif ( $mode eq 'admit' ) {

            # we would like to admit members
            $l->debug("enter mode [$mode]");

            $form->submit(
                [ $lh->maketext('admit'), $lh->maketext('cancel') ] );
            $form->field(
                name  => 'oid',
                value => "$oid",
                type  => 'static',
                force => 1
            );

            # [1] list all members of the group, to calulate
            #     what we can not admit later
            my $p_hr = { object => $oid };
            my $cmd = $task_hr->{$module}->{list_member};
            $l->debug("cmd [$cmd]");
            my $a_hr = $rpc->xmlrpc(
                {
                    cmd      => $cmd,
                    param_hr => $p_hr,
                }
            ) or die "RPC command [$cmd] failed!";
            $l->debug( 'rpc answer_hr ',
                { filter => \&Dumper, value => $a_hr } );
            my @member = sort @{ $a_hr->{cmdres_r}->{$oid}->{$target_attr} };
            if (    exists $a_hr->{cmdres_r}->{$oid}
                and exists $a_hr->{cmdres_r}->{$oid}->{$target_attr} )
            {
                push @member, @{ $a_hr->{cmdres_r}->{$oid}->{$target_attr} };
            }
            else {
                push @member, keys %{ $a_hr->{cmdres_r} };
            }
            $l->debug( 'member ', { filter => \&Dumper, value => \@member } );

            # [2] get all object as a set where we can choose from
            $cmd = $task_hr->{$module}->{list_all};
            $l->debug("list all cmd [$cmd]");
            $p_hr = {};
            $a_hr = $rpc->xmlrpc(
                {
                    cmd      => $cmd,
                    param_hr => $p_hr,
                }
            );
            $l->debug( 'rpc answer_hr ',
                { filter => \&Dumper, value => $a_hr } );

            my $return_hr = $rpc->extract_data_for_tpl(
                { answer_hr => $a_hr, use_ltarget => 1 } );
            my $tpl_data_ar = $return_hr->{tpl_data_ar};
            my $ltarget     = $return_hr->{ltarget};

            $l->debug( 'tpl_data_ar ',
                { filter => \&Dumper, value => $tpl_data_ar } );

            my @all = ();
            foreach my $anon_hash ( @{$tpl_data_ar} ) {
                foreach my $key ( keys %{$anon_hash} ) {
                    $l->debug("all key [$key] value [$anon_hash->{$key}]");
                    push @all, $anon_hash->{$key};
                }
            }

            # calculate difference quantity
            #my @all       = keys %{ $a_hr->{cmdres_r} };
            my %seen = map { $_ => 1 } @member;
            my @nonmember = sort grep { not exists $seen{$_} } @all;

            $form->field(
                name    => 'obj',
                options => \@nonmember,
                force   => 1
            );
            $form->field(
                name     => 'object',
                multiple => 1,
                options  => \@nonmember,
                force    => 1
            );
        }
        elsif ( $mode eq 'dismiss' ) {
            $l->debug("go mode eq [$mode]");
            $form->submit(
                [ $lh->maketext('dismiss'), $lh->maketext('cancel') ] );
            $form->field(
                name  => 'oid',
                value => "$oid",
                type  => 'static',
                force => 1
            );

            my $p_hr = { object => $oid };
            my $a_hr = $rpc->xmlrpc(
                {
                    cmd      => $task_hr->{$module}->{list_member},
                    param_hr => $p_hr
                }
            );

            my @member = sort @{ $a_hr->{cmdres_r}->{$oid}->{$target_attr} };

            $l->debug(' member_ar');
            $form->field(
                name    => 'obj',
                options => \@member,
                force   => 1
            );

            $form->field(
                name     => 'object',
                multiple => 1,
                type     => 'checkbox',
                options  => \@member,
                force    => 1
            );

        }
        $form->field(
            name  => 'mode',
            type  => 'static',
            value => "$mode",
            force => 1
        );
        $form->field(
            name  => 'module',
            type  => 'hidden',
            value => $module
        );

        $form->field(
            name  => 'letter',
            type  => 'hidden',
            value => "$letter"
        );

        $form->field(
            name  => 'showlist',
            type  => 'static',
            value => "$list",
            force => 1
        );

        return $form;
    }

}
1;

__END__

