--- loncom/interface/lonstatistics.pm	2004/02/19 20:17:01	1.97
+++ loncom/interface/lonstatistics.pm	2012/03/20 16:03:54	1.155
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonstatistics.pm,v 1.97 2004/02/19 20:17:01 matthew Exp $
+# $Id: lonstatistics.pm,v 1.155 2012/03/20 16:03:54 bisitz Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -28,19 +28,7 @@
 #
 ###
 
-=pod
-
-=head1 NAME
-
-lonstatistics
-
-=head1 SYNOPSIS
-
-Main handler for statistics and chart.
-
-=over 4
 
-=cut
 
 package Apache::lonstatistics;
 
@@ -49,24 +37,21 @@ use Apache::Constants qw(:common :http);
 use vars qw(
     @FullClasslist 
     @Students
-    @Sections 
-    @SelectedSections
+    @Sections
+    @Groups 
     %StudentData
     @StudentDataOrder
     @SelectedStudentData
-    $top_map 
-    @Sequences 
-    @SelectedMaps
-    @Assessments
     $enrollment_status);
 
-use Apache::lonnet();
+use Apache::lonnet;
 use Apache::lonhomework;
 use Apache::loncommon;
 use Apache::loncoursedata;
 use Apache::lonhtmlcommon;
 use Apache::lonmysql;
 use Apache::lonlocal;
+use Apache::longroup;
 use Time::HiRes;
 #
 # Statistics Packages
@@ -77,32 +62,11 @@ use Apache::lonproblemstatistics();
 use Apache::lonstudentassessment();
 use Apache::lonpercentage;
 use Apache::lonstudentsubmissions();
+use Apache::lonsurveyreports();
+use Apache::longradinganalysis();
+use Apache::lonquickgrades();
+use LONCAPA;
 
-#######################################################
-#######################################################
-
-=pod
-
-=item Package Variables
-
-=item @FullClasslist The full classlist
-
-=item @Students The students we are concerned with for this invocation
-
-=item @Sections The sections available in this class
-
-=item $curr_student The student currently being examined
-
-=item $prev_student The student previous in the classlist
-
-=item $next_student The student next in the classlist
-
-=over
-
-=cut 
-
-#######################################################
-#######################################################
 #
 # Classlist variables
 #
@@ -110,48 +74,12 @@ my $curr_student;
 my $prev_student;
 my $next_student;
 
-#######################################################
-#######################################################
 
