Diff for /loncom/interface/loncoursegroups.pm between versions 1.2 and 1.59

version 1.2, 2005/10/27 23:42:17 version 1.59, 2006/07/29 00:31:58
Line 1 Line 1
   # The LearningOnline Network with CAPA
   #
   # $Id$
 #  #
 # Copyright Michigan State University Board of Trustees  # Copyright Michigan State University Board of Trustees
 #  #
Line 29  use Apache::lonnet; Line 32  use Apache::lonnet;
 use Apache::loncommon;  use Apache::loncommon;
 use Apache::lonhtmlcommon;  use Apache::lonhtmlcommon;
 use Apache::lonlocal;  use Apache::lonlocal;
   use Apache::lonnavmaps;
   use Apache::longroup;
   use Apache::portfolio;
 use Apache::Constants qw(:common :http);  use Apache::Constants qw(:common :http);
   use lib '/home/httpd/lib/perl/';
   use LONCAPA;
   
 sub handler {  sub handler {
     my ($r) = @_;      my ($r) = @_;
   
     &Apache::loncommon::content_type($r,'text/html');      &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;      $r->send_http_header;
                                                                                   
     if ($r->header_only) {      if ($r->header_only) {
         return OK;          return OK;
     }      }
   
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},  
                                             ['action','state']);  
   
     $r->print(&header());  
   
     &Apache::lonhtmlcommon::clear_breadcrumbs();  
     &Apache::lonhtmlcommon::add_breadcrumb  
         ({href=>"/adm/groups",  
           text=>"Group Management",  
           faq=>9,bug=>'Instructor Interface',});  
     #  Needs to be in a course      #  Needs to be in a course
     if (! ($env{'request.course.fn'})) {      if (! ($env{'request.course.fn'})) {
         # Not in a course          # Not in a course
         $env{'user.error.msg'}=          $env{'user.error.msg'}=
             "/adm/groups:mdg:0:0:Cannot create, modify or delete course groups";       "/adm/coursegroups:mdg:0:0:Cannot edit or view course groups";
         return HTTP_NOT_ACCEPTABLE;          return HTTP_NOT_ACCEPTABLE;
     }      }
   
       &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                           ['action','refpage','state','groupname','branch']);
       my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
       my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
   
     my $view_permission =      my $view_permission =
         &Apache::lonnet::allowed('vcg',$env{'request.course.id'});            &Apache::lonnet::allowed('vcg',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''));
     my $manage_permission =      my $manage_permission =
         &Apache::lonnet::allowed('mdg',$env{'request.course.id'});            &Apache::lonnet::allowed('mdg',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''));
       &Apache::lonhtmlcommon::clear_breadcrumbs();
   
     if (! exists($env{'form.action'})) {      my $gpterm = &Apache::loncommon::group_term();
         $r->print(&Apache::lonhtmlcommon::breadcrumbs      my $ucgpterm = $gpterm;
                   (undef,'Course Group Manager'));      $ucgpterm =~ s/^(\w)/uc($1)/e;
         &print_main_menu($r,$manage_permission,$view_permission);      my $crstype = &Apache::loncommon::course_type();
     } elsif ($env{'form.action'} eq 'create' && $manage_permission) {  
       my %functions = (
                         email => 'E-mail',
                         discussion => 'Discussion boards',
                         chat => 'Chat',
                         files => 'File repository',
                         roster => 'Membership roster',
                         homepage => $ucgpterm.' home page',
                       );
   
       my %idx = ();
       $idx{id} = &Apache::loncoursedata::CL_ID();
       $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
       $idx{udom} = &Apache::loncoursedata::CL_SDOM();
       $idx{uname} = &Apache::loncoursedata::CL_SNAME();
       $idx{section} = &Apache::loncoursedata::CL_SECTION();
   
       my $action = $env{'form.action'};
       my $state = $env{'form.state'};
       if ((!defined($action)) || ($action eq 'view') || ($action eq 'modify')) {
           if (!defined($state)) {
               $state = 'view';
           }
       }
       if ($action eq 'create' || $action eq 'modify' || $action eq 'view') { 
           if ($view_permission || $manage_permission) {
               if ($state eq 'view') {
                   &print_main_menu($r,$cdom,$cnum,\%functions,\%idx,
                                    $view_permission,$manage_permission,
                                    $action,$state,$gpterm,$ucgpterm,$crstype);
               } else {
                   &group_administration($r,$action,$state,$cdom,$cnum,
                                         \%functions,\%idx,$view_permission,
                                         $manage_permission,$gpterm,$ucgpterm,
           $crstype);
               }
           } else {
               $r->print(&mt('You do not have [_1] administration '.
                             'privileges in this [_2]',$gpterm,lc($crstype)));
           }
       } else {
           &print_main_menu($r,$cdom,$cnum,\%functions,\%idx,$view_permission,
    $manage_permission,$action,$state,$gpterm,$ucgpterm,
    $crstype);
       }
       return OK;
   }
   
   sub print_main_menu {
       my ($r,$cdom,$cnum,$functions,$idx,$view_permission,$manage_permission,
    $action,$state,$gpterm,$ucgpterm,$crstype) = @_;
       my $jscript = qq|
   function changeSort(caller) {
       document.$state.sortby.value = caller;
       document.$state.submit();
   }\n|;
       $r->print(&header('Groups',$jscript,$action,$state));
       if ($env{'form.refpage'} eq 'enrl') {
         &Apache::lonhtmlcommon::add_breadcrumb          &Apache::lonhtmlcommon::add_breadcrumb
             ({href=>'/adm/coursegroups?action=create&state=',              ({href=>"/adm/dropadd",
               text=>"Create Group"});                text=>"Enrollment Manager"});
         $r->print(&Apache::lonhtmlcommon::breadcrumbs      }
                   (undef,'Create Group','Course_Create_Group'));      &Apache::lonhtmlcommon::add_breadcrumb
         if (! exists($env{'form.state'})) {          ({href=>"/adm/coursegroups",
             &first_creation_form($r);            text=>"Groups"});
         } elsif ($env{'form.state'} eq 'pick_members') {      $r->print(&Apache::lonhtmlcommon::breadcrumbs('Groups'));
             &second_creation_form($r);      &display_groups($r,$cdom,$cnum,$functions,$idx,$view_permission,
         } elsif ($env{'form.state'} eq 'complete') {      $manage_permission,$action,$state,$gpterm,$ucgpterm,
             &completed_creation($r);      $crstype);
       $r->print(&footer());
       return;
   }
   
   sub display_groups {
       my ($r,$cdom,$cnum,$functions,$idx,$view_permission,
           $manage_permission,$action,$state,$gpterm,$ucgpterm,$crstype) = @_;
       my %curr_groups = ();
       my %grp_info = ();
       my %actionlinks = (
         modify => '<a href="/adm/coursegroups?action=modify&refpage='.
                            $env{'form.refpage'}.'&state=pick_task&groupname=',
         view => '<a href="/adm/'.$cdom.'/'.$cnum.'/',
         delete => '<a href="/adm/coursegroups?action=delete&refpage='.
                            $env{'form.refpage'}.'&groupname=',
       );
       my %lt = &Apache::lonlocal::texthash( 
                             modify => 'Modify',
                             view   => 'View',
                             delete => 'Delete',
                             act    => 'Action',
                             gname  => 'Group Name',
                             desc   => 'Group Title',
                             crea   => 'Creator',
                             crtd   => 'Created',
                             last   => 'Last Modified',
                             func   => 'Collaborative Tools',
                             quot   => 'Quota (Mb)',
                             memb   => 'Members',
                             file   => 'Files',
                             dibd   => 'Discussion Boards',
                             dius   => 'Disk Use (%)',
                             nogr   => 'No groups exist.',
                             crng   => 'Create a new group',
                             alth   => 'Although your current role has privileges'.
                                       ' to view any existing groups in this'.
                                       lc($crstype).', you do not have privileges'.
                                       'to create new groups.',
                        );
       if ($view_permission) {
           if (!defined($action)) {
               $action = 'view';
           }
           my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
           if (%curr_groups) {
               if ($manage_permission) {
                   if (!exists($env{'form.refpage'})) { 
                       $r->print('<br /><a href="/adm/coursegroups?action=create">'.$lt{'crng'}.'</a>');
                   }
               }
               $r->print('<br /><br />');
       $r->print(&Apache::loncommon::start_data_table().
         &Apache::loncommon::start_data_table_header_row());
         
               $r->print(<<"END");
           <th>$lt{'act'}</th>
           <th><a href="javascript:changeSort('groupname')">$lt{'gname'}</a></th>
           <th><a href="javascript:changeSort('description')">$lt{'desc'}</a></th>
           <th><a href="javascript:changeSort('creator')">$lt{'crea'}</a></th>
           <th><a href="javascript:changeSort('creation')">$lt{'crtd'}</a></th>
           <th><a href="javascript:changeSort('modified')">$lt{'last'}</a></th>
           <th>$lt{'func'}</b></td>
           <th><a href="javascript:changeSort('quota')">$lt{'quot'}</a></th>
           <th><a href="javascript:changeSort('totalmembers')">$lt{'memb'}</a></th>
           <th><a href="javascript:changeSort('totalfiles')">$lt{'file'}</a></th>
           <th><a href="javascript:changeSort('boards')">$lt{'dibd'}</a></th>
           <th><a href="javascript:changeSort('diskuse')">$lt{'dius'}</a></th>
   END
       $r->print(&Apache::loncommon::end_data_table_header_row());
               my %Sortby = ();
               foreach my $group (sort(keys(%curr_groups))) {
                   %{$grp_info{$group}} = 
                                     &Apache::longroup::get_group_settings(
                                                            $curr_groups{$group});
                   my $members_result = &group_members($cdom,$cnum,$group,
                                                       \%grp_info);
                   my $port_path = '/userfiles/groups/'.$group.'/portfolio';
                   my $port_dir = &Apache::loncommon::propath($cdom,$cnum).$port_path;
                   my $totaldirs = 0;
                   my $totalfiles = 0;
                   &group_files($group,$port_dir,\$totalfiles,\$totaldirs);
                   $grp_info{$group}{'totalfiles'} = $totalfiles;
                   $grp_info{$group}{'totaldirs'} = $totaldirs;
                   my $diskuse = &Apache::lonnet::diskusage($cdom,$cnum,$port_dir);
                   if ($grp_info{$group}{'quota'} > 0) {
                       my $pct_use = 0.1 * $diskuse/$grp_info{$group}{'quota'};
                       $grp_info{$group}{'diskuse'} = sprintf("%.0f",$pct_use);
                   } else {
                       $grp_info{$group}{'diskuse'} = 'N/A';
                   }
                   my ($groupboards,$boardshash)=&Apache::longroup::get_group_bbinfo(
                                                                  $cdom,$cnum,$group);
                   $grp_info{$group}{'boards'} = scalar(@{$groupboards});
                   if ($env{'form.sortby'} eq 'groupname') {
                       push(@{$Sortby{$group}},$group);
                   } elsif ($env{'form.sortby'} eq 'description') {
                       push(@{$Sortby{$grp_info{$group}{'description'}}},$group);
                   } elsif ($env{'form.sortby'} eq 'creator') {
                       push(@{$Sortby{$grp_info{$group}{'creator'}}},$group);
                   } elsif ($env{'form.sortby'} eq 'creation') {
                       push(@{$Sortby{$grp_info{$group}{'creation'}}},$group);
                   } elsif ($env{'form.sortby'} eq 'modified') {
                       push(@{$Sortby{$grp_info{$group}{'modified'}}},$group);
                   } elsif ($env{'form.sortby'} eq 'quota') {
                       push(@{$Sortby{$grp_info{$group}{'quota'}}},$group);
                   } elsif ($env{'form.sortby'} eq 'totalmembers') {
                       push(@{$Sortby{$grp_info{$group}{'totalmembers'}}},
                                                                          $group);
                   } elsif ($env{'form.sortby'} eq 'totalfiles') {
                       push(@{$Sortby{$grp_info{$group}{'totalfiles'}}},$group);
                   } elsif ($env{'form.sortby'} eq 'boards') {
                       push(@{$Sortby{$grp_info{$group}{'boards'}}},$group);
                   } elsif ($env{'form.sortby'} eq 'diskuse') {
                       push(@{$Sortby{$grp_info{$group}{'diskuse'}}},$group);
                   } else {
                       push(@{$Sortby{$group}},$group);
                   }
               }
               foreach my $key (sort(keys(%Sortby))) {
                   foreach my $group (@{$Sortby{$key}}) {
                       my $description = 
    &unescape($grp_info{$group}{'description'});
                       my $creator = $grp_info{$group}{'creator'};
                       my $creation = $grp_info{$group}{'creation'};
                       my $modified = $grp_info{$group}{'modified'}; 
                       my $quota = $grp_info{$group}{'quota'};
                       my $totalmembers = $grp_info{$group}{'totalmembers'};
                       my $totalfiles = $grp_info{$group}{'totalfiles'};
                       my $totaldirs = $grp_info{$group}{'totaldirs'};
                       my $boards = $grp_info{$group}{'boards'};
                       my $diskuse = $grp_info{$group}{'diskuse'};
                       my $functionality;
                       foreach my $tool (sort(keys(%{$functions}))) {
                           if ($grp_info{$group}{functions}{$tool} eq 'on') {
                               $functionality .= ' '.$tool;
                           }
                       }
                       if (!$functionality) {
                           $functionality = &mt('None available');
                       }
                       my $link = $actionlinks{$action};
                       if ($action eq 'modify' || $action eq 'delete') {
                           $link .= $group;
                       } else {
                           $link .= $group.'/smppg?ref=grouplist';
                           if (exists($env{'form.refpage'})) {
                               $link .= '&amp;refpage='.$env{'form.refpage'};
                           }
                       }
                       $link .= '">'.$lt{$action}.'</a>';
                       if ($action eq 'view') { 
                           if (($manage_permission) && 
                               ($env{'form.refpage'} ne 'enrl')) {
                               $link .= '&nbsp;&nbsp;'.$actionlinks{'modify'}.
                                         $group.'">'.$lt{'modify'}.'</a>';
                           }
                       }
                       $r->print(&Apache::loncommon::start_data_table_row('LC_data_table_dense').
         '<td>'.$link.'</td>'.
         '<td>'.$group.'</td>'.
         '<td>'.$description.'</td>'.
         '<td>'.$creator.'</td>'.
         '<td>'. &Apache::lonnavmaps::timeToHumanString($creation).'</td>'.
         '<td>'. &Apache::lonnavmaps::timeToHumanString($modified).'</td>'.
         '<td>'.$functionality.'</td>'.
         '<td align="right">'.$quota.'</td>'.
         '<td align="right">'.$totalmembers.'</td>'.
         '<td align="right"><nobr>'.&mt('Files: ').$totalfiles.'</nobr><br /><nobr>'.&mt('Folders: ').$totaldirs.'</nobr></td>'.
         '<td align="right">'.$boards.'</td>'.
         '<td align="right">'.$diskuse.'</td>'.
         &Apache::loncommon::end_data_table_row());
                   }
               }
               $r->print(&Apache::loncommon::end_data_table());
               $r->print('<input type="hidden" name="refpage" '.
                         'value="'.$env{'form.refpage'}.'" />');
               if ($action eq 'view') {
                   if (!defined($state)) {
                       $state = 'view';
                   }
                   $r->print('<input type="hidden" name="state" value="'.
                         $state.'" />');
               }
           } else {
               $r->print($lt{'nogr'});
               if ($manage_permission) {
                   if (!exists($env{'form.refpage'})) {
                       $r->print('<br /><br /><a href="/adm/coursegroups?action=create">'.$lt{'crng'}.'</a>');
                   }
               } else {
                   $r->print('<br /><br />'.$lt{'alth'});
   
               }
           }
       } else {
           my @coursegroups = split(/:/,$env{'request.course.groups'});
           if (@coursegroups > 0) {
               $r->print('<br /><br />');
               my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
               if (%curr_groups) {
                   foreach my $group (@coursegroups) {
                       my %group_info =  &Apache::longroup::get_group_settings(
                                           $curr_groups{$group});
                       my $description = &unescape(
                                           $group_info{description});
                       $r->print('<font size="+1"><a href="/adm/'.$cdom.'/'.$cnum.'/'.$group.'/smppg?ref=grouplist">'.$group,'</a><font><br /><small>'.$description.'</small><br /><br />');
                   }
               }
           } else {
               $r->print(&mt('You are not currently a member of any '.
                             'active [_1]s in this [_2]',$gpterm,
                             lc($crstype)));
           }
       }
       return;
   }
   
   sub group_administration {
       my ($r,$action,$state,$cdom,$cnum,$functions,$idx,$view_permission,
    $manage_permission,$gpterm,$ucgpterm,$crstype) = @_;
       my %sectioncount = ();
       my @tools = ();
       my @types = ();
       my @roles = ();
       my @sections = ();
       my @buildsections = ();
       my %users = ();
       my %userdata = ();
       my @members = ();
       my %usertools = ();
       my %stored = ();
       my %memchg;
       my @member_changes = ('deletion','expire','activate','reenable',
                             'changefunc','changepriv');
       my ($groupname,$description,$startdate,$enddate,$granularity,$specificity,
           $quota,$validate_script);
   
       if (defined($env{'form.groupname'})) {
           $groupname = $env{'form.groupname'};
       }
   
       if (($action eq 'create') && ($state eq '')) {
           $state = 'pick_name';
       }
       if (($action eq 'create') || 
           (($action eq 'modify') && ($state eq 'chgresult'))) { 
           ($startdate,$enddate) = &get_dates_from_form();
           if (defined($env{'form.description'})) {
               $description = $env{'form.description'};
           }
           if (defined($env{'form.tool'})) {
               @tools=&Apache::loncommon::get_env_multiple('form.tool');
           }
           if (defined($env{'form.granularity'})) {
               $granularity=$env{'form.granularity'};
           }
           if (defined($env{'form.specificity'})) {
               $specificity=$env{'form.specificity'};
           }
           if (defined($env{'form.quota'})) {
               $quota=$env{'form.quota'};
           }
       }
       if (($action eq 'create') || (($action eq 'modify') 
           && (($state eq 'pick_privs') || ($state eq 'addresult')))) {
           if (defined($env{'form.member'})) {
               @members = &Apache::loncommon::get_env_multiple('form.member');
               foreach my $user (@members) {
                   %{$usertools{$user}} = ();
               }
           }
       }
   
       if ($action eq 'modify') {
           if ($state eq '') {
               if (defined($env{'form.groupname'})) {
                   $state = 'pick_task';
               }
         } else {          } else {
             &first_creation_form($r);              %stored = &retrieve_settings($cdom,$cnum,$groupname);
               if (ref($stored{'types'}) eq 'ARRAY') {
                   @types = @{$stored{'types'}};
               }
               if (ref($stored{'roles'}) eq 'ARRAY') {
                   @roles = @{$stored{'roles'}};
               }
               if (ref($stored{'sectionpick'}) eq 'ARRAY') {
                   @sections = @{$stored{'sectionpick'}};
               }
               unless ($state eq 'chgresult') {
                   if (ref($stored{'tool'}) eq 'ARRAY') { 
                       @tools = @{$stored{'tool'}};
                   }
                   $startdate = $stored{'startdate'};
                   $enddate = $stored{'enddate'};
                   $description = $stored{'description'};
                   $granularity = $stored{'granularity'};
                   $specificity =  $stored{'specificity'};
                   $quota = $stored{'quota'};
               }
           }
       }
   
       my $toolprivs = &Apache::longroup::get_tool_privs($gpterm);
   
       my $fixedprivs = &Apache::longroup::get_fixed_privs();
   
       my %elements = 
    (
    create => {
        pick_name => {
    startdate_month  => 'selectbox',
    startdate_hour   => 'selectbox',
    enddate_month    => 'selectbox',
    enddate_hour     => 'selectbox',
    startdate_day    => 'text',
    startdate_year   => 'text',
    startdate_minute => 'text',
    startdate_second => 'text',
    enddate_day      => 'text',
    enddate_year     => 'text',
    enddate_minute   => 'text',
    enddate_second   => 'text',
    groupname        => 'text',
    description      => 'text',
                    quota            => 'text',
    tool             => 'checkbox',
    granularity      => 'radio',
    no_end_date      => 'checkbox',
        },
        pick_members => {
    member          => 'checkbox',
    defpriv         => 'checkbox',
        },
    },
    );
       
       $elements{'modify'} = {
    change_settings => {
       %{$elements{'create'}{'pick_name'}},
       specificity => 'radio',
       defpriv     => 'checkbox',
       autorole    => 'checkbox',
       autoadd     => 'radio',
       autodrop    => 'radio',
    },
    add_members => {
       types       => 'selectbox',
       roles       => 'selectbox',
    },
       };
   
       if (ref($stored{'autorole'}) eq 'ARRAY') {
           foreach my $role (@{$stored{'autorole'}}) {
               unless ($role eq 'cc') {
                   $elements{'modify'}{'change_settings'}{'sec_'.$role} = 
                                                                      'selectbox';
               }
           }
       }
   
       if (($action eq 'create') && ($state eq 'pick_name')) {
           $elements{'create'}{'pick_name'}{'types'} = 'selectbox';
           $elements{'create'}{'pick_name'}{'roles'} = 'selectbox';
       }
       if ((($action eq 'create') &&  
           (($state eq 'pick_name') || ($state eq 'pick_privs'))) ||
          (($action eq 'modify') && (($state eq 'change_settings') ||
                                     ($state eq 'add_members')))) {
           %sectioncount = &Apache::loncommon::get_sections($cdom,$cnum);
           $elements{'create'}{'pick_name'}{'sectionpick'} = 'selectbox';
           $elements{'modify'}{'change_mapping'}{'sectionpick'} = 'selectbox';
           $elements{'modify'}{'add_members'}{'sectionpick'} = 'selectbox';
       }
   
       if (($action eq 'create') || 
           ($action eq 'modify' && $state eq 'pick_members')) {
           if (defined($env{'form.types'})) {
               @types=&Apache::loncommon::get_env_multiple('form.types');
           }
           if (defined($env{'form.roles'})) {
               @roles=&Apache::loncommon::get_env_multiple('form.roles');
           }
           if (defined($env{'form.sectionpick'})) {
               @sections=&Apache::loncommon::get_env_multiple('form.sectionpick');
               if (grep/^all$/,@sections) {
                   @buildsections = sort {$a cmp $b} keys(%sectioncount);
               } else {
                   @buildsections = @sections;
               }
           }
       }
   
       if (($state eq 'pick_members') || ($state eq 'pick_privs') || ($state eq 'change_privs')) {
           &build_members_list($cdom,$cnum,\@types,\@roles,\@buildsections,\%users,
                               \%userdata);
       }
       if ($state eq 'pick_members') {
           if ((keys(%users) > 0) && (@tools > 0)) {
               if ($granularity eq 'Yes') {
                   $elements{$action}{'pick_members'}{'togglefunc'} = 'checkbox';
               }
               foreach my $tool (@tools) {
                   if ($granularity eq 'Yes') {
                       $elements{$action}{'pick_members'}{'user_'.$tool} = 'checkbox';
                   }
               }
               $elements{$action}{'pick_members'}{'specificity'} = 'radio';
           }
       }
       if ($state eq 'change_members') {
           my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
                                                                  $groupname);
           my $now = time;
           my $num_expire = 0;
           my $num_activate = 0;
           my $num_reenable = 0;
           my $num_deletion = 0;
           my $numusers = 0;
           foreach my $key (sort(keys(%membership))) {
               if ($key =~ /^\Q$groupname\E:([^:]+:[^:]+)$/) {
                   my $user = $1;
                   my($end,$start,@userprivs) = split(/:/,$membership{$key});
                   unless ($start == -1) {
                       $numusers ++;
                       $num_deletion ++;
                       if (($end > 0) && ($end < $now)) {
                           $num_reenable ++;
                           next;
                       } elsif (($start > $now)) {
                           $num_activate ++;
                           next;
                       } else {
                           $num_expire ++;
                           next;
                       }
                       next;
                   }
                   if ($num_reenable && $num_activate && $num_expire) {
                       last;
                   }
               }
           }
           if ($num_deletion) {
               $elements{$action}{'change_members'}{'deletion'} = 'checkbox';
           }
           if ($num_expire) {
               $elements{$action}{'change_members'}{'expire'} = 'checkbox';
           }
           if ($num_activate) {
               $elements{$action}{'change_members'}{'activate'} = 'checkbox';
           }
           if ($num_reenable) {
               $elements{$action}{'change_members'}{'reenable'} = 'checkbox';
           }
           if ($numusers) {
               if ($granularity eq 'Yes') {
                   $elements{$action}{'change_members'}{'togglefunc'} = 'checkbox';
               }
               foreach my $tool (@tools) {
                   if ($granularity eq 'Yes') {
                       $elements{$action}{'change_members'}{'user_'.$tool} = 'checkbox';
                   }
               }
               if ($specificity eq 'Yes') {
                   $elements{$action}{'change_members'}{'changepriv'} = 'checkbox';
               }
           }
       }
   
       if (($state eq 'pick_privs') || ($state eq 'change_privs') ||
            (($specificity eq 'No') && 
             ($state eq 'memresult' || $state eq 'result' || $state eq 'addresult'))) { 
           foreach my $tool (@tools) {
               my @values = &Apache::loncommon::get_env_multiple('form.user_'.$tool);
               foreach my $user (@values) {
                   if ($state eq 'pick_privs' || $state eq 'result' 
                       || $state eq 'addresult') {
                       if (!grep(/^\Q$user\E$/,@members)) {
                           next;
                       }
                   }
                   unless(exists($usertools{$user}{$tool})) {
                       $usertools{$user}{$tool} = 1;
                   }
               }
           }
       }
   
       if (($action eq 'modify') && (($state eq 'change_privs') || ($state eq 'memresult'))) {
           foreach my $chg (@member_changes) {
               if (defined($env{'form.'.$chg})) {
                   @{$memchg{$chg}} = &Apache::loncommon::get_env_multiple('form.'.$chg);
               }
           }
                                                                                 
           if ($state eq 'change_privs') {
               my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
                                                                      $groupname);
               my $now = time;
               foreach my $key (sort(keys(%membership))) {
                   if ($key =~ /^\Q$groupname\E:([^:]+:[^:]+)$/) {
                       my $user = $1;
                       my $changefunc = 0;
                       my ($end,$start,@userprivs) = split(/:/,$membership{$key});
                       unless ($start == -1) {
                           if (($end > 0) && ($end < $now)) {
                               unless (grep/^$user$/,$memchg{'reenable'}) {
                                   next;
                               }
                           }
                           my @currtools = ();
                           if (@userprivs > 0) {
                               foreach my $tool (sort(keys(%{$fixedprivs}))) {
                                   foreach my $priv (keys(%{$$fixedprivs{$tool}})) {
                                       if (grep/^$priv$/,@userprivs) {
                                           push(@currtools,$tool);
                                           last;
                                       }
                                   }
                               }
                           }
                           foreach my $tool (@currtools) {
                               if (keys(%{$usertools{$user}}) > 0) {
                                   if (!$usertools{$user}{$tool}) {
                                       push(@{$memchg{'changefunc'}},$user);
                                       $changefunc = 1;
                                       last;
                                   }
                               } else {
                                   push(@{$memchg{'changefunc'}},$user);
                                   $changefunc = 1;
                               }
                           }
                           if ($changefunc) {
                               next;
                           }
                           if (keys(%{$usertools{$user}}) > 0) {
                               foreach my $tool (keys(%{$usertools{$user}})) {
                                   if (!grep/^$tool$/,@currtools) {
                                       push(@{$memchg{'changefunc'}},$user);
                                       $changefunc = 1;
                                       last;
                                   }
                               }
                           }
                       }
                   }
               }
               &check_changes(\@member_changes,\%memchg);
               my %temptools;
               foreach my $change (@member_changes) {
                   if (($change eq 'deletion') || ($change eq 'expire')) {
                       next;
                   }
                   foreach my $user (@{$memchg{$change}}) {
                       unless (exists($usertools{$user})) {
                           %{$usertools{$user}} = ();
                       }
                       %{$temptools{$user}} = %{$usertools{$user}}; 
                   }
               }
               %usertools = %temptools;
           } elsif ($state eq 'memresult') {
               foreach my $change (@member_changes) {
                   if ($change eq 'expire' || $change eq 'deletion') {
                       next;
                   }
                   if (ref($memchg{$change}) eq 'ARRAY') { 
                       my @users = @{$memchg{$change}};
                       foreach my $user (@users) {
                           unless (exists($usertools{$user})) {
                               %{$usertools{$user}} = ();
                           }
                       }
                   }
               }
           }
       }
   
       if ((($state eq 'pick_privs') || ($state eq 'change_privs'))
           && ($specificity eq 'Yes')) {
           foreach my $user (sort(keys(%usertools))) {
               foreach my $tool (keys(%{$usertools{$user}})) {
                   foreach my $priv (keys(%{$$toolprivs{$tool}})) {
                       unless (exists($$fixedprivs{$tool}{$priv})) {
                           $elements{$action}{$state}{'userpriv_'.$priv} = 'checkbox';
                       }
                   }
               }
           }
       }
   
       if (($action eq 'create' && $state eq 'pick_name') || 
           ($action eq 'modify' && $state eq 'change_settings')) {
           my ($crsquota,$freespace,$maxposs) = &get_quota_constraints($action,\%stored);
           my $space_trim = '/^\s*|\s*\$/g,""';
           my $float_check = '/^([0-9]*\.?[0-9]*)$/';
           $validate_script = '
       var newquota = new String(document.'.$state.'.quota.value);
       newquota.replace('.$space_trim.');
       if (newquota == "" ) {
           document.'.$state.'.quota.value = 0;
           newquota = "0";
       }
       var maxposs = '.sprintf("%.2f",$maxposs).';
       if (newquota > maxposs) {
           alert("The file repository quota you entered for this group ("+newquota+" Mb) exceeds the maximum possible ("+maxposs+" Mb). Please enter a smaller number.");
           return;
       }
       var re_quota = '.$float_check.';
       var check_quota = newquota.match(re_quota);
       if (check_quota == null) {
           alert("The quota you entered contains invalid characters, the quota should only include numbers, with or without a decimal point.");
           return;
       }
       if (newquota == 0) {
           var warn_zero = 0;
           for (var i=0; i<document.'.$state.'.tool.length; i++) {
               if (document.'.$state.'.tool[i].value == "files") {
                   if (document.'.$state.'.tool[i].checked) {
                       warn_zero = 1;
                   }
               }
           }
           if (warn_zero == 1) {
               alert("You have indicated that the file repository should be enabled, but you have set the respository quota to 0 Mb.\nThis will prevent any upload of files.\nPlease set a value or disable the repository feature.");
               return;
           }
       } 
   ';
       }
       my $jscript = &Apache::loncommon::check_uncheck_jscript();
       $jscript .= qq|
   function nextPage(formname,nextstate) {
       formname.state.value= nextstate;
       $validate_script
       formname.submit();
   }
   function backPage(formname,prevstate) {
       formname.state.value = prevstate;
       formname.submit();
   }
   function changeSort(caller) {
       document.$state.state.value = '$state';
       document.$state.sortby.value = caller;
       document.$state.submit();
   } 
   
   |;
       $jscript .= &Apache::lonhtmlcommon::set_form_elements(
                              \%{$elements{$action}{$state}},\%stored);
       my $page = 0;
       my %states = ();
       my %branchstates = ();
       @{$states{'create'}} = ('pick_name','pick_members','pick_privs','result');
       @{$states{'modify'}} = ('pick_task');
       @{$branchstates{'noprivs'}} = ('result');
       @{$branchstates{'settings'}} = ('change_settings','chgresult');
       @{$branchstates{'members'}} = ('change_members','change_privs','memresult');
       @{$branchstates{'adds'}} = ('add_members','pick_members','pick_privs',
                                   'addresult');
   
       if (defined($env{'form.branch'})) {
           push (@{$states{$action}},@{$branchstates{$env{'form.branch'}}});
       }
   
       if (($action eq 'create') || ($action eq 'modify')) {
           my $done = 0;
           my $i=0;
           while ($i<@{$states{$action}} && !$done) {
               if ($states{$action}[$i] eq $state) {
                   $page = $i;
                   $done = 1;
               }
               $i++;
           }
       }
   
       my $loaditems =  &onload_action($action,$state);
       $r->print(&header("Groups Manager",
         $jscript,$action,$state,$page,$loaditems));
   
       if ($env{'form.refpage'} eq 'enrl') {
           &Apache::lonhtmlcommon::add_breadcrumb
           ({href=>"/adm/dropadd",
             text=>"Enrollment Manager",
             faq=>9,bug=>'Instructor Interface',});
           if ($action eq 'modify') {
               &Apache::lonhtmlcommon::add_breadcrumb
               ({href=>"/adm/coursegroups?refpage=enrl&action=modify",
                 text=>"Groups",
                 faq=>9,bug=>'Instructor Interface',});
           }
       } else { 
           &Apache::lonhtmlcommon::add_breadcrumb
             ({href=>"/adm/coursegroups",
               text=>"Groups",
               faq=>9,bug=>'Instructor Interface',});
           if ($env{'form.refpage'} eq 'grouplist') {
               &Apache::lonhtmlcommon::add_breadcrumb
                ({href=>"/adm/$cdom/$cnum/$env{'form.groupname'}/smppg?ref=grouplist",
                  text=>"Group: $description",});
         }          }
     }      }
   
       my %trail = ();
       %{$trail{'create'}} = &Apache::lonlocal::texthash (
                               pick_name => $ucgpterm.' Settings',
                               pick_members => 'Select Members',
                               pick_privs => 'Choose Privileges',
                               result => 'Creation Complete',
                             );
       %{$trail{'modify'}} = &Apache::lonlocal::texthash(
                               pick_task => 'Choose Task',
                               change_settings => "$ucgpterm Settings",
                               change_members => 'Modify/Delete Members',
                               change_privs => 'Change Privileges',
                               change_mapping => 'Membership Mapping',
                               add_members => 'Add Members',
                               pick_members => 'Select Members',
                               pick_privs => 'Choose Privileges',
                               chgresult => 'Setting Changes Complete',
                               memresult => 'Modifications Complete',
                               addresult => 'Additions Complete',
                             );
       my %navbuttons = &Apache::lonlocal::texthash(
                                gtns => 'Go to next step',
                                gtps => 'Go to previous step',
                                crgr => 'Create '.$gpterm,
                                mose => 'Modify settings',
                                gtpp => 'Go to previous page',
                                adme => 'Add members',
       );
       if ((($action eq 'create') || ($action eq 'modify')) &&
                 ($manage_permission)) {
           for (my $i=0; $i<@{$states{$action}}; $i++) {
               if ($state eq $states{$action}[$i]) {
                   &Apache::lonhtmlcommon::add_breadcrumb(
                      {text=>"$trail{$action}{$state}"});
                   $r->print(&Apache::lonhtmlcommon::breadcrumbs
     ("Groups Manager"));
                   &display_control($r,$cdom,$cnum,$action,$state,$page,
                          \%sectioncount,$groupname,$description,$functions,
                          \@tools,$toolprivs,$fixedprivs,$startdate,$enddate,
                          \%users,\%userdata,$idx,\%memchg,\%usertools,
                          $view_permission,$manage_permission,
                          \%stored,$granularity,$quota,$specificity,\@types,\@roles,
                          \@sections,\%states,\%navbuttons,$gpterm,$ucgpterm,
    $crstype);
                   last;
               } else {
                   if (($state eq 'result') && ($i > 0)) {
                       &Apache::lonhtmlcommon::add_breadcrumb(
       {href=>"javascript:backPage(document.$state,'$states{$action}[0]')",
         text=>"$trail{$action}{$states{$action}[$i]}"});
                   } else { 
                       &Apache::lonhtmlcommon::add_breadcrumb(
        {href=>"javascript:backPage(document.$state,'$states{$action}[$i]')",
         text=>"$trail{$action}{$states{$action}[$i]}"});
                   }
               }
           }
       } elsif (($action eq 'view') && ($view_permission)) {
                           &Apache::lonhtmlcommon::add_breadcrumb(
                      {text=>"View $gpterm".'s'});
           $r->print(&Apache::lonhtmlcommon::breadcrumbs
     ('Groups Manager'));
           &display_groups($r,$cdom,$cnum,$functions,$idx,$view_permission,
    $manage_permission,$action,$state,$gpterm,$ucgpterm,
    $crstype);
   
       }
     $r->print(&footer());      $r->print(&footer());
     return OK;      return;
   }
   
   sub retrieve_settings {
       my ($cdom,$cnum,$groupname) = @_;
       my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum,$groupname);
   
       return if (!%curr_groups);
   
       my %groupinfo = 
    &Apache::longroup::get_group_settings($curr_groups{$groupname});
   
       my %stored;
   
       $stored{'description'} = 
    &unescape($groupinfo{'description'});
       $stored{'startdate'} = $groupinfo{'startdate'};
       $stored{'enddate'} = $groupinfo{'enddate'};
       if ($stored{'enddate'} == 0) {
    $stored{'no_end_date'} = 1;
       }
       $stored{'granularity'} = $groupinfo{'granularity'};
       $stored{'specificity'} = $groupinfo{'specificity'};
       $stored{'creation'} = $groupinfo{'creation'};
       $stored{'creator'} = $groupinfo{'creator'};
       $stored{'quota'} = $groupinfo{'quota'};
   
       foreach my $tool (sort(keys(%{$groupinfo{'functions'}}))) {
    if ($groupinfo{functions}{$tool} eq 'on') {
       push(@{$stored{tool}},$tool);
    }
       }
       foreach my $role (@{$groupinfo{'roles'}}) {
    push(@{$stored{roles}},$role);
       }
       foreach my $type (@{$groupinfo{'types'}}) {
    push(@{$stored{types}},$type);
       }
       foreach my $section (@{$groupinfo{'sectionpick'}}) {
    push(@{$stored{sectionpick}},$section);
       }
       foreach my $defpriv (@{$groupinfo{'defpriv'}}) {
    push(@{$stored{defpriv}},$defpriv);
       }
       $stored{'autoadd'} = $groupinfo{'autoadd'};
       $stored{'autodrop'} = $groupinfo{'autodrop'};
       if (exists($groupinfo{'autosec'})) {
    foreach my $role (sort(keys(%{$groupinfo{'autosec'}}))) {
               if (ref($groupinfo{'autosec'}{$role}) eq 'ARRAY') {
           foreach my $section (@{$groupinfo{'autosec'}{$role}}) {
   
               push (@{$stored{'sec_'.$role}},$section);
           }
           if (@{$groupinfo{'autosec'}{$role}} > 0) {
       push(@{$stored{'autorole'}},$role);
           }
               }
    }
       }
       return %stored;
   }
   
   sub display_control {
       my ($r,$cdom,$cnum,$action,$state,$page,$sectioncount,$groupname,
           $description,$functions,$tools,$toolprivs,$fixedprivs,$startdate,
           $enddate,$users,$userdata,$idx,$memchg,$usertools,
           $view_permission,$manage_permission,$stored,$granularity,$quota,
           $specificity,$types,$roles,$sections,$states,$navbuttons,
    $gpterm,$ucgpterm,$crstype) = @_;
       if ($action eq 'create') {
           if ($state eq 'pick_name') {
               &general_settings_form($r,$cdom,$cnum,$action,$state,$page,
                                      $functions,$tools,$toolprivs,$fixedprivs,
                                      $sectioncount,$stored,$states,$navbuttons,
                                      $gpterm,$ucgpterm,$crstype);
           } elsif ($state eq 'pick_members') {
               &choose_members_form($r,$cdom,$cnum,$action,$state,$page,
                                    $groupname,$description,$granularity,$quota,
                                    $startdate,$enddate,$tools,$fixedprivs,
                                    $toolprivs,$functions,$users,$userdata,$idx,
                                    $stored,$states,$navbuttons,$gpterm,$ucgpterm,
    $crstype);
           } elsif ($state eq 'pick_privs') {
               &choose_privs_form($r,$cdom,$cnum,$action,$state,$page,
                                  $startdate,$enddate,$tools,$functions,
                                  $toolprivs,$fixedprivs,$userdata,$usertools,
                                  $idx,$states,$stored,$sectioncount,$navbuttons,
                                  $gpterm,$ucgpterm,$crstype);
           } elsif ($state eq 'result') {
               &process_request($r,$cdom,$cnum,$action,$state,$page,
                                $groupname,$description,$specificity,$userdata,
                                $startdate,$enddate,$tools,$functions,
                                $toolprivs,$usertools,$idx,$types,$roles,
                                $sections,$states,$navbuttons,$memchg,
                                $sectioncount,$stored,$gpterm,$ucgpterm,$crstype);
           }
       } elsif ($action eq 'modify') {
           my $groupname = $env{'form.groupname'};
           if ($state eq 'pick_task') {
               &modify_menu($r,$groupname,$page,$gpterm);
           } elsif ($state eq 'change_settings') {
               &general_settings_form($r,$cdom,$cnum,$action,$state,$page,
                                      $functions,$tools,$toolprivs,$fixedprivs,
                                      $sectioncount,$stored,$states,$navbuttons,
                                      $gpterm,$ucgpterm,$crstype);
           } elsif ($state eq 'change_members') {
               &change_members_form($r,$cdom,$cnum,$action,$state,$page,
                                    $groupname,$description,$startdate,$enddate,
                                    $tools,$fixedprivs,$functions,$users,
                                    $userdata,$granularity,$quota,$specificity,
                                    $idx,$states,$navbuttons,$gpterm,$ucgpterm);
           } elsif ($state eq 'add_members') {
               &add_members_form($r,$cdom,$cnum,$action,$state,$page,$startdate,
                                 $enddate,$groupname,$description,$granularity,
                                 $quota,$sectioncount,$tools,$functions,$stored,
                                 $states,$navbuttons,$gpterm,$ucgpterm);
           } elsif ($state eq 'pick_members') {
               &choose_members_form($r,$cdom,$cnum,$action,$state,$page,
                                    $groupname,$description,$granularity,$quota,
                                    $startdate,$enddate,$tools,$fixedprivs,
                                    $toolprivs,$functions,$users,$userdata,$idx,
                                    $stored,$states,$navbuttons,$gpterm,$ucgpterm,
    $crstype);
           } elsif ($state eq 'pick_privs') {
               &choose_privs_form($r,$cdom,$cnum,$action,$state,$page,
                                  $startdate,$enddate,$tools,$functions,
                                  $toolprivs,$fixedprivs,$userdata,$usertools,
                                  $idx,$states,$stored,$sectioncount,$navbuttons,
                                  $gpterm,$ucgpterm,$crstype);
           } elsif ($state eq 'change_privs') {
               &change_privs_form($r,$cdom,$cnum,$action,$state,$page,
                                  $startdate,$enddate,$tools,$functions,
                                  $toolprivs,$fixedprivs,$userdata,$usertools,
                                  $memchg,$idx,$states,$stored,$sectioncount,
                                  $navbuttons,$gpterm,$ucgpterm);
           } elsif ($state eq 'chgresult' || $state eq 'memresult' || 
                    $state eq 'addresult') {
               &process_request($r,$cdom,$cnum,$action,$state,$page,
                                $groupname,$description,$specificity,$userdata,
                                $startdate,$enddate,$tools,$functions,
                                $toolprivs,$usertools,$idx,$types,$roles,
                                $sections,$states,$navbuttons,$memchg,
                                $sectioncount,$stored,$gpterm,$ucgpterm,$crstype);
           }
       }
 }  }
   
 sub header {  sub header {
     my $html=&Apache::lonxml::xmlbegin();      my ($bodytitle,$jscript,$action,$state,$page,$loaditems) = @_;
     my $bodytag=&Apache::loncommon::bodytag('Course Groups Manager');      my $start_page=
     my $title = &mt('LON-CAPA Groups Manager');   &Apache::loncommon::start_page($bodytitle,
     return(<<ENDHEAD);         '<script type="text/javascript">'.
 $html         $jscript.'</script>',
 <head>         {'add_entries' => $loaditems,});
 <title>$title</title>      my $output = <<"END";
 </head>  $start_page
 $bodytag  <form method="POST" name="$state">
 <form method="post"  
       action="/adm/coursegroup" name="form">  END
 ENDHEAD      if ($action eq 'create' || $action eq 'modify') {
           $output .= <<"END";
    <input type="hidden" name="action" value="$action" />
    <input type="hidden" name="state" value="" />
    <input type="hidden" name="origin" value="$state" />
    <input type="hidden" name="page" value="$page" />
   END
       }
       return $output;
 }  }
   
 sub print_main_menu {  sub onload_action {
     my ($r,$manage_permission,$view_permission)=@_;      my ($action,$state) = @_;
       my %loaditems;
       if ((defined($env{'form.origin'})) && ($action eq 'create') &&
                   ($state eq 'pick_name' || $state eq 'pick_members' || 
                    $state eq 'pick_privs')) {
           unless ($env{'form.origin'} eq '') {
       $loaditems{'onload'} = 
    'javascript:setFormElements(document.'.$state.')';
           }
       }
       if (($action eq 'modify') &&
                   ($state eq 'change_settings' || $state eq 'change_members' ||
                    $state eq 'change_privs' || $state eq 'add_members')) {
    $loaditems{'onload'} = 
       'javascript:setFormElements(document.'.$state.')';
       }
       return \%loaditems;
   }
   
   sub footer {
       my $end_page = &Apache::loncommon::end_page();
          return(<<ENDFOOT);
      <input type="hidden" name="sortby" value="$env{'form.sortby'}" />
     </form>
   $end_page
   ENDFOOT
   }
   
   sub build_members_list {
       my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata) = @_;
       my %access = ();
       foreach my $role (@{$roles}) {
           %{$$users{$role}} = ();
       }
       foreach my $type (@{$types}) {
           $access{$type} = $type;
       }
       &Apache::loncommon::get_course_users($cdom,$cnum,\%access,$roles,
                                            $sections,$users,$userdata);
       return;
   }
   
   sub group_files {
       my ($group,$currdir,$numfiles,$numdirs) = @_;
       my $dirptr=16384;
       my @dir_list=&Apache::portfolio::get_dir_list($currdir,$group);
       foreach my $line (@dir_list) {
           my ($filename,$dom,undef,$testdir,undef,undef,undef,undef,$size,undef,$mtime,undef,undef,undef,$obs,undef)=split(/\&/,$line,16);
           if (($filename !~ /^\.\.?$/) && ($filename !~ /\.meta$/ ) && ($filename !~ /(.*)\.(\d+)\.([^\.]*)$/) && ($filename ne 'no_such_dir')) { 
               if ($dirptr&$testdir) {
                   $currdir .= '/'.$filename;
                   $$numdirs ++;
                   &group_files($numfiles,$numdirs)
               } else {
                   $$numfiles ++;
               }
           }
       }
       return;
   }
   
   sub group_members {
       my ($cdom,$cnum,$group,$group_info) = @_;
       my %memberhash = &Apache::lonnet::get_group_membership($cdom,$cnum,$group);
       my $now = time;
       my ($tmp)=keys(%memberhash);
       if ($tmp=~/^error:/) {
           $$group_info{'totalmembers'} = 'Unknown - an error occurred';
           return $tmp;
       }
       my $totalmembers = 0;
       my $active = 0;
       my $previous = 0;
       my $future = 0;
       foreach my $member (keys %memberhash) {
           $totalmembers ++;
           my ($end,$start) = split(/:/,$memberhash{$member});
           unless ($start == -1) {
               if (($end!=0) && ($end<$now)) {
                   $previous ++;
               } elsif (($start!=0) && ($start>$now)) {
                   $future ++;
               } else {
                  $active ++;
               }
           }
       }
       if ($totalmembers == 0) {
           $$group_info{$group}{'totalmembers'} = 'None';
       } else {
           $$group_info{$group}{'totalmembers'} = '<nobr>'.$active.
               '&nbsp;-&nbsp;active</nobr><br /><nobr>'.$previous.
               '&nbsp;-&nbsp;previous</nobr><br /><nobr>'.$future.
               '&nbsp;-&nbsp;future</nobr>';
       }
       return 'ok';
   }
   
   
   sub general_settings_form {
       my ($r,$cdom,$cnum,$action,$formname,$page,$functions,$tools,
           $toolprivs,$fixedprivs,$sectioncount,$stored,$states,$navbuttons,
           $gpterm,$ucgpterm,$crstype) = @_;
       my ($nexttext,$prevtext);
       &groupsettings_options($r,$functions,$action,$formname,$stored,1,
                              $gpterm,$ucgpterm,$crstype);
       &access_date_settings($r,$action,$formname,$stored,2,$gpterm,$ucgpterm);
       if ($action eq 'create') {
           &membership_options($r,$cdom,$cnum,$action,$formname,$sectioncount,3,
                               $gpterm,$ucgpterm);
           $nexttext = $$navbuttons{'gtns'};
       } else {
           my @available = ();
           my @unavailable = ();
           &check_tools($functions,$tools,\@available,\@unavailable);
           @{$tools} = sort(keys(%{$functions}));
           &privilege_specificity($r,$action,3,$tools,$stored,$toolprivs,
          $fixedprivs,\@available,$formname,
          $gpterm,$ucgpterm);
           &mapping_options($r,$action,$formname,$page,$sectioncount,
                            $states,$stored,$navbuttons,4,5,
    $gpterm,$ucgpterm,$crstype,$cdom,$cnum);
           $nexttext = $$navbuttons{'mose'};
       }
       $prevtext = $$navbuttons{'gtpp'};
       &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
                           $$states{$action}[$page+1],$nexttext);
       return;
   }
   
   sub groupsettings_options {
       my ($r,$functions,$action,$formname,$stored,$image,$gpterm,
           $ucgpterm,$crstype) = @_;
       my %lt = &Apache::lonlocal::texthash(
           'gdat' => "Group access start and end dates",
           'gnde' => "Group name, title and available collaborative tools",
           'desc' => 'Group Title',
           'func' => 'Collaborative Tools',
           'gnam' => 'Group Name',
           'lett' => 'Letters, numbers and underscore only',
           'doyo' => 'Different subsets of the chosen collaborative tools '.
                     'for different group members?',
       );
       my ($crsquota,$freespace,$maxposs) = &get_quota_constraints($action,$stored);
       &topic_bar($r,$image,$lt{'gnde'});
       $r->print('
        <table class="LC_descriptive_input">
         <tr>
          <td class="LC_description">'.$lt{'gnam'}.':</td>
          <td colspan="5">
   ');
       if ($action eq 'create') {
           $r->print('<input type="text" name="groupname" size="25" />&nbsp;('.
                     $lt{'lett'}.')');
       } else {
           $r->print('<input type="hidden" name="groupname" value="'.
                            $env{'form.groupname'}.'" />'.$env{'form.groupname'});
       }
       $r->print(<<"END");
          </td>
         <tr>
         <tr>
          <td class="LC_description">$lt{'desc'}:</td>
          <td colspan="5"><input type="text" name="description" size="40"
                                                       value="" />
          </td>
         <tr>
         <tr>
          <td class="LC_description">$lt{'func'}:</td>
   END
       my $numitems = keys(%{$functions});
       my $halfnum = int($numitems/2);
       my $remnum = $numitems%2;
       if ($remnum) {
           $halfnum ++;
       }
       my @allfunctions = sort(keys (%{$functions}));
       for (my $i=0; $i<$halfnum; $i++) {
           $r->print('<td><label><input type="checkbox" name="tool" value="'.
                     $allfunctions[$i].'" />&nbsp;'.
                      $$functions{$allfunctions[$i]}.'</label></td>
                      <td>&nbsp;</td><td>&nbsp;</td>');
       }
       $r->print('<td><input type="button" value="check all" '.
                 'onclick="javascript:checkAll(document.'.$formname.'.tool)" />'.
                 '</td></tr><tr><td>&nbsp;</td>');
       for (my $j=$halfnum; $j<@allfunctions; $j++) {
           $r->print('<td><label><input type="checkbox" name="tool" value="'.
                     $allfunctions[$j].'" />&nbsp;'.
                     $$functions{$allfunctions[$j]}.'</label></td>
                     <td>&nbsp;</td><td>&nbsp;</td>');
       }
       if ($remnum) {
           $r->print('<td>&nbsp;</td>');
       }
       $r->print('
          <td>
           <input type="button" value="uncheck all"
             onclick="javascript:uncheckAll(document.'.$formname.'.tool)" />
          </td>
         </tr>
         <tr>
          <td class="LC_description">'.&mt('Granularity:').'</td>
          <td colspan="10">'.$lt{'doyo'}.'&nbsp;<label><input type="radio" name="granularity" value="Yes" />'.&mt('Yes').'</label>&nbsp;<label><input type="radio" name="granularity" value="No" checked="checked" />'.&mt('No').'</label>');
       if ($action eq 'modify') {
           $r->print('&nbsp;&nbsp;('.&mt('Currently set to "[_1]"',
                                         $$stored{'granularity'}).')');
       }
       $r->print('
          </td>
         </tr>
         <tr>
          <td class="LC_description">'.&mt('Disk quota: ').'</td><td colspan="10">');
       if ($action eq 'create') {
           $r->print(&mt('If you enable the file repository for the [_1], allocate a disk quota.',$gpterm));
       } else {
           $r->print(&mt('Quota allocated to file repository:'));
       } 
       $r->print('&nbsp;<input type="text" name="quota" size="4" />Mb');
       if ($action eq 'create') {
           $r->print('<br />'.
                     &mt('A total of [_1] Mb can be divided amongst all [_2]s in the '.
                     '[_3], and [_4] Mb are currently unallocated.',$crsquota,
                     $gpterm,lc($crstype),sprintf("%.2f",$freespace)));
       } else {
           $r->print('&nbsp;&nbsp;('.&mt('The quota is currently [_1] Mb',
                                         $$stored{'quota'}).').');
   
           $r->print('<br />'.&mt('The quota can be increased to [_1] Mb, '.
                     'by adding all unallocated space for [_2]s in the [_3].',
                     sprintf("%.2f",$maxposs),$gpterm,lc($crstype)));
       }
       $r->print('
          </td>
         </tr>
        </table>
   ');
       return;
   }
   
   sub get_quota_constraints {
       my ($action,$stored) = @_;
       my ($crsquota,$freespace,$maxposs); 
       $crsquota = $env{'course.'.$env{'request.course.id'}.'.internal.coursequota'};
       if ($crsquota eq '') {
           $crsquota = 20;
       }
       $freespace = $crsquota - &Apache::longroup::sum_quotas();
       if ($action eq 'create') {
           $maxposs = $freespace;
       } else {
           $maxposs = $$stored{'quota'} + $freespace;
       }
       return ($crsquota,$freespace,$maxposs);
   }
   
   sub membership_options {
       my ($r,$cdom,$cnum,$action,$state,$sectioncount,$image,$gpterm,$ucgpterm)=@_;
       my $crstype = &Apache::loncommon::course_type();
       my %lt = &Apache::lonlocal::texthash(
                   'pipa' => 'Build a list of users for selection of group members',
                   'gmem' => "Group membership selection list criteria:",
                   'picr' => 'Pick the criteria to use to build a list of '.
                             lc($crstype).' users from which you will select ',
                   'meof' => "members of the new group.",
                   'admg' => "additional members of the group.",
                   'ifno' => "If you do not wish to add members when you first ".
                             "create the group, there is no need to pick any criteria.",
                   'asub' => "A subsequent step will also allow you to specify automatic adding/dropping of group members triggered by specified user role and section <i>changes</i> in the course.",
                   'acty' => 'Access types',
                   'coro' => $crstype.' roles',
                   'cose' => $crstype.' sections',
                );
       my %status_types = (
                      active => &mt('Currently has access'),
                      previous => &mt('Previously had access'),
                      future => &mt('Will have future access'),
                      );
   
       my @roles = ('st','cc','in','ta','ep','cr');
   
       my @sections = keys(%{$sectioncount});
   
       &topic_bar($r,$image,$lt{'pipa'});
       $r->print('
        <b>'.$lt{'gmem'}.'</b><br />'.$lt{'picr'});
       if ($action eq 'create') {
           $r->print($lt{'meof'}.'<br />'.$lt{'ifno'}.'<br />'.$lt{'asub'});
       } else {
           $r->print($lt{'admg'});
       }
       $r->print('
        <br />
        <br />
        <table class="LC_status_selector">
         <tr>
          <th>'.$lt{'acty'}.'</th>
          <th>'.$lt{'coro'}.'</th>
          <th>'.$lt{'cose'}.'</th>
         </tr><tr><td>');
       $r->print(&Apache::lonhtmlcommon::status_select_row(\%status_types));
       $r->print('</td><td>');
       $r->print(&Apache::lonhtmlcommon::role_select_row(\@roles,undef,undef,1,$cdom,$cnum));
       if (@sections > 0) {
           @sections = sort {$a cmp $b} @sections;
           unshift(@sections,'none'); # Put 'no sections' next
           unshift(@sections,'all'); # Put 'all' at the front of the list
       } else {
           @sections = ('all','none');
       }
       $r->print('</td><td>'.
                 &sections_selection(\@sections,'sectionpick').'</td>
         </tr>
        </table>');
       return;
   }
   
   sub sections_selection {
       my ($sections,$elementname) = @_;
       my $section_sel;
       my $numvisible = 4;
       if (@{$sections} < 4) {
           $numvisible = @{$sections};
       }
       foreach my $sec (@{$sections}) {
           if ($sec eq 'all') {
               $section_sel .= '  <option value="'.$sec.'">'.&mt('all sections').'</option>'."\n";
           } elsif ($sec eq 'none') {
               $section_sel .= '  <option value="'.$sec.'">'.&mt('no section').'</option>'."\n"; 
           } else {
               $section_sel .= '  <option value="'.$sec.'">'.$sec."</option>\n";
           }
       }
       my $output = '
           <select name="'.$elementname.'" multiple="true" size="'.$numvisible.'">
             '.$section_sel.'
           </select>';
       return $output;
   }
   
   sub access_date_settings {
       my ($r,$action,$formname,$stored,$image,$gpterm,$ucgpterm) = @_;
       my %lt = &Apache::lonlocal::texthash(
                   'sten' => "Default start and end dates for $gpterm access",
                );
       my $starttime = time;
       my $endtime = time+(6*30*24*60*60); # 6 months from now, approx
       if ($action eq 'modify') {
           $starttime = $$stored{'startdate'};
           unless ($$stored{'enddate'} == 0) {
               $endtime = $$stored{'enddate'};
           }
       }
       my ($table) = &date_setting_table($starttime,$endtime,$formname);
       &topic_bar($r,$image,$lt{'sten'});
       $r->print('
       '.$table.'
       ');
       return;
   }
   
   sub choose_members_form {
       my ($r,$cdom,$cnum,$action,$formname,$page,$groupname,$description,
           $granularity,$quota,$startdate,$enddate,$tools,$fixedprivs,$toolprivs,
           $functions,$users,$userdata,$idx,$stored,$states,$navbuttons,
           $gpterm,$ucgpterm,$crstype) = @_;
       my @regexps = ('user_','userpriv_','sec_');
       my %origmembers;
       $r->print(&Apache::lonhtmlcommon::echo_form_input(
            ['origin','action','state','page','member','specificity','branch',
             'defpriv','autorole','autoadd','autodrop','sortby','togglefunc'],
            \@regexps));
       my $earlyout = &validate_groupname($groupname,$action,$cdom,$cnum,$gpterm,
                                          $ucgpterm,$crstype);
       if ($earlyout) {
    $r->print($earlyout);
           &display_navbuttons($r,$formname,$$states{$action}[$page-1],
                              $$navbuttons{'gtps'});
           return;
       } 
       my ($specimg,$memimg);
       my @available = ();
       my @unavailable = ();
       &check_tools($functions,$tools,\@available,\@unavailable);
       if ($action eq 'create') {
           &print_current_settings($r,$action,$functions,$startdate,$enddate,
    $groupname,$description,$granularity,$quota,
    \@available,\@unavailable,$gpterm,$ucgpterm);
           $specimg = 4;
           $memimg = 5;
       } else {
           $specimg = 2;
           $memimg = 3;
           my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
                                                                  $groupname);
           foreach my $key (sort(keys(%membership))) {
               if ($key =~ /^\Q$groupname\E:([^:]+):([^:]+)$/) {
                   my ($end,$start,@userprivs) = split(/:/,$membership{$key});
                   unless ($start == -1) {  
                       my $uname = $1;
                       my $udom = $2;
                       my $user = $uname.':'.$udom;
                       $origmembers{$user} = 1; 
                   }
               }
           }
       }
       &privilege_specificity($r,$action,$specimg,$tools,$stored,$toolprivs,
                             $fixedprivs,\@available,$formname,$gpterm,$ucgpterm);
       my $newusers = &pick_new_members($r,$action,$formname,\@available,$idx,
        $stored,$memimg,$users,$userdata,
        $granularity,\%origmembers,$gpterm,
        $ucgpterm);
       if ($newusers || $action eq 'create') {
           &display_navbuttons($r,$formname,$$states{$action}[$page-1],
                               $$navbuttons{'gtps'},$$states{$action}[$page+1],
                               $$navbuttons{'gtns'});
       } else {
           &display_navbuttons($r,$formname,$$states{$action}[$page-1],
                               $$navbuttons{'gtps'});
       }
       return;
   }
   
   sub display_navbuttons {
       my ($r,$formname,$prev,$prevtext,$next,$nexttext) = @_;
       $r->print('<div class="LC_navbuttons">');
       if ($prev) {
           $r->print('
         <input type="button" name="previous" value = "'.$prevtext.'"
       onclick="javascript:backPage(document.'.$formname.','."'".$prev."'".')"/>
      &nbsp;&nbsp;&nbsp;');
       }
       if ($next) {
           $r->print('
         <input type="button" name="next" value="'.$nexttext.'"
    onclick="javascript:nextPage(document.'.$formname.','."'".$next."'".')" />');
       }
       $r->print('</div>');
   }
   
   sub check_tools {
       my ($functions,$tools,$available,$unavailable) = @_;
       foreach my $item (sort(keys(%{$functions}))) {
           if (grep/^$item$/,@{$tools}) {
               push(@{$available},$item);
           } else {
               push(@{$unavailable},$item);
           }
       }
       return;
   }
   
   sub print_current_settings {
       my ($r,$action,$functions,$startdate,$enddate,$groupname,$description,
    $granularity,$quota,$available,$unavailable,$gpterm,$ucgpterm) = @_;
   
       my %lt = &Apache::lonlocal::texthash(
           grna => 'Group Name',
           desc => 'Group Title',
           grfn => "Collaborative Tools",
           gran => 'Granularity',
           quot => 'File quota',
           dfac => 'Default access dates',
           ygrs => "Your group selections - ",
           tfwa => "The following settings will apply to the group:",
           difn => 'Different collaborative tools<br />for different members:',
           stda => 'Start date',
           enda => 'End date:',
       );
       my $showstart = &Apache::lonlocal::locallocaltime($startdate);
       my $showend;
       if ($enddate == 0) {
           $showend = &mt('No end date set'); 
       } else {
           $showend = &Apache::lonlocal::locallocaltime($enddate);
       }
       if ($action eq 'create') {
           $r->print('
   <div><span style="font-size: larger">'.$lt{'ygrs'}.'</span>
   <br />'.$lt{'tfwa'}.'
   </div>');
       }
       $r->print(&Apache::loncommon::start_data_table('LC_course_group_status').
         &Apache::loncommon::start_data_table_header_row());
       $r->print('
     <th>'.$lt{'grna'}.'</th>
     <th>'.$lt{'desc'}.'</th>
     <th>'.$lt{'grfn'}.'</th>
     <th>'.$lt{'gran'}.'</th>
     <th>'.$lt{'quot'}.'</th>
     <th>'.$lt{'dfac'}.'</th>
   ');
       $r->print(&Apache::loncommon::end_data_table_header_row().
         &Apache::loncommon::start_data_table_row('LC_data_table_dense'));
       $r->print('
     <td valign="top">'.$groupname.'</td>
     <td valign="top">'.$description.'</td>
     <td>
   ');
       if (@{$available} > 0) {
           $r->print(&mt('<b>Available for assignment to members:</b>').
                       '<table class="LC_group_priv"><tr>');
           my $rowcell = int(@{$available}/2) + @{$available}%2;
           for (my $i=0; $i<@{$available}; $i++) {
               if (@{$available} > 3) {
                   if ($i==$rowcell) {
                       $r->print('</tr><tr>');
                   }
               }
               $r->print('<td>'.$$functions{$$available[$i]}.
         '</td><td>&nbsp;</td>');
           }
           if ((@{$available} > 3) && (@{$available}%2)) {
               $r->print('<td>&nbsp;</td><td>&nbsp;</td>');
           }
           $r->print('</tr></table><br />');
       }
       if (@{$unavailable} > 0) {
           $r->print(&mt('<b>Unavailable for assignment:</b>').
                       '<table class="LC_group_priv"><tr>');
           my $rowcell = int(@{$unavailable}/2) + @{$unavailable}%2;
           for (my $j=0; $j<@{$unavailable}; $j++) {
               if (@{$unavailable} > 3) {
                   if ($j==$rowcell) {
                       $r->print('</tr><tr>');
                   }
               }
               $r->print('<td>'.$$functions{$$unavailable[$j]}.
         '</td><td>&nbsp;</td>');
           }
           if ((@{$unavailable} > 3) && (@{$unavailable}%2)) {
               $r->print('<td>&nbsp;</td><td>&nbsp;</td>');
           }
           $r->print('</tr></table>');
       }
       $r->print(<<"END");
     </td>
     <td valign="top"><b>$lt{'difn'}</b> $granularity</td>
     <td valign="top">$quota Mb</td> 
     <td valign="top"><b>$lt{'stda'}</b> $showstart<br />
         <b>$lt{'enda'}</b> $showend
     </td>
   END
       $r->print(&Apache::loncommon::end_data_table_row().
         &Apache::loncommon::end_data_table());
       return;
   }
   
   sub pick_new_members {
       my ($r,$action,$formname,$available,$idx,$stored,$img,$users,$userdata,
    $granularity,$origmembers,$gpterm,$ucgpterm) = @_;
       my %lt = &Apache::lonlocal::texthash(
             'gpme' => "Group membership",
             'addm' => 'Add members',
             'setf' => 'Assign collaborative tools', 
             'func' => 'Tools',
             'nome' => 'No members to add at this time, as there are no users '.
                        'matching the specified type(s), role(s) and section(s).',
             'nnew' => "There are no users to add as new members, as all users".
                       " matching the specified type(s), role(s), and ".
                       "section(s) are already affiliated with this group.",
             'yoma' =>  'You may need to use the '."'".'modify existing, past or '.
                        'future members'."'".' page if you need to re-enable '.
                        'or activate access for previous or future members.',
       );
       my %members;
       my $totalusers = 0;
       my $newusers = 0;
       foreach my $role (keys(%{$users})) {
           foreach my $user (keys(%{$$users{$role}})) {
               $totalusers ++;
               if (ref($origmembers) eq 'HASH') {
                   if (exists($$origmembers{$user})) {
                       next;
                   }
               }    
               unless (defined($members{$user})) {
                   @{$members{$user}} = @{$$userdata{$user}};
                   $newusers ++;
               }
           }
       }
       if (keys(%members) > 0) {
           if (@{$available} > 0 && $granularity eq 'Yes') {
               $r->print(&check_uncheck_tools($r,$available));
           }
       }
       &topic_bar($r,$img,$lt{'gpme'});
       if (keys(%members) > 0) {
           $r->print('
       <table>
        <tr>');
           &check_uncheck_buttons($r,$formname,'member',$lt{'addm'});
           if (@{$available} > 0 && $granularity eq 'Yes') {
               $r->print('<td>
        <fieldset><legend><b>'.$lt{'setf'}.'</b></legend>
         <nobr>
         <input type="button" value="check all"
           onclick="javascript:checkAllTools(document.'.$formname.')" />
           &nbsp;&nbsp;
         <input type="button" value="uncheck all"
           onclick="javascript:uncheckAllTools(document.'.$formname.')" />
         </nobr>
        </fieldset></td>');
           }
           $r->print('</tr></table>
           ');
           $r->print(&Apache::loncommon::start_data_table().
     &Apache::loncommon::start_data_table_header_row());
           $r->print('
        <th>'.&mt('Add?').'</b></td>
        <th><a href="javascript:changeSort('."'fullname'".')">'.&mt('Name').'</a></td>
        <th><a href="javascript:changeSort('."'username'".')">'.&mt('Username').'</a></td>
        <th><a href="javascript:changeSort('."'domain'".')">'.&mt('Domain').'</a></td>
        <th><a href="javascript:changeSort('."'id'".')">'.&mt('ID').'</a></td>
        <th><a href="javascript:changeSort('."'section'".')">'.&mt('Section').'</a></td>
   ');
           if (@{$available} > 0) {
               $r->print('<th>'.$lt{'func'}.'</th>');
           }
           $r->print(&Apache::loncommon::end_data_table_header_row());
           if (@{$available} > 0) {
               if ($granularity eq 'Yes') {
                   $r->print(&Apache::loncommon::start_data_table_row('LC_data_table_dense LC_data_table_highlight').'
    <td colspan="6">&nbsp;</td>
    <td align="center"><nobr><b>'.&mt('All:').'</b>&nbsp;');
                   foreach my $tool (@{$available}) {
                       $r->print('<label><input type="checkbox" name="togglefunc" '.
      'onclick="javascript:toggleTools(document.'.$formname.'.user_'.$tool.',this);"'.
      ' value="'.$tool.'">'.'<b>'.$tool.'</b></label>&nbsp;&nbsp;&nbsp;');
                   }
                   $r->print('</nobr></td></tr>');
               }
           }
           my %Sortby = ();
           foreach my $user (sort(keys(%members))) {
               if ($env{'form.sortby'} eq 'fullname') {
                   push(@{$Sortby{$members{$user}[$$idx{fullname}]}},$user);
               } elsif ($env{'form.sortby'} eq 'username') {
                   push(@{$Sortby{$members{$user}[$$idx{uname}]}},$user);
               } elsif ($env{'form.sortby'} eq 'domain') {
                   push(@{$Sortby{$members{$user}[$$idx{udom}]}},$user);
               } elsif ($env{'form.sortby'} eq 'id') {
                   push(@{$Sortby{$members{$user}[$$idx{id}]}},$user);
               } elsif ($env{'form.sortby'} eq 'section') {
                   push(@{$Sortby{$members{$user}[$$idx{section}]}},$user);
               } else {
                   push(@{$Sortby{$members{$user}[$$idx{fullname}]}},$user);
               }
           }
           foreach my $key (sort(keys(%Sortby))) {
               foreach my $user (@{$Sortby{$key}}) {
                   my $id = $members{$user}[$$idx{id}];
                   my $fullname = $members{$user}[$$idx{fullname}];
                   my $udom = $members{$user}[$$idx{udom}];
                   my $uname = $members{$user}[$$idx{uname}];
                   my $section = $members{$user}[$$idx{section}];
                   $r->print(&Apache::loncommon::start_data_table_row('LC_data_table_dense').
     '<td align="right"><input type="checkbox" name="member" value="'.$user.'" /></td>'.
     '<td>'.$fullname.'</td>'.
     '<td>'.$uname.'</td>'.
     '<td>'.$udom.'</td>'.
     '<td>'.$id.'</td>'.
     '<td>'.$section.'</td>');
                   if (@{$available} > 0) {
                       $r->print('<td align="center"><nobr>'.
                                 '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;');
                       foreach my $tool (@{$available}) {
                           if ($granularity eq 'Yes') {
                               $r->print('<input type="checkbox" name="user_'.
                             $tool.'" value="'.$user.'" />'.$tool.'&nbsp;&nbsp;&nbsp;');
                           } else {
                               $r->print('<input type="hidden" name="user_'.
                             $tool.'" value="'.$user.'" />'.$tool.'&nbsp;&nbsp;&nbsp;');
                           }
                       }
                       $r->print('</nobr></td>');
                   }
                   $r->print(&Apache::loncommon::end_data_table_row()."\n");
               }
           }
           $r->print(&Apache::loncommon::end_data_table());
       } else {
           if ($totalusers > 0) {
               $r->print($lt{'nnew'}.'<br /><br />'.$lt{'yoma'});
           } else { 
               $r->print($lt{'nome'});
           }
       }
       return $newusers;
   }
   
   sub privilege_specificity {
       my ($r,$action,$img,$tools,$stored,$toolprivs,$fixedprivs,$available,
    $formname,$gpterm,$ucgpterm) = @_;
       my %lt = &Apache::lonlocal::texthash (
         'uprv' => 'User privileges for collaborative tools',
         'frty' => 'For each collaborative tool you have chosen to include, '.
                   'there is a set of core privileges which all group members '.
                   'assigned use of the tool will receive.',
         'thar' => 'For some tools there are also additional optional '.
                    'privileges which can be set.',
         'plch' => 'Choose one of the following:',
         'fort' => 'For the collaborative tools you have chosen to include '.
                   'only core privileges are available, '.
                   'so there are no optional privileges to assign.',
         'eaty' => 'Each collaborative tool includes core '.
                   'privileges assigned to all members with access to the '.
                   'tool. Some tools may also feature additional privileges '.
                   'which can be set for specific members.',
         'cutg' => 'Currently the group is configured ',
         'sdif' => 'so different members can receive different optional privileges for a particular tool.',
         'sall' => 'so all members will receive the same optional privileges for a particular tool.',
         'algm' => 'All group members will receive the same privileges for any tool assigned to them, including the default set of optional privileges.',
         'smgp' => 'Different group members may receive different privileges from '.
                   'others for the tools they have been assigned.',
         'thwi' => 'These will be the privileges all group members receive for a particular assigned tool, '. 
                   'if you selected the first option above.',
         'thes' => "These will be the privileges given to members assigned ".   
                   "in the future via automatic group assignment ".
                   "for users who receive specific sections/roles in the course ",
         'asyo' => "As you have chosen not to include any collaborative tools ".
                   "in the group, no default optional privileges need to be set.",
         'plin' => 'Indicate which <b>optional</b> privileges members '.
                   'will receive by default for a specific tool.',
         'oppr' => 'Optional privileges',
         'defp' => 'The default privileges new members will receive are:', 
       );
       my $totaloptionalprivs = 0;
       foreach my $tool (@{$tools}) {
           foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
               if (!exists($$fixedprivs{$tool}{$priv})) {
                   $totaloptionalprivs ++;
               }
           }
       }
       &topic_bar($r,$img,$lt{'uprv'});
       if ((($action eq 'create') && (@{$available} > 0)) || 
           (($action eq 'modify') && ($formname eq 'change_settings'))) {
           my %specific = (
                         'No'  => 'checked="checked"',
                         'Yes' => '',
                     );
           if ($action eq 'create') {
               $r->print($lt{'frty'}.'<br />');
               if ($totaloptionalprivs) {
                   $r->print($lt{'thar'}.'<br /><br />'.$lt{'plch'});
               } else {
                   $r->print($lt{'fort'});
               }
           } else {
               $r->print($lt{'eaty'}.'&nbsp;'.$lt{cutg});
               if ($$stored{'specificity'} eq 'Yes') {
                   $r->print($lt{'sdif'});
                   $specific{'Yes'} = $specific{'No'};
                   $specific{'No'} = '';
               } else {
                   $r->print($lt{'sall'});
               }
           }
           if ($totaloptionalprivs) {
               $r->print('
   <br />
   <label><nobr><input type="radio" name="specificity" value="No" '.$specific{'No'}.' />&nbsp;'.$lt{'algm'}.'</nobr></label><br />
   <label><nobr><input type="radio" name="specificity" value="Yes" '.$specific{'Yes'}.' />&nbsp;'.$lt{'smgp'}.'</nobr></label><br /><br />');
           } else {
               $r->print('<input type="hidden" name="specificity" value="No" />');
           }
           if ($totaloptionalprivs) {
               $r->print($lt{'plin'});
               if ($action eq 'create') {
                   $r->print('<br />'.$lt{'thwi'});
               }
               $r->print('<br />'.$lt{'thes'});
               if ($action eq 'create') {
                   $r->print('('.&mt('if enabled on the next page').').');
               } else {
                   $r->print('('.&mt('if enabled below').').');
               }
               $r->print('<br /><br />
     <table><tr>');
           &check_uncheck_buttons($r,$formname,'defpriv',$lt{'oppr'});
           $r->print('
       </tr>
      </table>
      <br />
   ');
           } else {
               $r->print($lt{'algm'}.'<br /><br />');
           }
           &default_privileges($r,$action,$tools,$toolprivs,$fixedprivs,
       $available);
       } else {
           if ($action eq 'create') {
               $r->print($lt{'asyo'});
               $r->print('<input type="hidden" name="specificity" value="No" />');
           } elsif ($action eq 'modify' && $formname eq 'pick_members') {
               my @defprivs;
               if (ref($$stored{'defpriv'}) eq 'ARRAY') {
                   @defprivs = @{$$stored{'defpriv'}};
               }
               $r->print($lt{'eaty'}.'&nbsp;'.$lt{cutg});
               if ($$stored{'specificity'} eq 'Yes') {
                   $r->print($lt{'sdif'});
               } else {
                   $r->print($lt{'sall'});
               }
               $r->print(' '.$lt{'defp'}.'<br /><br />');
               &display_defprivs($r,$tools,$toolprivs,\@defprivs);
           }
       }
       return;
   }
   
   sub default_privileges {
       my ($r,$action,$tools,$toolprivs,$fixedprivs,$available) = @_;
       my %lt = &Apache::lonlocal::texthash(
                                   'addp' => 'Additional privileges',
                                   'fixp' => 'Fixed privileges',
                                   'oppr' => 'Optional privileges',
                                   'func' => 'Collaborative Tool',
       );
       $r->print(&Apache::lonhtmlcommon::start_pick_box('LC_group_priv_box').
         &Apache::lonhtmlcommon::row_title($lt{'func'},undef,
    'LC_groups_functionality'));
       $r->print(join('</td><td class="LC_groups_functionality">',@{$tools}));
       $r->print(&Apache::lonhtmlcommon::row_closure(1));
       my $fixed = '';
       my $dynamic = '';
       foreach my $tool (@{$tools}) {
           my $privcount = 0;
    if ($dynamic ne '') {
       $dynamic .= '</td><td class="LC_groups_optional">';
    }
    $dynamic .= '<table class="LC_group_priv"><tr>';
           foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
               if (exists($$fixedprivs{$tool}{$priv})) {
    if ($fixed ne '') {
       $fixed .= '</td><td class="LC_groups_fixed">';
    }
                   $fixed .= '<input type="hidden" name="defpriv" value="'.$priv.'" /><nobr>'.$$toolprivs{$tool}{$priv}.'&nbsp;';
                   if ($action eq 'modify') {
                       if (grep(/^$tool$/,@{$available})) {
                           $fixed .= '<small>'.&mt('(on)').'<small>&nbsp;';
                       } else {
                           $fixed .= '<small>'.&mt('(off)').'<small>&nbsp;';
                       }
                   }
                   $fixed .= '</nobr>';
               } else {
                   $privcount++;
                   if ($privcount == 3) {
                       $dynamic .= '</tr>
                                    <tr>'."\n";
                   }
                   $dynamic .= '<td><nobr><label><input type="checkbox" name="defpriv" value="'.$priv.'" />'.$$toolprivs{$tool}{$priv}.'</label></nobr></td>'."\n";
               }
           }
           if ($privcount == 0) {
               $dynamic .= '<td>None</td>'."\n";
           }
           if ($privcount < 3) {
               $dynamic .= '<td>&nbsp;</td>'."\n";
           } elsif ($privcount%2) {
               $dynamic = '<td>&nbsp;</td>'."\n";
           }
    $dynamic .= '</tr></table>';
       }
       $r->print(&Apache::lonhtmlcommon::row_title($lt{'fixp'},undef,
    'LC_groups_fixed').
         $fixed.
         &Apache::lonhtmlcommon::row_closure(1));
       $r->print(&Apache::lonhtmlcommon::row_title($lt{'oppr'},undef,
    'LC_groups_optional').
         $dynamic.
         &Apache::lonhtmlcommon::end_pick_box());
       $r->print('<br />');
       return;
   
   }
   
   sub display_defprivs {
       my ($r,$tools,$toolprivs,$defprivs) = @_;
       my $function = &Apache::loncommon::get_users_function();
       my $tabcol = &Apache::loncommon::designparm($function.'.tabbg');
       my $rowColor1 = "#dddddd";
       my $rowColor2 = "#eeeeee";
       my %lt = &Apache::lonlocal::texthash(
                                   'priv' => 'Privileges',
                                   'func' => 'Collaborative Tool',
       );
       $r->print(&Apache::lonhtmlcommon::start_pick_box());
       $r->print('<tr>');
       my $numrows = 0;
       my %currprivs;
       foreach my $tool (@{$tools}) {
           @{$currprivs{$tool}} = ();
           foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
               if (ref($defprivs) eq 'ARRAY') {
                   if (grep(/^\Q$priv\E$/,@{$defprivs})) {
                       push(@{$currprivs{$tool}},$priv);
                   }
               }
           }
           my $rowcount = int(@{$currprivs{$tool}}/3);
           if (@{$currprivs{$tool}}%3 > 0) {
               $rowcount ++;
           }
           if ($rowcount > $numrows) {
               $numrows = $rowcount;
           }
       }
       my @rowCols = ($rowColor1,$rowColor2);
       foreach my $tool (@{$tools}) {
           $r->print('<td align="center" valign="top">
                       <table cellspacing="0" cellpadding="5">
                        <tr bgcolor="#cccccc">
                         <td colspan="3" align="center"><b>'.$tool.'</b></td>
                        </tr>
           ');
           my $rownum = 1;
           my $privcount = 0;
           $r->print('<tr bgcolor="'.$rowColor1.'">');
           foreach my $priv (@{$currprivs{$tool}}) {
               $privcount ++;
               if ($privcount%4 == 0) {
                   $rownum ++;
                   my $bgcol = $rownum%2; 
                   $r->print('</tr>
                                <tr bgcolor="'.$rowCols[$bgcol].'">'."\n");
               }
               $r->print('<td>'.$$toolprivs{$tool}{$priv}.'</td>'."\n");
           }
           if ($privcount%3 > 0) {
               my $emptycells = 3-($privcount%3);
               while($emptycells > 0) {
                   $r->print('<td>&nbsp;</td>'."\n");
                   $emptycells --;
               }
           }
           while ($rownum < $numrows) {
               $rownum ++;
               my $bgcol = $rownum%2;
               $r->print('<tr bgcolor="'.$rowCols[$bgcol].'"><td colspan="3">&nbsp;</td></tr>');
           }
           $r->print('</table>'."\n".'</td>');
       }
       $r->print('</tr>'."\n");
       $r->print(&Apache::lonhtmlcommon::end_pick_box());
       $r->print('<br />');
       return;
   }
   
   
   sub change_members_form {
       my ($r,$cdom,$cnum,$action,$formname,$page,$groupname,$description,
           $startdate,$enddate,$tools,$fixedprivs,$functions,$users,$userdata,
           $granularity,$quota,$specificity,$idx,$states,$navbuttons,$gpterm,
    $ucgpterm) = @_;
       my %lt = &Apache::lonlocal::texthash(
                                            grse => "$ucgpterm settings",
                                            mogm => "Modify $gpterm membership",
                                           );
       my @regexps = ('user_','userpriv_');
       $r->print(&Apache::lonhtmlcommon::echo_form_input(
                            ['origin','action','state','page','expire','deletion',
                             'reenable','activate','changepriv','sortby',
                             'togglefunc'],\@regexps));
       my $rowimg = 1;
       my @available = ();
       my @unavailable = ();
       &check_tools($functions,$tools,\@available,\@unavailable);
       my $nexttext = $$navbuttons{'gtns'};
       my $prevtext = $$navbuttons{'gtpp'};
       $r->print('
   <br />
   ');
       &topic_bar($r,1,$lt{'grse'});
       &print_current_settings($r,$action,$functions,$startdate,$enddate,
       $groupname,$description,$granularity,$quota,
       \@available,\@unavailable,$gpterm,$ucgpterm);
       &topic_bar($r,2,$lt{'mogm'});
       my $numcurrent = &current_membership($r,$cdom,$cnum,$formname,$groupname,
                                            \@available,\@unavailable,$fixedprivs,
                    $granularity,$specificity);
       if ($numcurrent > 0) {
           &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
                               $$states{$action}[$page+1],$nexttext);
       } else {
           &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext);
       }
       return;
   }
   
   sub current_membership {
       my ($r,$cdom,$cnum,$formname,$groupname,$available,$unavailable,
    $fixedprivs,$granularity,$specificity) = @_;
       my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
                                                                      $groupname);
       my %lt = &Apache::lonlocal::texthash(
                                             'actn' => 'Action?',
                                             'name' => 'Name',
                                             'usnm' => 'Username',
                                             'doma' => 'Domain',
                                             'stda' => 'Start Date',
                                             'enda' => 'End Date',
                                             'expi' => 'Expire',
                                             'reen' => 'Re-enable',
                                             'acti' => 'Activate',
                                             'dele' => 'Delete',
                                             'curf' => 'Current Tool Set',
                                             'chpr' => 'Change Privileges' 
                                           );
       my ($current,$num_items,$hastools,$addtools) =
           &Apache::longroup::group_memberlist($cdom,$cnum,$groupname,$fixedprivs,
                                               $available);
       my $numcurrent = scalar(keys(%{$current}));
       if ($numcurrent > 0) {
           $r->print('
      <table>
       <tr>');
           if ($num_items->{'active'}) {
               &check_uncheck_buttons($r,$formname,'expire',$lt{'expi'});
           }
           if ($num_items->{'previous'}) {
               &check_uncheck_buttons($r,$formname,'reenable',$lt{'reen'});
           }
           if ($num_items->{'future'}) {
               &check_uncheck_buttons($r,$formname,'activate',$lt{'acti'});
           }
           &check_uncheck_buttons($r,$formname,'deletion',$lt{'dele'});
           if (@{$available} > 0) {
               if ($specificity eq 'Yes') {
                   &check_uncheck_buttons($r,$formname,'changepriv',$lt{'chpr'});
               }
               if ($granularity eq 'Yes') {
                   $r->print(&check_uncheck_tools($r,$available));
                   $r->print('
        <td>
         <nobr>
          <fieldset><legend><b>'.$lt{'curf'}.'</b></legend>
          <input type="button" value="check all"
          onclick="javascript:checkAllTools(document.'.$formname.')" />
          &nbsp;&nbsp;
          <input type="button" value="uncheck all"
           onclick="javascript:uncheckAllTools(document.'.$formname.')" />
         </fieldset>
        </nobr>
       </td>
   ');
               }
           }
           $r->print(<<"END");
      </tr>
     </table>
     <br />
   END
           $r->print(&Apache::loncommon::start_data_table().
     &Apache::loncommon::start_data_table_header_row());
           $r->print(<<"END");
        <th>$lt{'actn'}</th>
        <th><a href="javascript:changeSort('fullname')">$lt{'name'}</a></th>
        <th><a href="javascript:changeSort('username')">$lt{'usnm'}</a></th>
        <th><a href="javascript:changeSort('domain')">$lt{'doma'}</a></th>
        <th><a href="javascript:changeSort('id')">ID</a></th>
        <th><a href="javascript:changeSort('start')">$lt{'stda'}</a></th>
        <th><a href="javascript:changeSort('end')">$lt{'enda'}</a></th>
   END
           my $colspan = 0;
           if ($hastools) {
               $r->print('<th>'.$lt{'curf'}.'</th>');
               $colspan++;  
           }
           if ($addtools) {
               $r->print('<th>'.&mt('Additional Tools').'</th>');
               $colspan++;
           }
           $r->print(&Apache::loncommon::end_data_table_header_row());
           if ($colspan) {
               if ($granularity eq 'Yes') {
                   $r->print(&Apache::loncommon::start_data_table_row('LC_data_table_dense LC_data_table_highlight').'
    <td colspan="7">&nbsp;</td>
    <td colspan="'.$colspan.'" align="center"><nobr><b>'.&mt('All:').
     '</b>&nbsp;');
                   foreach my $tool (@{$available}) {
                       $r->print('<label><input type="checkbox" name="togglefunc"'.
      ' onclick="javascript:toggleTools(document.'.$formname.'.user_'.$tool.',this);"'.
      ' value="'.$tool.'" />'.'<b>'.$tool.'</b></label>&nbsp;&nbsp;&nbsp;');
                   }
                   $r->print('</nobr></td></tr>');
               }
           }
           my %Sortby = ();
           foreach my $user (sort(keys(%{$current}))) {
               if ($env{'form.sortby'} eq 'fullname') {
                   push(@{$Sortby{$$current{$user}{fullname}}},$user);
               } elsif ($env{'form.sortby'} eq 'username') {
                   push(@{$Sortby{$$current{$user}{uname}}},$user);
               } elsif ($env{'form.sortby'} eq 'domain') {
                   push(@{$Sortby{$$current{$user}{udom}}},$user);
               } elsif ($env{'form.sortby'} eq 'id') {
                   push(@{$Sortby{$$current{$user}{id}}},$user);
               } else {
                   push(@{$Sortby{$$current{$user}{fullname}}},$user);
               }
           }
           foreach my $key (sort(keys(%Sortby))) {
               foreach my $user (@{$Sortby{$key}}) {
                   my $id = $$current{$user}{id};
                   my $fullname = $$current{$user}{fullname};
                   my $udom = $$current{$user}{udom};
                   my $uname = $$current{$user}{uname};
                   my $start = $$current{$user}{start};
                   my $end = $$current{$user}{end};
                   $r->print(&Apache::loncommon::start_data_table_row('LC_data_table_dense').'
                               <td>');
                   if ($$current{$user}{changestate} eq 'reenable') {
                       $r->print('<nobr><label>'. 
      '<input type="checkbox" name="reenable" value="'.$user.'" />'.
      $lt{'reen'}.'</label></nobr><br />');
                   } elsif ($$current{$user}{changestate} eq 'expire') {
                       $r->print('<nobr><label>'.
      '<input type="checkbox" name="expire" value="'.$user.'" />'.
      $lt{'expi'}.'</label></nobr><br />');
                   } elsif ($$current{$user}{changestate} eq 'activate') {
                       $r->print('<nobr><label>'.
      '<input type="checkbox" name="activate" value="'.$user.'" />'.
      $lt{'acti'}.'</label></nobr><br />');
                   }
                   $r->print('<nobr><label>'.
      '<input type="checkbox" name="deletion" value="'.$user.'" />'.
      $lt{'dele'}.'</label></nobr>');
                   if ($specificity eq 'Yes') {
                       $r->print('<br /><nobr><label>'.
      '<input type="checkbox" name="changepriv" value="'.$user.'" />'.$lt{'chpr'}.
      '</label></nobr>');
                   }
                   $r->print('
      </td>'.
      '<td>'.$fullname.'</td>'.
      '<td>'.$uname.'</td>'.
      '<td>'. $udom.'</td>'.
      '<td>'.$id.'</td>'.
      '<td>'.$start.'</td>'.
      '<td>'.$end.'</td>');
                   if ($hastools) {
                       $r->print('<td align="left"><nobr>'.
                                     '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;');
                       foreach my $tool (@{$$current{$user}{currtools}}) {
                           if ($granularity eq 'Yes') {
                               $r->print('<label><input type="checkbox" '. 
                                          'checked="checked" '. 
                                          'name="user_'.$tool.'" value="'.
                                          $user.'" />'.$tool.'</label>');
                            } else {
                                $r->print('<input type="hidden" '.
                                          'checked="checked" '.
                                          'name="user_'.$tool.'" value="'.
                                          $user.'" />'.$tool);
                            }
                            $r->print('&nbsp;&nbsp;&nbsp;');
                       }
                       $r->print('</nobr></td>');
                   }
                   if ($addtools) {
                       $r->print('<td align="left">');
                       if ($granularity eq 'Yes') {
                           foreach my $tool (@{$$current{$user}{newtools}}) {
                               $r->print('<nobr><label><input type="checkbox"
                                             name="user_'.$tool.'" value="'.
                                             $user.'" />'.$tool.
                                             '</label></nobr>&nbsp;&nbsp;&nbsp;');
                           }
                       } else {
                           foreach my $tool (@{$$current{$user}{newtools}}) {
                               $r->print('<nobr><input type="hidden" 
                                             name="user_'. $tool.'" value="'.
                                             $user.'" />'.$tool.
                                             '</nobr>&nbsp;&nbsp;&nbsp;');
                           }
                       }
                       $r->print('</td>');
                   }
                   $r->print(&Apache::loncommon::end_data_table_row()."\n");
               }
           }
           $r->print(&Apache::loncommon::end_data_table());
       } else {
           $r->print(&mt('There are no active, future or previous group members to modify.'));
       }
       return $numcurrent;
   }
   
   sub check_uncheck_buttons {
       my ($r,$formname,$field,$title,$colspan) = @_;
       $r->print('
        <td '.$colspan.'>
          <fieldset>
          <legend><b>'.$title.'</b></legend>
         <nobr>
          <input type="button" value="check all"
          onclick="javascript:checkAll(document.'.$formname.'.'.$field.')" />
          &nbsp;&nbsp;
          <input type="button" value="uncheck all"
          onclick="javascript:uncheckAll(document.'.$formname.'.'.$field.')" />
         </nobr>
          </fieldset>
        </td>
   ');
   }
   
   
   sub change_privs_form {
       my ($r,$cdom,$cnum,$action,$formname,$page,$startdate,$enddate,
    $tools,$functions,$toolprivs,$fixedprivs,$userdata,$usertools,
    $memchg,$idx,$states,$stored,$sectioncount,$navbuttons,$gpterm,
    $ucgpterm) = @_;
       my @regexps = ('userpriv_');
       my $nexttext;
       my %lt = &Apache::lonlocal::texthash(
                  'tode' => 'To be deleted',
                  'toex' => 'To be expired',
                  'nome' => "No members to be deleted or expired from the $gpterm.",
       );
       $r->print(&Apache::lonhtmlcommon::echo_form_input(
            ['origin','action','state','page','sortby'],\@regexps));
       if ($env{'form.branch'} eq 'adds') {
           $nexttext = $$navbuttons{'adme'};
       } else {
           $nexttext = $$navbuttons{'mose'};
       }
       &topic_bar($r,3,&mt('Members to delete or expire'));
       my $exp_or_del = 0;
       if (ref($$memchg{'deletion'}) eq 'ARRAY') {
           if (@{$$memchg{'deletion'}} > 0) {
               $r->print('<b>'.$lt{'tode'}.':</b><br /><ul>');
               foreach my $user (@{$$memchg{'deletion'}}) {
                   $r->print('<li>'.$$userdata{$user}[$$idx{fullname}].
                             '&nbsp;('.$user.')</li>');
               }
               $r->print('</ul>');
               $exp_or_del += @{$$memchg{'deletion'}};
           }
       }
       if (ref($$memchg{'expire'}) eq 'ARRAY') {
           if (@{$$memchg{'expire'}} > 0) {
               $r->print('<b>'.$lt{'toex'}.':</b><br /><ul>');
               foreach my $user (@{$$memchg{'expire'}}) {
                   $r->print('<li>'.$$userdata{$user}[$$idx{fullname}].
                             '&nbsp;('.$user.')</li>');
               }
               $r->print('</ul>');
               $exp_or_del += @{$$memchg{'expire'}};
           }
       }
       if (!$exp_or_del) {
           $r->print($lt{'nome'}.'<br />');
       }
       
       &topic_bar($r,4,&mt('Setting optional privileges for specific group members'));
   
       my $numchgs = &member_privileges_form($r,$action,$formname,$tools,
                                             $toolprivs,$fixedprivs,$userdata,
                                             $usertools,$idx,$memchg,$states,
                                             $stored,$gpterm);
       my $prevtext = $$navbuttons{'gtps'};
       if ($numchgs || $exp_or_del) {
           &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
                               $$states{$action}[$page+1],$nexttext);
       } else {
           &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext);
       }
       return;
   }
   
   sub add_members_form {
       my ($r,$cdom,$cnum,$action,$formname,$page,$startdate,$enddate,$groupname,
           $description,$granularity,$quota,$sectioncount,$tools,$functions,
           $stored,$states,$navbuttons,$gpterm,$ucgpterm)=@_; 
       $r->print(' <br />');
       my @available = ();
       my @unavailable = ();
       &check_tools($functions,$tools,\@available,\@unavailable);
       &print_current_settings($r,$action,$functions,$startdate,$enddate,
       $groupname,$description,$granularity,$quota,
       \@available,\@unavailable,$gpterm,$ucgpterm);
       &membership_options($r,$cdom,$cnum,$action,$formname,$sectioncount,1,$gpterm,
                           $ucgpterm);
       my $nexttext = $$navbuttons{'gtns'};
       my $prevtext = $$navbuttons{'gtpp'};
       &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
                           $$states{$action}[$page+1],$nexttext);
       return;
   }
   
   sub choose_privs_form {
       my ($r,$cdom,$cnum,$action,$formname,$page,$startdate,$enddate,
    $tools,$functions,$toolprivs,$fixedprivs,$userdata,$usertools,$idx,
    $states,$stored,$sectioncount,$navbuttons,$gpterm,$ucgpterm,
    $crstype) = @_;
   
       my @regexps = ('userpriv_');
       my $nexttext;
       
       if ($action eq 'create') {
           push(@regexps,'sec_');
           $r->print(&Apache::lonhtmlcommon::echo_form_input(
            ['origin','action','state','page','sortby','autoadd','autodrop'],
            \@regexps));
           $nexttext = $$navbuttons{'crgr'};
       } else {
           $r->print(&Apache::lonhtmlcommon::echo_form_input(
            ['origin','action','state','page','sortby'],\@regexps));
           $nexttext = $$navbuttons{'adme'};
       }
   
       &topic_bar($r,6,&mt('Setting optional privileges for specific group members'));
   
       &member_privileges_form($r,$action,$formname,$tools,$toolprivs,
                               $fixedprivs,$userdata,$usertools,$idx,undef,
                               $states,$stored,$gpterm);
   
       if ($action eq 'create') {
           my $img1 = 7;
           my $img2 = 8;
           &mapping_options($r,$action,$formname,$page,$sectioncount,
                            $states,$stored,$navbuttons,$img1,$img2,
                            $gpterm,$ucgpterm,$crstype,$cdom,$cnum);
       }
       my $prevtext = $$navbuttons{'gtps'};
       &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
                           $$states{$action}[$page+1],$nexttext);
       return;
   }
   
   sub build_boxes {
       my ($r,$tools,$usertools,$fixedprivs,$toolprivs,$showtools,
           $showboxes,$prefix,$specificity,$excluded) = @_;
       my $totalboxes = 0;
       if (@{$tools} > 0) {
           if ($specificity eq 'Yes') {
               foreach my $tool (@{$tools}) {
                   @{$$showboxes{$tool}} = ();
                   foreach my $user (sort(keys(%{$usertools}))) {
                       if (ref($excluded) eq 'ARRAY') {
                           if (grep/^$user$/,@{$excluded}) {
                               next;
                           }
                       }
                       if ($$usertools{$user}{$tool}) {
                           unless (grep/^$tool$/,@{$showtools}) {
                               push(@{$showtools},$tool);
                           }
                           foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
                               unless (exists($$fixedprivs{$tool}{$priv})) {
                                   unless(grep(/^$priv$/,@{$$showboxes{$tool}})) {
                                       push(@{$$showboxes{$tool}},$priv);
                                       $totalboxes ++;
                                   }
                               }
                           }
                       }
                   }
               }
               if ($totalboxes > 0) {
                   $r->print('
   <script type="text/javascript">
   function checkAllTools(formname) {
   ');
                   foreach my $tool (sort(keys(%{$showboxes}))) {
                       foreach my $priv (@{$$showboxes{$tool}}) {
                           $r->print('  checkAll(formname.'.$prefix.$priv.');'."\n");
                       }
                   }
                   $r->print('
   }
   function uncheckAllTools(formname) {
   ');
                   foreach my $tool (sort(keys(%{$showboxes}))) {
                       foreach my $priv (@{$$showboxes{$tool}}) {
                           $r->print('  uncheckAll(formname'.$prefix.$priv.');'."\n");
                       }
                   }
                   $r->print('
   }
   </script>
                   ');
               }
           }
       }
       return $totalboxes;
   }
   
   sub member_privileges_form {
       my ($r,$action,$formname,$tools,$toolprivs,$fixedprivs,$userdata,
           $usertools,$idx,$memchg,$states,$stored,$gpterm) = @_;
       my %lt = &Apache::lonlocal::texthash(
               'addp' => 'Additional privileges',
               'fixp' => 'Core privileges',
               'oppr' => 'Optional privileges',
               'func' => 'Tool',
               'forf' => 'For the collaborative tools included for group '.
                         'members being added or modified, '. 
                         'there are no optional privileges to set '.
                         'for specific members.',
               'algr' => 'All new group members will receive the same privileges.',            'ifex' => 'If previously expired members are being re-enabled, or '.
                         'if access for future members is being activated now, '.
                         'previously set privileges will be preserved.',
               'asno' => 'As no group members are being added, '.
                         'there are no specific user privileges to set.',
               'asng' => 'As no group tools will be made available to users, '.
                         'there are no specific user privileges to set.',
               'nogm' => 'No group member privileges to display or set, '.
                         'as you have not indicated that you will be activating,'.
                         ' re-enabling, changing privileges, or adding/removing '.
                         'tools for any current members.',
               'full' => 'Fullname',
               'user' => 'Username',
               'doma' => 'Domain',
       );
       my @defprivs;
       my $specificity;
       if ($action eq 'create') {
           if (defined($env{'form.defpriv'})) {
               @defprivs = &Apache::loncommon::get_env_multiple('form.defpriv');
           }
           $specificity = $env{'form.specificity'};
       } else {
           if (defined($$stored{'defpriv'})) {
               @defprivs = @{$$stored{'defpriv'}};
           }
           $specificity = $$stored{'specificity'};
       }
       my @showtools;
       my %showboxes = ();
       my $numtools = 1 + @{$tools};
   
       my @excluded = ();
       my $numchgs = 0;
       if ($formname eq 'change_privs') {
           my @currmembers = ();
           if (ref($$memchg{'deletion'}) eq 'ARRAY') {
               push(@excluded,@{$$memchg{'deletion'}});
           }
           if (ref($$memchg{'expire'}) eq 'ARRAY') {
               push(@excluded,@{$$memchg{'expire'}});
           }
           if (@excluded > 0) {
               foreach my $user (sort(keys(%{$usertools}))) {
                   if (grep/^$user$/,@excluded) {
                       next;
                   }
                   push(@currmembers,$user);
               }
           } else {
               @currmembers = sort(keys(%{$usertools}));
           }
           $numchgs = @currmembers;
           if (!$numchgs) {
               $r->print($lt{'nogm'}); 
               return $numchgs;
           }
       }
    
       my $totalboxes = &build_boxes($r,$tools,$usertools,$fixedprivs,
                                      $toolprivs,\@showtools,\%showboxes,
                                      'userpriv_',$specificity,\@excluded);
       if (@{$tools} > 0) {
           if ($specificity eq 'Yes') {
               if ($totalboxes > 0) {
                   my $numcells = 2;
                   my $colspan = $numcells + 1;
                   my %total;
                   if (keys(%{$usertools}) > 1) {
                       $r->print('
      <table border="0" cellspacing="2" cellpadding="2">
       <tr>
   ');
                       foreach my $tool (@{$tools}) {
                           if (@{$showboxes{$tool}} > 0) {
                               $r->print('<td valign="top">');
                               $r->print('<table class="thinborder"><tr>'.
         '<th colspan="'.$colspan.'">'.
                                         $tool.'</th></tr><tr>');
                               my $privcount = 0;
                               foreach my $priv (@{$showboxes{$tool}}) {
                                   $privcount ++;
                                   if (($privcount == @{$showboxes{$tool}}) && 
                                       ($privcount > 1)) {
                                       if ($privcount%$numcells) {
                                           $r->print('<td colspan="'.$colspan.'">');
                                       } else {
                                           $r->print('<td>');
                                       }
                                   } else {
                                       $r->print('<td>');
                                   }
                                   $r->print(qq|
          <fieldset><legend><b>$$toolprivs{$tool}{$priv}</b></legend>
          <nobr>
          <input type="button" value="check all"
            onclick="javascript:checkAll(document.$formname.userpriv_$priv)" />
          &nbsp;
          <input type="button" value="uncheck all"
           onclick="javascript:uncheckAll(document.$formname.userpriv_$priv)" />
         </nobr></fieldset><br />|);
                                   $r->print('</td>');
                                   if ($privcount < @{$showboxes{$tool}}) {
                                       if (@{$showboxes{$tool}} > 2) {
                                           if ($privcount%$numcells == 0) {
                                               $r->print('</tr><tr>');
                                           }
                                       } else {
                                           $r->print('<tr></tr>');
                                       }
                                   }
                               }
                               $r->print('</tr></table></td><td>&nbsp;</td>');
                           }
                       }
                       $r->print('</tr></table>');
                   }
                   $r->print(&Apache::loncommon::start_data_table().
     &Apache::loncommon::start_data_table_header_row());
                   $r->print(<<"END");
       <th>$lt{'full'}</th>
       <th>$lt{'user'}</th>
       <th>$lt{'doma'}</th>
       <th colspan="$numtools">$lt{'addp'}</th>
   END
                   $r->print(&Apache::loncommon::end_data_table_header_row());
                   &member_privs_entries($r,$usertools,$toolprivs,$fixedprivs,
                                         $userdata,$idx,\@showtools,\@defprivs,
                                         \@excluded);
                   $r->print(&Apache::loncommon::end_data_table());
               } else {
                   $r->print($lt{'forf'}.'<br />');
                   &display_defprivs($r,$tools,$toolprivs,\@defprivs);
               }
           } else {
               if (keys(%{$usertools}) > 0) {
                   $r->print($lt{'algr'}.'<br />'.$lt{'ifex'}.'<br /><br />');
                   &display_defprivs($r,$tools,$toolprivs,\@defprivs);
               } else {
                   $r->print($lt{'asno'}.'<br />');
               }
           }
       } else {
           $r->print($lt{'asng'});
       }
       return $numchgs;
   }
   
   sub process_request {
       my ($r,$cdom,$cnum,$action,$state,$page,$groupname,$description,
           $specificity,$userdata,$startdate,$enddate,$tools,$functions,$toolprivs,
           $usertools,$idx,$types,$roles,$sections,$states,$navbuttons,$memchg,
           $sectioncount,$stored,$gpterm,$ucgpterm,$crstype) = @_;
   
       $r->print(&Apache::lonhtmlcommon::echo_form_input(
                                    ['origin','action','state','page','sortby']));
   
       my $earlyout = &validate_groupname($groupname,$action,$cdom,$cnum,$gpterm,
                                          $ucgpterm,$crstype);
       if ($earlyout) {
           $r->print('
   <table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tr>
     <td>&nbsp;</td>
     <td colspan="3">
   '.$earlyout.'</td></tr>');
           &display_navbuttons($r,$state,$$states{$action}[$page-1],
                               $$navbuttons{'gtps'});
           $r->print('</table>');
           return;
       }
   
       my @defprivs = ();
       if ($action eq 'create' || $state eq 'chgresult') { 
           if (defined($env{'form.defpriv'})) {
               @defprivs = &Apache::loncommon::get_env_multiple('form.defpriv');
           }
           if ($state eq 'chgresult') {
               my @okprivs = ();
               foreach my $tool (@{$tools}) {
                   foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
                       push(@okprivs,$priv);
                   }
               }
               my @temp = ();
               foreach my $defpriv (@defprivs) {
                   if (grep/^$defpriv$/,@okprivs) {
                       push(@temp,$defpriv);
                   }
               }
               @defprivs = @temp; 
           }
       } else {
           if (defined($$stored{'defpriv'})) {
               @defprivs = @{$$stored{'defpriv'}};
           }
       }
   
       my $outcome;
       if ($action eq 'create' || $state eq 'chgresult') {
           $outcome = &write_group_data($r,$cdom,$cnum,$action,$state,$groupname,
                                        $description,$startdate,$enddate,
                                        $specificity,$functions,$tools,
                                        $sectioncount,$roles,$types,$sections,
                                        \@defprivs,$stored,$gpterm,$ucgpterm,
                                        $crstype); 
       }
       if (($action eq 'create' && $outcome eq 'ok') || (($action eq 'modify') && 
          (($state eq 'memresult') || ($state eq 'addresult')))) {
           &process_membership($r,$cdom,$cnum,$action,$state,$groupname,$tools,
                               $enddate,$startdate,$userdata,$idx,$toolprivs,
                               $usertools,$specificity,\@defprivs,$memchg,$gpterm,
                               $ucgpterm);
       }
       return;
   }
   
   sub write_group_data {
       my ($r,$cdom,$cnum,$action,$state,$groupname,$description,$startdate,
           $enddate,$specificity,$functions,$tools,$sectioncount,$roles,$types,
           $sections,$defprivs,$stored,$gpterm,$ucgpterm,$crstype) = @_;
       my $now = time;
       my $creation = $now;
       my $creator = $env{'user.name'}.':'.$env{'user.domain'};
       if ($state eq 'chgresult') {
           $creation = $$stored{'creation'};
           $creator = $$stored{'creator'};
       }
       my $esc_description = &escape($description);
       my @single_attributes = ('description','functions','startdate','enddate',
                                'creation','modified','creator','granularity',
                                'specificity','autoadd','autodrop','quota');
       my @mult_attributes = ('roles','types','sectionpick','defpriv');
   
       my ($crsquota,$freespace,$maxposs) = &get_quota_constraints($action,
                                                                   $stored);
       my $quota = $env{'form.quota'};
       
       $quota =~ s/^\s*([^\s]*)\s*$/$1/;
       if ($quota eq '') {
           $quota = 0;
       }
       if ($quota !~ /^\d*\.?\d*$/) {
           $quota = 0;
           $r->print(&mt('The value you entered for the quota for the file repository in this [_1] contained invalid characters, so it has been set to 0 Mb. You can change this by modifying the [_1] settings.<br />',$gpterm));
       }
       if ($quota > $maxposs) {
           $quota = $maxposs;
           $r->print(&mt('The value you entered for the quota for the file repository in this [_1] exceeded the maximum possible value, so it has been set to [_2] Mb (the maximum possible value).<br />',$gpterm,sprintf("%.2f",$maxposs)));
       }
       my %groupinfo = (
                        description => $esc_description,
                        startdate => $startdate,
                        enddate => $enddate,
                        creation => $creation,
                        modified => $now,
                        creator => $creator,
                        granularity => $env{'form.granularity'},
                        specificity => $specificity,
                        autoadd => $env{'form.autoadd'},
                        autodrop => $env{'form.autodrop'},
                        quota => $quota,
                      );
   
       foreach my $func (keys(%{$functions})) {
           my $status;
           if (grep(/^$func$/,@{$tools})) {
               $status = 'on';
           } else {
               $status = 'off';
           }
           $groupinfo{'functions'} .=  qq|<name id="$func">$status</name>|;
       }
   
       $groupinfo{'roles'} = $roles;
       $groupinfo{'types'} = $types;
       $groupinfo{'sectionpick'} = $sections;
       $groupinfo{'defpriv'} = $defprivs;
   
       my %groupsettings = ();
       foreach my $item (@single_attributes) {
           $groupsettings{$groupname} .= qq|<$item>$groupinfo{$item}</$item>|;
       }
       foreach my $item (@mult_attributes) {
           foreach my $entry (@{$groupinfo{$item}}) {
               $groupsettings{$groupname} .= qq|<$item>$entry</$item>|;
           }
       }
       my $autosec;
       my @autorole = &Apache::loncommon::get_env_multiple('form.autorole');
   
       foreach my $role (@autorole) {
           if (defined($env{'form.sec_'.$role})) {
               my @autosections=&Apache::loncommon::get_env_multiple('form.sec_'.
                                                                     $role);
               $autosec .= '<role id="'.$role.'">';
               foreach my $sec (@autosections) {
                   $autosec .= '<section>'.$sec.'</section>';
               }
               $autosec .= '</role>';
           }
       }
       if ($autosec) {
           $groupsettings{$groupname} .= qq|<autosec>$autosec</autosec>|;
       }
       my $result = &Apache::lonnet::modify_coursegroup($cdom,$cnum,
                                                        \%groupsettings);
   
       if ($result eq 'ok') {
           if ($action eq 'create') {
               my $result = &add_group_folder($cdom,$cnum,$now,$groupname,$action,
                                              $description,$tools,\%groupinfo,
                                              $gpterm,$ucgpterm,$crstype);
               if ($result ne 'ok') {
                   $r->print(&mt('A problem occurred when creating folders for the new [_1]. [_2].<br />',$gpterm,$result));
               }
               $r->print(&mt('[_1] [_2] was created.<br />',$ucgpterm,$groupname));
           } elsif ($action eq 'modify') {
               my (@oldtools,@newtools); 
               if (ref($$stored{'tool'}) eq 'ARRAY') {
                   @oldtools = @{$$stored{'tool'}};
               }
               if (ref($tools) eq 'ARRAY') {
                   @newtools = @{$tools};
               }
               if (!grep(/^discussion$/,@oldtools) && 
                    grep(/^discussion$/,@newtools)) {
                   my $crspath = '/uploaded/'.$cdom.'/'.$cnum.'/';
                   my $boardsmap = $crspath.'group_boards_'.$groupname.'.sequence';
                   my $navmap = Apache::lonnavmaps::navmap->new();
                   my $bbmapres = $navmap->getResourceByUrl($boardsmap);
                   undef($navmap);
                   if (!$bbmapres) {
                       my $grpmap = $crspath.'group_folder_'.$groupname.'.sequence';
                       my $disctitle = &mt('Discussion Boards');
                       my $outcome = &map_updater($cdom,$cnum,'group_boards_'.
                                                  $groupname.'.sequence','bbseq',
                                                  $disctitle,$grpmap);
                       my ($furl,$ferr) = 
                           &Apache::lonuserstate::readmap($cdom.'/'.$cnum);
                       $navmap = Apache::lonnavmaps::navmap->new();
                       # modify parameter
                       if ($outcome eq 'ok') {
                           my $parm_result = &parm_setter($navmap,$cdom,$boardsmap,
                                                          $groupname);
                           if ($parm_result) {
                               $r->print(&mt('Error while setting parameters '.
                                             'for Discussion Boards folder: '.
                                             '[_1]<br />.',$parm_result));
                           } else {
                               $r->print(&mt('Discussion Boards Folder created.<br />'));
                           }
                       } else {
                           $r->print($outcome);
                       }
                       undef($navmap);
                   }
               }
               $r->print(&mt('[_1] [_2] was updated.<br />',$ucgpterm,$groupname));
           }
       } else {
           my %actiontype = (
                             'create' => 'creating',
                             'modify' => 'modifying',
                            );
           &Apache::lonnet::logthis("Failed to store $gpterm $groupname ".
                                    'in '.lc($crstype).': '.$cnum.
                                    ' in domain: '.$cdom);
           $r->print(&mt('An error occurred when [_1] the [_2]. '.
                         'Please try again.',$actiontype{$action},$gpterm));
       }
       return $result;
   }
   
   sub process_membership {
       my ($r,$cdom,$cnum,$action,$state,$groupname,$tools,$enddate,$startdate,
           $userdata,$idx,$toolprivs,$usertools,$specificity,$defprivs,$memchg,
           $gpterm,$ucgpterm)=@_;
       my %usersettings = ();
       my %added= ();
       my %failed = ();
       my $num_ok = 0;
       my $num_fail = 0;
       my %group_privs = ();
       my %curr_privs = ();
       my %curr_start = ();
       my %curr_end = ();
       my %tooltype = ();
   
       foreach my $tool (@{$tools}) {
           foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
               $tooltype{$priv} = $tool;
               if ($specificity eq 'Yes') {
                   my @users =
                     &Apache::loncommon::get_env_multiple('form.userpriv_'.$priv);
                   foreach my $user (@users) {
                       $group_privs{$user} .= $priv.':';
                       if ($state eq 'memresult') { 
                           unless (exists($$usertools{$user}{$tool})) {
                               $$usertools{$user}{$tool} = 1;
                           }
                       }
                   }
               } else {
                   if (@{$defprivs} > 0) {
                       if (grep/^\Q$priv\E$/,@{$defprivs}) {
                           foreach my $user (sort(keys(%{$usertools}))) {
                               if ($$usertools{$user}{$tool}) {
                                   $group_privs{$user} .= $priv.':';
                               }
                           }
                       }
                   }
               }
           }
       }
       foreach my $user (keys(%group_privs)) {
           $group_privs{$user} =~ s/:$//;
       }
   
       my $now = time;
       my @activate = ();
       my @expire = ();
       my @deletion = ();
       my @reenable = ();
       my @unchanged = ();
       if ($state eq 'memresult') {
           if (ref($$memchg{'activate'}) eq 'ARRAY') {
               @activate = @{$$memchg{'activate'}};
           }
           if (ref($$memchg{'expire'}) eq 'ARRAY') {
               @expire = @{$$memchg{'expire'}};
           }
           if (ref($$memchg{'deletion'}) eq 'ARRAY') {
               @deletion = @{$$memchg{'deletion'}};
           }
           if (ref($$memchg{'reenable'}) eq 'ARRAY') {
               @reenable = @{$$memchg{'reenable'}};
           }
           my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
                                                                    $groupname);
           foreach my $key (sort(keys(%membership))) {
               if ($key =~ /^\Q$groupname\E:([^:]+:[^:]+)$/) {
                   ($curr_end{$1},$curr_start{$1},$curr_privs{$1}) = 
                                                   split(/:/,$membership{$key},3);
               }
           }
           if (@expire + @deletion > 0) {
               foreach my $user (@expire) {
                   my $savestart = $curr_start{$user};
                   if ($savestart > $now) {
                       $savestart = $now;
                   }
                   $usersettings{$groupname.':'.$user} = $now.':'.$savestart.':'.
                                                         $curr_privs{$user};
                   if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname,
                                                          $user,$now,$savestart,
                                                          $curr_privs{$user}) eq 'ok') {
                       push(@{$added{'expired'}},$user);
                       $num_ok ++;
                   } else {
                       push(@{$failed{'expired'}},$user);
                       $num_fail ++;
                   }
               }
               foreach my $user (@deletion) {
                   $usersettings{$groupname.':'.$user} = $now.':-1:';
                   if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname,
                                                          $user,$now,'-1','')
                                                            eq 'ok') {
                       push(@{$added{'deleted'}},$user);
                       $num_ok ++;
                   } else {
                       push(@{$failed{'deleted'}},$user);
                       $num_fail ++;
                   }
               }
           }
       }
   
       foreach my $user (sort(keys(%{$usertools}))) {
           if ((grep(/^$user$/,@expire)) || (grep(/^$user$/,@deletion))) {
               next;
           }
           my $type;
           my $start = $startdate;
           my $end = $enddate;
           if ($state eq 'memresult') {
               if (@activate > 0) {
                   if (grep/^$user$/,@activate) {
                       $start = $now;
                       $end = $enddate;
                       $type = 'activated';
                   }
               }
               if (@reenable > 0) {
                   if (grep/^$user$/,@reenable) {
                       $start = $startdate;
                       $end = $enddate;
                       $type = 'reenabled';
                   }
               }
               if ($type eq '') {
                   if ($curr_privs{$user} eq $group_privs{$user}) {
                       push(@unchanged,$user);
                       next;
                   }
                   if (exists($curr_start{$user})) {
                       $start = $curr_start{$user};
                   }
                   if (exists($curr_end{$user})) {
                       $end = $curr_end{$user};
                   }
                   $type = 'modified';
               }
           } else {
               $type = 'added';
           }
           $usersettings{$groupname.':'.$user} = $end.':'.$start.':'.
                                                 $group_privs{$user};
           if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname,
                                                   $user,$end,$start,
                                                   $group_privs{$user}) eq 'ok') {
               push(@{$added{$type}},$user);
               $num_ok ++;
           } else {
               push(@{$failed{$type}},$user);
               $num_fail ++;
           }
       }
       my $roster_result = &Apache::lonnet::modify_coursegroup_membership($cdom,
                                                          $cnum,\%usersettings);
       if ($num_ok) {
           foreach my $type (sort(keys(%added))) { 
               $r->print(&mt('The following users were successfully [_1]',$type));
               if (!($type eq 'deleted' || $type eq 'expired')) {   
                   $r->print(&mt(' with the following privileges'));
               }
               $r->print(':<br />');
               foreach my $user (@{$added{$type}}) {
                   my $privlist = '';
                   if (!($type eq 'deleted' ||  $type eq 'expired')) {
                       $privlist = ': ';
                       my @privs = split(/:/,$group_privs{$user});
                       my $curr_tool = '';
                       foreach my $priv (@privs) {
                           unless ($curr_tool eq $tooltype{$priv}) {
                               $curr_tool = $tooltype{$priv};
                               $privlist .= '<b>'.$curr_tool.'</b>: ';
                           }
                           $privlist .= $$toolprivs{$curr_tool}{$priv}.', ';
                       }
                       $privlist =~ s/, $//;
                   }
                   $r->print($$userdata{$user}[$$idx{fullname}].'&nbsp;-&nbsp;'.$user.$privlist.'<br />');
               }
               $r->print('<br />');
           }
       }
       if ($num_fail) {
           foreach my $type (sort(keys(%failed))) {
               $r->print(&mt('The following users could not be [_1], because an error occurred:<br />',$type));
               foreach my $user (@{$failed{$type}}) {
                   $r->print($$userdata{$user}[$$idx{fullname}].' - '.$user.'<br />');
               }
           }
           $r->print('<br />');
       }
       if (@unchanged > 0) {
           $r->print(&mt('No change occurred for the following users:<br />'));
           foreach my $user (sort(@unchanged)) {
               $r->print($$userdata{$user}[$$idx{fullname}].' - '.$user.'<br />');
           }
           $r->print('<br />');
       }
       if ($roster_result eq 'ok') {
           $r->print('<br />'.&mt('[_1] membership list updated.',$ucgpterm));
    $r->print('<p>'.&mt("Any currently logged in course users affected by the changes you made to group membership or privileges for the [_1] group will need to log out and log back in for their LON-CAPA sessions to reflect these changes.",$groupname).'</p>');
       } else {
           $r->print('<br />'.&mt('An error occurred while updating the [_1] membership list -',$gpterm).$roster_result.'<br />');
       }
       return;
   }
   
   sub mapping_options {
       my ($r,$action,$formname,$page,$sectioncount,$states,$stored,
           $navbuttons,$img1,$img2,$gpterm,$ucgpterm,$crstype,$cdom,$cnum) = @_;
       my %lt = &Apache::lonlocal::texthash(
           'auto' => "Settings for automatic $gpterm enrollment",
           'gmma' => "$ucgpterm membership mapping to specific sections/roles",
           'endi' => "Enable/disable automatic $gpterm enrollment for ".
                             "users in specified roles and sections",
           'adds'  => "If automatic $gpterm enrollment is enabled, when a user is newly assigned a ".lc($crstype)."-wide or section-specific role, he/she will automatically be added as a member of the $gpterm, with start and end access dates defined by the default dates set for the $gpterm, unless he/she is already a $gpterm member, with access dates that permit either current or future $gpterm access.",
           'drops'  => "If automatic $gpterm disenrollment is enabled, when a user's role is expired, access to the $gpterm will be terminated unless the user continues to have other ".lc($crstype)."-wide or section-specific active or future roles which receive automatic membership in the $gpterm.",
           'pirs' => "Pick roles and sections for automatic $gpterm enrollment",
           'curr' => 'Currently set to',
           'on' => 'on',
           'off' => 'off',
           'auad' => "Automatically enable $gpterm membership when roles are added?",
           'auex' => "Automatically expire $gpterm membership when roles are removed?",
           'mapr' => "Mapping of roles and sections affected by automatic $gpterm enrollment/disenrollment follows scheme chosen below.",
       );
       &automapping($r,$action,$stored,\%lt,$img1);
       &mapping_settings($r,$sectioncount,\%lt,$stored,$img2,$crstype,$cdom,$cnum,
                         $action);
       return;
   }
   
   sub automapping {
       my ($r,$action,$stored,$lt,$image) = @_;
       my $add = 'off';
       my $drop = 'off';
       if (exists($$stored{'autoadd'})) {
           $add = $$stored{'autoadd'};
       }
       if (exists($$stored{'autodrop'})) {
           $drop = $$stored{'autodrop'};
       }
       &topic_bar($r,$image,$$lt{'endi'});
       $r->print('
       <b>'.$$lt{'gmma'}.':</b><br />'.$$lt{'adds'}.'<br />'.$$lt{'drops'}.'<br /><br />
      <nobr>'.$$lt{'auad'}.':&nbsp;
       <label><input type="radio" name="autoadd" value="on" />on&nbsp;&nbsp;</label><label><input type="radio" name="autoadd" value="off" checked="checked" />off</label>');
       if ($action eq 'modify') {
           $r->print('&nbsp;&nbsp;&nbsp;&nbsp;('.$$lt{'curr'}.' <b>'.$$lt{$add}.'</b>)');
       }
       $r->print('
       </nobr><br />
       <nobr>'.$$lt{'auex'}.':&nbsp;
       <label><input type="radio" name="autodrop" value="on" />on&nbsp;&nbsp;</label><label><input type="radio" name="autodrop" value="off" checked="checked" />off</label>');
       if ($action eq 'modify') {
           $r->print('&nbsp;&nbsp;&nbsp;&nbsp;('.$$lt{'curr'}.' <b>'.$$lt{$drop}.'</b>)');
       }
       $r->print('</nobr><br /><br />'.$$lt{'mapr'});
   }
   
   sub mapping_settings {
       my ($r,$sectioncount,$lt,$stored,$image,$crstype,$cdom,$cnum,$action) = @_;
       my @sections = keys(%{$sectioncount});
       if (@sections > 0) {
           @sections = sort {$a cmp $b} @sections;
           unshift(@sections,'none'); # Put 'no sections' next
           unshift(@sections,'all'); # Put 'all' at the front of the list
       } else {
           @sections = ('all','none');
       }
       &topic_bar($r,$image,$$lt{'pirs'});
       my @roles = &standard_roles();
       my %customroles = &Apache::lonhtmlcommon::course_custom_roles($cdom,$cnum);
       $r->print(&Apache::loncommon::start_data_table().
         &Apache::loncommon::start_data_table_header_row());
       $r->print('
                    <th>'.&mt('Active?').'</th>
                    <th>'.&mt('Role').'</th>');
       if (@sections > 0) {
           $r->print('<th>'.&mt('Sections').'</th>');
       }
       $r->print(&Apache::loncommon::end_data_table_header_row()."\n");
       foreach my $role (@roles) {
           my $roletitle=&Apache::lonnet::plaintext($role,$crstype);
           $r->print(&print_autorole_item($role,$roletitle,\@sections));
       }
       my @customs;
       foreach my $role (sort(keys(%customroles))) {
           my ($roletitle) = ($role =~ m|^cr/[^/]+/[^/]+/(.+)$|);
           push (@customs,$role);
           $r->print(&print_autorole_item($role,$roletitle,\@sections));
       }
       if ($action eq 'modify') {
           foreach my $role (@{$$stored{'autorole'}}) {
               if ((!grep(/^\Q$role\E$/,@customs)) && 
                   (!grep(/^\Q$role\E$/,@roles))) {
                   my $roletitle;
                   if ($role =~ /^cr/) {
                       ($roletitle) = ($role =~ m|_([^_]+)$|);
                   } else {
                       $roletitle = &Apache::lonnet::plaintext($role,$crstype);
                   }
                   $r->print(&print_autorole_item($role,$roletitle,\@sections));
               }
           }
       }
       $r->print(&Apache::loncommon::end_data_table());
       return;
   }
   
   sub print_autorole_item {
       my ($role,$roletitle,$sections) = @_;
       my $sections_sel;
       if (@{$sections} > 0) {
           if ($role eq 'cc') {
               $sections_sel = '<td align="right">'.
                               &mt('all sections').'<input type="hidden" '.
                               'name="sec_cc" value="all" /></td>';
           } else {
               $sections_sel='<td align="right">'.
                             &sections_selection($sections,'sec_'.$role).
                             '</td>';
           }
       }
       my $output = &Apache::loncommon::start_data_table_row().
                    '<td><input type="checkbox" '.
                    'name="autorole" value="'.$role.'" />'.
                    '</td><td>'.$roletitle.'</td>'.$sections_sel.
                    &Apache::loncommon::end_data_table_row();
       return $output;
   } 
   
   sub standard_roles {
       my @roles = ('cc','in','ta','ep','st');
       return @roles;
   }
   
   sub modify_menu {
       my ($r,$groupname,$page,$gpterm) = @_;
     my @menu =      my @menu =
         (          (
           { text => 'Create a new group',            { text => "Modify default $gpterm settings",
             help => 'Course_Create_Group',  
             action => 'create',  
             permission => $manage_permission,  
             },  
           { text => 'Modify an existing group',  
             help => 'Course_Modify_Group',              help => 'Course_Modify_Group',
             action => 'modify',              state => 'change_settings',
             permission => $manage_permission,              branch => 'settings',
             },              },
           { text => 'Delete an existing group',            { text => 'Modify access, tools and/or privileges for previous, '.
             help => 'Course_Delete_Group',                      'future, or current members',
             action => 'delete',              help => 'Course_Modify_Group_Membership',
             permission => $manage_permission,              state => 'change_members',
               branch => 'members',
             },              },
           { text => 'Enter an existing group',            { text => "Add member(s) to the $gpterm",
             help => 'Course_Display_Group',              help => 'Course_Group_Add_Members',
             action => 'display',              state => 'add_members',
             permission => $view_permission,              branch => 'adds',
             },              },
           );            );
     my $menu_html = '';      my $menu_html = '';
     foreach my $menu_item (@menu) {      foreach my $menu_item (@menu) {
         next if (! $menu_item->{'permission'});          $menu_html .=
         $menu_html.='<p>';          '<p><font size="+1"><a href="/adm/coursegroups?action=modify&refpage='.$env{'form.refpage'}.'&groupname='.$groupname.'&state='.$menu_item->{'state'}.'&branch='.$menu_item->{'branch'}.'">';
         $menu_html.='<font size="+1">';  
         if (exists($menu_item->{'url'})) {  
             $menu_html.=qq{<a href="$menu_item->{'url'}">};  
         } else {  
             $menu_html.=  
                 qq{<a href="/adm/coursegroups?action=$menu_item->{'action'}">};  
         }  
         $menu_html.= &mt($menu_item->{'text'}).'</a></font>';          $menu_html.= &mt($menu_item->{'text'}).'</a></font>';
         if (exists($menu_item->{'help'})) {          if (exists($menu_item->{'help'})) {
             $menu_html.=              $menu_html.=
Line 149  sub print_main_menu { Line 3241  sub print_main_menu {
     return;      return;
 }  }
   
 sub footer {  sub member_privs_entries {
        return(<<ENDFOOT);      my ($r,$usertools,$toolprivs,$fixedprivs,$userdata,$idx,$showtools,
   </form>   $defprivs,$excluded) = @_;
  </body>      foreach my $user (sort(keys(%{$usertools}))) {
 </html>          if (defined($excluded)) {
 ENDFOOT              if (ref($excluded) eq 'ARRAY') {
                    if (grep/^$user$/,@{$excluded}) {
                       next;
                   }
               }
           }
           my ($uname,$udom) = split(/:/,$user);
           $r->print(&Apache::loncommon::start_data_table_row().'
                   <td>'.$$userdata{$user}[$$idx{fullname}].'</td>
                   <td>'.$uname.'</td>
                   <td>'.$udom.'</td>
                   <td valign="top">
                     <table>
                      <tr>
                       <td><b>'.
                       &mt('Collaborative Tool').'</b></td>
                      </tr>
                      <tr>
                       <td><b>'.&mt('Fixed').'</b></td>
                      </tr>
                      <tr>
                       <td><b>'.&mt('Optional').'</b></td>
                      </tr>
                     </table>
                    </td>');
           foreach my $tool (@{$showtools}) {
               if (exists($$usertools{$user}{$tool})) {
                   $r->print('<td valign="top"><table><tr><th colspan="2">'.$tool.'</th></tr>');
                   my $privcount = 0;
                   my $fixed = '';
                   my $dynamic = '';
                   foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) {
                       if (exists($$fixedprivs{$tool}{$priv})) {
                           $fixed .= '<input type="hidden" name="userpriv_'.$priv.'" value="'.$user.'" />'.$$toolprivs{$tool}{$priv}.'&nbsp;';
                       } else {
                           $privcount ++;
                           if ($privcount == 3) {
                               $dynamic .= '</tr><tr>';
                           }
                           $dynamic .='<td><nobr><label><input type="checkbox" '.
                                  'name="userpriv_'.$priv.'" value="'.$user.'"';
                           if (grep/^\Q$priv\E$/,@{$defprivs}) {
                               $dynamic .= ' checked="checked" ';
                           }
                           $dynamic .= ' />'.$$toolprivs{$tool}{$priv}.
                                       '</label></nobr></td>';
                       }
                   }
                   $r->print('<tr><td colspan="2"><nobr>'.$fixed.'</nobr></td></tr><tr>'.$dynamic.'</tr></table></td>');
               } else {
                   $r->print('<td valign="top"><table width="100%"><tr><th colspan="2">'.$tool.'</th></tr><tr><td>&nbsp;</td></tr><tr><td>&nbsp;</td></tr></table></td>');
               }
           }
           $r->print(&Apache::loncommon::end_data_table_row());
       }
 }  }
   
 sub first_creation_form {  sub get_dates_from_form {
     my ($r) = @_;      my $startdate;
     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};      my $enddate;
     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};      $startdate = &Apache::lonhtmlcommon::get_date_from_form('startdate');
     my %lt = &Apache::lonlocal::texthash(      $enddate   = &Apache::lonhtmlcommon::get_date_from_form('enddate');
         'gmem' => 'Group membership options',      if ( exists ($env{'form.no_end_date'}) ) {
         'picr' => 'Pick the criteria to use to build a list of course users from which you will select members of the new group',             $enddate = 0;
         'gdat' => 'Group open and close dates',      }
         'sten' => 'Set a start date/time and end date/time for the group',      return ($startdate,$enddate);
         'acst' => 'Active/Inactive status',  }
         'coro' => 'Course roles',  
         'cose' => 'Course sections',  
         'gfun' => 'Group functionality',  
     );  
   
     my %status_types = (  sub date_setting_table {
                    active => &mt('Currently has access'),      my ($starttime,$endtime,$formname) = @_;
                    previous => &mt('Previously had access'),      my $startform = &Apache::lonhtmlcommon::date_setter($formname,
                    future => &mt('Will have future access'),                                                        'startdate',$starttime);
       my $endform = &Apache::lonhtmlcommon::date_setter($formname,
                                                         'enddate',$endtime);
       my $perpetual = 
    '<nobr><label><input type="checkbox" name="no_end_date" />'.
    &mt('None').'</label></nobr>';
       my $table = "<table class=\"LC_descriptive_input\">\n".
    '<tr><td class="LC_description">'.&mt('Start:').'</td>'.
           '<td>'.$startform.'</td>'.
           '<td>&nbsp;</td>'."</tr>\n".
    '<tr><td class="LC_description">'.&mt('End:').'</td>'.
           '<td>'.$endform.'</td>'.
           '<td>'.$perpetual.'</td>'."</tr>\n".
    "</table>\n";
       return $table;
   }
   
   sub add_group_folder {
       my ($cdom,$cnum,$now,$groupname,$action,$description,$tools,$groupinfo,
           $gpterm,$ucgpterm,$crstype) = @_;
       if ($cdom eq '' || $cnum eq '') {
           return &mt('Error: invalid course domain or number - group folder creation failed');  
       }
       my ($outcome,$allgrpsmap,$grpmap,$boardsmap,$grppage);
       my $navmap = Apache::lonnavmaps::navmap->new();
       my $crspath = '/uploaded/'.$cdom.'/'.$cnum.'/';
       $allgrpsmap = $crspath.'group_allfolders.sequence';
       my $topmap = $navmap->getResourceByUrl($allgrpsmap);
       undef($navmap);
       if ($action eq 'create') {
       # check if group_allfolders.sequence exists.
           if (!$topmap) {
               my $grpstitle = &mt('[_1] [_2]s',$crstype,$ucgpterm);
               my $topmap_url = '/'.$env{'course.'.$env{'request.course.id'}.'.url'};
               $topmap_url =~ s|/+|/|g;
               if ($topmap_url =~ m|^/uploaded|) {
                   $outcome = &map_updater($cdom,$cnum,'group_allfolders.sequence',
                                           'toplevelgroup',$grpstitle,$topmap_url);
                   if ($outcome ne 'ok') {
                       return $outcome;
                   }
               } else {
                   $outcome = &mt('Non-standard course - folder for all groups not added.');
                   return $outcome;
               }
           }
           my $grpfolder = &mt('[_1] Folder -',$ucgpterm,).$description;
           $grppage='/adm/'.$cdom.'/'.$cnum.'/'.$groupname.'/smppg';
           my $grptitle = &mt('Group homepage').' - '.$description;
           my ($discussions,$disctitle);
           my $outcome = &map_updater($cdom,$cnum,'group_folder_'.$groupname.'.sequence',
                                      'grpseq',$grpfolder,$allgrpsmap,$grppage,
                                      $grptitle);
           if ($outcome ne 'ok') {
               return $outcome;
           }
           my $pageout = &create_homepage($cdom,$cnum,$groupname,$groupinfo,
                                          $tools,$gpterm,$ucgpterm,$now);
           # Link to folder for bulletin boards
           $grpmap = $crspath.'group_folder_'.$groupname.'.sequence';
           if (grep/^discussion$/,@{$tools}) {
               $disctitle = &mt('Discussion Boards');
               my $outcome = &map_updater($cdom,$cnum,'group_boards_'.$groupname.
                                          '.sequence','bbseq',$disctitle,$grpmap);
               if ($outcome ne 'ok') {
                   return $outcome;
               }
               $boardsmap = $crspath.'group_boards_'.$groupname.'.sequence';
           }
       } else {
           #modify group folder if status of discussions tools is changed
       }
       my ($furl,$ferr)= &Apache::lonuserstate::readmap($cdom.'/'.$cnum);
       $navmap = Apache::lonnavmaps::navmap->new();
       # modify parameters
       my $parm_result;
       if ($action eq 'create') {
           if ($grpmap) {
               $parm_result .= &parm_setter($navmap,$cdom,$grpmap,$groupname);
           }
           if ($grppage) {
               $parm_result .= &parm_setter($navmap,$cdom,$grppage,$groupname);
           }
           if ($boardsmap) {
               $parm_result .= &parm_setter($navmap,$cdom,$boardsmap,$groupname);
           }
       }
       if ($parm_result) {
           return $parm_result;
       } else {
           return 'ok';
       }
   }
   
   sub map_updater {
       my ($cdom,$cnum,$newfile,$itemname,$itemtitle,$parentmap,$startsrc,
           $starttitle,$endsrc,$endtitle) = @_;
       my $outcome;
       $env{'form.'.$itemname} = &new_map($startsrc,$starttitle,$endsrc,
                                          $endtitle);
       my $newmapurl=&Apache::lonnet::finishuserfileupload($cnum,$cdom,$itemname,
                                                           $newfile);
       if ($newmapurl !~ m|^/uploaded|) {
           $outcome = &mt('Error uploading new folder.')." ($newfile): $newmapurl".'<br />';
           return $outcome;
       } 
       my ($errtext,$fatal)=&Apache::lonratedt::mapread($parentmap);
       if ($fatal) {
           $outcome = &mt('Error reading contents of parent folder')." ($parentmap): $errtext".'<br />';
           return $outcome;
       } else {
           my $newidx=&Apache::lonratedt::getresidx($newmapurl);
           $Apache::lonratedt::resources[$newidx] = $itemtitle.':'.$newmapurl.
                                                    ':false:normal:res';
           $Apache::lonratedt::order[1+$#Apache::lonratedt::order]=$newidx;
           my ($outtext,$errtext) = &Apache::lonratedt::storemap($parentmap,1);
           if ($errtext) {
               $outcome = &mt('Error storing updated parent folder')." ($parentmap):  $errtext".'<br />';
               return $outcome;
           }
       }
       return 'ok';
   }
   
   sub new_map {
       my ($startsrc,$starttitle,$endsrc,$endtitle) = @_;
       my $newmapstr = '
   <map>
    <resource id="1" src="'.$startsrc.'" type="start" title="'.$starttitle.'"></resource>
    <link from="1" to="2" index="1"></link>
    <resource id="2" src="'.$endsrc.'" type="finish" title="'.$endtitle.'"></resource>
   </map>
   ';
       return $newmapstr;
   }
   
   sub parm_setter {
       my ($navmap,$cdom,$url,$groupname) = @_;
       my $allresults;
       my %hide_settings = (
                              'course' =>  {
                                             'num' => 13,
                                             'set' => 'yes',
                                           },
                               'group' =>  {
                                             'num' => 5,
                                             'set' => 'no',
                                             'extra' => $groupname,
                                           },
                           );
       my $res = $navmap->getResourceByUrl($url);
       my $symb = $res->symb();
       foreach my $level (keys(%hide_settings)) {
           my $parmresult =  &Apache::lonparmset::storeparm_by_symb($symb,
                                                    '0_hiddenresource',
                                                    $hide_settings{$level}{'num'},
                                                    $hide_settings{$level}{'set'},
                                                    'string_yesno',undef,$cdom,
                                                    undef,undef,
                                                    $hide_settings{$level}{'extra'});
           if ($parmresult) {
               $allresults .= $level.': '.$parmresult;
           }
       }
       return $allresults;
   }
   
   sub create_homepage {
       my ($cdom,$cnum,$name,$groupinfo,$tools,$gpterm,$ucgpterm,$now) = @_;
       my $functionality = join(',',@{$tools});
       my $content = &unescape($$groupinfo{description});
       $content=~s/\s+$//s;
       $content=~s/^\s+//s;
       $content=~s/\<br\s*\/*\>$//s;
       $content=&Apache::lonfeedback::clear_out_html($content,1);
   
       my %pageinfo = (
                        'aaa_title' => "$ucgpterm: $name",
                        'abb_links' => $functionality,
                        'bbb_content' => $content,
                        'ccc_webreferences' => '',
                        'uploaded.lastmodified' => $now,
                    );                     );
      my $putresult = &Apache::lonnet::put('grppage_'.$name,\%pageinfo,$cdom,$cnum);
      return $putresult;
   }
   
     my @roles = ('st','cc','in','ta','ep','cr');  sub check_uncheck_tools {
       my ($r,$available) = @_;
       if (ref($available) eq 'ARRAY') { 
           $r->print('
   <script type="text/javascript">
   function checkAllTools(formname) {
   ');
           foreach my $tool (@{$available}) {
               $r->print('  checkAll(formname.user_'.$tool.');'."\n");
           }
           $r->print(' checkAll(formname.togglefunc);'."\n");
           $r->print('
   }
   function uncheckAllTools(formname) {
   ');
           foreach my $tool (@{$available}) {
               $r->print('  uncheckAll(formname.user_'.$tool.');'."\n");
           }
           $r->print(' uncheckAll(formname.togglefunc);'."\n");
           $r->print('
   }
   function toggleTools(field,caller) {
        if (caller.checked) {
            checkAll(field);
        } else {
            uncheckAll(field);
        }
        return;   
   }
   </script>
   ');
       }
       return;
   }
   
     my %sectioncount = ();  sub validate_groupname {
     my @sections = ();      my ($groupname,$action,$cdom,$cnum,$gpterm,$ucgpterm,$crstype) = @_;
     my $section_sel = '';      my %sectioncount = &Apache::loncommon::get_sections($cdom,$cnum);
     my $numvisible;      my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
     my $numsections = &Apache::loncommon::get_sections($cdom,$cnum,  
                            \%sectioncount);      my %lt = &Apache::lonlocal::texthash (
                         igna => "Invalid $gpterm name",
     @sections = sort {$a cmp $b} keys(%sectioncount);                        tgne => "The $gpterm name entered ",
     unshift(@sections,'all'); # Put 'all' at the front of the list                        grna => "$ucgpterm names and section names used in a ".
     if ($numsections < 4) {                                 "$crstype must be unique.",
         $numvisible = $numsections + 1;                        isno => "is not a valid name.",
                         gnmo => "$ucgpterm names may only contain letters, ". 
                                 "numbers or underscores.",
                         cnnb => "can not be used as it is the name of ",
                         inth => " in this $crstype", 
                         thgr => "- does not correspond to the name of an ".
                                 "existing $gpterm",    
       );
   
       my $exitmsg = '<span class="LC_error">'.$lt{'igna'}.'</span><br /><br />'.
    $lt{'tgne'}.' "'.$groupname.'" ';
       my $dupmsg = $lt{'grna'};
       my $earlyout;
       if (($groupname eq '') || ($groupname =~ /\W/)) {
           $earlyout = $exitmsg.$lt{'isno'}.'<br />'.$lt{'gnmo'};
           return $earlyout;
       }
       if (exists($sectioncount{$groupname})) {
    return $exitmsg.$lt{'cnnb'}.&mt('a section').$lt{'inth'}.
       '<br />'.$lt{'grna'};
     }      }
       if ($action eq 'create' 
    && exists($curr_groups{$groupname})) {
   
     $r->print(<<"END");   return $exitmsg.$lt{'cnnb'}.&mt('an existing [_1]',$gpterm).
 <b>$lt{'gmem'}</b><br/> $lt{'picr'}      $lt{'inth'}.'<br />'.$lt{'grna'};
 <br /><br />  
 <table border="0">      } elsif ($action eq 'modify') {
  <tr>          unless(exists($curr_groups{$groupname})) {
  <td><b>$lt{'acst'}</b></td>              $earlyout = &mt('[_1] name:',$ucgpterm).' '.$groupname.$lt{'thgr'}.
   <td>&nbsp;</td>                          $lt{'inth'};
   <td><b>$lt{'coro'}</b></td>              return $earlyout;
   <td>&nbsp;</td>          }
   <td><b>$lt{'cose'}</b></td>      }
   <td>&nbsp;</td>  
  </tr>  
  <tr>  
  <tr>  
 END  
     $r->print(&Apache::lonhtmlcommon::status_select_row(\%status_types));  
     $r->print('<td>&nbsp;</td>');  
     $r->print(&Apache::lonhtmlcommon::role_select_row(\@roles));  
     $r->print(<<"END");  
   <td>&nbsp;</td>  
   <td align="center">  
    <select name="sectionpick" multiple="true" size="$numvisible">  
     $section_sel  
    </select>  
   </td>  
  </tr>  
 </table>  
 END  
     return;      return;
 }  }
   
 sub second_creation_form {  sub topic_bar {
     my ($r) = @_;      my ($r,$imgnum,$title) = @_;
       $r->print('
   <div class="LC_topic_bar">
       <img alt="'.&mt('Step [_1]',$imgnum).
         '"src="/res/adm/pages/bl_step'.$imgnum.'.gif" />&nbsp;
       <span>'.$title.'</span>
   </div>
   ');
       return;
 }  }
   
 sub completed_creation {  sub check_changes {
     my ($r) = @_;      my ($member_changes,$memchg) = @_;
       my %exclusions;
       @{$exclusions{'changefunc'}} = ('expire');
       @{$exclusions{'changepriv'}} = ('expire','changefunc');
   
       foreach my $change (@{$member_changes}) {
           if ($change eq 'deletion') {
               next;
           }
           my @checks = ('deletion');
           if (exists($exclusions{$change})) {
               push(@checks,@{$exclusions{$change}});
           }
           my @temp = ();
           foreach my $item (@{$$memchg{$change}}) {
               my $match = 0;
               foreach my $check (@checks) {
                   if (defined($$memchg{$check})) { 
                       if (ref(@{$$memchg{$check}}) eq 'ARRAY') {
                           if (@{$$memchg{$check}} > 0) {
                               if (grep/^$item$/,@{$$memchg{$check}}) {
                                   $match = 1;
                                   last;
                               }
                           }
                       }
                   }
               }
               if ($match) {
                   next;
               }
               push(@temp,$item);
           }
           @{$$memchg{$change}} = @temp;
       }
 }  }
   
 1;  1;

Removed from v.1.2  
changed lines
  Added in v.1.59


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>