%# BEGIN BPS TAGGED BLOCK {{{
%#
%# COPYRIGHT:
%#
%# This software is Copyright (c) 1996-2025 Best Practical Solutions, LLC
%#                                          <sales@bestpractical.com>
%#
%# (Except where explicitly superseded by other copyright notices)
%#
%#
%# LICENSE:
%#
%# This work is made available to you under the terms of Version 2 of
%# the GNU General Public License. A copy of that license should have
%# been provided with this software, but in any event can be snarfed
%# from www.gnu.org.
%#
%# This work is distributed in the hope that it will be useful, but
%# WITHOUT ANY WARRANTY; without even the implied warranty of
%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
%# General Public License for more details.
%#
%# You should have received a copy of the GNU General Public License
%# along with this program; if not, write to the Free Software
%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
%# 02110-1301 or visit their web page on the internet at
%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
%#
%#
%# CONTRIBUTION SUBMISSION POLICY:
%#
%# (The following paragraph is not intended to limit the rights granted
%# to you to modify and distribute this software under the terms of
%# the GNU General Public License and is only of importance to you if
%# you choose to contribute your changes and enhancements to the
%# community by submitting them to Best Practical Solutions, LLC.)
%#
%# By intentionally submitting any modifications, corrections or
%# derivatives to this work, or any other work intended for use with
%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
%# you are the copyright holder for those contributions and you grant
%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
%# royalty-free, perpetual, license to use, copy, create derivative
%# works based on those contributions, and sublicense and distribute
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
%# The SelectionBox Widget
%# 
%# SYNOPSIS
%#
%# <%init>:
%# my $sel = $m->comp ('/Widgets/SelectionBox:new',
%#                Action => me.html',
%#                Name => 'my-selection',
%#                Available => \@items,
%#                # you can do things with @{$sel->{Current}} in the 
%#                # OnSubmit callback
%#                OnSubmit => sub { my $sel = shift; },
%#                Selected => \@selected);
%#
%# $m->comp ('/Widgets/SelectionBox:process', %ARGS, self => $sel)
%#
%# where @items is an arrayref, each element is [value, label],
%# and @selected is an arrayref of selected values from @items.
%#
%# and in html:
%# <& /Widgets/SelectionBox:show, self => $sel &>
%#
%# if the SelectionBox is created with AutoSave option, OnSubmit will be called
%# on every button clicked
<%method new>
<%init>
$ARGS{_item_map} = {map {$_->[0] => $_->[1]} @{$ARGS{Available}}};
return \%ARGS;
</%init>
</%method>

<%method process>
<%init>
unless ($ARGS{$self->{Name}.'-Submit'}) {
    # init
    $self->{Current} = $self->{Selected};
    $self->{Selected} = [];
    return;
}

$self->{Selected} = $ARGS{$self->{Name}.'-Selected'};
if ($self->{Selected} && !ref($self->{Selected})) {
    $self->{Selected} = [$self->{Selected}];
}

my $current = $self->{Current} = $ARGS{$self->{Name}.'-Current'};
if ($current && !ref ($current)) {
    $current = [$current];
}

unless ($self->{ReadOnly}) {
    ++$self->{Modified};
    if ($ARGS{add}) {
        my $choosed = $ARGS{$self->{Name}.'-Available'};
        for my $add (ref($choosed) ? @$choosed : $choosed) {
            next if grep { $_ eq $add } @$current;
            push @$current, $add;
        }
    }

    if ($ARGS{remove}) {
        my $choosed = $ARGS{$self->{Name}.'-Selected'};
        for my $del (ref($choosed) ? @$choosed : $choosed) {
            @$current = map { $_ eq $del ? () : $_ } @$current;
        }
    }

    if ($ARGS{moveup} or $ARGS{movedown}) {
        my $offset = $ARGS{moveup} ? 1 : 0;
        my $choosed = $ARGS{$self->{Name}.'-Selected'};
        $choosed = [$choosed] unless ref ($choosed);
        my $canmove = 0; # not in the cornor
        for my $i ($ARGS{moveup} ? 0..$#{$current} : reverse 0..$#{$current}) {
            if (grep {$_ eq $current->[$i]} @$choosed) {
            if ($canmove) {
                splice (@$current, $i-$offset, 2,
                    @{$current}[$i+1-$offset,$i-$offset]);
            }
            }
            else {
            ++$canmove;
            }
        }
    }

    if ($ARGS{clear}) {
        $current = [];
    }

    $self->{Current} = $current;
}

@{$self->{Current}} = grep { exists $self->{_item_map}{$_} } @{$self->{Current}};

if ($self->{AutoSave} or $ARGS{$self->{Name}.'-Save'}) {
    $self->{OnSubmit}->($self);
    delete $self->{Modified};
}

</%init>
<%ARGS>
$self => undef
</%ARGS>

</%method>

<%method current>
% for (@{$self->{Current}}) {
<input type="hidden" class="hidden" name="<% $self->{Name} %>-Current" value="<%$_%>" />
% }
<%INIT>
</%INIT>
<%ARGS>
$self => undef
</%ARGS>

</%method>

<%method show>
<form method="post" action="<%$self->{Action}%>" name="SelectionBox-<% $name %>" id="SelectionBox-<% $name %>">
<input type="hidden" class="hidden" name="<% $self->{Name} %>-Submit" value="1" />
<& SelectionBox:current, self => $self &>
<&|/l&>Available</&>:
<br />
<select name="<%$name%>-Available" id="<%$name%>-Available" size="<%$size%>" multiple="multiple" class="selection-box">
% for (@{$self->{Available}}) {
<option value="<% $_->[0] %>"><% $_->[1] %></option>
% }
</select>

% unless ($self->{ReadOnly}) {
<input aria-label="Add" name="add" type="submit" class="button" value=" &rarr; " />
% }

<select name="<%$name%>-Selected" id="<%$name%>-Selected" size="<%$size%>" multiple="multiple" class="selection-box">
% for (@{$self->{Current}}) {
<option value="<% $_ %>"
% if (exists $selected{$_}) {
selected="selected"
% }
><% $self->{_item_map}{$_} ||'' %></option>
% }
</select>
% unless ($self->{'ReadOnly'}) {
% unless ($ARGS{'NoArrows'}) {
 <input aria-label="Move up" name="moveup" type="submit" class="button" value=" &uarr; " />
 <input aria-label="Move down" name="movedown" type="submit" class="button" value=" &darr; " />
% }
 <input name="remove" type="submit" class="button" value="<&|/l&>Delete</&>" />
% if ($ARGS{'Clear'}) {
 <input name="clear" type="submit" class="button" value="<&|/l&>Clear</&>" />
% }
% if ( $ARGS{'ShowUpdate'} ) {
 <input name="update" type="submit" class="button" value="<&|/l&>Update</&>" />
% }
% }

% my $caption = "";
% unless ($self->{'AutoSave'}) {
% if ($self->{Modified}) {
% $caption = loc('Selections modified. Please save your changes');
% }
<& /Elements/Submit, Caption => loc($caption), Label => loc('Save'), Name => $name.'-Save' &>
% }
</form>

<%ARGS>
$self => undef
$size => 10
</%ARGS>
<%INIT>
my $name = $self->{Name};
my %selected = map {$_ => 1} @{$self->{Selected}};
</%INIT>

</%method>
