--- loncom/interface/statistics/lonstudentassessment.pm	2005/04/07 06:56:24	1.121
+++ loncom/interface/statistics/lonstudentassessment.pm	2006/02/27 19:40:30	1.131
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonstudentassessment.pm,v 1.121 2005/04/07 06:56:24 albertel Exp $
+# $Id: lonstudentassessment.pm,v 1.131 2006/02/27 19:40:30 albertel 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 Apache::grades;
 use Time::HiRes;
 use Spreadsheet::WriteExcel;
 use Spreadsheet::WriteExcel::Utility();
@@ -430,14 +431,9 @@ sub CreateAndParseOutputSelector {
                                             [$elementname]);
     #
     # Format for output options is 'mode, restrictions';
-    my $selected = 'html, without links';
-    if (exists($env{'form.'.$elementname})) {
-        if (ref($env{'form.'.$elementname} eq 'ARRAY')) {
-            $selected = $env{'form.'.$elementname}->[0];
-        } else {
-            $selected = $env{'form.'.$elementname};
-        }
-    }
+    my $selected = (&Apache::loncommon::get_env_multiple('form.'.$elementname))[0];
+    $selected = 'html, without links' if (!$selected);
+
     #
     # Set package variables describing output mode
     $show_links  = 'no';
@@ -477,6 +473,7 @@ my @OutputDataOptions =
        grand_maximum => 1,
        summary_table => 1,
        maximum_row => 1,
+       ignore_weight => 0,
        shortdesc => 'Total Score and Maximum Possible for each '.
            'Sequence or Folder',
        longdesc => 'The score of each student as well as the '.
@@ -495,6 +492,7 @@ my @OutputDataOptions =
        grand_maximum => 1,
        summary_table => 1,
        maximum_row => 1,
+       ignore_weight => 0,
        shortdesc => 'Score on each Problem Part',
        longdesc =>'The students score on each problem part, computed as'.
            'the part weight * part awarded',
@@ -512,6 +510,7 @@ my @OutputDataOptions =
        grand_maximum => 0,
        summary_table => 0,
        maximum_row => 0,
+       ignore_weight => 0,
        shortdesc => 'Number of Tries before success on each Problem Part',
        longdesc =>'The number of tries before success on each problem part.',
        non_html_notes => 'negative values indicate an incorrect problem',
@@ -529,6 +528,7 @@ my @OutputDataOptions =
        grand_maximum => 1,
        summary_table => 1,
        maximum_row => 0,
+       ignore_weight => 1,
        shortdesc => 'Number of Problem Parts completed successfully.',
        longdesc => 'The Number of Problem Parts completed successfully and '.
            'the maximum possible for each student',
