package Bric::App::Callback::Perm;

use base qw(Bric::App::Callback);
__PACKAGE__->register_subclass;
use constant CLASS_KEY => 'perm';

use strict;
use Bric::App::Authz qw(:all);
use Bric::App::Event qw(log_event);
use Bric::App::Util qw(:aref :msg);
use Bric::Util::Priv::Parts::Const qw(:all);

my $type = 'perm';
my $disp_name = 'Permissions';
my $class = 'Bric::Util::Priv';
my $grp_class = 'Bric::Util::Grp';
my $not = {
    'usr' => 'obj',
    'obj' => 'usr',
};

my ($do_save);


sub save : Callback {
    my $self = shift;
    my $gid = $do_save->($self);
    $self->set_redirect("/admin/profile/grp/$gid")
      if defined $gid;
}

sub save_and_stay : Callback {
    &$do_save;
}

sub cancel : Callback {
    my $self = shift;
    my $gid = $self->params->{'grp_id'};
    $self->set_redirect("/admin/profile/grp/$gid");
}

###

$do_save = sub {
    my $self = shift;
    my $param = $self->params;

    # Assemble the relevant IDs.
    my $grp_ids = { usr => mk_aref($param->{usr_grp_id}),
                    obj => mk_aref($param->{obj_grp_id})
                };
    my $perm_ids = { usr => mk_aref($param->{usr_perm_id}),
                     obj => mk_aref($param->{obj_perm_id})
                 };
    # Instantiate the group object and check permissions.
    my $gid = $param->{grp_id};
    my $grp = $grp_class->lookup({ id => $gid });
    chk_authz($grp, EDIT);

    # Get the existing permissions for this group.
    my $perms = {
        (map { $_->get_id => $_ } $class->list({ obj_grp_id => $gid })),
        (map { $_->get_id => $_ } $class->list({ usr_grp_id => $gid })),
    };

    # Loop through each user group ID.
    my $chk;
    foreach my $type (qw(usr obj)) {
        my $i = 0;
        foreach my $ugid (@{$grp_ids->{$type}}) {
            if (my $perm_val = $param->{"$type|$ugid"}) {
                # There's a permssion value.
                if ($perm_ids->{$type}[$i]) {
                    # There's an existing permission object for this value.
                    my $perm = $perms->{$perm_ids->{$type}[$i]};
                    if ($perm->get_value != $perm_val) {
                        # The value is different. Make sure the user has
                        # permssion to change it by having permission to its
                        # objects already.
                        my $tgid = $type eq 'obj' ? $ugid : $gid;
                        unless (chk_authz(0, $perm_val, 1, $tgid)
                                || ($perm_val == DENY && chk_authz(0, READ, 1, $tgid))) {
                            add_msg('Permission to grant permission "[_1]" to group'
                                    . ' "[_2]" denied',
                                    Bric::Util::Priv->vals_href->{$perm_val},
                                    $perm->get_obj_grp->get_name);
                            return;
                        }

                        # Update it.
                        $perm->set_value($perm_val);
                        $perm->save;
                        $chk = 1;
                    }
                } else {
                    # There is no existing permission object. Make sure the
                    # user has permssion to create a new one by having
                    # permission to its objects already.
                    my $tgid = $type eq 'obj' ? $ugid : $gid;
                    unless (chk_authz(0, $perm_val, 1, $tgid)
                            || ($perm_val == DENY && chk_authz(0, READ, 1, $tgid))) {
                        my $bad_grp = Bric::Util::Grp->lookup({ id => $tgid });
                        add_msg('Permission to grant permission "[_1]" to group'
                                . ' "[_2]" denied',
                                Bric::Util::Priv->vals_href->{$perm_val},
                                $bad_grp->get_name);
                        return;
                    }

                    my $perm = $class->new({ "$not->{$type}_grp" => $gid,
                                             "${type}_grp"       => $ugid,
                                             value               => $perm_val
                                         });
                    $perm->save;
                    $chk = 1;
                }
            } elsif ($perm_ids->{$type}[$i]) {
                # There's an existing permisison. Delete it.
                my $perm = $perms->{$perm_ids->{$type}[$i]};
                $perm->del;
                $perm->save;
                $chk = 1;
            }
            $i++;
        }
    }

    if ($chk) {
        # Make sure all users update.
        $self->cache->set_lmu_time;
        # Log an event.
        log_event('grp_perm_save', $grp);
    }

    # Set a message and redirect!
    add_msg("$disp_name saved.");

    return $gid;
};


1;
