<%perl>;
# Output the header.
$m->comp('/widgets/wrappers/sharky/header.mc',
          title => $title,
          context => $context);

# Output the search widget.
my $obj_key = $type;
my ($groupList, $constrain);
my $behavior = $def->{$type}{behavior};
my $searchType = 'dual';
# Offer a list of groups to choose from, if this is a group manager.
if ($type eq 'grp') {
    # Set the constraint.
    $constrain = $def->{$type}{constrain};
    if ($ARGS{'search|alpha_cb'} || exists $ARGS{'search|substr_cb'}) {
        # It's a search. Reset the group type.
        $ARGS{grp_type} = 'all';
        set_state_data($type, 'prev_grp_type', undef);
    } elsif (exists $ARGS{grp_type} or
             $ARGS{grp_type} = get_state_data($type, 'prev_grp_type')) {
        # It's just a query by group type. Set the default obj_key and
        # set the behavior to ensure that the results are listed.
        $obj_key = $ARGS{grp_type} || 'grp';
        $behavior = 'narrow';
        set_state_data($type, 'prev_grp_type', $ARGS{'grp_type'});
    } else {
        # It's the first time accessing.
        $ARGS{grp} = 'all';
    }

    set_state_name($type, $obj_key);
    $groupList = $m->scomp('/widgets/profile/select.mc',
                            disp => 'Or Pick a Type',
                            options => \%grp_sel,
                            indent  => 140,
                            width   => 500,
                            value => $ARGS{grp_type} || 'all',
                            js => qq{onChange="location.href='} . $r->uri .
                                 "?grp_type=' + " .
                                 qq{escape(this.options[this.selectedIndex].value)"}
                           );
    # Set the type to the new value, if it has been submitted.
    $searchType = "triple";
} elsif ($type eq 'contrib') {
    my $ctype = $ARGS{ctype};

    # Set the constraint.
    $constrain = { %{ $def->{$type}{constrain} } };
    if ($ARGS{'search|alpha_cb'} || exists $ARGS{'search|substr_cb'}) {
        # They're doing a search. Use default constraints.
        $ctype = 'all';
    } elsif ($ctype) {
        # They're limiting it to a contributor type. Add it to the constraint
        # and set the behavior to ensure that the results are listed.
        $constrain->{grp_id} = $ctype unless $ctype eq 'all';
        $behavior = 'narrow';
    } else {
        # It's the first time accessing.
        $ctype = 'all';
    }

    $groupList = $m->scomp('/widgets/select_object/select_object.mc',
                            object => 'contrib_type',
                            field => 'name',
                            disp => 'Or Pick a Type',
                            default => ['all', 'All Contributors'],
                            constrain => { all => 1},
                            exclude => [Bric::Biz::Person->INSTANCE_GROUP_ID],
                            indent  => 140,
                            width   => 500,
                            selected => $ctype,
                            js => qq{onChange="location.href='} . $r->uri .
                                 "?ctype=' + " .
                                 qq{escape(this.options[this.selectedIndex].value)"}
                           );

    # Set the type to the new value, if it has been submitted.
    $searchType = "triple";
} elsif ($type eq 'category') {
    $searchType = 'singular';
}

$m->comp('/widgets/search/search.mc',
   object    => $type,
   field     => $def->{$type}{srch_field},
   type      => $searchType,
   groupList => $groupList
);

# Output a form tag if necessary.
if (defined $def->{$type}{select}) {
    $m->out(qq{<form method="post" action="${ \$r->uri }" name="manager"}
          . qq{onsubmit="return confirmDeletions()">});
}

$m->comp('/widgets/wrappers/sharky/table_top.mc',
          caption => $def->{$type}{title} || 'Existing %n',
          object  => $obj_key
);

# Output the list of found objects.
$m->comp('/widgets/listManager/listManager.mc',
    behavior => $behavior,
    object => $obj_key,
    profile => $prof_sub,
    fields => @$sites > 1 ? $def->{$type}{list_fields} : [ grep $_ ne 'site', @{ $def->{$type}{list_fields} } ],
    addition => $type eq 'pref' || $type eq 'job'
                ? undef
                : $obj_key eq 'contrib_type' ? $ct_add_sub : $add_sub,
    select => $def->{$type}{select},
    constrain => $constrain || $def->{$type}{constrain},
      field_titles => $def->{$type}{field_titles},
      field_values => $def->{$type}{field_values},
    alter => $def->{$type}{alter},
    exclude => $def->{$type}{exclude} || $excl_sub,
    sortBy => $def->{$type}{sort_by} );

$m->comp('/widgets/wrappers/sharky/table_bottom.mc');

# Output the form closing tag if necessary.
if (defined $def->{$type}{select} && $can_del) {
    if ($type ne "job") {
        $m->comp("/widgets/buttons/submit.mc",
                  disp      => 'Delete Checked',
                  name      => 'action',
                  button    => 'delete_checked_red',
                  useTable  => 0
                );
        $m->out(qq{\n</form>\n});
    } else {
        $m->comp("/widgets/buttons/submit.mc",
                  disp      => "$sel_label Checked",
                  name      => 'action',
                  button    => 'cancel_checked_red',
                  useTable  => 0
                );
        $m->out(qq{\n</form>\n});
    }
}

# Output the footer.
$m->comp('/widgets/wrappers/sharky/footer.mc', param => \%ARGS);

# Undef $can_del and $users for the next request.
($can_del, $users, $ets) = ();
</%perl>
<%init>;
# Figure out where we are.
my ($section, $mode, $type) = parse_uri($r->uri);

# Redirect if necessary.
$m->comp('/errors/404.mc') unless $type && $def->{$type};

# Set the title.
my $title = get_disp_name($type) . " Manager";
my $context = "Admin | Manager | " . get_class_info($type)->get_plural_name;

# Set the selection label and widget.
$sel_label = 'Delete';

if ($type eq 'job') {
    $sel_label = 'Cancel';
    $sel_widg = 'job|cancel_cb';
} elsif ($type eq 'alert_type') {
    $sel_widg = 'alert_type|delete_cb';
} elsif ($type eq 'workflow') {
    $sel_widg = 'workflow|delete_cb';
} elsif ($type eq 'dest') {
    $sel_widg = 'dest|delete_cb';
} elsif ($type eq 'site') {
    $sel_widg = 'site|delete_cb';
} else {
    $sel_widg = 'listManager|deactivate_cb';
}

$fmt = get_pref('List Name Format') if $type eq 'job' || $type eq 'alert_type';

my $prefix = '';
if ($type eq 'user') {
    # We'll probably need to redirect them to ssl if its enabled
    if (get_state_name('login') ne 'ssl') {
    my ($http, $p) = SSL_ENABLE ? ('https://', $ssl_port)
      : ('http://', $port);
    $prefix = $http . $r->hostname . $p;
    }
}

# We'll use this coderef to display the proper profile link labels.
my $prof_sub = sub {
    # Get the object ID.
    my $id = $_[0]->get_id;
    # Assume user can edit the profile.
    my $edit = ($type eq "contrib")
      ? ['Edit', "/admin/profile/$type/edit/$id", '']
      : ['Edit', "$prefix/admin/profile/$type/$id", ''];
    # Change the label to "Edit" if they can edit it.
    $edit->[0] = 'View' unless chk_authz($_[0], EDIT, 1)
      || ($type eq 'user' && $_[0]->get_id == get_user_id())
      || ($type eq 'alert_type' && $_[0]->get_owner_id == get_user_id());
    my $override = ($type eq "user" && chk_authz($_[0], EDIT, 1))
      ? ['Log In', '/', 'login|masquerade_cb='.$_[0]->get_login]
      : undef;
    return ($type ne 'contrib')
      ? ($override) ? [ $edit, [ 'Log', "/admin/events/$type/$id", ''], $override ]
                    : [ $edit, [ 'Log', "/admin/events/$type/$id", ''] ]
      : [ $edit, [$_[0]->all_for_subsys
                    ? ('New', "/admin/profile/contrib/extend/$id", '')
                    : ()
                 ],
                 [ 'Log', "/admin/events/$type/$id", ''] ];
};

# And we'll use this coderef to determine whether to include an Add link
# or not.
my $add_sub = sub {
    return chk_authz($_[0], CREATE, 1) ?
        ['Add', "$prefix/admin/profile/$type"] : undef;
};

my $ct_add_sub = sub {
    return chk_authz($_[0], CREATE, 1) ?
        ['Add', "$prefix/admin/profile/$type", 'Contributor Group'] : undef;
};

# Check where we were last.
my $changed = get_state_name('admin_mgr') || '';
set_state_name('admin_mgr', $type);
$changed = $changed eq $type ? 0 : 1;
</%init>
<%once>;
# We'll use this coderef below.
my $yes_no = sub { $lang->maketext( $_[0] ? 'Yes' : 'No'  ) };
my $site_name = sub { my $s=Bric::Biz::Site->lookup({id => $_[0]});
                      return $s->get_name
                  };
my $sites = $c->get('__SITES__') || Bric::Biz::Site->list({ active => 1 });
                  
# And we'll use this coderef to determine whether the user can delete objects.
my ($can_del, $users, $sel_label, $sel_widg, $ets);
my $sel_sub = sub {
    if (chk_authz($_[0], EDIT, 1)) {
    # User can delete.
    $can_del = 1;
    return [$sel_label, $sel_widg];
    }
    return undef;
};

# This coderef will be used for category delete checkboxes.
my $cat_sel_sub = sub {
    # Don't create a checkbox for the root category.
    &$sel_sub if ! $_[0]->is_root_category;
};

# We'll use this coderef to make sure the user can at least READ the object.
my $excl_sub = sub { ! chk_authz($_[0], READ, 1) };

# We'll use this for displaying a select list of groups.
my %grp_sel = Bric::Util::Grp->href_grp_class_keys;
$grp_sel{''} = ' All Groups'; # XXX The space makes it first in the list.
# XXX Make sure contrib_grp is properly re-labled.
$grp_sel{contrib_type} = 'Contributor Groups';
my $fmt;

# We'll use this coderef for displaying users.
my $usr_sub = sub {
    return unless $_[1] eq 'user_id';
    my $uid = $_[0]->get_user_id;
    my $u = $users->{$uid} ||= Bric::Biz::Person::User->lookup({ id => $uid });
    $u->format_name($fmt);
};

# And this one for owners.
my $owner_sub = sub {
    return unless $_[1] eq 'owner_id';
    my $uid = $_[0]->get_owner_id;
    my $u = $users->{$uid} ||= Bric::Biz::Person::User->lookup({ id => $uid });
    $u->format_name($fmt);
};

# For marking failed jobs as failed
my $job_name_sub = sub {
    my ($name, $job) = @_;
    if ($job->has_failed) {
        return qq{<span class="redLabel"><image src="/media/images/bang_red.gif" /> $name</span>};
    } else {
        return $name;
    }
};

# Deals with the job type and class
my $job_type_sub = sub {
    my ($type, $job) = @_;
    if (ref $job eq 'Bric::Util::Job::Dist') {
        return $type ? 'Expire' : 'Deliver';
    } else {
        return 'Publish';
    }
};

# We'll use these variables for redirection relative to the user profiles.
my $port = LISTEN_PORT == 80 ? '' : ':' . LISTEN_PORT;
my $ssl_port = SSL_PORT == 443 ? '' : ':' . SSL_PORT;

# Define the look and feel for each type of manager.
my $def = {
    user => {
        list_fields => [qw(name login)],
        srch_field  => 'lname',
        sort_by     => 'name',
        constrain   => {},
        behavior    => 'expand',
        select      => $sel_sub,
        field_values => sub {
            return unless $_[1] eq 'name';
            return shift->get_name( get_pref('List Name Format') );
        },
        exclude => sub {
            return if $_[0]->get_id == get_user_id;
            !chk_authz( $_[0], READ, 1 );
        },
    },
    org => {
        list_fields => [qw(name long_name description)],
        srch_field  => 'name',
        constrain   => { active => 1 },
        behavior    => 'expand',
        select      => $sel_sub,
    },
    grp => {
        title       => 'Group Manager',
        list_fields => [qw(name member_type)],
        srch_field  => 'name',
        behavior    => 'expand',
        sort_by     => 'name',
        constrain   => {},
        select      => sub {
            if (   chk_authz( $_[0], EDIT, 1 )
                && !$_[0]->get_permanent
                && $_[0]->get_id != ADMIN_GRP_ID )
            {
                $can_del = 1;
                return [ 'Delete', 'grp|deactivate_cb' ];
            }
            return undef;
        },
    },
    pref => {
        list_fields => [qw(name description val_name can_be_overridden)],
        select      => undef,
        behavior    => 'narrow',
        title       => '%n',
        srch_field  => 'name',
        constrain   => {},
        alter => {
            val_name          => sub { escape_html( $_[0] ) },
            can_be_overridden => $yes_no,
        },
    },
    media_type => {
        list_fields  => [qw(name extension)],
        field_titles => { extension => 'Extensions' },
        sort_by      => 'name',
        behavior     => 'expand',
        srch_field   => 'name',
        constrain    => { active => 1 },
        select       => $sel_sub,
        field_values => sub {
            return unless $_[1] eq 'extension';
            join( ', ', $_[0]->get_exts );
        },
        exclude => sub {
            return 1 if $_[0]->get_id == 0;
            !chk_authz( $_[0], READ, 1 );
        },
    },
    output_channel => {
        list_fields => [qw(name burner_name site description)],
        srch_field  => 'name',
        behavior    => 'narrow',
        constrain   => { active => 1 },
        select      => $sel_sub,
    },
    source => {
        list_fields => [qw(source_name description expire)],
        srch_field  => 'source_name',
        behavior    => 'narrow',
        constrain   => {},
        select      => $sel_sub,
    },
    contrib_type => {
        list_fields => [qw(name description)],
        srch_field  => 'name',
        sort_by     => 'name',
        behavior    => 'narrow',
        constrain   => { permanent => 0, secret => 1 },
        select      => $sel_sub,
    },
    alert_type => {
        list_fields  => [qw(name owner_id active)],
        srch_field   => 'name',
        behavior     => 'narrow',
        sort_by      => 'name',
        field_titles => { owner_id => 'Owner' },
        field_values => $owner_sub,
        constrain    => {},
        alter        => { active => $yes_no },
        select       => $sel_sub,
        exclude => sub {
            return if $_[0]->get_owner_id == get_user_id;
            !chk_authz( $_[0], READ, 1 );
        },
    },
    contrib => {
        list_fields => [qw(name type)],
        behavior    => 'expand',
        sort_by     => 'name',
        srch_field  => 'lname',
        constrain   => { no_grp_id => Bric::Biz::Person->INSTANCE_GROUP_ID },
        select      => $sel_sub,
        field_values => sub {
            return unless $_[1] eq 'name';
            shift->get_name( get_pref('List Name Format') );
        },
    },
    category => {
        list_fields => [qw(uri site name)],
        behavior    => 'expand',
        srch_field  => 'uri',
        constrain   => {},
        select      => $cat_sel_sub,
    },
    workflow => {
        list_fields => [qw(name type site)],
        behavior    => 'narrow',
        srch_field  => 'name',
        constrain   => {},
        select      => $sel_sub,
        field_values => sub {
            return unless $_[1] eq 'type';
            WORKFLOW_TYPE_MAP->{ $_[0]->get_type };
        },
    },
    dest => {
        list_fields => [qw(name site description publish preview)],
        behavior    => 'narrow',
        srch_field  => 'name',
        constrain   => { active => 1 },
        select      => $sel_sub,
        alter => {
            publish => $yes_no,
            preview => $yes_no,
        },
    },
    job => {
        list_fields  => [qw(name type user_id sched_time)],
        srch_field   => 'name',
        behavior     => 'narrow',
        title        => 'Pending %n',
        constrain    => { comp_time => undef },
        field_values => $usr_sub,
        select       => $sel_sub,
        sort_by      => 'sched_time',
        alter => {
            type => $job_type_sub,
            name => $job_name_sub,
        },
    },
    site => {
        list_fields => [qw(name domain_name)],
        behavior    => 'narrow',
        srch_field  => 'name',
        constrain   => { active => 1 },
        select      => $sel_sub,
    },
    keyword => {
        list_fields => [qw(sort_name name screen_name)],
        srch_field  => 'name',
        behavior    => 'expand',
        constrain   => { active => 1 },
        select      => $sel_sub,
    },
};

unless (Bric::Config::ENCODE_OK) {
    # Exclude the character set preference if we can't convert character sets.
    $def->{pref}{exclude} = sub { shift->get_name eq 'Character Set' };
}
</%once>
<%doc>
###############################################################################

=head1 NAME

/admin/manager/dhandler - Admin tools type manager

=head1 VERSION

$LastChangedRevision$

=head1 DATE

$LastChangedDate$

=head1 SYNOPSIS

<a href="/admin/manager/user">User Manager</a>

=head1 DESCRIPTION

This is the generalized admin manager for handling the administration of all
kinds of admin objects. It uses the URL to determine what type of object it's
administrating, and then takes care of the listing and search features.

</%doc>
