--- loncom/homework/grades.pm	2007/08/18 00:57:25	1.429
+++ loncom/homework/grades.pm	2007/08/29 13:41:32	1.436
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.429 2007/08/18 00:57:25 banghart Exp $
+# $Id: grades.pm,v 1.436 2007/08/29 13:41:32 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -45,7 +45,11 @@ use LONCAPA;
 
 use POSIX qw(floor);
 
+
 my %perm=();
+my %bubble_lines_per_response;     # no. bubble lines for each response.
+                                   # index is "symb.part_id"
+
 
 # ----- These first few routines are general use routines.----
 #
@@ -194,22 +198,54 @@ sub showResourceInfo {
     return $result,$responseType,$hdgrade,$partlist,$handgrade;
 }
 
+sub reset_caches {
+    &reset_analyze_cache();
+    &reset_perm();
+}
 
-sub get_order {
-    my ($partid,$respid,$symb,$uname,$udom)=@_;
-    my (undef,undef,$url)=&Apache::lonnet::decode_symb($symb);
-    $url=&Apache::lonnet::clutter($url);
-    my $subresult=&Apache::lonnet::ssi($url,
-				       ('grade_target' => 'analyze'),
-				       ('grade_domain' => $udom),
-				       ('grade_symb' => $symb),
-				       ('grade_courseid' => 
-					        $env{'request.course.id'}),
-				       ('grade_username' => $uname));
-    (undef,$subresult)=split(/_HASH_REF__/,$subresult,2);
-    my %analyze=&Apache::lonnet::str2hash($subresult);
-    return ($analyze{"$partid.$respid.shown"});
+{
+    my %analyze_cache;
+
+    sub reset_analyze_cache {
+	undef(%analyze_cache);
+    }
+
+    sub get_analyze {
+	my ($symb,$uname,$udom)=@_;
+	my $key = "$symb\0$uname\0$udom";
+	return $analyze_cache{$key} if (exists($analyze_cache{$key}));
+
+	my (undef,undef,$url)=&Apache::lonnet::decode_symb($symb);
+	$url=&Apache::lonnet::clutter($url);
+	my $subresult=&Apache::lonnet::ssi($url,
+					   ('grade_target' => 'analyze'),
+					   ('grade_domain' => $udom),
+					   ('grade_symb' => $symb),
+					   ('grade_courseid' => 
+					    $env{'request.course.id'}),
+					   ('grade_username' => $uname));
+	(undef,$subresult)=split(/_HASH_REF__/,$subresult,2);
+	my %analyze=&Apache::lonnet::str2hash($subresult);
+	return $analyze_cache{$key} = \%analyze;
+    }
+
+    sub get_order {
+	my ($partid,$respid,$symb,$uname,$udom)=@_;
+	my $analyze = &get_analyze($symb,$uname,$udom);
+	return $analyze->{"$partid.$respid.shown"};
+    }
+
+    sub get_radiobutton_correct_foil {
+	my ($partid,$respid,$symb,$uname,$udom)=@_;
+	my $analyze = &get_analyze($symb,$uname,$udom);
+	foreach my $foil (@{&get_order($partid,$respid,$symb,$uname,$udom)}) {
+	    if ($analyze->{"$partid.$respid.foil.value.$foil"} eq 'true') {
+		return $foil;
+	    }
+	}
+    }
 }
+
 #--- Clean response type for display
 #--- Currently filters option/rank/radiobutton/match/essay/Task
 #        response types only.
@@ -258,11 +294,11 @@ sub cleanRecord {
     } elsif ($response eq 'radiobutton') {
 	my %answer=&Apache::lonnet::str2hash($answer);
 	my ($toprow,$bottomrow);
-	my $correct=($order->[0])+1;
-	for (my $i=1;$i<=$#$order;$i++) {
-	    my $foil=$order->[$i];
+	my $correct = 
+	    &get_radiobutton_correct_foil($partid,$respid,$symb,$uname,$udom);
+	foreach my $foil (@$order) {
 	    if (exists($answer{$foil})) {
-		if ($i == $correct) {
+		if ($foil eq $correct) {
 		    $toprow.='<td><b>true</b></td>';
 		} else {
 		    $toprow.='<td><i>true</i></td>';
@@ -723,7 +759,6 @@ LISTJAVASCRIPT
 
     my $saveStatus = $env{'form.Status'} eq '' ? 'Active' : $env{'form.Status'};
     $env{'form.Status'} = $saveStatus;
-
     $gradeTable.='<label><input type="radio" name="lastSub" value="lastonly" '.$checklastsub.' /> last submission only </label>'."\n".
 	'<label><input type="radio" name="lastSub" value="last" /> last submission & parts info </label>'."\n".
 	'<label><input type="radio" name="lastSub" value="datesub" /> by dates and submissions </label>'."\n".
@@ -734,8 +769,7 @@ LISTJAVASCRIPT
         '<option value=".25">Quarter Points</option>'.
         '<option value=".1">Tenths of a Point</option>'.
         '</select>'.
-
-	'<input type="hidden" name="section"     value="'.$getsec.'" />'."\n".
+        &build_section_inputs().
 	'<input type="hidden" name="submitonly"  value="'.$submitonly.'" />'."\n".
 	'<input type="hidden" name="handgrade"   value="'.$env{'form.handgrade'}.'" /><br />'."\n".
 	'<input type="hidden" name="showgrading" value="'.$env{'form.showgrading'}.'" /><br />'."\n".
@@ -1661,6 +1695,19 @@ sub download_all_link {
     return
 }
 
+sub build_section_inputs {
+    my $section_inputs;
+    if ($env{'form.section'} eq '') {
+        $section_inputs .= '<input type="hidden" name="section" value="all" />'."\n";
+    } else {
+        my @sections = &Apache::loncommon::get_env_multiple('form.section');
+        foreach my $section (@sections) {
+            $section_inputs .= '<input type="hidden" name="section" value="'.$section.'" />'."\n";
+        }
+    }
+    return $section_inputs;
+}
+
 # --------------------------- show submissions of a student, option to grade 
 sub submission {
     my ($request,$counter,$total) = @_;
@@ -1741,7 +1788,6 @@ sub submission {
 	    $env{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0';
 	}
 	my $overRideScore = $env{'form.overRideScore'} eq '' ? 'no' : $env{'form.overRideScore'};
-
 	$request->print('<form action="/adm/grades" method="post" name="SCORE" enctype="multipart/form-data">'."\n".
 			'<input type="hidden" name="command"    value="handgrade" />'."\n".
 			'<input type="hidden" name="saveState"  value="'.$env{'form.saveState'}.'" />'."\n".
@@ -1756,7 +1802,7 @@ sub submission {
 			'<input type="hidden" name="vProb"      value="'.$env{'form.vProb'}.'" />'."\n".
 			'<input type="hidden" name="vAns"       value="'.$env{'form.vAns'}.'" />'."\n".
 			'<input type="hidden" name="lastSub"    value="'.$env{'form.lastSub'}.'" />'."\n".
-			'<input type="hidden" name="section"    value="'.$env{'form.section'}.'" />'."\n".
+			&build_section_inputs().
 			'<input type="hidden" name="submitonly" value="'.$env{'form.submitonly'}.'" />'."\n".
 			'<input type="hidden" name="handgrade"  value="'.$env{'form.handgrade'}.'" />'."\n".
 			'<input type="hidden" name="NCT"'.
@@ -2965,20 +3011,21 @@ sub viewgrades {
     $result.= '<form action="/adm/grades" method="post" name="classgrade">'."\n".
 	'<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
 	'<input type="hidden" name="command" value="editgrades" />'."\n".
-	'<input type="hidden" name="section" value="'.$env{'form.section'}.'" />'."\n".
+	&build_section_inputs().
 	'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".
 	'<input type="hidden" name="Status" value="'.$env{'form.Status'}.'" />'."\n".
 	'<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n";
 
     my $sectionClass;
+    my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
     if ($env{'form.section'} eq 'all') {
 	$sectionClass='Class </h3>';
     } elsif ($env{'form.section'} eq 'none') {
-	$sectionClass='Students in no Section </h3>';
+	$sectionClass=&mt('Students in no Section').'</h3>';
     } else {
-	$sectionClass='Students in Section '.$env{'form.section'}.'</h3>';
+	$sectionClass=&mt('Students in Section(s) [_1]',$section_display).'</h3>';
     }
-    $result.='<h3>Assign Common Grade To '.$sectionClass;
+    $result.='<h3>'.&mt('Assign Common Grade To [_1]',$sectionClass);
     $result.= '<table border=0><tr><td bgcolor="#777777">'."\n".
 	'<table border=0><tr bgcolor="#ffffdd"><td>';
     #radio buttons/text box for assigning points for a section or class.
@@ -3084,8 +3131,11 @@ sub viewgrades {
 	'onClick="javascript:submit();" target="_self" /></form>'."\n";
     if (scalar(%$fullname) eq 0) {
 	my $colspan=3+scalar(@parts);
-	$result='<span class="LC_warning">There are no students in section "'.$env{'form.section'}.
-	    '" with enrollment status "'.$env{'form.Status'}.'" to modify or grade.</span>';
+	my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
+	$result='<span class="LC_warning">'.
+	    &mt('There are no students in section(s) [_1] with enrollment status [_2] to modify or grade',
+	        $section_display, $env{'form.Status'}).
+	    '</span>';
     }
     $result.=&show_grading_menu_form($symb);
     return $result;
@@ -3162,9 +3212,10 @@ sub editgrades {
     my ($request) = @_;
 
     my $symb=&get_symb($request);
-    my $title='<h3><span class="LC_info">Current Grade Status</span></h3>';
-    $title.='<h4><b>Current Resource: </b>'.$env{'form.probTitle'}.'</h4><br />'."\n";
-    $title.='<h4><b>Section: </b>'.$env{'form.section'}.'</h4>'."\n";
+    my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
+    my $title='<h3><span class="LC_info">'.&mt('Current Grade Status').'</span></h3>';
+    $title.='<h4>'.&mt('<b>Current Resource: </b>[_1]',$env{'form.probTitle'}).'</h4><br />'."\n";
+    $title.='<h4>'.&mt('<b>Section: </b>[_1]',$section_display).'</h4>'."\n";
 
     my $result= '<table border="0"><tr><td bgcolor="#777777">'."\n";
     $result.= '<table border="0"><tr bgcolor="#deffff">'.
@@ -3865,9 +3916,9 @@ LISTJAVASCRIPT
 	'<label><input type="radio" name="lastSub" value="none" /> none</label>'."\n".
 	'<label><input type="radio" name="lastSub" value="datesub" checked="checked" /> by dates and submissions</label>'."\n".
 	'<label><input type="radio" name="lastSub" value="all" /> all details</label>'."\n";
-
-    $result.='<input type="hidden" name="section"     value="'.$getsec.'" />'."\n".
-	'<input type="hidden" name="Status"  value="'.$env{'form.Status'}.'" />'."\n".
+    
+    $result.=&build_section_inputs();
+    $result.='<input type="hidden" name="Status"  value="'.$env{'form.Status'}.'" />'."\n".
 	'<input type="hidden" name="command" value="displayPage" />'."\n".
 	'<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
 	'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."<br />\n";
@@ -4381,7 +4432,7 @@ one of the predefined configurations for
 like.
 
 Next each scanline is checked for any errors of either 'missing
-bubbles' (it's an error because it may have been missed scanned
+bubbles' (it's an error because it may have been mis-scanned
 because too light bubbling), 'double bubble' (each bubble line should
 have no more that one letter picked), invalid or duplicated CODE,
 invalid student ID
@@ -4392,7 +4443,7 @@ username:domain.
 
 During the validation phase the instructor can choose to skip scanlines. 
 
-After the validation phase, there is now 3 bubble sheet files
+After the validation phase, there are now 3 bubble sheet files
 
   scantron_original_filename (unmodified original file)
   scantron_corrected_filename (file where the corrected information has replaced the original information)
@@ -6462,6 +6513,7 @@ sub scantron_validate_doublebubble {
 =cut
 
 sub scantron_get_maxbubble {    
+
     if (defined($env{'form.scantron_maxbubble'}) &&
 	$env{'form.scantron_maxbubble'}) {
 	return $env{'form.scantron_maxbubble'};
@@ -6476,14 +6528,40 @@ sub scantron_get_maxbubble {
 
     &Apache::lonxml::clear_problem_counter();
 
+    my $uname       = $env{'form.student'};
+    my $udom        = $env{'form.userdom'};
+    my $cid         = $env{'request.course.id'};
+    my $total_lines = 0;
+    %bubble_lines_per_response = ();
+
     foreach my $resource (@resources) {
+	my $symb = $resource->symb();
 	my $result=&Apache::lonnet::ssi($resource->src(),
-					('symb' => $resource->symb()));
+					('symb' => $resource->symb()),
+					('grade_target' => 'analyze'),
+					('grade_courseid' => $cid),
+					('grade_domain' => $udom),
+					('grade_username' => $uname));
+	my (undef, $an) =
+	    split(/_HASH_REF__/,$result, 2);
+
+	my %analysis = &Apache::lonnet::str2hash($an);
+
+
+
+	foreach my $part_id (@{$analysis{'parts'}}) {
+	    my $bubble_lines = $analysis{"$part_id.bubble_lines"}[0];
+	    if (!$bubble_lines) {
+		$bubble_lines = 1;
+	    }
+	    $bubble_lines_per_response{"$symb.$part_id"} = $bubble_lines;
+	    $total_lines = $total_lines + $bubble_lines;
+	}
+
     }
     &Apache::lonnet::delenv('scantron\.');
     $env{'form.scantron_maxbubble'} =
-	&Apache::lonxml::get_problem_counter()-1;
-
+	$total_lines;
     return $env{'form.scantron_maxbubble'};
 }
 
@@ -7500,7 +7578,7 @@ ENDHEADER
 sub handler {
     my $request=$_[0];
 
-    &reset_perm();
+    &reset_caches();
     if ($env{'browser.mathml'}) {
 	&Apache::loncommon::content_type($request,'text/xml');
     } else {
@@ -7613,6 +7691,7 @@ sub handler {
 	}
     }
     $request->print(&Apache::loncommon::end_page());
+    &reset_caches();
     return '';
 }