@@ -551,14 +551,9 @@ sub CreateAndParseOutputDataSelector {
     my $Str = '';
     my $elementname = 'chartoutputdata';
     #
-    my $selected = 'scores';
-    if (exists($env{'form.'.$elementname})) {
-        if (ref($env{'form.'.$elementname} eq 'ARRAY')) {
-            $selected = $env{'form.'.$elementname}->[0];
-        } else {
-            $selected = $env{'form.'.$elementname};
-        }
-    }
+    my $selected = (&Apache::loncommon::get_env_multiple('form.'.$elementname))[0];
+    $selected = 'scores' if (!$selected);
+
     #
     $chosen_output = $OutputDataOptions[0];
     foreach my $option (@OutputDataOptions) {
@@ -632,17 +627,21 @@ Return a line of the chart for a student
     my @sequences;
     my $navmap; # Have to keep this around since weakref is a bit zealous
 
+sub html_cleanup {
+    undef(%prog_state);
+    undef(%width);
+    #
+    undef($navmap);
+    undef(@sequences);
+}
+
 sub html_initialize {
     my ($r) = @_;
     #
     $padding = ' 'x3;
     $count = 0;
     $nodata_count = 0;
-    undef(%prog_state);
-    undef(%width);
-    #
-    undef($navmap);
-    undef(@sequences);
+    &html_cleanup();
     ($navmap,@sequences) = 
         &Apache::lonstatistics::selected_sequences_with_assessments();
     if (! ref($navmap)) {
@@ -720,6 +719,21 @@ sub html_initialize {
     $Str .= "<pre>";
     $r->print($Str);
     $r->rflush();
+    #
+    # Let the user know what we are doing
+    my $studentcount = scalar(@Apache::lonstatistics::Students); 
+    if ($env{'form.SelectedStudent'}) {
+        $studentcount = '1';
+    }
+    #
+    # Initialize progress window
+    %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
+        ($r,'HTML Chart Status',
+         'HTML Chart Progress', $studentcount,
+         'inline',undef,'Statistics','stats_status');
+    #
+    &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,
+                                          'Processing first student');
     return;
 }
 
@@ -772,7 +786,8 @@ sub html_outputstudent {
         } else {
             ($performance,$performance_length,$score,$seq_max,$rawdata) =
                 &student_performance_on_sequence($student,\%StudentsData,
-                                                 $navmap,$seq,$show_links);
+                                                 $navmap,$seq,$show_links,
+                                                 $chosen_output->{ignore_weight});
         }
         my $ratio='';
         if ($chosen_output->{'every_problem'} && 
@@ -832,6 +847,7 @@ sub html_outputstudent {
     $r->print($Str);
     #
     $r->rflush();
+    &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,'last student');
     return;
 }    
 
@@ -849,7 +865,8 @@ sub html_finish {
         }
     }
     $r->rflush();
-    undef($navmap);
+    &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
+    &html_cleanup();
     return;
 }
 
@@ -956,8 +973,7 @@ my %formula_data;
 my $navmap;
 my @sequences;
 