-=pod
-
-=item &clear_classlist_variables()
-
-undef the following package variables:
-
-=over
-
-=item @FullClasslist
-
-=item @Students
-
-=item @Sections
-
-=item @SelectedSections
-
-=item %StudentData
-
-=item @StudentDataOrder
-
-=item @SelectedStudentData
-
-=item $curr_student
-
-=item $prev_student
-
-=item $next_student
-
-=back
-
-=cut
-
-#######################################################
-#######################################################
 sub clear_classlist_variables {
     undef(@FullClasslist);
     undef(@Students);
     undef(@Sections);
-    undef(@SelectedSections);
+    undef(@Groups);
     undef(%StudentData);
     undef(@SelectedStudentData);
     undef($curr_student);
@@ -159,87 +87,49 @@ sub clear_classlist_variables {
     undef($next_student);
 }
 
-#######################################################
-#######################################################
-
-=pod
-
-=item &PrepareClasslist()
-
-Build up the classlist information.  The classlist information is kept in
-the following package variables:
-
-=over
-
-=item @FullClasslist
-
-=item @Students
-
-=item @Sections
-
-=item @SelectedSections
-
-=item %StudentData
-
-=item @SelectedStudentData
-
-=item $curr_student
-
-=item $prev_student
-
-=item $next_student
-
-=back
-
-$curr_student, $prev_student, and $next_student may not be defined, depending
-upon the calling context.
-
-=cut
 
-#######################################################
-#######################################################
 sub PrepareClasslist {
     my %Sections;
     &clear_classlist_variables();
     #
     # Retrieve the classlist
-    my $cid  = $ENV{'request.course.id'};
-    my $cdom = $ENV{'course.'.$cid.'.domain'};
-    my $cnum = $ENV{'course.'.$cid.'.num'};
-    my ($classlist,$field_names) = &Apache::loncoursedata::get_classlist($cid,
-                                                                  $cdom,$cnum);
-    if (exists($ENV{'form.Section'})) {
-        if (ref($ENV{'form.Section'})) {
-            @SelectedSections = @{$ENV{'form.Section'}};
-        } elsif ($ENV{'form.Section'} !~ /^\s*$/) {
-            @SelectedSections = ($ENV{'form.Section'});
-        }
-    }
-    @SelectedSections = ('all') if (! @SelectedSections);
-    foreach (@SelectedSections) {
-        if ($_ eq 'all') {
-            @SelectedSections = ('all');
-        }
-    }
+    my $cid  = $env{'request.course.id'};
+    my $cdom = $env{'course.'.$cid.'.domain'};
+    my $cnum = $env{'course.'.$cid.'.num'};
+    my ($classlist,$field_names) = &Apache::loncoursedata::get_classlist($cdom,
+									$cnum);
+    my @selected_sections = &get_selected_sections();
+    my @selected_groups = &get_selected_groups();
     #
     # Deal with instructors with restricted section access
-    if ($ENV{'request.course.sec'} !~ /^\s*$/) {
-        @SelectedSections = ($ENV{'request.course.sec'});
+    if ($env{'request.course.sec'} !~ /^\s*$/) {
+        @selected_sections = ($env{'request.course.sec'});
     }
     #
     # Set up %StudentData
-    @StudentDataOrder = qw/fullname username domain id section status/;
+    @StudentDataOrder = qw/fullname username domain id section status groups comments/;
     foreach my $field (@StudentDataOrder) {
-        $StudentData{$field}->{'title'} = $field;
-        $StudentData{$field}->{'base_width'} = length($field);
+        $StudentData{$field}->{'title'} = &mt($field);
+        $StudentData{$field}->{'base_width'} = length(&mt($field));
         $StudentData{$field}->{'width'} = 
                                $StudentData{$field}->{'base_width'};
     }
     #
     # get the status requested
     $enrollment_status = 'Active';
-    $enrollment_status = $ENV{'form.Status'} if (exists($ENV{'form.Status'}));
+    $enrollment_status = $env{'form.Status'} if (exists($env{'form.Status'}));
     #
+    # Get groupmembership
+    my ($classgroups,$studentgroups);
+    my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
+    if (%curr_groups) {
+        ($classgroups,$studentgroups) = 
+	    &Apache::loncoursedata::get_group_memberships($classlist,
+                                                          $field_names,
+							  $cdom,$cnum);
+    }
+    my $now = time;
+
     # Process the classlist
     while (my ($student,$student_data) = each (%$classlist)) {
         my $studenthash = ();
@@ -254,6 +144,16 @@ sub PrepareClasslist {
                 $StudentData{$field}->{'width'} = $length; 
             }
         }
+        my @studentsgroups = &Apache::loncoursedata::get_students_groups
+                                                   ($student,$enrollment_status,
+                                                    $classgroups);
+        if (@studentsgroups) {
+            $studenthash->{'groups'} = join(', ',@studentsgroups);
+            $studenthash->{'groupref'} = \@studentsgroups;
+        } else {
+            $studenthash->{'groups'} = 'none';
+            $studenthash->{'groupref'} = []; 
+        }
         push (@FullClasslist,$studenthash);
         #
         # Build up a list of sections
@@ -265,38 +165,66 @@ sub PrepareClasslist {
         $Sections{$section}++;
         #
         # Only put in the list those students we are interested in
-        foreach my $sect (@SelectedSections) {
+        foreach my $sect (@selected_sections) {
             if ( (($sect eq 'all') || 
                   ($section eq $sect)) &&
                  (($studenthash->{'status'} eq $enrollment_status) || 
                   ($enrollment_status eq 'Any')) 
                  ){
-                push (@Students,$studenthash);
-                last;
+                my $groupcheck = 0;
+                if (grep(/^all$/,@selected_groups)) {
+                    push(@Students,$studenthash);
+                    last;
+                } elsif (grep(/^none$/,@selected_groups)) {
+                    if ($studenthash->{'groups'} eq 'none') {
+                        push(@Students,$studenthash);
+                        last;
+                    }     
+                } else {
+                    foreach my $group (@selected_groups) {
+                        if (grep(/^$group$/,@studentsgroups)) {
+                            push(@Students,$studenthash);
+                            $groupcheck = 1;
+                            last;
+                        }
+                    }
+                    if ($groupcheck) {
+                        last;
+                    }
+                }
             }
         }
     }
     #
     # Put the consolidated section data in the right place
-    if ($ENV{'request.course.sec'} !~ /^\s*$/) {
-        @Sections = ($ENV{'request.course.sec'});
+    if ($env{'request.course.sec'} !~ /^\s*$/) {
+        @Sections = ($env{'request.course.sec'});
     } else {
-        @Sections = sort {$a cmp $b} keys(%Sections);
+        @Sections = sort {
+	    if ($a == $a && $b == $b ) { return $a <=> $b; }
+	    return $a cmp $b;
+	} keys(%Sections);
+
         unshift(@Sections,'all'); # Put 'all' at the front of the list
     }
+    # Sort the groups
+    @Groups = sort {$a cmp $b} keys(%{$studentgroups});
+    unshift(@Groups,'all'); # Put 'all' at the front of the list
+
     #
     # Sort the Students
     my $sortby = 'fullname';
-    $sortby = $ENV{'form.sort'} if (exists($ENV{'form.sort'}));
-    my @TmpStudents = sort { $a->{$sortby} cmp $b->{$sortby} ||
-                             $a->{'fullname'} cmp $b->{'fullname'} } @Students;
+    $sortby = $env{'form.sort'} if (exists($env{'form.sort'}));
+    my @TmpStudents = sort { lc($a->{$sortby}) cmp lc($b->{$sortby}) ||
+                             lc($a->{'fullname'}) cmp lc($b->{'fullname'}) ||
+			     lc($a->{'username'}) cmp lc($b->{'username'}) } @Students;
     @Students = @TmpStudents;
     # 
     # Now deal with that current student thing....
     $curr_student = undef;
-    if (exists($ENV{'form.SelectedStudent'})) {
+    if (exists($env{'form.SelectedStudent'})) {
         my ($current_uname,$current_dom) = 
-            split(':',$ENV{'form.SelectedStudent'});
+            split(':',$env{'form.SelectedStudent'});
         my $i;
         for ($i = 0; $i<=$#Students; $i++) {
             next if (($Students[$i]->{'username'} ne $current_uname) || 
@@ -318,12 +246,9 @@ sub PrepareClasslist {
         }
     }
     #
-    if (exists($ENV{'form.StudentData'})) {
-        if (ref($ENV{'form.StudentData'}) eq 'ARRAY') {
-            @SelectedStudentData = @{$ENV{'form.StudentData'}};
-        } else {
-            @SelectedStudentData = ($ENV{'form.StudentData'});
-        }
+    if (exists($env{'form.StudentData'})) {
+	@SelectedStudentData = 
+	    &Apache::loncommon::get_env_multiple('form.StudentData');
     } else {
         @SelectedStudentData = ('username');
     }
@@ -338,262 +263,134 @@ sub PrepareClasslist {
 }
 
 
-#######################################################
-#######################################################
-
-=pod
-
-=item get_students
-
-Returns a list of the selected students
-
-=cut
-
-#######################################################
-#######################################################
-sub get_students {
-    if (! @Students) {
-        &PrepareClasslist()
+sub get_selected_sections {
+    my @selected_sections = 
+	&Apache::loncommon::get_env_multiple('form.Section');
+    @selected_sections = ('all') if (! @selected_sections);
+    foreach (@selected_sections) {
+        if ($_ eq 'all') {
+            @selected_sections = ('all');
+        }
     }
-    return @Students;
-}
-
-#######################################################
-#######################################################
-
-=pod
-
-=item &current_student()
-
-Returns a pointer to a hash containing data about the currently
-selected student.
-
-=cut
-
-#######################################################
-#######################################################
-sub current_student { 
-    return $curr_student;
-}
-
-#######################################################
-#######################################################
-
-=pod
-
-=item &previous_student()
-
-Returns a pointer to a hash containing data about the student prior
-in the list of students.  Or something.  
-
-=cut
-
-#######################################################
-#######################################################
-sub previous_student { 
-    return $prev_student;
-}
-
-#######################################################
-#######################################################
-
-=pod
-
-=item &next_student()
-
-Returns a pointer to a hash containing data about the next student
-to be viewed.
-
-=cut
-
-#######################################################
-#######################################################
-sub next_student { 
-    return $next_student;
+    #
+    # Deal with instructors with restricted section access
+    if ($env{'request.course.sec'} !~ /^\s*$/) {
+        @selected_sections = ($env{'request.course.sec'});
+    }
+    return @selected_sections;
 }
 
-#######################################################
-#######################################################
-
-=pod
-
-=item &clear_sequence_variables()
-
-=cut
 
-#######################################################
-#######################################################
-sub clear_sequence_variables {
-    undef($top_map);
-    undef(@Sequences);
-    undef(@Assessments);
+sub get_selected_groups {
+    my @selected_groups =
+        &Apache::loncommon::get_env_multiple('form.Group');
+    @selected_groups = ('all') if (! @selected_groups);
+    foreach my $grp (@selected_groups) {
+        if ($grp eq 'all') {
+            @selected_groups = ('all');
+            last;
+        }
+    }
+    return @selected_groups;
 }
+                                                                                    
 
-#######################################################
-#######################################################
-
-=pod
-
-=item &SetSelectedMaps($elementname)
-
-Sets the @SelectedMaps array from $ENV{'form.'.$elementname};
-
-=cut
 
-#######################################################
-#######################################################
-sub SetSelectedMaps {
-    my $elementname = shift;
-    if (exists($ENV{'form.'.$elementname})) {
-        if (ref($ENV{'form.'.$elementname})) {
-            @SelectedMaps = @{$ENV{'form.'.$elementname}};
-        } else {
-            @SelectedMaps = ($ENV{'form.'.$elementname});
-        }
+sub section_and_enrollment_description {
+    my ($mode) = @_;
+    if (! defined($mode)) { $mode = 'localized'; }
+    my @sections = &Apache::lonstatistics::get_selected_sections();
+    my @groups = &Apache::lonstatistics::get_selected_groups();
+    my $description;
+    if ($mode eq 'localized') {
+        $description = &mt('Unable to determine section, groups and access status');
+    } elsif ($mode eq 'plaintext') {
+        $description = 'Unable to determine section, groups and access status';
     } else {
-        @SelectedMaps = ('all');
+        $description = 'Bad parameter passed to lonstatistics::section_and_enrollment_description';
+        &Apache::lonnet::logthis($description);
     }
+    $description = &section_or_group_text($mode,'section',@sections).
+	' '.&section_or_group_text($mode,'group',@groups);
+    if ($mode eq 'localized') {
+        $description .= ' '.&mt($env{'form.Status'}.' access status.');
+    } elsif ($mode eq 'plaintext') {
+        $description .= ' '.$env{'form.Status'}.' access status.';
+    }
+    return $description;
 }
 
 
-#######################################################
-#######################################################
-
-=pod
 
-=item &Sequences_with_Assess()
 
-Returns an array containing the subset of @Sequences which contain
-assessments.
-
-=cut
-
-#######################################################
-#######################################################
-sub Sequences_with_Assess {
-    my @Sequences_to_Show;
-    foreach my $map_symb (@SelectedMaps) {
-        foreach my $sequence (@Sequences) {
-            next if ($sequence->{'symb'} ne $map_symb && $map_symb ne 'all');
-            next if ($sequence->{'num_assess'} < 1);
-            push (@Sequences_to_Show,$sequence);
+sub section_or_group_text {
+    my ($mode,$type,@items) = @_;
+    my $text;
+    my %phrases = ();
+    %{$phrases{'section'}} = (
+                              single => 'Section',
+                              all => 'All sections',
+                              plural => 'Sections',
+                             );
+    %{$phrases{'group'}} = (
+                              single => 'Group',
+                              all => 'All groups',
+                              plural => 'Groups',
+                             );
+    if (scalar(@items) == 1 && $items[0] ne 'all') {
+        if ($mode eq 'localized') {
+            $text = &mt($phrases{$type}{single}.' [_1].',$items[0]);
+        } elsif ($mode eq 'plaintext') {
+            $text = $phrases{$type}{single}.' '.$items[0].'.';
+
+        }
+    } elsif (scalar(@items) && $items[0] eq 'all') {
+        if ($mode eq 'localized') {
+            $text = &mt($phrases{$type}{all}.'.');
+        } elsif ($mode eq 'plaintext') {
+            $text = $phrases{$type}{all}.'.';
+        }
+    } elsif (scalar(@items)) {
+        my $lastitem = pop(@items);
+        if ($mode eq 'localized') {
+            $text = &mt($phrases{$type}{plural}.' [_1] and [_2].',
+                        join(', ',@items),$lastitem);
+        } elsif ($mode eq 'plaintext') {
+            $text = $phrases{$type}{plural}.' '.join(', ',@items).' and '.
+                    $lastitem.'.';
         }
     }
-    return @Sequences_to_Show;
+    return $text;
 }
 
-#######################################################
-#######################################################
-
-=pod
-
-=item &PrepareCourseData($r)
-
-=cut
 
-#######################################################
-#######################################################
-sub PrepareCourseData {
-    my ($r) = @_;
-    &clear_sequence_variables();
-    my ($top,$sequences,$assessments) = 
-        &Apache::loncoursedata::get_sequence_assessment_data();
-    if (! defined($top) || ! ref($top)) {
-        # There has been an error, better report it
-        &Apache::lonnet::logthis('top is undefined');
-        return;
+sub get_students {
+    if (! @Students) {
+        &PrepareClasslist()
     }
-    $top_map = $top if (ref($top));
-    @Sequences = @{$sequences} if (ref($sequences) eq 'ARRAY');
-    @Assessments = @{$assessments} if (ref($assessments) eq 'ARRAY');
-    return;
+    return @Students;
 }
 
-#######################################################
-#######################################################
 
-=pod
 
-=item &log_sequence($sequence,$recursive,$padding)
-
-Write data about the sequence to a logfile.  If $recursive is not
-undef the data is written recursively.  $padding is used for recursive
-calls.
-
-=cut
-
-#######################################################
-#######################################################
-sub log_sequence {
-    my ($seq,$recursive,$padding) = @_;
-    $padding = '' if (! defined($padding));
-    if (ref($seq) ne 'HASH') {
-        &Apache::lonnet::logthis('log_sequence passed bad sequnce');
-        return;
-    }
-    &Apache::lonnet::logthis($padding.'sequence '.$seq->{'title'});
-    while (my($key,$value) = each(%$seq)) {
-        next if ($key eq 'contents');
-        if (ref($value) eq 'ARRAY') {
-            for (my $i=0;$i< scalar(@$value);$i++) {
-                &Apache::lonnet::logthis($padding.$key.'['.$i.']='.
-                                         $value->[$i]);
-            }
-        } else {
-            &Apache::lonnet::logthis($padding.$key.'='.$value);
-        }
-    }
-    if (defined($recursive)) {
-        &Apache::lonnet::logthis($padding.'-'x20);
-        &Apache::lonnet::logthis($padding.'contains:');
-        foreach my $item (@{$seq->{'contents'}}) {
-            if ($item->{'type'} eq 'container') {
-                &log_sequence($item,$recursive,$padding.'    ');
-            } else {
-                &Apache::lonnet::logthis($padding.'title = '.$item->{'title'});
-                while (my($key,$value) = each(%$item)) {
-                    next if ($key eq 'title');
-                    if (ref($value) eq 'ARRAY') {
-                        for (my $i=0;$i< scalar(@$value);$i++) {
-                            &Apache::lonnet::logthis($padding.$key.'['.$i.']='.
-                                                     $value->[$i]);
-                        }
-                    } else {
-                        &Apache::lonnet::logthis($padding.$key.'='.$value);
-                    }
-                }
-            }
-        }
-        &Apache::lonnet::logthis($padding.'end contents of '.$seq->{'title'});
-        &Apache::lonnet::logthis($padding.'-'x20);
-    }
-    return;
+sub current_student { 
+    return $curr_student;
 }
 
-##############################################
-##############################################
 
-=pod 
 
-=item &StudentDataSelect($elementname,$status,$numvisible,$selected)
-
-Returns html for a selection box allowing the user to choose one (or more) 
-of the fields of student data available (fullname, username, id, section, etc)
-
-=over 4
+sub previous_student { 
+    return $prev_student;
+}
 
-=item $elementname The name of the HTML form element
 
-=item $status 'multiple' or 'single' selection box
 
-=item $numvisible The number of options to be visible
+sub next_student { 
+    return $next_student;
+}
 
-=back
 
-=cut
 
-##############################################
-##############################################
 sub StudentDataSelect {
     my ($elementname,$status,$numvisible)=@_;
     if ($numvisible < 1) {
@@ -604,144 +401,141 @@ sub StudentDataSelect {
     my $Str = "\n";
     $Str .= '<select name="'.$elementname.'" ';
     if ($status ne 'single') {
-        $Str .= 'multiple="true" ';
+        $Str .= 'multiple="multiple" ';
     }
     $Str .= 'size="'.$numvisible.'" >'."\n";
     #
     # Deal with 'all'
-    $Str .= '    <option value="all" ';
+    $Str .= '    <option value="all"';
     foreach (@SelectedStudentData) {
         if ($_ eq 'all') {
-            $Str .= 'selected ';
+            $Str .= ' selected="selected"';
             last;
         }
     }
-    $Str .= ">all</option>\n";
+    $Str .= '>'.&mt('all')."</option>\n";
     #
     # Loop through the student data fields
     foreach my $item (@StudentDataOrder) {
-        $Str .= '    <option value="'.$item.'" ';
+        $Str .= '    <option value="'.$item.'"';
         foreach (@SelectedStudentData) {
             if ($item eq $_ ) {
-                $Str .= 'selected ';
+                $Str .= ' selected="selected"';
                 last;
             }
         }
-        $Str .= '>'.$item."</option>\n";
+        $Str .= '>'.&mt($item)."</option>\n";
     }
     $Str .= "</select>\n";
     return $Str;
 }
 
-##############################################
-##############################################
-
-=pod 
 
-=item &MapSelect($elementname,$status,$numvisible,$restriction) 
 
-Returns html for a selection box allowing the user to choose one (or more) 
-of the sequences in the course.  The values of the sequences are the symbs.
-If the top sequence is selected, the value 'top' will result.
+sub get_selected_maps {
+    my ($elementname) = @_;
+    my @selected_maps = 
+	&Apache::loncommon::get_env_multiple('form.'.$elementname);
+    @selected_maps = ('all') if (! @selected_maps);
+    foreach my $map (@selected_maps) {
+        if ($map eq 'all') {
+            @selected_maps = ('all');
+            last;
+        }
+    }
+    return @selected_maps;
+}
 
-=over 4
 
-=item $elementname The name of the HTML form element
 
-=item $status 'multiple' or 'single' selection box
 
-=item $numvisible The number of options to be visible
+sub selected_sequences_with_assessments {
+    my ($mode) = @_;
+    $mode = 'selected' if (! defined($mode));
+    my $navmap = Apache::lonnavmaps::navmap->new();
+    if (!defined($navmap)) {
+        return ('Can not open Coursemap');
+    }
+    #
+    my @sequences = $navmap->retrieveResources(undef,
+                                               sub { shift->is_map(); },1,0,1);
+    my $toplevelseq = $navmap->getById('0.0');
+    if (!grep(/^\Q$toplevelseq\E$/,@sequences)) {
+        unshift(@sequences,$toplevelseq);
+    }
 
-=item $restriction Code reference to subroutine which returns true or 
-false.  The code must expect a reference to a sequence data structure.
+    my @sequences_with_assessments;
+    foreach my $sequence (@sequences) {
+	if ($navmap->hasResource($sequence,sub { shift->is_problem(); },0,1)){
+            push(@sequences_with_assessments,$sequence);
+        }
+    }
+    #
+    my @sequences_to_show;
+    foreach my $sequence (@sequences_with_assessments) {
+        if ($mode eq 'all') {
+            push (@sequences_to_show,$sequence);
+        } elsif ($mode eq 'selected') {
+            foreach my $map_symb (&get_selected_maps('Maps')) {
+                if ($sequence->symb eq $map_symb || $map_symb eq 'all'){
+                    push (@sequences_to_show,$sequence);
+                    last; # Only put it in once
+                }
+            }
+        }
 
-=back
+    }
+    return $navmap,@sequences_to_show;
+}
 
-=cut
 
-##############################################
-##############################################
-sub MapSelect {
-    my ($elementname,$status,$numvisible,$restriction)=@_;
+sub map_select {
+    my ($elementname,$status,$numvisible)=@_;
     if ($numvisible < 1) {
         return;
     }
     #
     # Set up array of selected items
-    &SetSelectedMaps($elementname);
-    #
-    # Set up the restriction call
-    if (! defined($restriction)) {
-        $restriction = sub { 1; };
-    }
+    my @selected_maps = &get_selected_maps($elementname);
     #
     # Build the form element
-    my $Str = "\n";
-    $Str .= '<select name="'.$elementname.'" ';
+    my $form = "\n";
+    $form .= '<select name="'.$elementname.'" ';
     if ($status ne 'single') {
-        $Str .= 'multiple="true" ';
-    }
-    $Str .= 'size="'.$numvisible.'" >'."\n";
-    #
-    # Deal with 'all'
-    foreach (@SelectedMaps) {
-        if ($_ eq 'all') {
-            @SelectedMaps = ('all');
-            last;
-        }
+        $form .= 'multiple="multiple" ';
     }
+    $form .= 'size="'.$numvisible.'" >'."\n";
     #
     # Put in option for 'all'
-    $Str .= '    <option value="all" ';
-    foreach (@SelectedMaps) {
-        if ($_ eq 'all') {
-            $Str .= 'selected ';
-            last;
-        }
+    $form .= '    <option value="all"';
+    if ($selected_maps[0] eq 'all') {
+        $form .= ' selected="selected"';
     }
-    $Str .= ">all</option>\n";
+    $form .= ">all</option>\n";
     #
     # Loop through the sequences
-    foreach my $seq (@Sequences) {
-        next if (! $restriction->($seq));
-        $Str .= '    <option value="'.$seq->{'symb'}.'" ';
-        foreach (@SelectedMaps) {
-            if ($seq->{'symb'} eq $_) {
-                $Str .= 'selected ';
+    my @sequences = &selected_sequences_with_assessments('all');
+    my $navmap;
+    if (!ref($sequences[0])) {
+        return $sequences[0];
+    } else {
+        $navmap = shift(@sequences);
+    }
+    foreach my $seq (@sequences){
+        $form .= '    <option value="'.$seq->symb.'"';
+        foreach (@selected_maps) {
+            if ($seq->symb eq $_) {
+                $form .= ' selected="selected"';
                 last;
             }
         }
-        $Str .= '>'.$seq->{'title'}."</option>\n";
+        $form .= '>'.$seq->compTitle."</option>\n";
     }
-    $Str .= "</select>\n";
-    return $Str;
+    $form .= "</select>\n";
+    return $form;
 }
 
-##############################################
-##############################################
 
-=pod 
-
-=item &SectionSelect($elementname,$status,$numvisible) 
-
-Returns html for a selection box allowing the user to choose one (or more) 
-of the sections in the course.  
-
-Uses the package variables @Sections and @SelectedSections
-=over 4
-
-=item $elementname The name of the HTML form element
-
-=item $status 'multiple' or 'single' selection box
-
-=item $numvisible The number of options to be visible
-
-=back
-
-=cut
-
-##############################################
-##############################################
 sub SectionSelect {
     my ($elementname,$status,$numvisible)=@_;
     if ($numvisible < 1) {
@@ -757,16 +551,16 @@ sub SectionSelect {
     my $Str = "\n";
     $Str .= '<select name="'.$elementname.'" ';
     if ($status ne 'single') {
-        $Str .= 'multiple="true" ';
+        $Str .= 'multiple="multiple" ';
     }
     $Str .= 'size="'.$numvisible.'" >'."\n";
     #
     # Loop through the sequences
     foreach my $s (@Sections) {
-        $Str .= '    <option value="'.$s.'" ';
-        foreach (@SelectedSections) {
+        $Str .= '    <option value="'.$s.'"';
+        foreach (&get_selected_sections()) {
             if ($s eq $_) {
-                $Str .= 'selected ';
+                $Str .= ' selected="selected"';
                 last;
             }
         }
@@ -776,234 +570,163 @@ sub SectionSelect {
     return $Str;
 }
 
-#######################################################
-#######################################################
-
-=pod
-
-=item &CreateAndParseOutputSelector()
-
-Construct a selection list of options for output and parse output selections.
-
-=cut
-
-#######################################################
-#######################################################
-sub OutputDescriptions {
-    my (@OutputOptions) = @_;
-    my $Str = '';
-    $Str .= "<h2>Output Modes</h2>\n";
-    $Str .= "<dl>\n";
-    foreach my $outputmode (@OutputOptions) {
-	$Str .="    <dt>".$outputmode->{'name'}."</dt>\n";
-	$Str .="        <dd>".$outputmode->{'description'}."</dd>\n";
-    }
-    $Str .= "</dl>\n";
-    return $Str;
-}
 
-sub CreateAndParseOutputSelector {
-    my ($elementname,$default,@OutputOptions) = @_;
-    my $output_mode;
-    my $show;
-    my $Str = '';
-    #
-    # Format for output options is 'mode, restrictions';
-    my $selected = $default;
-    if (exists($ENV{'form.'.$elementname})) {
-        if (ref($ENV{'form.'.$elementname} eq 'ARRAY')) {
-            $selected = $ENV{'form.'.$elementname}->[0];
-        } else {
-            $selected = $ENV{'form.'.$elementname};
-        }
+sub GroupSelect {
+    my ($elementname,$status,$numvisible)=@_;
+    if ($numvisible < 1) {
+        return;
     }
     #
-    # Set package variables describing output mode
-    $output_mode = 'html';
-    $show        = 'all';
-    foreach my $option (@OutputOptions) {
-        next if ($option->{'value'} ne $selected);
-        $output_mode = $option->{'mode'};
-        $show        = $option->{'show'};
+    # Make sure we have the data we need to continue
+    if (! @Groups) {
+        &PrepareClasslist();
     }
     #
     # Build the form element
-    $Str = qq/<select size="5" name="$elementname">/;
-    foreach my $option (@OutputOptions) {
-        if (exists($option->{'special'}) && 
-            $option->{'special'} =~ /do not show/) {
-            next;
-        }
-        $Str .= "\n".'    <option value="'.$option->{'value'}.'"';
-        $Str .= " selected " if ($option->{'value'} eq $selected);
-        $Str .= ">".&mt($option->{'name'})."<\/option>";
+    my $Str = "\n";
+    $Str .= '<select name="'.$elementname.'" ';
+    if ($status ne 'single') {
+        $Str .= 'multiple="multiple" ';
     }
-    $Str .= "\n</select>";
-    return ($Str,$output_mode,$show);
-}
-
-###############################################
-###############################################
-
-=pod 
-
-=item &Gather_Student_Data()
-
-Ensures all student data is up to date.
-
-=cut
-
-###############################################
-###############################################
-sub Gather_Student_Data {
-    my ($r) = @_;
-    my $c = $r->connection();
-    #
-    &Apache::loncoursedata::clear_internal_caches();
-    #
-    my @Sequences = &Apache::lonstatistics::Sequences_with_Assess();
-    #
-    my @Students = @Apache::lonstatistics::Students;
+    $Str .= 'size="'.$numvisible.'" >'."\n";
     #
-    # Open the progress window
-    my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
-        ($r,'Statistics Compilation Status',
-         'Statistics Compilation Progress', scalar(@Students));
-    #
-    while (my $student = shift @Students) {
-        return if ($c->aborted());
-        my ($status,undef) = &Apache::loncoursedata::ensure_current_data
-            ($student->{'username'},$student->{'domain'},
-             $ENV{'request.course.id'});
-        &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
-                                                 &mt('last student'));
+    # Loop through the groups
+    foreach my $s (@Groups) {
+        $Str .= '    <option value="'.$s.'"';
+        foreach my $group (&get_selected_groups()) {
+            if ($s eq $group) {
+                $Str .= ' selected="selected"';
+                last;
+            }
+        }
+        $Str .= '>'.$s."</option>\n";
     }
-    &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
-    $r->rflush();
+    $Str .= "</select>\n";
 }
 
-###############################################
-###############################################
-
-=pod 
-
-=item &Gather_Full_Student_Data()
-
-Ensures all student data is up to date.
 
-=cut
 
-###############################################
-###############################################
-sub Gather_Full_Student_Data {
-    my ($r) = @_;
-    my $c = $r->connection();
-    #
-    &Apache::loncoursedata::clear_internal_caches();
-    #
-    my @Students = @Apache::lonstatistics::Students;
-    #
-    # Open the progress window
-    my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
-        ($r,&mt('Student Data Compilation Status'),
-         &mt('Student Data Compilation Progress'), scalar(@Students));
-    #
-    while (my $student = shift @Students) {
-        return if ($c->aborted());
-        my ($status,undef) = &Apache::loncoursedata::ensure_current_full_data
-            ($student->{'username'},$student->{'domain'},
-             $ENV{'request.course.id'});
-        &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
-                                                 &mt('last student'));
-    }
-    &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
-    $r->rflush();
-}
 
-##################################################
-##################################################
 sub DisplayClasslist {
     my ($r)=@_;
+    &Apache::lonhtmlcommon::add_breadcrumb
+        ({text=>'Select One Student'});
     #
-    my @Fields = ('fullname','username','domain','id','section');
+    # Output some of the standard interface components
+    my $Str;
+    $Str .= &Apache::lonhtmlcommon::breadcrumbs('Select One Student');
+    $Str .= '<p><table cellspacing="5">'."\n";
+    $Str .= '<tr>';
+    $Str .= '<th align="center"><b>'.&mt('Sections').'</b></th>';
+    $Str .= '<th align="center"><b>'.&mt('Groups').'</b></th>';
+    $Str .= '<th align="center"><b>'.&mt('Access Status').'</b></th>';
+    $Str .= '</tr>'.$/;
+    $Str .= '<tr>';
+    $Str .= '<td>'.
+        &Apache::lonstatistics::SectionSelect('Section','multiple',5).
+        '</td>';
+    $Str .=  '<td>'.
+        &Apache::lonstatistics::GroupSelect('Group','multiple',5).
+        '</td>';
+    $Str .= '<td>'.
+        &Apache::lonhtmlcommon::StatusOptions(undef,undef,5).
+        '</td>';
+    
+    $Str .= '</tr>'.$/;
+    $Str .= '</table></p>';
+    $Str .= '<input type="submit" name="selectstudent" value="'.
+        &mt('Update Display').'" />';
+    $r->print($Str);
+    $r->rflush();
+    #
+    my @Fields = ('fullname','username','domain','id','section','status','groups');
     #
-    my $Str='';
+    $Str = '';
+    my @selected_sections = &get_selected_sections();
     if (! @Students) {
-        if ($SelectedSections[0] eq 'all') { 
-            if (lc($ENV{'form.Status'}) eq 'any') {
-                $Str .= '<h2>There are no students in the course.</h2>';
-            } elsif (lc($ENV{'form.Status'}) eq 'active') {
-                $Str .= '<h2>There are no currently enrolled students in '.
-                    'the course.</h2>';
-            } elsif (lc($ENV{'form.Status'}) eq 'expired') {
-                $Str .= '<h2>There are no previously enrolled '.
-                    'students in the course.</h2>';
+        if ($selected_sections[0] eq 'all') { 
+            if (lc($env{'form.Status'}) eq 'active') {
+                $Str .= '<p class="LC_info">'.
+                &mt('There are no currently enrolled students in the course.').
+                    '</p>';
+            } elsif (lc($env{'form.Status'}) eq 'expired') {
+                $Str .= '<p class="LC_info">'.
+                    &mt('There are no previously enrolled students in the course.').
+                        '</p>';
+            } elsif (lc($env{'form.Status'}) eq 'future') {
+                $Str .= '<p class="LC_info">'.
+                    &mt('There are no students with future access in the course.').
+                        '</p>';
+            } else { # 'any' and any others
+               $Str .= '<p class="LC_info">'.
+                    &mt('There are no students in the course.').
+                    '</p>';
             }
         } else { 
-            my $sections;
-            if (@SelectedSections == 1) {
-                $sections = 'section '.$SelectedSections[0];
-            } elsif (@SelectedSections > 2) {
-                $sections = 'sections '.join(', ',@SelectedSections);
-                $sections =~ s/, ([^,])*$/, and $1/;
-            } else {
-                $sections = 'sections '.join(' and ',@SelectedSections);
-            }
-            if (lc($ENV{'form.Status'}) eq 'any') {
-                $Str .= '<h2>There are no students in '.$sections.'.</h2>';
-            } elsif (lc($ENV{'form.Status'}) eq 'active') {
-                $Str .= '<h2>There are no currently enrolled students '.
-                    'in '.$sections.'.</h2>';
-            } elsif (lc($ENV{'form.Status'}) eq 'expired') {
-                $Str .= '<h2>There are no previously enrolled students '.
-                    'in '.$sections.'.</h2>';
+            if (lc($env{'form.Status'}) eq 'active') {
+                $Str .= '<p class="LC_info">'.
+                    &mt('There are no currently enrolled students in the selected sections.').
+                    '</p>';
+            } elsif (lc($env{'form.Status'}) eq 'expired') {
+                $Str .= '<p class="LC_info">'.
+                    &mt('There are no previously enrolled students in the selected sections.').
+                    '</p>';
+            } elsif (lc($env{'form.Status'}) eq 'future') {
+                $Str .= '<p class="LC_info">'.
+                    &mt('There are no students with future access in the selected sections.').
+                        '</p>';
+            } else { # 'any' and any others
+                $Str .= '<p class="LC_info">'.
+                    &mt('There are no students in the selected sections.').
+                    '</p>';
             }
         }
-        $Str.= '<a href="/adm/statistics?reportSelected=student_assessment">'.
-            'Return to the chart.</a>';
+        $Str.= '<p>'
+              .'<a href="/adm/statistics?reportSelected=student_assessment">'
+              .&mt('Return to the chart').'</a>'
+              .'</p>';
         $r->print($Str);
         $r->rflush();
         return;
     }
 
-    # "Click" is asinine but it is probably not my place to change the world.
-    $Str .= '<h2>Click on a students name or username to view their chart</h2>';
-    $Str .= '<table border="0"><tr><td bgcolor="#777777">'."\n";
-    $Str .= '<table border="0" cellpadding="3"><tr bgcolor="#e6ffff">'."\n";
+    $Str .= '<h2>'.&mt('Select One Student').'</h2>'
+           .'<p>'.&mt("Click on a student's name or username to view their chart").'</p>'
+           .&Apache::loncommon::start_data_table()
+           .&Apache::loncommon::start_data_table_header_row();
     foreach my $field (@Fields) {
-        $Str .= '<th><a href="/adm/statistics?reportSelected=classlist&sort='.$field.'">'.$field.
+        $Str .= '<th><a href="/adm/statistics?'.
+            'reportSelected=student_assessment&'.
+            'selectstudent=1&'.
+            'sort='.$field.'">'.&mt($field).
             '</a></th>';
     }
-    $Str .= '</tr>'."\n";
+    $Str .= &Apache::loncommon::end_data_table_header_row();
     #
-    my $alternate = 0;
     foreach my $student (@Students) { # @Students is a package variable
         my $sname = $student->{'username'}.':'.$student->{'domain'};
-        if($alternate) {
-            $Str .= '<tr bgcolor="#ffffe6">';
-        } else {
-            $Str .= '<tr bgcolor="#ffffc6">';
-        }
-        $alternate = ($alternate + 1) % 2;
+        $Str .= &Apache::loncommon::start_data_table_row();
         #
         foreach my $field (@Fields) {
             $Str .= '<td>';
             if ($field eq 'fullname' || $field eq 'username') {
                 $Str .= '<a href="/adm/statistics?reportSelected=';
-                $Str .= &Apache::lonnet::escape('student_assessment');
-                $Str .= '&sort='.&Apache::lonnet::escape($ENV{'form.sort'});
+                $Str .= &escape('student_assessment');
+                $Str .= '&sort='.&escape($env{'form.sort'});
                 $Str .= '&SelectedStudent=';
-                $Str .= &Apache::lonnet::escape($sname).'">';
-                $Str .= $student->{$field}.'&nbsp';
+                $Str .= &escape($sname).'">';
+                $Str .= $student->{$field}.'&nbsp;';
                 $Str .= '</a>';
+            } elsif ($field eq 'status') {
+                $Str .= &mt($student->{$field});
             } else {
                 $Str .= $student->{$field};
             }
             $Str .= '</td>';
         }
-        $Str .= "</tr>\n";
+        $Str .= &Apache::loncommon::end_data_table_row();
     }
-    $Str .= '</table></td></tr></table>'."\n";
+    $Str .= &Apache::loncommon::end_data_table();
     #
     $r->print($Str);
     $r->rflush();
@@ -1011,81 +734,72 @@ sub DisplayClasslist {
     return;
 }
 
-##############################################
-##############################################
+
+
 sub CreateMainMenu {
     #
     # Define menu data
-    my @reports = ({ internal_name => 'problem_statistics',
-                     name => &mt('Overall Problem Statistics'),
-                     short_description => 
-    &mt('Student performance statistics on all problems.'),
-                 },
-                   { internal_name => 'problem_analysis',
-                     name => &mt('Detailed Problem Analysis'),
-                     short_description => 
-    &mt('Detailed statistics and graphs of student performance on problems.'),
-                 },
-                   { internal_name => 'submissiontime_analysis',
-                     name => &mt('Submission Time Plots'),
-                     short_description => 
-    &mt('Display and analysis of submission times on assessments.'),
-                 },
-                   { internal_name => 'student_submission_reports',
-                     name => &mt('Student Submission Reports'),
-                     short_description => 
-    &mt('Prepare Excel spreadsheets of student submissions.'),
-                 },
-                   { internal_name => 'correct_problems_plot',
-                     name => &mt('Correct Problems Plot'),
-                     short_description => 
-    &mt('Display a histogram of student performance in the course.'),
-                 },
-#                   { internal_name => 'student_assessment',
-#                     name => &mt('Problem Status Chart'),
-#                     short_description => 
-#    &mt('Brief view of each students performance in course.'),
-#                 },
-                   # 'percentage'  => 'Correct-problems Plot',
-                   # 'activitylog' => 'Activity Log',
-                   );
-    #
-    # Create the menu
-    my $Str;
-    $Str .= '<h1>'.&mt('Please select a report to generate').'</h1>';
-    foreach my $reportdata (@reports) {
-        $Str .='    <h3><a href="/adm/statistics?reportSelected='.
-            $reportdata->{'internal_name'}.'" >'.
-            $reportdata->{'name'}."</a></h3>\n";
-        $Str .= '    '.('&nbsp;'x8).$reportdata->{'short_description'}.
-            "\n";
-    }
-    $Str .="</dl>\n";
-    #
-    return $Str;
+    my @reports = (
+	    {categorytitle => 'Statistics and Analyses',
+         items => [
+            {url => '/adm/statistics?reportSelected=problem_statistics',
+			 permission => 'F',
+             icon => 'document-open.png',
+             linktext => ('Overall Problem Statistics'),
+             linktitle => ('Student performance statistics on all problems.')},
+       
+            {url => '/adm/statistics?reportSelected=problem_analysis',
+			 permission => 'F',
+             icon => 'prob_ana.png',
+             linktext => ('Detailed Problem Analysis'),
+             linktitle => ('Detailed statistics and graphs of student performance on problems.')},
+         ]},
+        {categorytitle => 'Plots',
+         items => [
+            {url => '/adm/statistics?reportSelected=submissiontime_analysis',
+			 permission => 'F',
+             icon => 'subtimpl.png',
+             linktext => ('Submission Time Plots'),
+             linktitle => ('Display and analysis of submission times on assessments.')},
+      
+            {url => '/adm/statistics?reportSelected=correct_problems_plot',
+			 permission => 'F',
+             icon => 'coprplot.png',
+             linktext => ('Correct Problems Plot'),
+             linktitle => ('Display a histogram of student performance in the course.')},
+         ]},
+        {categorytitle => 'Reports',
+         items => [
+            {url => '/adm/statistics?reportSelected=student_submission_reports',
+			 permission => 'F',
+             icon => 'edit-copy.png',
+             linktext => ('Student Submission Reports'),
+             linktitle => ('Prepare reports of student submissions.')},
+                    
+            {url => '/adm/statistics?reportSelected=survey_reports',
+			 permission => 'F',
+             icon => 'survey_rep.png',
+			 linktext => ('Survey Reports'),
+             linktitle => ('Prepare reports on survey results.')},
+         ]});
+    
+return &Apache::lonhtmlcommon::generate_menu(@reports);
+ 
 }
 
-##############################################
-##############################################
+
+
 sub handler {
     my $r=shift;
     my $c = $r->connection();
     #
-    # Check for overloading
-    my $loaderror=&Apache::lonnet::overloaderror($r);
-    if ($loaderror) { return $loaderror; }
-    $loaderror=
-       &Apache::lonnet::overloaderror($r,
-         $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
-    if ($loaderror) { return $loaderror; }
-    #
     # Check for access
-    if (! &Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
-        $ENV{'user.error.msg'}=
+    if (! &Apache::lonnet::allowed('vgr',$env{'request.course.id'})) {
+        $env{'user.error.msg'}=
             $r->uri.":vgr:0:0:Cannot view grades for complete course";
         if (! &Apache::lonnet::allowed('vgr',
-                      $ENV{'request.course.id'}.'/'.$ENV{'request.course.sec'})) {
-            $ENV{'user.error.msg'}=
+                      $env{'request.course.id'}.'/'.$env{'request.course.sec'})) {
+            $env{'user.error.msg'}=
                 $r->uri.":vgr:0:0:Cannot view grades with given role";
             return HTTP_NOT_ACCEPTABLE;
         }
@@ -1103,77 +817,119 @@ sub handler {
                                              'SelectedStudent']);
     #
     # Give the LON-CAPA page header
-    $r->print('<html><head><title>'.
-              &mt('Course Statistics and Charts').
-              "</title></head>\n".
-              &Apache::loncommon::bodytag('Course Statistics and Charts')."\n".
-	      &Apache::loncommon::help_open_faq(139).
-	      &Apache::loncommon::help_open_bug('Statistics and Charts'));
+    my $style = <<ENDSTYLE;
+<style type="text/css">
+    ul.sub_studentans { list-style-type: none }
+    ul.sub_correctans { list-style-type: none }
+    tr.even           { background-color: \#CCCCCC }
+    td.essay          { border: 1px solid gray; }
+</style>
+ENDSTYLE
+      
+    $r->print(&Apache::loncommon::start_page('Course Statistics and Charts',
+					     $style));
     $r->rflush();
     # 
     # Either print out a menu for them or send them to a report
-    if (! exists($ENV{'form.reportSelected'}) || 
-        $ENV{'form.reportSelected'} eq '') {
+    &Apache::lonhtmlcommon::clear_breadcrumbs();
+    &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/statistics',
+                                            title=>'Statistics',
+                                            text =>'Statistics',
+                                            faq=>139,
+                                            bug=>'Statistics and Charts'});
+    if (! exists($env{'form.reportSelected'}) || 
+        $env{'form.reportSelected'} eq '') {
+        $r->print(&Apache::lonhtmlcommon::breadcrumbs('Statistics Main Page'));
+        &Apache::lonquickgrades::startGradeScreen($r,'statistics');
         $r->print(&CreateMainMenu());
     } else {
     #
         if (! &Apache::lonmysql::verify_sql_connection()) {
             my $serveradmin = $r->dir_config('lonAdmEMail');
-            $r->print('<h2><font color="Red">'.
+            $r->print('<h2 class="LC_error">'.
                       &mt('Unable to connect to database!').
-                      '</font></h2>');
-            $r->print('<p>'.
-                      &mt('Please notify the server administrator ').
-                      '<b>'.$serveradmin.'</b></p>');
+                      '</h2>');
+            $r->print('<p>'
+                     .&mt('Please notify the server administrator [_1]',
+                         ,'<b>'.$serveradmin.'</b>')
+                     .'</p>');
             $r->print('<p>'.
                       &mt('Course Statistics and Charts cannot be '.
-                          'retrieved until the database is restarted.  '.
+                          'retrieved until the database is restarted. '.
                           'Your data is intact but cannot be displayed '.
                           'at this time.').'</p>');
-            $r->print('</body></html>');
+            $r->print(&Apache::loncommon::end_page());
             return;
         }
         #
         # Clean out the caches
-        if (exists($ENV{'form.ClearCache'})) {
-            &Apache::loncoursedata::delete_caches($ENV{'requres.course.id'});
+        if (exists($env{'form.ClearCache'})) {
+            &Apache::loncoursedata::delete_caches($env{'requres.course.id'});
         }
         #
+        my $GoToPage = $env{'form.reportSelected'};
+        #
         # Begin form output
         $r->print('<form name="Statistics" ');
+        if ($GoToPage eq 'student_submission_reports') {
+            $r->print('onsubmit="return checkanon();" ');
+        }
         $r->print('method="post" action="/adm/statistics">');
         $r->rflush();
-        #
-        my $GoToPage = $ENV{'form.reportSelected'};
-        #
-        # Set up the statistics and chart environment
-        &PrepareCourseData($r);
-        #
         $r->print('<input type="hidden" name="reportSelected" value="'.
-                  $GoToPage.'">');
+                  $GoToPage.'" />');
         if($GoToPage eq 'activitylog') {
 #        &Apache::lonproblemstatistics::Activity();
         } elsif($GoToPage eq 'problem_statistics') {
+            &Apache::lonhtmlcommon::add_breadcrumb
+                ({href=>'/adm/statistics?reportselected=problem_statistics',
+                  text=>'Overall Problem Statistics'});
             &Apache::lonproblemstatistics::BuildProblemStatisticsPage($r,$c);
         } elsif($GoToPage eq 'problem_analysis') {
+            &Apache::lonhtmlcommon::add_breadcrumb
+                ({href=>'/adm/statistics?reportselected=problem_analysis',
+                  text=>'Detailed Problem Analysis'});
             &Apache::lonproblemanalysis::BuildProblemAnalysisPage($r,$c);
         } elsif($GoToPage eq 'submissiontime_analysis') {
+            &Apache::lonhtmlcommon::add_breadcrumb
+                ({href=>
+                      '/adm/statistics?reportselected=submissiontime_analysis',
+                      text=>'Submission Time Plots'});
             &Apache::lonsubmissiontimeanalysis::BuildSubmissionTimePage($r,$c);
         } elsif($GoToPage eq 'student_submission_reports') {
+            &Apache::lonhtmlcommon::add_breadcrumb
+                ({href=>
+                  '/adm/statistics?reportselected=student_submission_reports',
+                  text=>'Student Submission Reports'});
             &Apache::lonstudentsubmissions::BuildStudentSubmissionsPage($r,$c);
+        } elsif($GoToPage eq 'survey_reports') {
+            &Apache::lonhtmlcommon::add_breadcrumb
+                ({href=>
+                  '/adm/statistics?reportselected=survey_reports',
+                  text=>'Survey Reports'});
+            &Apache::lonsurveyreports::BuildSurveyReportsPage($r,$c);
         } elsif($GoToPage eq 'correct_problems_plot') {
+            &Apache::lonhtmlcommon::add_breadcrumb
+                ({href=>'/adm/statistics?reportselected=correct_problems_plot',
+                  text=>'Correct Problems Plot'});
             &Apache::loncorrectproblemplot::BuildCorrectProblemsPage($r,$c);
         } elsif($GoToPage eq 'student_assessment') {
+            &Apache::lonhtmlcommon::clear_breadcrumbs();
+            &Apache::lonhtmlcommon::add_breadcrumb
+                ({href=>'/adm/statistics?reportselected=student_assessment',
+                  text=>'Chart'});
             &Apache::lonstudentassessment::BuildStudentAssessmentPage($r,$c);
-        } elsif($GoToPage eq 'DoDiffGraph' || $GoToPage eq 'PercentWrongGraph') {
-#        &Apache::lonproblemstatistics::BuildGraphicChart($r,$c);
-        } elsif($GoToPage eq 'Correct-problems Plot') {
-            #	&Apache::lonpercentage::BuildPercentageGraph($r,$c);
-        }
+        } elsif($GoToPage eq 'grading_analysis') {
+            &Apache::lonhtmlcommon::add_breadcrumb
+                ({href=>'/adm/statistics?reportselected=grading_anaylsis',
+                  text=>'Grading Analysis'});
+            &Apache::longradinganalysis::build_grading_analysis_page($r,$c);
+	}
         #
         $r->print("</form>\n");
     }
-    $r->print("</body>\n</html>\n");
+    &Apache::lonquickgrades::endGradeScreen($r);
+    $r->print(&Apache::loncommon::end_page());
     $r->rflush();
     #
     return OK;
@@ -1181,17 +937,227 @@ sub handler {
 
 1;
 
-#######################################################
-#######################################################
+__END__
 
 =pod
 
+=head1 NAME
+
+lonstatistics
+
+=head1 SYNOPSIS
+
+Main handler for statistics and chart.
+
+This is part of the LearningOnline Network with CAPA project
+described at http://www.lon-capa.org.
+
+
+=head1 PACKAGE VARIABLES
+
+=over
+
+=item @FullClasslist The full classlist
+
+=item @Students The students we are concerned with for this invocation
+
+=item @Sections The sections available in this class
+
+=item @Groups The groups available in the class
+
+=item $curr_student The student currently being examined
+
+=item $prev_student The student previous in the classlist
+
+=item $next_student The student next in the classlist
+
 =back
 
-=cut
+=head1 SUBROUTINES
 
-#######################################################
-#######################################################
+=over
 
-__END__
+=item &clear_classlist_variables()
+
+undef the following package variables:
+
+=over 4
+
+=item * @FullClasslist
+
+=item * @Students
+
+=item * @Sections
+
+=item * @Groups
+
+=item * %StudentData
+
+=item * @StudentDataOrder
+
+=item * @SelectedStudentData
+
+=item * $curr_student
+
+=item * $prev_student
+
+=item * $next_student
+
+=back
+
+=item &PrepareClasslist()
+
+Build up the classlist information.  The classlist information is kept in
+the following package variables:
+
+=over 4 
+
+=item * @FullClasslist
+
+=item * @Students
+
+=item * @Sections
+
+=item * @Groups 
+
+=item * %StudentData
+
+=item * @SelectedStudentData
+
+=item * $curr_student
+
+=item * $prev_student
+
+=item * $next_student
+
+=back
+
+$curr_student, $prev_student, and $next_student may not be defined, depending
+upon the calling context.
+
+=item get_selected_sections()
+
+Returns an array of the selected sections
+
+=item get_selected_groups()
+                                                                                    
+Returns an array of the selected groups
+
+=item &section_and_enrollment_description()
+
+Returns a string describing the currently selected section(s), group(s) and 
+access status.  
+
+Inputs: mode = 'plaintext' or 'localized'  (defaults to 'localized')
+    'plaintext' is used for example in Excel spreadsheets.
+Returns: scalar description string.
+
+=item section_or_group_text()
+
+=item get_students()
+
+Returns a list of the selected students
+
+=item &current_student()
+
+Returns a pointer to a hash containing data about the currently
+selected student.
+
+=item &previous_student()
+
+Returns a pointer to a hash containing data about the student prior
+in the list of students.  Or something. 
+
+=item &next_student()
+
+Returns a pointer to a hash containing data about the next student
+to be viewed. 
+
+=item &StudentDataSelect($elementname,$status,$numvisible,$selected)
+
+Returns html for a selection box allowing the user to choose one (or more) 
+of the fields of student data available (fullname, username, id, section, etc)
+
+=over 4
+
+=item * $elementname The name of the HTML form element
+
+=item * $status 'multiple' or 'single' selection box
+
+=item * $numvisible The number of options to be visible
+
+=back
+
+=item &get_selected_maps($elementname)
+
+Input: Name of the <select> form element used to specify the maps.
+
+Returns: Array of symbs of selected maps or the description 'all'.
+   If form.$elementname does not exist, 'all' is returned.
+
+=item &selected_sequences_with_assessments()
+
+Retrieve the sequences which were selected by the user to show.  
+
+Input: $mode: scalar.  Either 'selected' or 'all'.  If not specified,
+    'selected' is used.
+
+Returns: an array containing a navmap object and navmap resources, 
+    or an array containing a scalar with an error message.
+
+=item &map_select($elementname,$status,$numvisible,$restriction) 
+
+Returns html for a selection box allowing the user to choose one (or more) 
+of the sequences in the course.  The values of the sequences are the symbs.
+If the top sequence is selected, the value 'top' will result.
+
+=over 4
+
+=item * $elementname The name of the HTML form element
+
+=item * $status 'multiple' or 'single' selection box
+
+=item * $numvisible The number of options to be visible
+
+=back
+
+=item &SectionSelect($elementname,$status,$numvisible) 
+
+Returns html for a selection box allowing the user to choose one (or more) 
+of the sections in the course.  
+
+Uses the package variables @Sections
+
+=over 4
+
+=item * $elementname The name of the HTML form element
+
+=item * $status 'multiple' or 'single' selection box
+
+=item * $numvisible The number of options to be visible
+
+=back
+
+=item &GroupSelect($elementname,$status,$numvisible)
+                                                                                    
+Returns html for a selection box allowing the user to choose one (or more)
+of the groups in the course.
+                                                                                    
+Uses the package variables @Groups
+
+=over 4
+                                                                                    
+=item * $elementname The name of the HTML form element
+                                                                                    
+=item * $status 'multiple' or 'single' selection box
+                                                                                    
+=item * $numvisible The number of options to be visible
+                                                                                    
+=back
+
+=item CreateMainMenu()
+
+=back
+
+=cut