--- loncom/interface/statistics/lonstudentassessment.pm	2005/01/21 18:52:40	1.110
+++ loncom/interface/statistics/lonstudentassessment.pm	2005/02/28 17:23:11	1.116
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonstudentassessment.pm,v 1.110 2005/01/21 18:52:40 albertel Exp $
+# $Id: lonstudentassessment.pm,v 1.116 2005/02/28 17:23:11 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -56,6 +56,7 @@ use Apache::loncommon();
 use Apache::loncoursedata;
 use Apache::lonnet; # for logging porpoises
 use Apache::lonlocal;
+use Time::HiRes;
 use Spreadsheet::WriteExcel;
 use Spreadsheet::WriteExcel::Utility();
 
@@ -176,6 +177,7 @@ sub BuildStudentAssessmentPage {
     my $initialize     = \&html_initialize;
     my $output_student = \&html_outputstudent;
     my $finish         = \&html_finish;
+    &Apache::lonnet::logthis('got here! 1');
     #
     if ($output_mode eq 'excel') {
         $initialize     = \&excel_initialize;
@@ -187,6 +189,7 @@ sub BuildStudentAssessmentPage {
         $finish         = \&csv_finish;
     }
     #
+    &Apache::lonnet::logthis('got here! 2');
     if($c->aborted()) {  return ; }
     #
     # Determine which students we want to look at
@@ -211,6 +214,7 @@ sub BuildStudentAssessmentPage {
     #
     # Call the initialize routine selected above
     $initialize->($r);
+    &Apache::lonnet::logthis('got here! 3');
     foreach my $student (@Students) {
         if($c->aborted()) { 
             $finish->($r);
@@ -327,21 +331,12 @@ sub CreateInterface {
     $Str .= '<tr><td align="center">'."\n";
     $Str .= &Apache::lonstatistics::SectionSelect('Section','multiple',5);
     $Str .= '</td><td align="center">';
-    my $only_seq_with_assessments = sub { 
-        my $s=shift;
-        if ($s->{'num_assess'} < 1) { 
-            return 0;
-        } else { 
-            return 1;
-        }
-    };
     $Str .= &Apache::lonstatistics::StudentDataSelect('StudentData','multiple',
                                                       5,undef);
     $Str .= '</td><td>'."\n";
     $Str .= &Apache::lonhtmlcommon::StatusOptions(undef,undef,5);
     $Str .= '</td><td>'."\n";
-    $Str .= &Apache::lonstatistics::MapSelect('Maps','multiple,all',5,
-                                              $only_seq_with_assessments);
+    $Str .= &Apache::lonstatistics::map_select('Maps','multiple,all',5);
     $Str .= '</td><td>'."\n";
     $Str .= &CreateAndParseOutputSelector();
     $Str .= '</td><td>'."\n";
@@ -586,6 +581,26 @@ sub CreateAndParseOutputDataSelector {
 
 #######################################################
 #######################################################
+sub count_parts {
+    my ($navmap,$sequence) = @_;
+    my @resources = &get_resources($navmap,$sequence);
+    my $count = 0;
+    foreach my $res (@resources) {
+        $count += scalar(@{$res->parts});
+    }
+    return $count;
+}
+
+sub get_resources {
+    my ($navmap,$sequence) = @_;
+    my @resources = $navmap->retrieveResources($sequence,
+                                               sub { shift->is_problem(); },
+                                               0,0,0);
+    return @resources;
+}
+
+#######################################################
+#######################################################
 
 =pod
 
@@ -613,6 +628,10 @@ Return a line of the chart for a student
     my %prog_state;   # progress state used by loncommon PrgWin routines
     my $total_sum_width;
 
+    my %width; # Holds sequence width information
+    my @sequences;
+    my $navmap; # Have to keep this around since weakref is a bit zealous
+
 sub html_initialize {
     my ($r) = @_;
     #
@@ -620,10 +639,22 @@ sub html_initialize {
     $count = 0;
     $nodata_count = 0;
     undef(%prog_state);
+    undef(%width);
+    #
+    undef($navmap);
+    undef(@sequences);
+    ($navmap,@sequences) = 
+        &Apache::lonstatistics::selected_sequences_with_assessments();
+    if (! ref($navmap)) {
+        # Unable to get data, so bail out
+        $r->print("<h3>".
+                  &mt('Unable to retrieve course information.').
+                  '</h3>');
+    }
     #
     $r->print("<h3>".$ENV{'course.'.$ENV{'request.course.id'}.'.description'}.
               "&nbsp;&nbsp;".localtime(time)."</h3>");
-
+    #
     if ($chosen_output->{'base'} !~ /^final table/) {
         $r->print("<h3>".$chosen_output->{'shortdesc'}."</h3>");        
     }
@@ -639,45 +670,50 @@ sub html_initialize {
     #
     # Compute the column widths and output the sequence titles
     my $total_count;
-    foreach my $sequence (&Apache::lonstatistics::Sequences_with_Assess()){
-        #
-        # Comptue column widths
-        $sequence->{'width_sum'} = 0;
+    #
+    # Compute sequence widths
+    my $starttime = Time::HiRes::time;
+    foreach my $seq (@sequences) {
+        my $symb = $seq->symb;
+        my $title = $seq->compTitle;
+        $width{$symb}->{'width_sum'} = 0;
+        # Compute width of sum
         if ($chosen_output->{'sequence_sum'}) {
             if ($chosen_output->{'every_problem'}) {
                 # Use 1 digit for a space
-                $sequence->{'width_sum'} += 1;            
+                $width{$symb}->{'width_sum'} += 1;            
             }
-	    $total_count += $sequence->{'num_assess_parts'};
+	    $total_count += $width{$symb}->{'num_assess_parts'};
             # Use 3 digits for the sum
-            $sequence->{'width_sum'} += 3;
+            $width{$symb}->{'width_sum'} += 3;
         }
+        # Compute width of maximum
         if ($chosen_output->{'sequence_max'}) {
-            if ($sequence->{'width_sum'}>0) {
+            if ($width{$symb}->{'width_sum'}>0) {
                 # One digit for the '/'
-                $sequence->{'width_sum'} +=1;
+                $width{$symb}->{'width_sum'} +=1;
             }
             # Use 3 digits for the total
-            $sequence->{'width_sum'}+=3;
+            $width{$symb}->{'width_sum'}+=3;
         }
 	#
         if ($chosen_output->{'every_problem'}) {
             # one problem per digit
-            $sequence->{'width_problem'} = $sequence->{'num_assess_parts'};
+            $width{$symb}->{'width_parts'}= &count_parts($navmap,$seq);
+            $width{$symb}->{'width_problem'} += $width{$symb}->{'width_parts'};
         } else {
-            $sequence->{'width_problem'} = 0;
+            $width{$symb}->{'width_problem'} = 0;
         }
-        $sequence->{'width_total'} = $sequence->{'width_problem'} + 
-                                     $sequence->{'width_sum'};
-        if ($sequence->{'width_total'} < length(&HTML::Entities::decode($sequence->{'title'}))) {
-            $sequence->{'width_total'} = length(&HTML::Entities::decode($sequence->{'title'}));
+        $width{$symb}->{'width_total'} = $width{$symb}->{'width_problem'} + 
+                                     $width{$symb}->{'width_sum'};
+        if ($width{$symb}->{'width_total'} < length(&HTML::Entities::decode($title))) {
+            $width{$symb}->{'width_total'} = length(&HTML::Entities::decode($title));
         }
         #
         # Output the sequence titles
-        $Str .= 
-            $sequence->{'title'}.' 'x($sequence->{'width_total'}-
-                                      length($sequence->{'title'})
-                                      ).$padding;
+        $Str .= $title.(' 'x($width{$symb}->{'width_total'}-
+                            length($title)
+                            )).$padding;
     }
     $total_sum_width = length($total_count)+1;
     $Str .= "    total</pre>\n";
@@ -690,6 +726,7 @@ sub html_initialize {
 sub html_outputstudent {
     my ($r,$student) = @_;
     my $Str = '';
+    return if (! defined($navmap));
     #
     if($count++ % 5 == 0 && $count > 0) {
         $r->print("</pre><pre>");
@@ -725,23 +762,25 @@ sub html_outputstudent {
     # By sequence build up the data
     my $studentstats;
     my $PerformanceStr = '';
-    foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+    foreach my $seq (@sequences) {
+        &Apache::lonnet::logthis('computing student data for '.$seq->compTitle);
         my ($performance,$performance_length,$score,$seq_max,$rawdata);
         if ($chosen_output->{'tries'}) {
             ($performance,$performance_length,$score,$seq_max,$rawdata) =
-                &StudentTriesOnSequence($student,\%StudentsData,
-                                        $seq,$show_links);
+                &student_tries_on_sequence($student,\%StudentsData,
+                                           $navmap,$seq,$show_links);
         } else {
             ($performance,$performance_length,$score,$seq_max,$rawdata) =
-                &StudentPerformanceOnSequence($student,\%StudentsData,
-                                              $seq,$show_links);
+                &student_performance_on_sequence($student,\%StudentsData,
+                                                 $navmap,$seq,$show_links);
         }
         my $ratio='';
         if ($chosen_output->{'every_problem'}) {
             $ratio .= ' ';
         }
         if ($chosen_output->{'sequence_sum'} && $score ne ' ') {
-            $ratio .= sprintf("%3.0f",$score);
+            my $score .= sprintf("%3.0f",$score);
+            $ratio .= (' 'x(3-length($score))).$score;
         } elsif($chosen_output->{'sequence_sum'}) {
             $ratio .= ' 'x3;
         }
@@ -756,13 +795,15 @@ sub html_outputstudent {
             $performance = '';
 	    $performance_length=0;
         }
-        $performance .= ' 'x($seq->{'width_total'}-$performance_length-$seq->{'width_sum'}).
+        $performance .= ' 'x($width{$seq->symb}->{'width_total'} -
+                             $performance_length -
+                             $width{$seq->symb}->{'width_sum'}).
             $ratio;
         #
         $Str .= $performance.$padding;
         #
-        $studentstats->{$seq->{'symb'}}->{'score'}= $score;
-        $studentstats->{$seq->{'symb'}}->{'max'}  = $seq_max;
+        $studentstats->{$seq->symb}->{'score'}= $score;
+        $studentstats->{$seq->symb}->{'max'}  = $seq_max;
     }
     #
     # Total it up and store the statistics info.
@@ -782,6 +823,7 @@ sub html_outputstudent {
         $score = ' ' x $total_sum_width;
     } else {
         $score = sprintf("%.0f",$score);
+        $score = (' 'x(3-length($score))).$score;
     }
     $Str .= ' '.' 'x($total_sum_width-length($score)).$score.' / '.$max;
     $Str .= " \n";
@@ -794,6 +836,7 @@ sub html_outputstudent {
 
 sub html_finish {
     my ($r) = @_;
+    return if (! defined($navmap));
     #
     # Check for suppressed output and close the progress window if so
     $r->print("</pre>\n"); 
@@ -805,6 +848,7 @@ sub html_finish {
         }
     }
     $r->rflush();
+    undef($navmap);
     return;
 }
 
@@ -816,19 +860,20 @@ sub StudentAverageTotal {
         '<th>'.&mt('Average').'</th>'.
         '<th>'.&mt('Maximum').'</th>'.
         '</tr>'.$/;
-    foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+    foreach my $seq (@sequences) {
+        my $symb = $seq->symb;
         my $ave;
-        my $num_students = $Statistics->{$seq->{'symb'}}->{'num_students'};
+        my $num_students = $Statistics->{$symb}->{'num_students'};
         if ($num_students > 0) {
             $ave = int(100*
-                       ($Statistics->{$seq->{'symb'}}->{'score'}/$num_students)
+                       ($Statistics->{$symb}->{'score'}/$num_students)
                        )/100;
         } else {
             $ave = 0;
         }
-        my $max = $Statistics->{$seq->{'symb'}}->{'max'};
+        my $max = $Statistics->{$symb}->{'max'};
         $ave = sprintf("%.2f",$ave);
-        $Str .= '<tr><td>'.$seq->{'title'}.'</td>'.
+        $Str .= '<tr><td>'.$seq->compTitle.'</td>'.
             '<td align="right">'.$ave.'&nbsp;</td>'.
             '<td align="right">'.$max.'&nbsp;'.'</td></tr>'."\n";
     }
@@ -837,6 +882,7 @@ sub StudentAverageTotal {
 }
 
 sub SingleStudentTotal {
+    return if (! defined($navmap));
     my $student = &Apache::lonstatistics::current_student();
     my $Str = '<h3>'.&mt('Summary table for [_1] ([_2]@[_3])',
                          $student->{'fullname'},
@@ -854,10 +900,10 @@ sub SingleStudentTotal {
     $Str .= '<th>'.&mt('Maximum').'</th>'."</tr>\n";
     my $total = 0;
     my $total_max = 0;
-    foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
-        my $value = $Statistics->{$seq->{'symb'}}->{'score'};
-        my $max = $Statistics->{$seq->{'symb'}}->{'max'};
-        $Str .= '<tr><td>'.$seq->{'title'}.'</td>'.
+    foreach my $seq (@sequences) {
+        my $value = $Statistics->{$seq->symb}->{'score'};
+        my $max = $Statistics->{$seq->symb}->{'max'};
+        $Str .= '<tr><td>'.&HTML::Entities::encode($seq->compTitle).'</td>'.
             '<td align="right">'.$value.'</td>'.
                 '<td align="right">'.$max.'</td></tr>'."\n";
         $total += $value;
@@ -903,6 +949,10 @@ my $request_aborted;
 
 my $total_formula;
 my $maximum_formula;
+my %formula_data;
+
+my $navmap;
+my @sequences;
 
 sub excel_initialize {
     my ($r) = @_;
@@ -917,12 +967,25 @@ sub excel_initialize {
     undef ($total_formula);
     undef ($maximum_formula);
     #
+    undef(%formula_data);
+    #
+    undef($navmap);
+    undef(@sequences);
+    ($navmap,@sequences) = 
+        &Apache::lonstatistics::selected_sequences_with_assessments();
+    if (! ref($navmap)) {
+        # Unable to get data, so bail out
+        $r->print("<h3>".
+                  &mt('Unable to retrieve course information.').
+                  '</h3>');
+    }
+    #
     my $total_columns = scalar(&get_student_fields_to_show());
     my $num_students = scalar(@Apache::lonstatistics::Students);
     #
-    foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+    foreach my $seq (@sequences) {
         if ($chosen_output->{'every_problem'}) {
-            $total_columns += $seq->{'num_assess_parts'};
+            $total_columns+=&count_parts($navmap,$seq);
         }
         # Add 2 because we need a 'sequence_sum' and 'total' column for each
         $total_columns += 2;
@@ -960,7 +1023,7 @@ sub excel_initialize {
     my $summary_header_row;
     if ($chosen_output->{'summary_table'}) {
         $summary_header_row = $rows_output++;
-        $rows_output+= scalar(&Apache::lonstatistics::Sequences_with_Assess());
+        $rows_output+= scalar(@sequences);
         $rows_output++;
     }
     my $sequence_name_row = $rows_output++;
@@ -1051,63 +1114,58 @@ sub excel_initialize {
     # Add the remaining column headers
     my $total_formula_string = '=0';
     my $maximum_formula_string = '=0';
-    foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+    foreach my $seq (@sequences) {
+        my $symb = $seq->symb;
         $excel_sheet->write($sequence_name_row,,
-                            $cols_output,$seq->{'title'},$format->{'bold'});
+                            $cols_output,$seq->compTitle,$format->{'bold'});
         # Determine starting cell
-        $seq->{'Excel:startcell'}=
+        $formula_data{$symb}->{'Excel:startcell'}=
             &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
             ($first_data_row,$cols_output);
-        $seq->{'Excel:startcol'}=$cols_output;
+        $formula_data{$symb}->{'Excel:startcol'}=$cols_output;
         my $count = 0;
         if ($chosen_output->{'every_problem'}) {
             # Put the names of the problems and parts into the sheet
-            foreach my $res (@{$seq->{'contents'}}) {
-                if ($res->{'type'} ne 'assessment'  || 
-                    ! exists($res->{'parts'})       ||
-                    ref($res->{'parts'}) ne 'ARRAY' ||
-                    scalar(@{$res->{'parts'}}) < 1) {
-                    next;
-                }
-                if (scalar(@{$res->{'parts'}}) > 1) {
-                    foreach my $part (@{$res->{'parts'}}) {
+            foreach my $res (&get_resources($navmap,$seq)) {
+                if (scalar(@{$res->parts}) > 1) {
+                    foreach my $part (@{$res->parts}) {
                         $excel_sheet->write($resource_name_row,
                                             $cols_output++,
-                                            $res->{'title'}.' part '.$part,
+                                            $res->compTitle.' part '.$res->part_display($part),
                                             $format->{'bold'});
                         $count++;
                     }
                 } else {
                     $excel_sheet->write($resource_name_row,
                                         $cols_output++,
-                                        $res->{'title'},$format->{'bold'});
+                                        $res->compTitle,$format->{'bold'});
                     $count++;
                 }
             }
         }
         # Determine ending cell
         if ($count <= 1) {
-            $seq->{'Excel:endcell'} = $seq->{'Excel:startcell'};
-            $seq->{'Excel:endcol'}  = $seq->{'Excel:startcol'};
+            $formula_data{$symb}->{'Excel:endcell'} = $formula_data{$symb}->{'Excel:startcell'};
+            $formula_data{$symb}->{'Excel:endcol'}  = $formula_data{$symb}->{'Excel:startcol'};
         } else {
-            $seq->{'Excel:endcell'} = 
+            $formula_data{$symb}->{'Excel:endcell'} = 
                 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
                 ($first_data_row,$cols_output-1);
-            $seq->{'Excel:endcol'} = $cols_output-1;
+            $formula_data{$symb}->{'Excel:endcol'} = $cols_output-1;
         }
         # Create the formula for summing up this sequence
-        if (! exists($seq->{'Excel:endcell'}) ||
-            ! defined($seq->{'Excel:endcell'})) {
-            $seq->{'Excel:endcell'} = $seq->{'Excel:startcell'};
-        }
-        $seq->{'Excel:sum'}= $excel_sheet->store_formula
-            ('=SUM('.$seq->{'Excel:startcell'}.
-             ':'.$seq->{'Excel:endcell'}.')');
+        if (! exists($formula_data{$symb}->{'Excel:endcell'}) ||
+            ! defined($formula_data{$symb}->{'Excel:endcell'})) {
+            $formula_data{$symb}->{'Excel:endcell'} = $formula_data{$symb}->{'Excel:startcell'};
+        }
+        $formula_data{$symb}->{'Excel:sum'}= $excel_sheet->store_formula
+            ('=SUM('.$formula_data{$symb}->{'Excel:startcell'}.
+             ':'.$formula_data{$symb}->{'Excel:endcell'}.')');
         # Determine cell the score is held in
-        $seq->{'Excel:scorecell'} = 
+        $formula_data{$symb}->{'Excel:scorecell'} = 
             &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
             ($first_data_row,$cols_output);
-        $seq->{'Excel:scorecol'}=$cols_output;
+        $formula_data{$symb}->{'Excel:scorecol'}=$cols_output;
         if ($chosen_output->{'base'} eq 'parts correct total') {
             $excel_sheet->write($resource_name_row,$cols_output++,
                                 'parts correct',
@@ -1132,10 +1190,10 @@ sub excel_initialize {
             $excel_sheet->write($resource_name_row,$cols_output,
                                 'maximum',
                                 $format->{'bold'});
-            $seq->{'Excel:maxcell'} = 
+            $formula_data{$symb}->{'Excel:maxcell'} = 
                 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
                 ($first_data_row,$cols_output);
-            $seq->{'Excel:maxcol'}=$cols_output;
+            $formula_data{$symb}->{'Excel:maxcol'}=$cols_output;
             $maximum_formula_string.='+'.
                 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
                 ($first_data_row,$cols_output);
@@ -1171,19 +1229,19 @@ sub excel_initialize {
         # Add the maximums for each sequence or assessment
         my %total_cell_translation;
         my %maximum_cell_translation;
-        foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
-            $cols_output=$seq->{'Excel:startcol'};
-            $total_cell_translation{$seq->{'Excel:scorecell'}} = 
+        foreach my $seq (@sequences) {
+            my $symb = $seq->symb;
+            $cols_output=$formula_data{$symb}->{'Excel:startcol'};
+            $total_cell_translation{$formula_data{$symb}->{'Excel:scorecell'}}=
                 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
-                ($maximum_data_row,$seq->{'Excel:scorecol'});
-            $maximum_cell_translation{$seq->{'Excel:maxcell'}} = 
+                ($maximum_data_row,$formula_data{$symb}->{'Excel:scorecol'});
+            $maximum_cell_translation{$formula_data{$symb}->{'Excel:maxcell'}}=
                 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
-                ($maximum_data_row,$seq->{'Excel:maxcol'});
+                ($maximum_data_row,$formula_data{$symb}->{'Excel:maxcol'});
             my $weight;
             my $max = 0;
-            foreach my $resource (@{$seq->{'contents'}}) {
-                next if ($resource->{'type'} ne 'assessment');
-                foreach my $part (@{$resource->{'parts'}}) {
+            foreach my $resource (&get_resources($navmap,$seq)) {
+                foreach my $part (@{$resource->parts}){
                     $weight = 1;
                     if ($chosen_output->{'scores'}) {
                         $weight = &Apache::lonnet::EXT
@@ -1205,12 +1263,12 @@ sub excel_initialize {
             if ($chosen_output->{'sequence_sum'} && 
                 $chosen_output->{'every_problem'}) {
 		my %replaceCells=
-		    ('^'.$seq->{'Excel:startcell'}.':'.
-		         $seq->{'Excel:endcell'}.'$' =>
-		     &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($maximum_data_row,$seq->{'Excel:startcol'}).':'.
-		     &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($maximum_data_row,$seq->{'Excel:endcol'}));
+		    ('^'.$formula_data{$symb}->{'Excel:startcell'}.':'.
+		         $formula_data{$symb}->{'Excel:endcell'}.'$' =>
+		     &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($maximum_data_row,$formula_data{$symb}->{'Excel:startcol'}).':'.
+		     &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($maximum_data_row,$formula_data{$symb}->{'Excel:endcol'}));
                 $excel_sheet->repeat_formula($maximum_data_row,$cols_output++,
-                                             $seq->{'Excel:sum'},undef,
+                                             $formula_data{$symb}->{'Excel:sum'},undef,
 					     %replaceCells);
 			
             } elsif ($chosen_output->{'sequence_sum'}) {
@@ -1251,25 +1309,26 @@ sub excel_initialize {
         $excel_sheet->write($summary_header_row,$cols_output++,
                             'Std Dev',$format->{'bold'});
         my $row = $summary_header_row+1;
-        foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+        foreach my $seq (@sequences) {
+            my $symb = $seq->symb;
             $cols_output = 0;
             $excel_sheet->write($row,$cols_output++,
-                                $seq->{'title'},
+                                $seq->compTitle,
                                 $format->{'bold'});
             if ($chosen_output->{'maximum_row'}) {
                 $excel_sheet->write
                     ($row,$cols_output++,
                      '='.
                      &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
-                     ($maximum_data_row,$seq->{'Excel:scorecol'})
+                     ($maximum_data_row,$formula_data{$symb}->{'Excel:scorecol'})
                      );
             }
             my $range = 
                 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
-                ($first_data_row,$seq->{'Excel:scorecol'}).
+                ($first_data_row,$formula_data{$symb}->{'Excel:scorecol'}).
                 ':'.
                 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
-                ($first_data_row+$num_students-1,$seq->{'Excel:scorecol'});
+                ($first_data_row+$num_students-1,$formula_data{$symb}->{'Excel:scorecol'});
             $excel_sheet->write($row,$cols_output++,
                                 '=AVERAGE('.$range.')');
             $excel_sheet->write($row,$cols_output++,
@@ -1311,8 +1370,9 @@ sub excel_initialize {
 
 sub excel_outputstudent {
     my ($r,$student) = @_;
-    return if ($request_aborted);
-    return if (! defined($excel_sheet));
+    if ($request_aborted || ! defined($navmap) || ! defined($excel_sheet)) {
+        return;
+    }
     $cols_output=0;
     #
     # Write out student data
@@ -1339,26 +1399,27 @@ sub excel_outputstudent {
     # Write out sequence scores and totals data
     my %total_cell_translation;
     my %maximum_cell_translation;
-    foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
-        $cols_output = $seq->{'Excel:startcol'};
+    foreach my $seq (@sequences) {
+        my $symb = $seq->symb;
+        $cols_output = $formula_data{$symb}->{'Excel:startcol'};
         # Keep track of cells to translate in total cell
-        $total_cell_translation{$seq->{'Excel:scorecell'}} = 
+        $total_cell_translation{$formula_data{$symb}->{'Excel:scorecell'}} = 
             &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
-                        ($rows_output,$seq->{'Excel:scorecol'});
+                        ($rows_output,$formula_data{$symb}->{'Excel:scorecol'});
         # and maximum cell
-        $maximum_cell_translation{$seq->{'Excel:maxcell'}} = 
+        $maximum_cell_translation{$formula_data{$symb}->{'Excel:maxcell'}} = 
             &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
-            ($rows_output,$seq->{'Excel:maxcol'});
+            ($rows_output,$formula_data{$symb}->{'Excel:maxcol'});
         #
         my ($performance,$performance_length,$score,$seq_max,$rawdata);
         if ($chosen_output->{'tries'} || $chosen_output->{'correct'}){
             ($performance,$performance_length,$score,$seq_max,$rawdata) =
-                &StudentTriesOnSequence($student,\%StudentsData,
-                                        $seq,'no');
+                &student_tries_on_sequence($student,\%StudentsData,
+                                           $navmap,$seq,'no');
         } else {
             ($performance,$performance_length,$score,$seq_max,$rawdata) =
-                &StudentPerformanceOnSequence($student,\%StudentsData,
-                                              $seq,'no');
+                &student_performance_on_sequence($student,\%StudentsData,
+                                                 $navmap,$seq,'no');
         } 
         if ($chosen_output->{'every_problem'}) {
             if ($chosen_output->{'correct'}) {
@@ -1383,14 +1444,14 @@ sub excel_outputstudent {
             $chosen_output->{'every_problem'}) {
             # Write a formula for the sum of this sequence
             my %replaceCells=
-		('^'.$seq->{'Excel:startcell'}.':'.$seq->{'Excel:endcell'}.'$'
+		('^'.$formula_data{$symb}->{'Excel:startcell'}.':'.$formula_data{$symb}->{'Excel:endcell'}.'$'
 		 => 
-		 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($rows_output,$seq->{'Excel:startcol'}).':'.
-		 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($rows_output,$seq->{'Excel:endcol'})
+		 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($rows_output,$formula_data{$symb}->{'Excel:startcol'}).':'.
+		 &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($rows_output,$formula_data{$symb}->{'Excel:endcol'})
 		 );
             # The undef is for the format	    
 	    $excel_sheet->repeat_formula($rows_output,$cols_output++,
-					 $seq->{'Excel:sum'},undef,
+					 $formula_data{$symb}->{'Excel:sum'},undef,
 					 %replaceCells);
         } elsif ($chosen_output->{'sequence_sum'}) {
             if ($score eq ' ') {
@@ -1426,8 +1487,9 @@ sub excel_outputstudent {
 
 sub excel_finish {
     my ($r) = @_;
-    return if ($request_aborted);
-    return if (! defined($excel_sheet));
+    if ($request_aborted || ! defined($navmap) || ! defined($excel_sheet)) {
+        return;
+    }
     #
     # Write the excel file
     $excel_workbook->close();
@@ -1469,6 +1531,8 @@ my $outputfile;
 my $filename;
 my $request_aborted;
 my %prog_state; # progress window state
+my $navmap;
+my @sequences;
 
 sub csv_initialize{
     my ($r) = @_;
@@ -1479,6 +1543,17 @@ sub csv_initialize{
     undef($request_aborted);
     undef(%prog_state);
     #
+    undef($navmap);
+    undef(@sequences);
+    ($navmap,@sequences) = 
+        &Apache::lonstatistics::selected_sequences_with_assessments();
+    if (! ref($navmap)) {
+        # Unable to get data, so bail out
+        $r->print("<h3>".
+                  &mt('Unable to retrieve course information.').
+                  '</h3>');
+    }
+    #
     # Deal with unimplemented requests
     $request_aborted = undef;
     if ($chosen_output->{'base'} =~ /final table/) {
@@ -1530,23 +1605,19 @@ END
         $sequence_row .='"",';
         $resource_row .= '"'.&Apache::loncommon::csv_translate($field).'",';
     }
-    foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+    foreach my $seq (@sequences) {
         $sequence_row .= '"'.
-            &Apache::loncommon::csv_translate($seq->{'title'}).'",';
+            &Apache::loncommon::csv_translate($seq->compTitle).'",';
         my $count = 0;
         if ($chosen_output->{'every_problem'}) {
-            foreach my $res (@{$seq->{'contents'}}) {
-                if ($res->{'type'} ne 'assessment'  || 
-                    ! exists($res->{'parts'})       ||
-                    ref($res->{'parts'}) ne 'ARRAY' ||
-                    scalar(@{$res->{'parts'}}) < 1) {
+            foreach my $res (&get_resources($navmap,$seq)) {
+                if (scalar(@{$res->parts}) < 1) {
                     next;
                 }
-                foreach my $part (@{$res->{'parts'}}) {
+                foreach my $part (@{$res->parts}) {
                     $resource_row .= '"'.
-                        &Apache::loncommon::csv_translate($res->{'title'}.
-                                                          ', Part '.$part
-                                                          ).'",';
+                        &Apache::loncommon::csv_translate
+                        ($res->compTitle.', Part '.$res->part_display($part)).'",';
                     $count++;
                 }
             }
@@ -1581,8 +1652,9 @@ END
 
 sub csv_outputstudent {
     my ($r,$student) = @_;
-    return if ($request_aborted);
-    return if (! defined($outputfile));
+    if ($request_aborted || ! defined($navmap) || ! defined($outputfile)) {
+        return;
+    }
     my $Str = '';
     #
     # Output student fields
@@ -1609,16 +1681,16 @@ sub csv_outputstudent {
     # Output performance data
     my $total = 0;
     my $maximum = 0;
-    foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+    foreach my $seq (@sequences) {
         my ($performance,$performance_length,$score,$seq_max,$rawdata);
         if ($chosen_output->{'tries'}){
             ($performance,$performance_length,$score,$seq_max,$rawdata) =
-                &StudentTriesOnSequence($student,\%StudentsData,
-                                        $seq,'no');
+                &student_tries_on_sequence($student,\%StudentsData,
+                                           $navmap,$seq,'no');
         } else {
             ($performance,$performance_length,$score,$seq_max,$rawdata) =
-                &StudentPerformanceOnSequence($student,\%StudentsData,
-                                              $seq,'no');
+                &student_performance_on_sequence($student,\%StudentsData,
+                                                 $navmap,$seq,'no');
         }
         if ($chosen_output->{'every_problem'}) {
             if ($chosen_output->{'correct'}) {
@@ -1661,8 +1733,9 @@ sub csv_outputstudent {
 
 sub csv_finish {
     my ($r) = @_;
-    return if ($request_aborted);
-    return if (! defined($outputfile));
+    if ($request_aborted || ! defined($navmap) || ! defined($outputfile)) {
+        return;
+    }
     close($outputfile);
     #
     my $c = $r->connection();
@@ -1706,8 +1779,8 @@ Inputs:
 
 #######################################################
 #######################################################
-sub StudentTriesOnSequence {
-    my ($student,$studentdata,$seq,$links) = @_;
+sub student_tries_on_sequence {
+    my ($student,$studentdata,$navmap,$seq,$links) = @_;
     $links = 'no' if (! defined($links));
     my $Str = '';
     my ($sum,$max) = (0,0);
@@ -1715,11 +1788,10 @@ sub StudentTriesOnSequence {
     my @TriesData = ();
     my $tries;
     my $hasdata = 0; # flag - true if the student has any data on the sequence
-    foreach my $resource (@{$seq->{'contents'}}) {
-        next if ($resource->{'type'} ne 'assessment');
-        my $resource_data = $studentdata->{$resource->{'symb'}};
+    foreach my $resource (&get_resources($navmap,$seq)) {
+        my $resource_data = $studentdata->{$resource->symb};
         my $value = '';
-        foreach my $partnum (@{$resource->{'parts'}}) {
+        foreach my $partnum (@{$resource->parts()}) {
             $tries = undef;
             $max++;
             $performance_length++;
@@ -1796,7 +1868,7 @@ sub StudentTriesOnSequence {
                     &Apache::lonnet::logthis('length of symbol "'.$symbol.'" > 1');
                 }
                 $symbol = '<a href="/adm/grades'.
-                    '?symb='.&Apache::lonnet::escape($resource->{'symb'}).
+                    '?symb='.&Apache::lonnet::escape($resource->symb).
                         '&student='.$student->{'username'}.
                             '&userdom='.$student->{'domain'}.
                                 '&command=submission">'.$symbol.'</a>';
@@ -1805,8 +1877,8 @@ sub StudentTriesOnSequence {
         }
         $Str .= $value;
     }
-    if ($seq->{'randompick'}) {
-        $max = $seq->{'randompick'};
+    if ($seq->randompick()) {
+        $max = $seq->randompick();
     }
     if (! $hasdata && $sum == 0) {
         $sum = ' ';
@@ -1819,7 +1891,7 @@ sub StudentTriesOnSequence {
 
 =pod
 
-=item &StudentPerformanceOnSequence()
+=item &student_performance_on_sequence
 
 Inputs:
 
@@ -1839,8 +1911,8 @@ Inputs:
 
 #######################################################
 #######################################################
-sub StudentPerformanceOnSequence {
-    my ($student,$studentdata,$seq,$links) = @_;
+sub student_performance_on_sequence {
+    my ($student,$studentdata,$navmap,$seq,$links) = @_;
     $links = 'no' if (! defined($links));
     my $Str = ''; # final result string
     my ($score,$max) = (0,0);
@@ -1849,13 +1921,13 @@ sub StudentPerformanceOnSequence {
     my @ScoreData = ();
     my $partscore;
     my $hasdata = 0; # flag, 0 if there were no submissions on the sequence
-    foreach my $resource (@{$seq->{'contents'}}) {
-        next if ($resource->{'type'} ne 'assessment');
-        my $resource_data = $studentdata->{$resource->{'symb'}};
-        foreach my $part (@{$resource->{'parts'}}) {
+    foreach my $resource (&get_resources($navmap,$seq)) {
+        my $symb = $resource->symb;
+        my $resource_data = $studentdata->{$symb};
+        foreach my $part (@{$resource->parts()}) {
             $partscore = undef;
             my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',
-                                              $resource->{'symb'},
+                                              $symb,
                                               $student->{'domain'},
                                               $student->{'username'},
                                               $student->{'section'});
@@ -1893,7 +1965,7 @@ sub StudentPerformanceOnSequence {
                     $max -= $weight; # Do not count 'excused' problems.
                 }
                 $hasdata = 1;
-            } else {
+            } elsif (!exists($resource_data->{'resource.'.$part.'.awarded'})){
                 # Unsolved.  Did they try?
                 if (exists($resource_data->{'resource.'.$part.'.tries'})){
                     $symbol = '.';
@@ -1910,7 +1982,7 @@ sub StudentPerformanceOnSequence {
             #
             if ( ($links eq 'yes' && $symbol ne ' ') || ($links eq 'all')) {
                 $symbol = '<a href="/adm/grades'.
-                    '?symb='.&Apache::lonnet::escape($resource->{'symb'}).
+                    '?symb='.&Apache::lonnet::escape($symb).
                     '&student='.$student->{'username'}.
                     '&userdom='.$student->{'domain'}.
                     '&command=submission">'.$symbol.'</a>';