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

version 1.2, 2005/10/27 23:42:17 version 1.12, 2006/03/29 16:22:46
Line 29  use Apache::lonnet; Line 29  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::Constants qw(:common :http);  use Apache::Constants qw(:common :http);
   
 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;
                                                                                                                                                                   
Line 40  sub handler { Line 42  sub handler {
         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 $function = &Apache::loncommon::get_users_function();
       my $tabcol = &Apache::loncommon::designparm($function.'.tabbg');
       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'});
     my $manage_permission =      my $manage_permission =
         &Apache::lonnet::allowed('mdg',$env{'request.course.id'});            &Apache::lonnet::allowed('mdg',$env{'request.course.id'});
       &Apache::lonhtmlcommon::clear_breadcrumbs();
   
     if (! exists($env{'form.action'})) {      my %functions = (
         $r->print(&Apache::lonhtmlcommon::breadcrumbs                        email => 'E-mail',
                   (undef,'Course Group Manager'));                        discussion => 'Discussion boards',
         &print_main_menu($r,$manage_permission,$view_permission);                        chat => 'Chat',
     } elsif ($env{'form.action'} eq 'create' && $manage_permission) {                        files => 'File repository',
         &Apache::lonhtmlcommon::add_breadcrumb                        roster => 'Membership roster',
             ({href=>'/adm/coursegroups?action=create&state=',                        homepage => 'Group home page',
               text=>"Create Group"});                      );
         $r->print(&Apache::lonhtmlcommon::breadcrumbs  
                   (undef,'Create Group','Course_Create_Group'));      my %idx = ();
         if (! exists($env{'form.state'})) {      $idx{id} = &Apache::loncoursedata::CL_ID();
             &first_creation_form($r);      $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
         } elsif ($env{'form.state'} eq 'pick_members') {      $idx{udom} = &Apache::loncoursedata::CL_SDOM();
             &second_creation_form($r);      $idx{uname} = &Apache::loncoursedata::CL_SNAME();
         } elsif ($env{'form.state'} eq 'complete') {  
             &completed_creation($r);      my $rowColor1 = "#dddddd";
       my $rowColor2 = "#eeeeee";
   
       my $action = $env{'form.action'};
       if ($action eq 'create' || $action eq 'modify' || $action eq 'view') { 
           if ($view_permission || $manage_permission) {
               &group_administration($r,$action,$cdom,$cnum,$function,$tabcol,
                                     \%functions,\%idx,$view_permission,
                                     $manage_permission,$rowColor1,$rowColor2);
         } else {          } else {
             &first_creation_form($r);              $r->print(&mt('You do not have group administration '.
                             'privileges in this course'));
         }          }
       } else {
           &print_main_menu($r,$cdom,$cnum,$function,$tabcol,\%functions,\%idx,
                            $view_permission,$manage_permission,$action,
                            $rowColor1,$rowColor2);
     }      }
     $r->print(&footer());  
     return OK;      return OK;
 }  }
   
 sub header {  sub print_main_menu {
     my $html=&Apache::lonxml::xmlbegin();      my ($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,$view_permission,
     my $bodytag=&Apache::loncommon::bodytag('Course Groups Manager');          $manage_permission,$action,$rowColor1,$rowColor2) = @_;
     my $title = &mt('LON-CAPA Groups Manager');      $r->print(&header('Course Groups',undef,undef,undef,undef,$function));
     return(<<ENDHEAD);      &Apache::lonhtmlcommon::add_breadcrumb
 $html          ({href=>"/adm/coursegroups",
 <head>            text=>"Course Groups",});
 <title>$title</title>      $r->print(&Apache::lonhtmlcommon::breadcrumbs
 </head>                (undef,'Course Groups'));
 $bodytag      &display_groups($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,
 <form method="post"                      $view_permission,$manage_permission,$action,$rowColor1,
       action="/adm/coursegroup" name="form">                      $rowColor2);
 ENDHEAD      $r->print(&footer());
       return;
 }  }
   
 sub print_main_menu {  sub display_groups {
     my ($r,$manage_permission,$view_permission)=@_;      my ($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,$view_permission,
     my @menu =          $manage_permission,$action,$rowColor1,$rowColor2) = @_;
         (      my %curr_groups = ();
           { text => 'Create a new group',      my %grp_info = ();
             help => 'Course_Create_Group',  
             action => 'create',      my %actionlinks = (
             permission => $manage_permission,        modify => '<a href="/adm/coursegroups?action=modify&state=pick_task&refpage='.
             },                  $env{'form.refpage'}.'&groupname=',
           { text => 'Modify an existing group',        view => '<a href="/adm/'.$cdom.'/'.$cnum.'/',
             help => 'Course_Modify_Group',        delete => '<a href="/adm/coursegroups?action=delete&refpage='.
             action => 'modify',                  $env{'form.refpage'}.'&groupname=',
             permission => $manage_permission,      );
             },      my %lt = &Apache::lonlocal::texthash( 
           { text => 'Delete an existing group',                            modify => 'Modify',
             help => 'Course_Delete_Group',                            view   => 'View',
             action => 'delete',                            delete => 'Delete',
             permission => $manage_permission,                            act    => 'Action',
             },                            gname  => 'Group Name',
           { text => 'Enter an existing group',                            desc   => 'Description',
             help => 'Course_Display_Group',                            crea   => 'Creator',
             action => 'display',                            crtd   => 'Created',
             permission => $view_permission,                            last   => 'Last Modified',
             },                            func   => 'Functionality',
           );                            quot   => 'Quota (Mb)',
     my $menu_html = '';                            memb   => 'Members',
     foreach my $menu_item (@menu) {                            file   => 'Files',
         next if (! $menu_item->{'permission'});                            dibd   => 'Discussion Boards',
         $menu_html.='<p>';                            dius   => 'Disk Use',
         $menu_html.='<font size="+1">';                            nogr   => 'No groups exist.',
         if (exists($menu_item->{'url'})) {                            crng   => 'Create a new group',
             $menu_html.=qq{<a href="$menu_item->{'url'}">};                            alth   => 'Although your current role has privileges'.
                                       ' to view any existing groups in this course,'.
                                       ' you do not have privileges to create new'.
                                       ' groups.',
                        );
       if ($view_permission) {
           if (!defined($action)) {
               $action = 'view';
           }
           my %curr_groups;
           if (&Apache::loncommon::coursegroups(\%curr_groups,$cdom,$cnum)) {
               $r->print('<br /><br />');
               $r->print(&Apache::lonhtmlcommon::start_pick_box());
               $r->print(<<"END");
         <table border="0" cellpadding="4" cellspacing="1">
          <tr bgcolor="$tabcol" align="center">
           <td><b>$lt{'act'}</b></td>
           <td><b><a href="javascript:changeSort('groupname')">$lt{'gname'}</a></b></td>
           <td><b><a href="javascript:changeSort('description')">$lt{'desc'}</a></b></td>
           <td><b><a href="javascript:changeSort('creator')">$lt{'crea'}</a></b>
           </td>
           <td><b><a href="javascript:changeSort('creation')">$lt{'crtd'}</a></b>
           </td>
           <td><b><a href="javascript:changeSort('modified')">$lt{'last'}</a></b>
           </td>
           <td><b>$lt{'func'}</b>
           </td>
           <td><b><a href="javascript:changeSort('quota')">$lt{'quot'}</a></b></td>
           <td><b><a href="javascript:changeSort('totalmembers)">$lt{'memb'}</a></b></td>
           <td><b><a href="javascript:changeSort('totalfiles')">$lt{'file'}</a></b></td>
           <td><b><a href="javascript:changeSort('boards')">$lt{'dibd'}</a></b></td>
           <td><b><a href="javascript:changeSort('diskuse')">$lt{'dius'}</a></b></td>
          </tr>
   END
               my %Sortby = ();
               foreach my $group (sort(keys(%curr_groups))) {
                   %{$grp_info{$group}} = 
                                     &Apache::loncommon::get_group_settings(
                                                            $curr_groups{$group});
                   my $members_result = &group_members($cdom,$cnum,$group,
                                                       \%grp_info);
                   my $files_result = &group_files($group,\%grp_info); 
                   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);
                   }
               }
               my $rowNum = 0;
               my $rowColor;
               foreach my $key (sort(keys(%Sortby))) {
                   foreach my $group (@{$Sortby{$key}}) {
                       if ($rowNum %2 == 1) {
                           $rowColor = $rowColor1;
                       } else {
                           $rowColor = $rowColor2;
                       }
                       my $description = 
                      &Apache::lonnet::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 $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.'/grppg?register=1';
                       }
                       $link .= '">'.$lt{$action}.'</a>';  
                       $r->print('<tr bgcolor="'.$rowColor.'"><td><small>'.$link.'</small></td><td><small>'.$group.'</small></td><td><small>'.$description.'</small></td><td><small>'.$creator.'</small></td><td><small>'. &Apache::lonnavmaps::timeToHumanString($creation).'</small></td><td><small>'. &Apache::lonnavmaps::timeToHumanString($modified).'</small></td><td><small>'.$functionality.'</small></td><td><small>'.$quota.'</small></td><td><small>'.$totalmembers.'</small></td><td><small>'.$totalfiles.'</small></td><td><small>'.$boards.'</small></td><td><small>'.$diskuse.'</small></td></tr>');
                       $rowNum ++;
                   }
               }
               $r->print('</table>');
               $r->print(&Apache::lonhtmlcommon::end_pick_box());
         } else {          } else {
             $menu_html.=              $r->print($lt{'nogr'});
                 qq{<a href="/adm/coursegroups?action=$menu_item->{'action'}">};              if ($manage_permission) {
                   $r->print('<br /><br /><a href="/adm/coursegroups?action=create&refpage='.$env{'form.refpage'}.'">'.$lt{'crng'}.'</a>');
               } else {
                   $r->print('<br /><br />'.$lt{'crng'});
   
               }
         }          }
         $menu_html.= &mt($menu_item->{'text'}).'</a></font>';      } else {
         if (exists($menu_item->{'help'})) {          my @coursegroups = split(/:/,$env{'request.course.groups'});
             $menu_html.=          if (@coursegroups > 0) {
                 &Apache::loncommon::help_open_topic($menu_item->{'help'});              $r->print('<br /><br />');
               my %curr_groups;
               if (&Apache::loncommon::coursegroups(\%curr_groups,$cdom,$cnum)) {
                   foreach my $group (@coursegroups) {
                       my %group_info =  &Apache::loncommon::get_group_settings(
                                           $curr_groups{$group});
                       my $description = &Apache::lonnet::unescape(
                                           $group_info{description});
                       my ($uname,$udom) = split(/:/,$group_info{creator});
                       $r->print('<font size="+1"><a href="/adm/'.$udom.'/'.$uname.'/'.$group.'/grppg?register=1">'.$group,'</a><font><br /><small>'.$description.'</small><br /><br />');
                   }
               }
           } else {
               $r->print(&mt('You are not currently a member of any '.
                             'active groups in this course'));
         }          }
         $menu_html.='</p>'.$/;  
     }      }
     $r->print($menu_html);  
     return;      return;
 }  }
   
   sub group_administration {
       my ($r,$action,$cdom,$cnum,$function,$tabcol,$functions,$idx,
           $view_permission,$manage_permission,$rowColor1,$rowColor2) = @_;
       my %sectioncount = ();
       my @tools = ();
       my @types = ();
       my @roles = ();
       my @sections = ();
       my %users = ();
       my %userdata = ();
       my @members = ();
       my %usertools = ();
       my %stored = ();
       my %memchg;
       my @member_changes = ('deletion','expire','activate','reenable',
                             'changefunc','changepriv');
       my $state = $env{'form.state'};
       my ($groupname,$description,$startdate,$enddate,$granularity,$specificity);
   
       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 (($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 '') {
               $state = 'pick_group';
           } else {
               %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'};
               }
           }
       }
   
       my %toolprivs = ();
       %{$toolprivs{'email'}} = (
                                    sgm => 'Send group mail',
                                    sgb => 'Broadcast mail',
                                );
       %{$toolprivs{'discussion'}} =  (
                                        cgb => 'Create boards',
                                        pgd => 'Post',
                                        pag => 'Anon. posts',
                                        rgi => 'Get identities', 
                                        vgb => 'View boards',
                                      );
       %{$toolprivs{'chat'}} =  (
                                   pgc => 'Chat',
                                );
       %{$toolprivs{'files'}} =  (
                                    rgf => 'Retrieve',
                                    ugf => 'Upload',
                                    dgf => 'Delete',
                                 );
       %{$toolprivs{'roster'}} = (
                                    vgm => 'View',
                                 );
       %{$toolprivs{'homepage'}} = (
                                   vgh => 'View page',
                                   mgh => 'Modify page',
                                 );
       my %fixedprivs = ();
       %{$fixedprivs{'email'}} = ('sgm' => 1);
       %{$fixedprivs{'discussion'}} = ('vgb' => 1);
       %{$fixedprivs{'chat'}} = ('pgc' => 1);
       %{$fixedprivs{'files'}} = ('rgf' => 1);
       %{$fixedprivs{'roster'}} = ('vgm' => 1);
       %{$fixedprivs{'homepage'}} = ('vgh' => 1);
   
       my %elements = ();
       %{$elements{'create'}} = ();
       %{$elements{'modify'}} = ();
       %{$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',
           tool => 'checkbox',
           granularity => 'radio',
           no_end_date => 'checkbox',
       );
       %{$elements{'modify'}{'change_settings'}} = (
                                      %{$elements{'create'}{'pick_name'}},
                                                   specificity => 'radio',
                                                   defpriv => 'checkbox',
                                                   autorole => 'checkbox',
                                                   autoadd => 'radio',
                                                   autodrop => 'radio',
                                      );
       if (ref($stored{'autorole'}) eq 'ARRAY') {
           foreach my $role (@{$stored{'autorole'}}) {
               $elements{'modify'}{'change_settings'}{'sec_'.$role} = 'selectbox'; 
           }
       }
       %{$elements{'create'}{'pick_members'}} = (
           member => 'checkbox',
           defpriv => 'checkbox',
       );
   
       %{$elements{'modify'}{'add_members'}} = (
           types => 'selectbox',
           roles => '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')))) {
           my $numsections = &Apache::loncommon::get_sections($cdom,$cnum,
                                                              \%sectioncount);
           if ($numsections > 0) {
               $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) {
                   @sections = sort {$a cmp $b} keys(%sectioncount);
               }
           }
       }
   
       if (($state eq 'pick_members') || ($state eq 'pick_privs') || ($state eq 'change_privs')) {
           &build_members_list($cdom,$cnum,\@types,\@roles,\@sections,\%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 = 1;
                           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 'result') || ($state eq 'memresult')))) {
           foreach my $tool (@tools) {
               my @values = &Apache::loncommon::get_env_multiple('form.user_'.$tool);
               foreach my $user (@values) {
                   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';
                       }
                   }
               }
           }
       }
    
       my $jscript = &Apache::loncommon::check_uncheck_jscript();
       $jscript .= qq|
   function nextPage(formname,nextstate) {
       formname.state.value= nextstate;
       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_group','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('Course Groups Manager',
         $jscript,$action,$state,$page,$function,$loaditems));
   
       if ($env{'form.refpage'} eq 'enrl') {
           &Apache::lonhtmlcommon::add_breadcrumb
           ({href=>"/adm/dropadd",
             text=>"Enrollment Manager",
             faq=>9,bug=>'Instructor Interface',});
       } else {
           &Apache::lonhtmlcommon::add_breadcrumb
          ({href=>"/adm/coursegroups",
             text=>"Course Groups",
             faq=>9,bug=>'Instructor Interface',});
       }
   
       my %trail = ();
       %{$trail{'create'}} = &Apache::lonlocal::texthash (
                               pick_name => 'Group Settings',
                               pick_members => 'Select Members',
                               pick_privs => 'Choose Privileges',
                               result => 'Creation Complete',
                             );
       %{$trail{'modify'}} = &Apache::lonlocal::texthash(
                               pick_group => 'Groups',
                               pick_task => 'Choose Task',
                               change_settings => 'Group 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 group',
                                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
                        (undef,'Course Groups Manager'));
                   &display_control($r,$cdom,$cnum,$tabcol,$action,$state,$page,
                          \%sectioncount,$groupname,$description,$functions,
                          \@tools,\%toolprivs,\%fixedprivs,$startdate,$enddate,
                          \%users,\%userdata,$idx,\%memchg,\%usertools,
                          $function,$view_permission,$manage_permission,
                          \%stored,$granularity,$specificity,\@types,\@roles,
                          \@sections,\%states,\%navbuttons,$rowColor1,$rowColor2);
                   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 groups"});
           $r->print(&Apache::lonhtmlcommon::breadcrumbs
                        (undef,'Course Groups Manager'));
           &display_groups($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,
                           $view_permission,$manage_permission,$action,
                           $rowColor1,$rowColor2);
   
       }
       $r->print(&footer());
       return;
   }
   
   sub retrieve_settings {
       my ($cdom,$cnum,$groupname) = @_;
       my %groupinfo;
       my %stored;
       my %curr_groups;
       my $numgroups = &Apache::loncommon::coursegroups(\%curr_groups,$cdom,
                                                                $cnum,$groupname);
       if ($numgroups > 0) {
           %groupinfo = &Apache::loncommon::get_group_settings(
                                                        $curr_groups{$groupname});
           $stored{'description'} = &Apache::lonnet::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'};
   
           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'}}))) {
                   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,$tabcol,$action,$state,$page,$sectioncount,$groupname,
           $description,$functions,$tools,$toolprivs,$fixedprivs,$startdate,
           $enddate,$users,$userdata,$idx,$memchg,$usertools,$function,
           $view_permission,$manage_permission,$stored,$granularity,$specificity,
           $types,$roles,$sections,$states,$navbuttons,$rowColor1,$rowColor2)=@_;
       if ($action eq 'create') {
           if ($state eq 'pick_name') {
               &general_settings_form($r,$cdom,$cnum,$action,$tabcol,$state,$page,
                                      $functions,$tools,$toolprivs,$fixedprivs,
                                      $sectioncount,$stored,$states,$navbuttons,
                                      $rowColor1,$rowColor2);
           } elsif ($state eq 'pick_members') {
               &choose_members_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
                                    $groupname,$description,$granularity,
                                    $startdate,$enddate,$tools,$fixedprivs,
                                    $toolprivs,$functions,$users,$userdata,$idx,
                                    $stored,$states,$navbuttons,$rowColor1,
                                    $rowColor2);
           } elsif ($state eq 'pick_privs') {
               &choose_privs_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
                                  $startdate,$enddate,$tools,$functions,
                                  $toolprivs,$fixedprivs,$userdata,$usertools,
                                  $idx,$states,$stored,$sectioncount,$navbuttons,
                                  $rowColor1,$rowColor2);
           } elsif ($state eq 'result') {
               &process_request($r,$cdom,$cnum,$tabcol,$action,$state,$page,
                                $groupname,$description,$specificity,$userdata,
                                $startdate,$enddate,$tools,$functions,
                                $toolprivs,$usertools,$idx,$types,$roles,
                                $sections,$states,$navbuttons,$memchg,
                                $sectioncount,$stored,$rowColor1,$rowColor2);
           }
       } elsif ($action eq 'modify') {
           my $groupname = $env{'form.groupname'};
           if ($state eq 'pick_group') {
               &display_groups($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,
                               $view_permission,$manage_permission,$action,
                               $rowColor1,$rowColor2);
           } elsif ($state eq 'pick_task') {
               &modify_menu($r,$groupname,$page);
           } elsif ($state eq 'change_settings') {
               &general_settings_form($r,$cdom,$cnum,$action,$tabcol,$state,$page,
                                      $functions,$tools,$toolprivs,$fixedprivs,
                                      $sectioncount,$stored,$states,$navbuttons,
                                      $rowColor1,$rowColor2);
           } elsif ($state eq 'change_members') {
               &change_members_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
                                    $groupname,$description,$startdate,$enddate,
                                    $tools,$fixedprivs,$functions,$users,
                                    $userdata,$granularity,$specificity,$idx,
                                    $states,$navbuttons,$rowColor1,$rowColor2);
           } elsif ($state eq 'add_members') {
               &add_members_form($r,$tabcol,$action,$state,$page,$startdate,
                                 $enddate,$groupname,$description,$granularity,
                                 $sectioncount,$tools,$functions,$stored,$states,
                                 $navbuttons,$rowColor1,$rowColor2);
           } elsif ($state eq 'pick_members') {
               &choose_members_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
                                    $groupname,$description,$granularity,
                                    $startdate,$enddate,$tools,$fixedprivs,
                                    $toolprivs,$functions,$users,$userdata,$idx,
                                    $stored,$states,$navbuttons,$rowColor1,
                                    $rowColor2);
           } elsif ($state eq 'pick_privs') {
               &choose_privs_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
                                  $startdate,$enddate,$tools,$functions,
                                  $toolprivs,$fixedprivs,$userdata,$usertools,
                                  $idx,$states,$stored,$sectioncount,$navbuttons,
                                  $rowColor1,$rowColor2);
           } elsif ($state eq 'change_privs') {
               &change_privs_form($r,$cdom,$cnum,$tabcol,$action,$state,$page,
                                  $startdate,$enddate,$tools,$functions,
                                  $toolprivs,$fixedprivs,$userdata,$usertools,
                                  $memchg,$idx,$states,$stored,$sectioncount,
                                  $navbuttons,$rowColor1,$rowColor2);
           } elsif ($state eq 'chgresult' || $state eq 'memresult' || 
                    $state eq 'addresult') {
               &process_request($r,$cdom,$cnum,$tabcol,$action,$state,$page,
                                $groupname,$description,$specificity,$userdata,
                                $startdate,$enddate,$tools,$functions,
                                $toolprivs,$usertools,$idx,$types,$roles,
                                $sections,$states,$navbuttons,$memchg,
                                $sectioncount,$stored,$rowColor1,$rowColor2);
           }
       }
   }
   
   sub header {
       my ($bodytitle,$jscript,$action,$state,$page,$function,$loaditems) = @_;
       my $start_page=
    &Apache::loncommon::start_page($bodytitle,
          '<script type="text/javascript">'.
          $jscript.'</script>',
          {'function'    => $function,
    'add_entries' => $loaditems,});
       my $output = <<"END";
   $start_page
   <form method="POST" name="$state">
   
   END
       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 onload_action {
       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' ||
                    $state eq 'pick_members')) {
               $loaditems =
                'onload="javascript:setFormElements(document.'.$state.')"';
       }
       return $loaditems;
   }
   
 sub footer {  sub footer {
       my $end_page = &Apache::loncommon::end_page();
        return(<<ENDFOOT);         return(<<ENDFOOT);
      <input type="hidden" name="sortby" value="$env{'form.sortby'}" />
   </form>    </form>
  </body>  $end_page
 </html>  
 ENDFOOT  ENDFOOT
    
 }  }
   
 sub first_creation_form {  sub build_members_list {
     my ($r) = @_;      my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata) = @_;
     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};      my %access = ();
     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};      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 {
       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 $now = time;
       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'} = $active.' - active<br />'.$previous.' -previous<br />'.$future.' -future';
       }
       return 'ok';
   }
   
   
   sub general_settings_form {
       my ($r,$cdom,$cnum,$action,$tabcol,$formname,$page,$functions,$tools,
           $toolprivs,$fixedprivs,$sectioncount,$stored,$states,$navbuttons,
           $rowColor1,$rowColor2) = @_;
       my ($nexttext,$prevtext);
       $r->print(' <br />
    <table width="100%" cellpadding="0" cellspacing="0" border="0">
   ');
       &groupsettings_options($r,$tabcol,$functions,$action,$formname,$stored,1);
       $r->print(' 
     <tr>
      <td colspan="4">&nbsp;</td>
     </tr>');
       &access_date_settings($r,$tabcol,$action,$formname,$stored,2);
       $r->print('
     <tr>
      <td colspan="4">&nbsp;</td>
     </tr>');
       if ($action eq 'create') {
           &membership_options($r,$action,$formname,$tabcol,$sectioncount,3);
           $nexttext = $$navbuttons{'gtns'};
       } else {
           my @available = ();
           my @unavailable = ();
           &check_tools($functions,$tools,\@available,\@unavailable);
           @{$tools} = sort(keys(%{$functions}));
           &privilege_specificity($r,$tabcol,$rowColor1,$rowColor2,$action,
                                  3,$tools,$stored,$toolprivs,$fixedprivs,
                                  \@available,$formname);
           $r->print('
     <tr>
      <td colspan="4">&nbsp;</td>
     </tr>');
           &mapping_options($r,$action,$formname,$page,$tabcol,$sectioncount,
                            $states,$stored,$navbuttons,4,5,$rowColor1,
                            $rowColor2);
           $nexttext = $$navbuttons{'mose'};
       }
       $prevtext = $$navbuttons{'gtpp'};
       &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
                           $$states{$action}[$page+1],$nexttext);
       $r->print('
    </table>');
       return;
   }
   
   sub groupsettings_options {
       my ($r,$tabcol,$functions,$action,$formname,$stored,$image) = @_;
     my %lt = &Apache::lonlocal::texthash(      my %lt = &Apache::lonlocal::texthash(
         'gmem' => 'Group membership options',  
         'picr' => 'Pick the criteria to use to build a list of course users from which you will select members of the new group',     
         'gdat' => 'Group open and close dates',          'gdat' => 'Group open and close dates',
         'sten' => 'Set a start date/time and end date/time for the group',          'sten' => 'Set a start date/time and end date/time for the group',
         'acst' => 'Active/Inactive status',  
         'coro' => 'Course roles',  
         'cose' => 'Course sections',  
         'gfun' => 'Group functionality',          'gfun' => 'Group functionality',
           'gnde' => 'Group name, description and available functionality',
           'desc' => 'Description',
           'func' => 'Functionality',
           'gnam' => 'Group Name',
           'doyo' => 'Do you want to assign different functionality '.
                     'to different group members?',
     );      );
       &topic_bar($r,$tabcol,$image,$lt{'gnde'});
       $r->print('
      <tr>
       <td>&nbsp;</td>
       <td colspan="3">
        <table border="0" cellpadding="2" cellspacing="2">
         <tr>
          <td><b>'.$lt{'gnam'}.':</b></td>
          <td colspan="5">
   ');
       if ($action eq 'create') {
           $r->print('<input type="text" name="groupname" size="25" />');
       } else {
           $r->print('<input type="hidden" name="groupname" value="'.
                            $env{'form.groupname'}.'" />'.$env{'form.groupname'});
       }
       $r->print(<<"END");
          </td>
         <tr>
         <tr>
          <td><b>$lt{'desc'}:</b></td>
          <td colspan="5"><input type="text" name="description" size="40"
                                                       value="" />
          </td>
         <tr>
         <tr>
          <td><b>$lt{'func'}:</b></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><b>Granularity:</b></td>
          <td colspan="9">'.$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>
        </table>
       </td>
      </tr>
   ');
       return;
   }
   
   sub membership_options {
       my ($r,$action,$state,$tabcol,$sectioncount,$image) = @_;
       my %lt = &Apache::lonlocal::texthash(
                   'pipa' => 'Pick parameters to generate membership list',
                   'gmem' => 'Group membership options',
                   'picr' => 'Pick the criteria to use to build a list of '.
                             'course 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, do not make any selections',  
                   'acty' => 'Access types',
                   'coro' => 'Course roles',
                   'cose' => 'Course sections',
                );
     my %status_types = (      my %status_types = (
                    active => &mt('Currently has access'),                     active => &mt('Currently has access'),
                    previous => &mt('Previously had access'),                     previous => &mt('Previously had access'),
                    future => &mt('Will have future access'),                     future => &mt('Will have future access'),
                    );                     );
                                                                                    
     my @roles = ('st','cc','in','ta','ep','cr');      my @roles = ('st','cc','in','ta','ep','cr');
   
     my %sectioncount = ();      my @sections = keys(%{$sectioncount});
     my @sections = ();  
     my $section_sel = '';      &topic_bar($r,$tabcol,$image,$lt{'pipa'});
     my $numvisible;      $r->print('
     my $numsections = &Apache::loncommon::get_sections($cdom,$cnum,     <tr>
                            \%sectioncount);      <td>&nbsp;</td>
       <td colspan="3">
     @sections = sort {$a cmp $b} keys(%sectioncount);       <b>'.$lt{'gmem'}.'</b><br/>'.$lt{'picr'});
     unshift(@sections,'all'); # Put 'all' at the front of the list      if ($action eq 'create') {
     if ($numsections < 4) {          $r->print($lt{'meof'}.'<br />'.$lt{'ifno'});
         $numvisible = $numsections + 1;      } else {
           $r->print($lt{'admg'});
       }
       $r->print('
        <br />
        <br />
        <table border="0">
         <tr>
          <td><b>'.$lt{'acty'}.'</b></td>
          <td>&nbsp;</td>
          <td><b>'.$lt{'coro'}.'</b></td>');
       if (@sections >0) {
           $r->print('
          <td>&nbsp;</td>
          <td><b>'.$lt{'cose'}.'</b></td>
          <td>&nbsp;</td>');
       }
       $r->print('</tr><tr>');
       $r->print(&Apache::lonhtmlcommon::status_select_row(\%status_types));
       $r->print('<td>&nbsp;</td>');
       $r->print(&Apache::lonhtmlcommon::role_select_row(\@roles));
       if (@sections > 0) {
           @sections = sort {$a cmp $b} @sections;
           unshift(@sections,'_all'); # Put 'all' at the front of the list
           unshift(@sections,'_nosec'); # Put 'no sections' next
           $r->print('<td>&nbsp;</td>
                      <td colspan="3" align="center" valign="top">'.
           &sections_selection(\@sections,'sectionpick').'</td>');
       }
       $r->print('
         </tr>
        </table>
       </td>
      </tr>');
       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.'" />all sections'."\n";
           } elsif ($sec eq '_nosec') {
               $section_sel .= '  <option value="'.$sec.'" />no section'."\n"; 
           } else {
               $section_sel .= '  <option value="'.$sec.'" />'.$sec."\n";
           }
       }
       my $output = '
           <select name="'.$elementname.'" multiple="true" size="'.$numvisible.'">
             '.$section_sel.'
           </select>';
       return $output;
   }
   
   sub access_date_settings {
       my ($r,$tabcol,$action,$formname,$stored,$image) = @_;
       my %lt = &Apache::lonlocal::texthash(
                   'sten' => 'Default start and end dates for group 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 ($start_table,$end_table) = &date_setting_table
                                       ($starttime,$endtime,$formname);
       &topic_bar($r,$tabcol,$image,$lt{'sten'});
       $r->print('
      <tr>
       <td>&nbsp;</td>
       <td colspan="3">'.$start_table.'</td>
      <tr>
      <tr>
       <td colspan="4">&nbsp;</td>
      </tr>
      <tr>
       <td>&nbsp;</td>
       <td colspan="3">'.$end_table.'</td>
      <tr>');
       return;
   }
   
   sub choose_members_form {
       my ($r,$cdom,$cnum,$tabcol,$action,$formname,$page,$groupname,$description,
           $granularity,$startdate,$enddate,$tools,$fixedprivs,$toolprivs,
           $functions,$users,$userdata,$idx,$stored,$states,$navbuttons,
           $rowColor1,$rowColor2) = @_;
       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);
       $r->print('
   <table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tr>
     <td>&nbsp;</td>
     <td colspan="3">
   ');
       if ($earlyout) {
           $r->print($earlyout.'</td></tr>');
           &display_navbuttons($r,$formname,$$states{$action}[$page-1],
                              $$navbuttons{'gtps'});
           $r->print('</table>');
           return;
       } 
       my ($specimg,$memimg);
       my @available = ();
       my @unavailable = ();
       &check_tools($functions,$tools,\@available,\@unavailable);
       if ($action eq 'create') {
           &print_current_settings($r,$action,$tabcol,$rowColor1,$rowColor2,
                                   $functions,$startdate,$enddate,$groupname,
                                   $description,$granularity,\@available,
                                   \@unavailable);
           $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,$tabcol,$rowColor1,$rowColor2,$action,
                             $specimg,$tools,$stored,$toolprivs,
                             $fixedprivs,\@available,$formname);
       my $newusers = &pick_new_members($r,$action,$formname,$tabcol,$rowColor1,
                                       $rowColor2,\@available,$idx,$stored,
                                       $memimg,$users,$userdata,$granularity,
                                       \%origmembers);
       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'});
       }
       $r->print('</table>');
       return;
   }
   
   sub display_navbuttons {
       my ($r,$formname,$prev,$prevtext,$next,$nexttext) = @_;
       $r->print('
       <tr>
        <td colspan="4">&nbsp;</td>
       </tr>
       <tr>
        <td>&nbsp;</td>
        <td colspan="3">');
       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('
        </td>
       </tr>
   ');
   }
   
   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,$tabcol,$rowColor1,$rowColor2,$functions,$startdate,$enddate,
              $groupname,$description,$granularity,$available,$unavailable) =@_;
   
       my %lt = &Apache::lonlocal::texthash(
           grna => 'Group Name',
           desc => 'Description',
           grfn => 'Group Functions',
           gran => 'Granularity',
           dfac => 'Default access dates',
           ygrs => 'Your group selections',
           tfwa => 'The following settings will apply to the group:',
           difn => 'Different functionality<br />for different users:',
           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);
       }
       $r->print('<table border="0" cellpadding="0" cellspacing="20">');
       if ($action eq 'create') {
           $r->print('
   <tr>
    <td><font face="arial,helvetica,sans-serif"><b>'.$lt{'ygrs'}.'</b></font>
   <br />'.$lt{'tfwa'}.'
    </td>
   </tr>');
       }
       $r->print('<tr><td>');
       $r->print(&Apache::lonhtmlcommon::start_pick_box());
       $r->print('
   <tr>
    <td>
   <table cellspacing="1" cellpadding="4">
    <tr bgcolor="'.$tabcol.'" align="center">
     <td><b>'.$lt{'grna'}.'</b></td>
     <td><b>'.$lt{'desc'}.'</b></td>
     <td><b>'.$lt{'grfn'}.'</b></td>
     <td><b>'.$lt{'gran'}.'</b></td>
     <td><b>'.$lt{'dfac'}.'</b></td>
    </tr>
    <tr bgcolor="'.$rowColor2.'">
     <td valign="top"><small>'.$groupname.'</small></td>
     <td valign="top"><small>'.$description.'</small></td>
     <td>
   ');
       if (@{$available} > 0) {
           $r->print('<small><b>Available:</b></small>
                       <table cellpadding="" cellspacing="1"><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><small>'.$$functions{$$available[$i]}.
                                             '</small></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('<small><b>Unavailable:</b></small>
                       <table cellpadding="0" cellspacing="1"  border="0"><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><small>'.$$functions{$$unavailable[$j]}.
                                                 '</small></td><td>&nbsp;</td>');
           }
           if ((@{$unavailable} > 3) && (@{$unavailable}%2)) {
               $r->print('<td>&nbsp;</td><td>&nbsp;</td>');
           }
           $r->print('</tr></table>');
       }
     $r->print(<<"END");      $r->print(<<"END");
 <b>$lt{'gmem'}</b><br/> $lt{'picr'}    </td>
 <br /><br />    <td valign="top"><small><b>$lt{'difn'}
 <table border="0">    </b> $granularity</small> 
     <td valign="top"><small><b>$lt{'stda'}</b> $showstart<br />
         <b>$lt{'enda'}</b> $showend</small>
     </td>
    </tr>
   </table>
   </td>
   </tr>
   END
       $r->print(&Apache::lonhtmlcommon::end_pick_box());
       $r->print('</td></tr></table><br />');
       return;
   }
   
   sub pick_new_members {
       my ($r,$action,$formname,$tabcol,$rowColor1,$rowColor2,$available,$idx,
           $stored,$img,$users,$userdata,$granularity,$origmembers) = @_;
       my %lt = &Apache::lonlocal::texthash(
             'gpme' => 'Group membership',
             'addm' => 'Add members',
             'setf' => 'Set functionality',
             'func' => 'Functionality',
             'nome' => 'No members to add at this time.',
             'nnew' => 'There are no users to add as new members, as all users'.
                       ' matching the specified type(s), role(s), and/or '.
                       '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,$tabcol,$img,$lt{'gpme'});
       if (keys(%members) > 0) {
           $r->print('
  <tr>   <tr>
  <td><b>$lt{'acst'}</b></td>  
   <td>&nbsp;</td>    <td>&nbsp;</td>
   <td><b>$lt{'coro'}</b></td>    <td colspan="3">
       <table>
        <tr>');
           &check_uncheck_buttons($r,$formname,'member',$lt{'addm'});
           if (@{$available} > 0 && $granularity eq 'Yes') {
               $r->print('<td><nobr>
        <fieldset><legend><b>'.$lt{'setf'}.'</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('</tr></table>
     </td>
    </tr>
    <tr>
     <td colspan="4">&nbsp;</td>
    </tr>
    <tr>
   <td>&nbsp;</td>    <td>&nbsp;</td>
   <td><b>$lt{'cose'}</b></td>    <td colspan="3">
           ');
           $r->print(&Apache::lonhtmlcommon::start_pick_box());
           $r->print('
      <table border="0" cellpadding="4" cellspacing="1">
       <tr bgcolor="'.$tabcol.'" align="center">
        <td><b>'.&mt('Add?').'</b></td>
        <td><b><a href="javascript:changeSort('."'fullname'".')">'.&mt('Name').'</a></b></td>
        <td><b><a href="javascript:changeSort('."'username'".')">'.&mt('Username').'</a></b>
        </td>
        <td><b><a href="javascript:changeSort('."'domain'".')">'.&mt('Domain').'</a></b></td>
        <td><b><a href="javascript:changeSort('."'id'".')">ID</a></b></td>
   ');
           if (@{$available} > 0) {
               $r->print('<td><b>'.$lt{'func'}.'</b></td>');
           }
           $r->print('</tr>');
           if (@{$available} > 0) {
               if ($granularity eq 'Yes') {
                   $r->print('<tr bgcolor="#cccccc">
    <td colspan="5">&nbsp;</td>
    <td align="center"><small><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></small></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);
               } else {
                   push(@{$Sortby{$members{$user}[$$idx{fullname}]}},$user);
               }
           }
           my $rowNum = 0;
           my $rowColor;
           foreach my $key (sort(keys(%Sortby))) {
               foreach my $user (@{$Sortby{$key}}) {
                   if ($rowNum %2 == 1) {
                       $rowColor = $rowColor1;
                   } else {
                       $rowColor = $rowColor2;
                   }
                   my $id = $members{$user}[$$idx{id}];
                   my $fullname = $members{$user}[$$idx{fullname}];
                   my $udom = $members{$user}[$$idx{udom}];
                   my $uname = $members{$user}[$$idx{uname}];
                   $r->print('<tr bgcolor="'.$rowColor.'"><td align="right">
      <input type="checkbox" name="member" value="'.$user.'" /></td><td><small>'.
       $fullname.'</small></td><td><small>'.$uname.'</small></td><td><small>'.
       $udom.'</small></td><td><small>'.$id.'</small></td>');
                   if (@{$available} > 0) {
                       $r->print('<td align="center"><nobr><small>'.
                                 '&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('</small></nobr></td>');
                   }
                   $r->print('</tr>'."\n");
                   $rowNum ++;
               }
           }
           $r->print(&Apache::lonhtmlcommon::end_pick_box());
           $r->print('
        </td>
       </tr>');
       } else {
           $r->print('
       <tr>
        <td>&nbsp;</td>
        <td colspan="3">
   ');
           if ($totalusers > 0) {
               $r->print($lt{'nnew'}.'<br /><br />'.$lt{'yoma'});
           } else { 
               $r->print($lt{'nome'});
           }
           $r->print('
        </td>
       </tr>');
       }
       return $newusers;
   }
   
   sub privilege_specificity {
       my ($r,$tabcol,$rowColor1,$rowColor2,$action,$img,$tools,$stored,
           $toolprivs,$fixedprivs,$available,$formname) = @_;
       my %lt = &Apache::lonlocal::texthash (
         'uprv' => 'User privileges',
         'frty' => 'For each type of functionality you have chosen to include, '.
                   'there is a set of standard privileges which apply to all '.
                   'of those for whom the functionality is enabled.',
         'thar' => 'There are also additional privileges which can be set for '.
                   'some, or all, members. Please choose one of the following:',
         'fort' => 'For the types of functionality you have chosen to include '.
                   'there are no additional privileges which can be set for some '.
                   'or all members.',
         'eaty' => 'Each of the types of functionality includes standard '.
                   'privileges which apply to members with access to that '.
                   'functionality, and may also include additional privileges '.
                   'which can be set for specific members.',
         'cutg' => 'Currently the group is configured ',
         'sdif' => 'so different group members can receive different privileges.',
         'sall' => 'so all group members will receive the same privileges.',
         'algm' => 'All group members will receive the same privileges.',
         'smgp' => 'Some group members will receive different privileges from '.
                   'others.',
         'thwi' => 'These will be the privileges all group members receive, '. 
                   'if you selected the first option above.',
         'thes' => 'These will be the privileges given to members assigned '.   
                   'in the future, including via automatic group assignment '.
                   'for specific sections/roles ',
         'asyo' => 'As you have chosen not to include any functionality in the '.
                   'group, no default user privileges settings need to be set.',
         'plin' => 'Please indicate which <b>optional</b> privileges members '.
                   'will receive by default.',
         '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,$tabcol,$img,$lt{'uprv'});
       $r->print('
    <tr>
   <td>&nbsp;</td>    <td>&nbsp;</td>
     <td colspan="3">
     ');
       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'});
               } 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 /><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>
     </td>
  </tr>   </tr>
  <tr>   <tr>
     <td colspan="4">&nbsp;</td>
    </tr>');
           } else {
               $r->print('<input type="hidden" name="specificity" value="No" />');
           }
           if ($totaloptionalprivs) {
               $r->print('
  <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>&nbsp;</td>
   <td align="center">    <td colspan="3">'.$lt{'plin'});
    <select name="sectionpick" multiple="true" size="$numvisible">              if ($action eq 'create') {
     $section_sel                  $r->print(' '.$lt{'thwi'});
    </select>              }
               $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 />
   </td>    </td>
  </tr>   </tr>
 </table>   <tr>
     <td>&nbsp;</td>
     <td colspan="2"><table><tr>');
           &check_uncheck_buttons($r,$formname,'defpriv',$lt{'oppr'});
           $r->print('
       </tr>
      </table>
     </td>
     <td width="100%">&nbsp;</td>
    </tr><tr>
     <td>&nbsp;</td>
     <td colspan="3">
      <br />
   ');
           } else {
               $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'algm'}.'<br /><br />');
           }
           &default_privileges($r,$action,$tabcol,$rowColor1,$rowColor2,
                               $tools,$toolprivs,$fixedprivs,$available);
       } else {
           if ($action eq 'create') {
               $r->print($lt{'asyo'});
           } 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,$tabcol,$rowColor1,$rowColor2,$tools,
                                 $toolprivs,\@defprivs);
           }
       }
       $r->print('
     </td>
    </tr>
   ');
       return;
   }
   
   sub default_privileges {
       my ($r,$action,$tabcol,$rowColor1,$rowColor2,$tools,$toolprivs,
           $fixedprivs,$available) = @_;
       my %lt = &Apache::lonlocal::texthash(
                                   'addp' => 'Additional privileges',
                                   'fixp' => 'Fixed privileges',
                                   'oppr' => 'Optional privileges',
                                   'func' => 'Function',
       );
       $r->print(&Apache::lonhtmlcommon::start_pick_box());
       $r->print('<tr>
                   <td bgcolor="'.$tabcol.'" valign="top">
                    <table cellspacing="0" cellpadding="1">
                     <tr>
                      <td valign="top"><b>'.$lt{'func'}.'</b></td>
                     </tr>
                     <tr>
                      <td valign="top"><b>'.$lt{'fixp'}.'</b></td>
                     </tr>
                     <tr>
                      <td valign="top"><b>'.$lt{'oppr'}.'</b></td>
                     </tr>
                    </table>
                   </td>
       ');
       foreach my $tool (@{$tools}) {
           $r->print('<td align="center" valign="top">
                       <table cellspacing="0" cellpadding="1">
                        <tr bgcolor="#cccccc">
                         <td colspan="2" align="center"><b>'.$tool.'</b></td>
                        </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="defpriv" value="'.$priv.'" />'.$$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;';
                       }
                   }
               } else {
                   $privcount ++;
                   if ($privcount == 3) {
                       $dynamic .= '</tr>
                                    <tr bgcolor="'.$rowColor1.'">'."\n";
                   }
                   $dynamic .= '<td><label><input type="checkbox" name="defpriv" value="'.$priv.'" />'.$$toolprivs{$tool}{$priv}.'</label></td>'."\n";
               }
           }
           if ($dynamic eq '') {
               $dynamic = '<td>None</td>'."\n";
           }
           if ($privcount < 3) {
               $dynamic .= '</tr>
                            <tr bgcolor="'.$rowColor1.'">
                             <td colspan="2">&nbsp;</td>'."\n";
           } elsif ($privcount%2) {
               $dynamic = '<td>&nbsp;</td>'."\n";
           }
           $r->print('<tr bgcolor="'.$rowColor2.'">
                       <td colspan="2" align="center"><nobr>'.$fixed.'</nobr></td>
                      </tr>
                      <tr bgcolor="'.$rowColor1.'">'."\n".$dynamic.'</tr>'."\n".'</table>'."\n".'</td>
           ');
       }
       $r->print('</tr>'."\n");
       $r->print(&Apache::lonhtmlcommon::end_pick_box());
       $r->print('<br />');
       return;
   }
   
   sub display_defprivs {
       my ($r,$tabcol,$rowColor1,$rowColor2,$tools,$toolprivs,$defprivs) = @_;
       my %lt = &Apache::lonlocal::texthash(
                                   'priv' => 'Privileges',
                                   'func' => 'Function',
       );
       $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,$tabcol,$action,$formname,$page,$groupname,$description,
           $startdate,$enddate,$tools,$fixedprivs,$functions,$users,$userdata,
           $granularity,$specificity,$idx,$states,$navbuttons,$rowColor1,
           $rowColor2) = @_;
       my %lt = &Apache::lonlocal::texthash(
                                            grse => 'Group settings',
                                            mogm => 'Modify group 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 />
   <table width="100%" cellpadding="0" cellspacing="0" border="0">
   ');
       &topic_bar($r,$tabcol,1,$lt{'grse'});
       $r->print('
    <tr>
     <td>&nbsp;</td>
     <td colspan="3">
   ');
       &print_current_settings($r,$action,$tabcol,$rowColor1,$rowColor2,
                               $functions,$startdate,$enddate,$groupname,
                             $description,$granularity,\@available,\@unavailable);
   $r->print('
   </td></tr><tr><td colspan="4">&nbsp;</td></tr>');
       &topic_bar($r,$tabcol,2,$lt{'mogm'});
       $r->print('
    <tr>
     <td>&nbsp;</td>
     <td colspan="3">
   ');
       &current_membership($r,$cdom,$cnum,$formname,$tabcol,$rowColor1,
                           $rowColor2,$groupname,\@available,\@unavailable,
                           $fixedprivs,$granularity,$specificity);
       $r->print('</td>');
       &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
                           $$states{$action}[$page+1],$nexttext);
       $r->print('</table>');
       return;
   }
   
   sub current_membership {
       my ($r,$cdom,$cnum,$formname,$tabcol,$rowColor1,$rowColor2,$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 Functionality',
                                             'chpr' => 'Change Privileges' 
                                           );
       if (keys(%membership) > 0) {
           my %current = ();
           my %allnames = ();
           my $hastools = 0;
           my $addtools = 0;
           my $num_reenable = 0;
           my $num_activate = 0;
           my $num_expire - 0;
           foreach my $key (sort(keys(%membership))) {
               if ($key =~ /^\Q$groupname\E:([^:]+):([^:]+)$/) {
                   my $uname = $1;
                   my $udom = $2;
                   my $user = $uname.':'.$udom;
                   my($end,$start,@userprivs) = split(/:/,$membership{$key});
                   unless ($start == -1) {
                       $allnames{$udom}{$uname} = 1;
                       %{$current{$user}} = ();
                       $current{$user}{uname} = $uname;
                       $current{$user}{udom} = $udom;
                       $current{$user}{start} = 
                                        &Apache::lonlocal::locallocaltime($start);
                       if ($end == 0) {
                           $current{$user}{end} =  'No end date';
                       } else {
                           $current{$user}{end} = 
                                        &Apache::lonlocal::locallocaltime($end);
                       }
                       my $now = time;
                       if (($end > 0) && ($end < $now)) {
                           $current{$user}{changestate} = 'reenable';
                           $num_reenable++;
                       } elsif (($start > $now)) {
                           $current{$user}{changestate} = 'activate';
                           $num_activate ++;
                       } else {
                           $current{$user}{changestate} = 'expire';
                           $num_expire ++;
                       }
                       @{$current{$user}{currtools}} = ();
                       @{$current{$user}{newtools}} = ();
                       if (@userprivs > 0) {
                           foreach my $tool (sort(keys(%{$fixedprivs}))) {
                               foreach my $priv (keys(%{$$fixedprivs{$tool}})) {
                                   if (grep/^$priv$/,@userprivs) {
                                       push(@{$current{$user}{currtools}},$tool);
                                       last;
                                   }
                               }
                           }
                           $hastools = 1;
                       }
                       if (@{$available} > 0) {
                           if (@{$current{$user}{currtools}} > 0) {
                               if ("@{$available}" ne "@{$current{$user}{currtools}}") {
                                   foreach my $tool (@{$available}) {
                                       unless (grep/^$tool$/,@{$current{$user}{currtools}}) {
                                           push(@{$current{$user}{newtools}},$tool);
                                       }
                                   }
                               }
                           } else {
                               @{$current{$user}{newtools}} = @{$available};
                           }
                           if (@{$current{$user}{newtools}} > 0) {
                               $addtools = 1;
                           }
                       }
                   }
               }
           }
           if (keys(%current) > 0) {
               my %idhash;
               foreach my $udom (keys(%allnames)) {
                   %{$idhash{$udom}} = &Apache::lonnet::idrget($udom,
                                                   keys(%{$allnames{$udom}}));
                   foreach my $uname (keys(%{$idhash{$udom}})) {
                       $current{$uname.':'.$udom}{'id'} = $idhash{$udom}{$uname};
                   }
                   foreach my $uname (keys(%{$allnames{$udom}})) {
                       $current{$uname.':'.$udom}{'fullname'} =
                                   &Apache::loncommon::plainname($uname,$udom,
                                                                     'lastname');
                   }
               }
               $r->print('
    <tr>
     <td>&nbsp;</td>
     <td colspan="2">
      <table>
       <tr>');
               if ($num_expire) {
                   &check_uncheck_buttons($r,$formname,'expire',$lt{'expi'});
               }
               if ($num_reenable) {
                   &check_uncheck_buttons($r,$formname,'reenable',$lt{'reen'});
               }
               if ($num_activate) {
                   &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>
     </td>
     <td width="100%">&nbsp;</td>
    </tr>
    <tr>
     <td colspan="4">&nbsp;</td>
    </tr>
    <tr>
     <td>&nbsp;</td>
     <td colspan="3">
   END
               $r->print(&Apache::lonhtmlcommon::start_pick_box());
               $r->print(<<"END");
      <table border="0" cellpadding="4" cellspacing="1">
       <tr bgcolor="$tabcol" align="center">
        <td><b>$lt{'actn'}</b></td>
        <td><b><a href="javascript:changeSort('fullname')">$lt{'name'}</a></b></td>
        <td><b><a href="javascript:changeSort('username')">$lt{'usnm'}</a></b>
        </td>
        <td><b><a href="javascript:changeSort('domain')">$lt{'doma'}</a></b></td>
        <td><b><a href="javascript:changeSort('id')">ID</a></b></td>
        <td><b><a href="javascript:changeSort('start')">$lt{'stda'}</a></b></td>
        <td><b><a href="javascript:changeSort('end')">$lt{'enda'}</a></b></td>
 END  END
               my $colspan = 0;
               if ($hastools) {
                   $r->print('<td><b>'.$lt{'curf'}.'</b></td>');
                   $colspan ++;  
               }
               if ($addtools) {
                   $r->print('<td><b>Additional Functionality</b></td>');
                   $colspan ++;
               }
               $r->print('</tr>');
               if ($colspan) {
                   if ($granularity eq 'Yes') {
                       $r->print('<tr bgcolor="#cccccc">
    <td colspan="7">&nbsp;</td>
    <td colspan="'.$colspan.'" align="center"><small><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></small></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);
                   }
               }
               my $rowNum = 0;
               my $rowColor;
               foreach my $key (sort(keys(%Sortby))) {
                   foreach my $user (@{$Sortby{$key}}) {
                       if ($rowNum %2 == 1) {
                           $rowColor = $rowColor1;
                       } else {
                           $rowColor = $rowColor2;
                       }
                       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('<tr bgcolor="'.$rowColor.'">
                                   <td><small>');
                       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><small>'.
       $fullname.'</small></td><td><small>'.$uname.'</small></td><td><small>'.
       $udom.'</small></td><td><small>'.$id.'</small></td><td><small>'.$start.
       '</small></td><td><small>'.$end.'</small></td>');
                       if ($hastools) {
                           $r->print('<td align="left"><small><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></small></td>');
                       }
                       if ($addtools) {
                           $r->print('<td align="left"><small>');
                           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('</small></td>');
                       }
                       $r->print('</tr>'."\n");
                       $rowNum ++;
                   }
               }
               $r->print(&Apache::lonhtmlcommon::end_pick_box());
               $r->print('
     </td>
    </tr>');
           }
       }
     return;      return;
 }  }
   
 sub second_creation_form {  sub check_uncheck_buttons {
     my ($r) = @_;      my ($r,$formname,$field,$title,$colspan) = @_;
       $r->print('
        <td '.$colspan.'>
         <nobr>
          <fieldset>
          <legend><b>'.$title.'</b></legend>
          <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.')" />
          </fieldset>
         </nobr>
        </td>
   ');
 }  }
   
 sub completed_creation {  
     my ($r) = @_;  sub change_privs_form {
       my ($r,$cdom,$cnum,$tabcol,$action,$formname,$page,$startdate,$enddate,
          $tools,$functions,$toolprivs,$fixedprivs,$userdata,$usertools,
          $memchg,$idx,$states,$stored,$sectioncount,$navbuttons,$rowColor1,
          $rowColor2) = @_;
       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 group.',
       );
       $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'};
       }
       $r->print('<br /><table width="100%" cellpadding="0" cellspacing="0" border="0">');
       &topic_bar($r,$tabcol,3,&mt('Members to delete or expire'));
       my $exp_or_del = 0;
       if (ref($$memchg{'deletion'}) eq 'ARRAY') {
           if (@{$$memchg{'deletion'}} > 0) {
               $r->print('<tr><td>&nbsp;</td><td colspan="3"><b>'.$lt{'tode'}.':</b><br /><ul>');
               foreach my $user (@{$$memchg{'deletion'}}) {
                   $r->print('<li>'.$$userdata{$user}[$$idx{fullname}].
                             '&nbsp;('.$user.')</li>');
               }
               $r->print('</ul></td><tr><td colspan="4">&nbsp;</td></tr>');
               $exp_or_del += @{$$memchg{'deletion'}};
           }
       }
       if (ref($$memchg{'expire'}) eq 'ARRAY') {
           if (@{$$memchg{'expire'}} > 0) {
               $r->print('<tr><td>&nbsp;</td><td colspan="3"><b>'.$lt{'toex'}.':</b><br /><ul>');
               foreach my $user (@{$$memchg{'expire'}}) {
                   $r->print('<li>'.$$userdata{$user}[$$idx{fullname}].
                             '&nbsp;('.$user.')</li>');
               }
               $r->print('</ul></td><tr><td colspan="4">&nbsp;</td></tr>');
               $exp_or_del += @{$$memchg{'expire'}};
           }
       }
       if (!$exp_or_del) {
           $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'nome'}.
                     '</td></tr><tr><td colspan="4">&nbsp;</td></tr>');
       }
       
       &topic_bar($r,$tabcol,4,&mt('Group member privileges'));
   
       my $numchgs = &member_privileges_form($r,$tabcol,$action,$formname,$tools,
                                             $toolprivs,$fixedprivs,$userdata,
                                             $usertools,$idx,$memchg,$states,
                                             $stored,$rowColor1,$rowColor2);
       $r->print('</td></tr><tr><td colspan="4">&nbsp;</td></tr>');
       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);
       }
       $r->print('</table>');
       return;
   }
   
   sub add_members_form {
       my ($r,$tabcol,$action,$formname,$page,$startdate,$enddate,$groupname,
           $description,$granularity,$sectioncount,$tools,$functions,$stored,
           $states,$navbuttons,$rowColor1,$rowColor2) = @_; 
       $r->print(' <br />
   <table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tr>
     <td>&nbsp;</td>
     <td colspan="3">
   ');
       my @available = ();
       my @unavailable = ();
       &check_tools($functions,$tools,\@available,\@unavailable);
       &print_current_settings($r,$action,$tabcol,$rowColor1,$rowColor2,
                               $functions,$startdate,$enddate,$groupname,
                               $description,$granularity,\@available,\@unavailable);
       $r->print('
      </td>
     </tr>
     <tr>
      <td colspan="4">&nbsp;</td>
     </tr>');
   
       &membership_options($r,$action,$formname,$tabcol,$sectioncount,1);
       my $nexttext = $$navbuttons{'gtns'};
       my $prevtext = $$navbuttons{'gtpp'};
       &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
                           $$states{$action}[$page+1],$nexttext);
       $r->print('
    </table>');
       return;
   }
   
   sub choose_privs_form {
       my ($r,$cdom,$cnum,$tabcol,$action,$formname,$page,$startdate,$enddate,
          $tools,$functions,$toolprivs,$fixedprivs,$userdata,$usertools,$idx,
          $states,$stored,$sectioncount,$navbuttons,$rowColor1,$rowColor2) = @_;
   
       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'};
       }
   
       $r->print('<br /><table width="100%" cellpadding="0" cellspacing="0" border="0">');
       &topic_bar($r,$tabcol,6,&mt('Group member privileges'));
   
       &member_privileges_form($r,$tabcol,$action,$formname,$tools,$toolprivs,
                               $fixedprivs,$userdata,$usertools,$idx,undef,
                               $states,$stored,$rowColor1,$rowColor2);
   
       $r->print('</td></tr><tr><td colspan="4">&nbsp;</td></tr>');
       if ($action eq 'create') {
           if (keys(%{$sectioncount}) > 0) {
               my $img1 = 7;
               my $img2 = 8;
               &mapping_options($r,$action,$formname,$page,$tabcol,$sectioncount,
                                $states,$stored,$navbuttons,$img1,$img2,
                                $rowColor1,$rowColor2);
           }
       }
       my $prevtext = $$navbuttons{'gtps'};
       &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext,
                           $$states{$action}[$page+1],$nexttext);
       $r->print('</table>');
       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,$tabcol,$action,$formname,$tools,$toolprivs,$fixedprivs,$userdata,
           $usertools,$idx,$memchg,$states,$stored,$rowColor1,$rowColor2) = @_;
       my %lt = &Apache::lonlocal::texthash(
               'addp' => 'Additional privileges',
               'fixp' => 'Fixed privileges',
               'oppr' => 'Optional privileges',
               'func' => 'Function',
               'forf' => 'For the functionality you have chosen to include '.
                         'there are no optional privileges to set besides '.
                         'the standard privileges.',
               'algr' => 'All group members will receive the same privileges.',
               '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 '.
                         'functionality 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 {
           @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('<tr><td>&nbsp;</td><td colspan="3">'.$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('
    <tr>
     <td>&nbsp;</td>
     <td colspan="3">
      <table border="0" cellspacing="2" cellpadding="2" border="0">
       <tr>
   ');
                       foreach my $tool (@{$tools}) {
                           if (@{$showboxes{$tool}} > 0) {
                               $r->print('<td valign="top">');
                               $r->print('<table class="thinborder"><tr bgcolor="'.
                                         $tabcol.'"><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></td></tr>');
                       $r->print('<tr><td colspan="4">&nbsp;</td></tr>');
                   }
                   $r->print('<tr><td>&nbsp;</td><td colspan="3">');
                   $r->print(&Apache::lonhtmlcommon::start_pick_box());
                   $r->print(<<"END");
      <tr bgcolor="$tabcol">
       <th><b>$lt{'full'}</th>
       <th><b>$lt{'user'}</th>
       <th>$lt{'doma'}</th>
       <th colspan="$numtools">$lt{'addp'}</th>
     </tr>
   END
                   &member_privs_entries($r,$tabcol,$rowColor1,$rowColor2,
                                         $usertools,$toolprivs,$fixedprivs,
                                         $userdata,$idx,\@showtools,\@defprivs,
                                         \@excluded);
                   $r->print('</td>');
                   $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   $r->print('</td></tr>
    <tr>
     <td colspan="4">&nbsp;</td>
    </tr>
   ');
               } else {
                   $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'forf'}.
                             '<br />');
                   &display_defprivs($r,$tabcol,$rowColor1,$rowColor2,$tools,
                               $toolprivs,\@defprivs);
                                                                                         
               }
           } else {
               if (keys(%{$usertools}) > 0) {
                   $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'algr'}.
                             '<br /><br />');
                   &display_defprivs($r,$tabcol,$rowColor1,$rowColor2,$tools,
                               $toolprivs,\@defprivs);
               } else {
                   $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'asno'}.
                             '<br />');
               }
           }
       } else {
           $r->print('<tr><td>&nbsp;</td><td colspan="3">'.$lt{'asng'});
       }
       return $numchgs;
   }
   
   sub process_request {
       my ($r,$cdom,$cnum,$tabcol,$action,$state,$page,$groupname,$description,
           $specificity,$userdata,$startdate,$enddate,$tools,$functions,$toolprivs,
           $usertools,$idx,$types,$roles,$sections,$states,$navbuttons,$memchg,
           $sectioncount,$stored,$rowColor1,$rowColor2) = @_;
   
       $r->print(&Apache::lonhtmlcommon::echo_form_input(
                                    ['origin','action','state','page','sortby']));
   
       my $earlyout = &validate_groupname($groupname,$action,$cdom,$cnum);
       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 {
           @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); 
       }
       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);
       }
       return;
   }
   
   sub write_group_data {
       my ($r,$cdom,$cnum,$action,$state,$groupname,$description,$startdate,
           $enddate,$specificity,$functions,$tools,$sectioncount,$roles,$types,
           $sections,$defprivs,$stored) = @_;
       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 = &Apache::lonnet::escape($description);
       my @single_attributes = ('description','functions','startdate','enddate',
                                'creation','modified','creator','granularity',
                                'specificity','autoadd','autodrop');
       my @mult_attributes = ('roles','types','sectionpick','defpriv');
                                                                                       
       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'},
                      );
       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);
               if (grep/^_all$/,@autosections) {
                   @autosections = sort {$a cmp $b} keys(%{$sectioncount});
               }
               $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 $put_result = &create_homepage($cdom,$cnum,$groupname,
                                                 \%groupinfo,$tools);
               $r->print('Group '.$groupname.' was created.<br />');
           } else {
               $r->print('Group '.$groupname.' was updated.<br />');
           }
       } else {
           my %actiontype = (
                             'create' => 'creating',
                             'modify' => 'modifying',
                            );
           &Apache::lonnet::logthis('Failed to store group '.$groupname.
                                    'in course: '.$cnum.' in domain: '.$cdom);
           $r->print(&mt('An error occurred when [_1] the new group. '.
                         'Please try again.',$actiontype{$action}));
       }
       return $result;
   }
   
   sub process_membership {
       my ($r,$cdom,$cnum,$action,$state,$groupname,$tools,$enddate,$startdate,
           $userdata,$idx,$toolprivs,$usertools,$specificity,$defprivs,$memchg)=@_;
       my %usersettings = ();
       my %added= ();
       my %failed = ();
       my $num_ok = 0;
       my $num_fail = 0;
       my %group_privs = ();
       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) {
                       foreach my $priv (@{$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 = ();
       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'}};
           }
           if (@expire + @deletion > 0) {
               my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum,
                                                                      $groupname);
               foreach my $user (@expire) {
                   my ($currend,$currstart,@userprivs) = 
                                     split(/:/,$membership{$groupname.':'.$user});
                   $group_privs{$user} = join(':',@userprivs); 
                   if ($currstart > $now) {
                       $currstart = $now;
                   }
                   $usersettings{$groupname.':'.$user} = $now.':'.$currstart.':'.
                                                         $group_privs{$user};
                   if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname,
                                                          $user,$now,$currstart,
                                                          $group_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}))) {
           my $type;
           my $start = $startdate;
           my $end = $enddate;
           if ($state eq 'memresult') {
               $type = 'modified';
               if (@activate > 0) {
                   if (grep/^$user$/,@activate) {
                       $start = $now;
                       $type = 'activated';
                   }
               }
               if (@reenable > 0) {
                   if (grep/^$user$/,@reenable) {
                       $type = 'reenabled';
                   }
               }
           } 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 />');
               }
           }
       }
       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 />');
               }
           }
       }
       if ($roster_result eq 'ok') {
           $r->print('<br />Group membership list updated.');
       } else {
           $r->print('<br />An error occurred while updating the group membership list -'.$roster_result.'<br />');
       }
       return;
   }
   
   sub mapping_options {
       my ($r,$action,$formname,$page,$tabcol,$sectioncount,$states,$stored,
           $navbuttons,$img1,$img2,$rowColor1,$rowColor2) = @_;
       my %lt = &Apache::lonlocal::texthash(
           'auto' => 'Settings for automatic group enrollment',
           'gmma' => 'Group membership mapping to specific sections/roles',
           'endi' => 'Enable/disable automatic group enrollment for '.
                             'users in specified roles and sections',
           'adds'  => 'If automatic group enrollment is enabled, when a user is assigned a course-wide or section-specific role, he/she will automatically be added as a member of the group, with start and end access dates defined by the default dates set for the group, unless he/she is already a group member, with access dates that permit either current or future group access.',
           'drops'  => "If automatic group disenrollment is enabled, when a user's role is expired, access to the group will be terminated unless the user continues to have other course-wide or section-specific active or future roles which receive automatic membership in the group.",
           'pirs' => 'Pick roles and sections for automatic group enrollment',
           'curr' => 'Currently set to',
           'on' => 'on',
           'off' => 'off',
           'auad' => 'Automatically enable group membership when roles are added?',
           'auex' => 'Automatically expire group membership when roles are removed?',
           'mapr' => 'Mapping of roles and sections affected by automatic group enrollment/disenrollment follows scheme chosen below.',
       );
       &automapping($r,$action,$tabcol,$stored,\%lt,$img1);
       $r->print('
      <tr>
       <td colspan="4">&nbsp;</td>
      </tr>');
       &mapping_settings($r,$tabcol,$rowColor1,$rowColor2,$sectioncount,\%lt,
                                                          $stored,$img2);
       return;
   }
   
   sub automapping {
       my ($r,$action,$tabcol,$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,$tabcol,$image,$$lt{'endi'});
       $r->print('
     <tr>
      <td>&nbsp;</td>
      <td colspan="3">
       <b>'.$$lt{'gmma'}.':</b><br />'.$$lt{'adds'}.'<br />'.$$lt{'drops'}.'<br />
      </td>
     </tr>
     <tr>
      <td colspan="4">&nbsp;</td>
     </tr>
     <tr>
      <td>&nbsp;</td>
      <td colspan="3">
      <nobr>'.$$lt{'auad'}.':&nbsp;
       <input type="radio" name="autoadd" value="on" />on&nbsp;&nbsp;<input type="radio" name="autoadd" value="off" />off');
       if ($action eq 'modify') {
           $r->print('&nbsp;&nbsp;&nbsp;&nbsp;('.$$lt{'curr'}.' <b>'.$$lt{$add}.'</b>)');
       }
       $r->print('
       </nobr>
      </td>
     </tr>
     <tr>
      <td>&nbsp;</td>
      <td colspan="3">
       <nobr>'.$$lt{'auex'}.':&nbsp;
       <input type="radio" name="autodrop" value="on" />on&nbsp;&nbsp;<input type="radio" name="autodrop" value="off" />off');
       if ($action eq 'modify') {
           $r->print('&nbsp;&nbsp;&nbsp;&nbsp;('.$$lt{'curr'}.' <b>'.$$lt{$drop}.'</b>)');
       }
       $r->print('</nobr>
      </td>
     </tr>
     <tr>
      <td colspan="4">&nbsp;</td>
     </tr>
     <tr>
      <td>&nbsp;</td>
      <td colspan="3">'.$$lt{'mapr'}.'
      </td>
     </tr>
   ');
   }
   
   sub mapping_settings {
       my ($r,$tabcol,$rowColor1,$rowColor2,$sectioncount,$lt,$stored,$image) = @_;
       my @sections = keys(%{$sectioncount});
       if (@sections > 0) {
           @sections = sort {$a cmp $b} @sections;
           unshift(@sections,'_nosec'); # Put 'no sections' next
           unshift(@sections,'_all'); # Put 'all' at the front of the list
       }
       &topic_bar($r,$tabcol,$image,$$lt{'pirs'});
       $r->print('
      <tr>
       <td>&nbsp;</td>
       <td colspan="3">
   ');
       my @roles = &standard_roles();
       my %customroles = &my_custom_roles();
       $r->print(&Apache::lonhtmlcommon::start_pick_box());
       $r->print('
                   <tr bgcolor="'.$tabcol.'">
                    <th>'.&mt('Active?').'</th>
                    <th>'.&mt('Role').'</th>');
       if (@sections > 0) {
           $r->print('<th>'.&mt('Sections').'</th></tr>'."\n");
       }
       my $rowNum = 0;
       my $rowColor;
       foreach my $role (@roles) {
           my $plrole=&Apache::lonnet::plaintext($role);
           my $sections_sel;
           if (@sections > 0) {
               $sections_sel='<td>'.&sections_selection(\@sections,'sec_'.$role).
                                                                          '</td>';
           }
           if ($rowNum %2 == 1) {
               $rowColor = $rowColor1;
           } else {
               $rowColor = $rowColor2;
           }
           $r->print('<tr bgcolor="'.$rowColor.'"><td><input type="checkbox" '.
                     'name="autorole" value="'.$role.'"></td><td>'.$plrole.
                     '</td>'.$sections_sel.'</tr>');
           $rowNum ++;
       }
       foreach my $role (sort(keys(%customroles))) {
           my $sections_sel;
           if (@sections > 0) {
               $sections_sel = '<td>'.&sections_selection(\@sections,'sec_'.$role).
                                                                           '</td>';
           }
           if ($rowNum %2 == 1) {
               $rowColor = $rowColor1;
           } else {
               $rowColor = $rowColor2;
           }
           $r->print('<tr bgcolor="'.$rowColor.'"><td><input type="checkbox" '.
                     'value="'.$role.'"></td><td>'.$role.'</td>'.
                     $sections_sel.'</tr>');
           $rowNum ++;
       }
       $r->print(&Apache::lonhtmlcommon::end_pick_box());
       return;
   }
   
   sub standard_roles {
       my @roles = ('st','ep','ta','in','cc');
       return @roles;
   }
   
   sub my_custom_roles {
       my %returnhash=();
       my %rolehash=&Apache::lonnet::dump('roles');
       foreach (keys %rolehash) {
           if ($_=~/^rolesdef\_(\w+)$/) {
               $returnhash{$1}=$1;
           }
       }
       return %returnhash;
   }
   
   sub modify_menu {
       my ($r,$groupname,$page) = @_;
       my @menu =
           (
             { text => 'Modify default group settings',
               help => 'Course_Modify_Group',
               state => 'change_settings',
               branch => 'settings',
               },
             { text => 'Modify access, tools and/or privileges for previous, '.
                       'future, or current members',
               help => 'Course_Modify_Group_Membership',
               state => 'change_members',
               branch => 'members',
               },
             { text => 'Add member(s) to the group',
               help => 'Course_Group_Add_Members',
               state => 'add_members',
               branch => 'adds',
               },
             );
       my $menu_html = '';
       foreach my $menu_item (@menu) {
           $menu_html .=
           '<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.= &mt($menu_item->{'text'}).'</a></font>';
           if (exists($menu_item->{'help'})) {
               $menu_html.=
                   &Apache::loncommon::help_open_topic($menu_item->{'help'});
           }
           $menu_html.='</p>'.$/;
       }
       $r->print($menu_html);
       return;
   }
   
   sub member_privs_entries {
       my ($r,$tabcol,$rowColor1,$rowColor2,$usertools,$toolprivs,
           $fixedprivs,$userdata,$idx,$showtools,$defprivs,$excluded) = @_;
       my $rowColor;
       my $rowNum = 0;
       foreach my $user (sort(keys(%{$usertools}))) {
           if (defined($excluded)) {
               if (ref($excluded) eq 'ARRAY') {
                   if (grep/^$user$/,@{$excluded}) {
                       next;
                   }
               }
           }
           my ($uname,$udom) = split(/:/,$user);
           if ($rowNum %2 == 1) {
               $rowColor = $rowColor1;
           } else {
               $rowColor = $rowColor2;
           }
           $r->print('<tr bgcolor="'.$rowColor.'">
                   <td>'.$$userdata{$user}[$$idx{fullname}].'</td>
                   <td>'.$uname.'</td>
                   <td>'.$udom.'</td>
                   <td valign="top"><table><tr><td><b>Function</b></td></tr><tr><td><b>Fixed</b></td></tr><tr><td><b>Optional</b></td></tr></table></td>');
           foreach my $tool (@{$showtools}) {
               if (exists($$usertools{$user}{$tool})) {
                   $r->print('<td valign="top"><table><tr bgcolor="'.$tabcol.'"><td colspan="2" align="center"><b>'.$tool.'</b></td></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 bgcolor="'.$tabcol.'"><td colspan="2" align="center"><b>'.$tool.'</b></td></tr><tr><td>&nbsp;</td></tr><tr><td>&nbsp;</td></tr></table></td>');
               }
           }
           $rowNum ++;
       }
   }
   
   sub get_dates_from_form {
       my $startdate;
       my $enddate;
       $startdate = &Apache::lonhtmlcommon::get_date_from_form('startdate');
       $enddate   = &Apache::lonhtmlcommon::get_date_from_form('enddate');
       if ( exists ($env{'form.no_end_date'}) ) {
           $enddate = 0;
       }
       return ($startdate,$enddate);
   }
   
   sub date_setting_table {
       my ($starttime,$endtime,$formname) = @_;
       my $startform = &Apache::lonhtmlcommon::date_setter($formname,
                                                         'startdate',$starttime);
       my $endform = &Apache::lonhtmlcommon::date_setter($formname,
                                                         'enddate',$endtime);
       my $perpetual = '<nobr><label><input type="checkbox" name="no_end_date" />
                                                   no ending date</label></nobr>';
       my $start_table = '';
       $start_table .= "<table>\n";
       $start_table .= '<tr><td align="right">Default starting date for 
                                              member access</td>'.
           '<td>'.$startform.'</td>'.
           '<td>&nbsp;</td>'."</tr>\n";
       $start_table .= "</table>";
       my $end_table = '';
       $end_table .= "<table>\n";
       $end_table .= '<tr><td align="right">Default ending date for 
                                            member access</td>'.
           '<td>'.$endform.'</td>'.
           '<td>'.$perpetual.'</td>'."</tr>\n";
       $end_table .= "</table>\n";
       return ($start_table, $end_table);
   }
   
   sub create_homepage {
       my ($cdom,$cnum,$name,$groupinfo,$tools) = @_;
       my $functionality = join(',',@{$tools});
       my $content = &Apache::lonnet::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' => 'Group: '.$name,
                        'abb_links' => $functionality,
                        'bbb_content' => $content,
                        'ccc_webreferences' => '',
                        'uploaded.lastmodified' => time,
                      );
      my $putresult = &Apache::lonnet::put('grppage_'.$name,\%pageinfo,$cdom,$cnum);
      return $putresult;
   }
   
   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;
   }
   
   sub validate_groupname {
       my ($groupname,$action,$cdom,$cnum) = @_;
       my %sectioncount;
       my $numsec=&Apache::loncommon::get_sections($cdom,$cnum,\%sectioncount);
       my %curr_groups;
       my $numgroups=&Apache::loncommon::coursegroups(\%curr_groups,$cdom,$cnum);
                                                                                            
       my %lt = &Apache::lonlocal::texthash (
                         igna => 'Invalid group name',
                         tgne => 'The group name entered ',
                         grna => 'Group names and section names used in a course '.
                                 'must be unique.',
                         isno => 'is not a valid name.',
                         gnmo => 'Group names may only contain letters, numbers '.
                                 'or underscores.',
                         cnnb => 'can not be used as it is the name of ',
                         inth => ' in this course.',
                         thgr => '- does not correspond to the name of an existing'.  
                                 ' group ',    
       );
                                                                                            
       my $exitmsg = '<b>'.$lt{'igna'}.'</b><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 ($numsec) {
           if (exists($sectioncount{$groupname})) {
               $earlyout = $exitmsg.$lt{'cnnb'}.&mt('a section').$lt{'inth'}.
                           '<br />'.$lt{'grna'};
               return $earlyout;
           }
       }
       if ($action eq 'create') {
           if ($numgroups) {
               if (exists($curr_groups{$groupname})) {
                   $earlyout = $exitmsg.$lt{'cnnb'}.&mt('an existing group').
                               $lt{'inth'}.'<br />'.$lt{'grna'};
                   return $earlyout;
               }
           }
       } elsif ($action eq 'modify') {
           unless(exists($curr_groups{$groupname})) {
               $earlyout = &mt('Group name:').' '.$groupname.$lt{'thgr'}.$lt{'inth'};
               return $earlyout;
           }
       }
       return;
   }
   
   sub topic_bar {
       my ($r,$tabcol,$imgnum,$title) = @_;
       $r->print('
    <tr bgcolor="'.$tabcol.'">
     <td>&nbsp;</td>
     <td valign="middle" align="left">
      <nobr>
       <img src="/res/adm/pages/bl_step'.$imgnum.'.gif" valign="middle">&nbsp;
      </nobr>
     </td>
     <th align="left"><nobr>'.$title.'<nobr>
     </th>
     <td width="100%">&nbsp;</td>
    </tr>
    <tr>
     <td colspan="4">&nbsp;</td>
    </tr>
   ');
       return;
   }
   
   sub check_changes {
       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.12


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