-sub excel_initialize {
-    my ($r) = @_;
+sub excel_cleanup {
     #
     undef ($excel_sheet);
     undef ($excel_workbook);
@@ -973,6 +989,12 @@ sub excel_initialize {
     #
     undef($navmap);
     undef(@sequences);
+}
+
+sub excel_initialize {
+    my ($r) = @_;
+
+    &excel_cleanup();
     ($navmap,@sequences) = 
         &Apache::lonstatistics::selected_sequences_with_assessments();
     if (! ref($navmap)) {
@@ -1053,7 +1075,7 @@ sub excel_initialize {
     my $sectionstring = '';
     my @Sections = &Apache::lonstatistics::get_selected_sections();
     $excel_sheet->write($header_row,$cols_output++,
-                        &Apache::lonstatistics::section_and_enrollment_description('plain text'),
+                        &Apache::lonstatistics::section_and_enrollment_description('plaintext'),
                         $format->{'h3'});
     #
     # Put the date in there too
@@ -1128,9 +1150,11 @@ sub excel_initialize {
             ! defined($formula_data{$symb}->{'Excel:endcell'})) {
             $formula_data{$symb}->{'Excel:endcell'} = $formula_data{$symb}->{'Excel:startcell'};
         }
+
+        my $start = $formula_data{$symb}->{'Excel:startcell'};
+        my $end = $formula_data{$symb}->{'Excel:endcell'};
         $formula_data{$symb}->{'Excel:sum'}= $excel_sheet->store_formula
-            ('=SUM('.$formula_data{$symb}->{'Excel:startcell'}.
-             ':'.$formula_data{$symb}->{'Excel:endcell'}.')');
+            ("=IF(COUNT($start\:$end),SUM($start\:$end),\"\")");
         # Determine cell the score is held in
         $formula_data{$symb}->{'Excel:scorecell'} = 
             &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
@@ -1215,7 +1239,7 @@ sub excel_initialize {
                     $weight = 1;
                     if ($chosen_output->{'scores'}) {
                         $weight = &Apache::lonnet::EXT
-                            ('resource.'.$part.'.weight',$resource->{'symb'},
+                            ('resource.'.$part.'.weight',$resource->symb,
                              undef,undef,undef);
                         if (!defined($weight) || ($weight eq '')) { 
                             $weight=1;
@@ -1239,7 +1263,7 @@ sub excel_initialize {
 		     &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($maximum_data_row,$formula_data{$symb}->{'Excel:endcol'}));
                 $excel_sheet->repeat_formula($maximum_data_row,$cols_output++,
                                              $formula_data{$symb}->{'Excel:sum'},undef,
-					     %replaceCells);
+					     %replaceCells, %replaceCells);
 			
             } elsif ($chosen_output->{'sequence_sum'}) {
                 $excel_sheet->write($maximum_data_row,$cols_output++,$max);
@@ -1389,14 +1413,16 @@ sub excel_outputstudent {
         } else {
             ($performance,$performance_length,$score,$seq_max,$rawdata) =
                 &student_performance_on_sequence($student,\%StudentsData,
-                                                 $navmap,$seq,'no');
+                                                 $navmap,$seq,'no',
+                                                 $chosen_output->{ignore_weight});
         } 
         if ($chosen_output->{'every_problem'}) {
             if ($chosen_output->{'correct'}) {
                 # only indiciate if each item is correct or not
                 foreach my $value (@$rawdata) {
-                    # nonzero means correct
-                    $value = 1 if ($value > 0);
+                    # positive means correct, 0 or negative means
+                    # incorrect
+                    $value = $value > 0 ? 1 : 0;
                     $excel_sheet->write($rows_output,$cols_output++,$value);
                 }
             } else {
@@ -1422,7 +1448,7 @@ sub excel_outputstudent {
             # The undef is for the format	    
 	    $excel_sheet->repeat_formula($rows_output,$cols_output++,
 					 $formula_data{$symb}->{'Excel:sum'},undef,
-					 %replaceCells);
+					 %replaceCells, %replaceCells);
         } elsif ($chosen_output->{'sequence_sum'}) {
             if ($score eq ' ') {
                 $cols_output++;
@@ -1458,14 +1484,12 @@ sub excel_outputstudent {
 sub excel_finish {
     my ($r) = @_;
     if ($request_aborted || ! defined($navmap) || ! defined($excel_sheet)) {
+	&excel_cleanup();
         return;
     }
     #
     # Write the excel file
     $excel_workbook->close();
-    my $c = $r->connection();
-    #
-    return if($c->aborted());
     #
     # Close the progress window
     &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
@@ -1474,6 +1498,7 @@ sub excel_finish {
     $r->print('<br />'.
               '<a href="'.$filename.'">Your Excel spreadsheet.</a>'."\n");
     $r->rflush();
+    &excel_cleanup();
     return;
 }
 
@@ -1504,10 +1529,7 @@ my %prog_state; # progress window state
 my $navmap;
 my @sequences;
 
-sub csv_initialize{
-    my ($r) = @_;
-    # 
-    # Clean up
+sub csv_cleanup {
     undef($outputfile);
     undef($filename);
     undef($request_aborted);
@@ -1515,6 +1537,12 @@ sub csv_initialize{
     #
     undef($navmap);
     undef(@sequences);
+}
+
+sub csv_initialize{
+    my ($r) = @_;
+
+    &csv_cleanup();
     ($navmap,@sequences) = 
         &Apache::lonstatistics::selected_sequences_with_assessments();
     if (! ref($navmap)) {
@@ -1656,7 +1684,8 @@ sub csv_outputstudent {
         } else {
             ($performance,$performance_length,$score,$seq_max,$rawdata) =
                 &student_performance_on_sequence($student,\%StudentsData,
-                                                 $navmap,$seq,'no');
+                                                 $navmap,$seq,'no',
+                                                 $chosen_output->{ignore_weight});
         }
         if ($chosen_output->{'every_problem'}) {
             if ($chosen_output->{'correct'}) {
@@ -1700,13 +1729,11 @@ sub csv_outputstudent {
 sub csv_finish {
     my ($r) = @_;
     if ($request_aborted || ! defined($navmap) || ! defined($outputfile)) {
+	&csv_cleanup();
         return;
     }
     close($outputfile);
     #
-    my $c = $r->connection();
-    return if ($c->aborted());
-    #
     # Close the progress window
     &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
     #
@@ -1714,6 +1741,7 @@ sub csv_finish {
     $r->print('<br />'.
               '<a href="'.$filename.'">'.&mt('Your csv file.').'</a>'."\n");
     $r->rflush();
+    &csv_cleanup();
     return;
     
 }
@@ -1807,7 +1835,7 @@ sub student_tries_on_sequence {
                 } elsif ($status eq 'incorrect_by_override') {
                     $symbol = '-';
                 } elsif ($status eq 'ungraded_attempted') {
-                    $symbol = '#';
+                    $symbol = 'u';
                 } elsif ($status eq 'incorrect_attempted' ||
                          $tries > 0)  {
                     $symbol = '.';
@@ -1878,7 +1906,7 @@ Inputs:
 #######################################################
 #######################################################
 sub student_performance_on_sequence {
-    my ($student,$studentdata,$navmap,$seq,$links) = @_;
+    my ($student,$studentdata,$navmap,$seq,$links,$awarded_only) = @_;
     $links = 'no' if (! defined($links));
     my $Str = ''; # final result string
     my ($score,$max) = (0,0);
@@ -1892,11 +1920,14 @@ sub student_performance_on_sequence {
         my $resource_data = $studentdata->{$symb};
         foreach my $part (@{$resource->parts()}) {
             $partscore = undef;
-            my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',
-                                              $symb,
-                                              $student->{'domain'},
-                                              $student->{'username'},
-                                              $student->{'section'});
+            my $weight;
+            if (!$awarded_only){
+                $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',
+                                               $symb,
+                                               $student->{'domain'},
+                                               $student->{'username'},
+                                               $student->{'section'});
+            }
             if (!defined($weight) || ($weight eq '')) { 
                 $weight=1;
             }
@@ -1912,7 +1943,7 @@ sub student_performance_on_sequence {
                 $hasdata = 1;
             }
             #
-            $partscore = $weight*$awarded;
+            $partscore = &Apache::grades::compute_points($weight,$awarded);
             if (! defined($awarded)) {
                 $partscore = undef;
             }
@@ -1924,13 +1955,19 @@ sub student_performance_on_sequence {
             if (length($symbol) > 1) {
                 $symbol = '*';
             }
-            if (exists($resource_data->{'resource.'.$part.'.solved'})) {
+            if (exists($resource_data->{'resource.'.$part.'.solved'}) &&
+                $resource_data->{'resource.'.$part.'.solved'} ne '') {
                 my $status = $resource_data->{'resource.'.$part.'.solved'};
                 if ($status eq 'excused') {
                     $symbol = 'x';
                     $max -= $weight; # Do not count 'excused' problems.
+                } elsif ($status eq 'ungraded_attempted') {
+                    $symbol = 'u';
                 }
                 $hasdata = 1;
+            } elsif ($resource_data->{'resource.'.$part.'.award'} eq 'DRAFT') {
+                $symbol = 'd';
+                $hasdata = 1;
             } elsif (!exists($resource_data->{'resource.'.$part.'.awarded'})){
                 # Unsolved.  Did they try?
                 if (exists($resource_data->{'resource.'.$part.'.tries'})){
@@ -1979,13 +2016,13 @@ problems.
 #######################################################
 sub CreateLegend {
     my $Str = "<p><pre>".
-              "   1  correct by student in 1 try\n".
-              "   7  correct by student in 7 tries\n".
+              " digit score or number of tries to get correct ".
               "   *  correct by student in more than 9 tries\n".
 	      "   +  correct by hand grading or override\n".
               "   -  incorrect by override\n".
 	      "   .  incorrect attempted\n".
-	      "   #  ungraded attempted\n".
+	      "   u  ungraded attempted\n".
+              "   d  draft answer saved but not submitted\n".
               "      not attempted (blank field)\n".
 	      "   x  excused".
               "</pre><p>";