--- loncom/homework/grades.pm	2006/02/07 14:18:18	1.311
+++ loncom/homework/grades.pm	2006/02/26 02:55:11	1.318
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.311 2006/02/07 14:18:18 banghart Exp $
+# $Id: grades.pm,v 1.318 2006/02/26 02:55:11 banghart Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -40,6 +40,7 @@ use Apache::lonmsg qw(:user_normal_msg);
 use Apache::Constants qw(:common);
 use Apache::lonlocal;
 use String::Similarity;
+use POSIX qw(floor);
 
 my %oldessays=();
 my %perm=();
@@ -467,6 +468,33 @@ sub jscriptNform {
     return $jscript;
 }
 
+# Given the score (as a number [0-1] and the weight) what is the final
+# point value? This function will round to the nearest tenth, third,
+# or quarter if one of those is within the tolerance of .00001.
+sub compute_points {
+    my ($score, $weight) = @_;
+    
+    my $tolerance = .00001;
+    my $points = $score * $weight;
+
+    # Check for nearness to 1/x.
+    my $check_for_nearness = sub {
+        my ($factor) = @_;
+        my $num = ($points * $factor) + $tolerance;
+        my $floored_num = floor($num);
+        if ($num - $floored_num < 2 * $tolerance * $factor) {
+            return $floored_num / $factor;
+        }
+        return $points;
+    };
+
+    $points = $check_for_nearness->(10);
+    $points = $check_for_nearness->(3);
+    $points = $check_for_nearness->(4);
+    
+    return $points;
+}
+
 #------------------ End of general use routines --------------------
 
 #
@@ -1385,11 +1413,9 @@ SUBJAVASCRIPT
 
 #--- displays the grading box, used in essay type problem and grading by page/sequence
 sub gradeBox {
-    my ($request,$symb,$uname,$udom,$counter,$partid,$record) = @_;
-
+    my ($request,$symb,$uname,$udom,$counter,$partid,$record,$respid) = @_;
     my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL').
 	'/check.gif" height="16" border="0" />';
-
     my $wgt    = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb,$udom,$uname);
     my $wgtmsg = ($wgt > 0 ? '(problem weight)' : 
 		  '<font color="red">problem weight assigned by computer</font>');
@@ -1397,19 +1423,16 @@ sub gradeBox {
     my $score  = ($$record{'resource.'.$partid.'.awarded'} eq '' ?
 		  '' : $$record{'resource.'.$partid.'.awarded'}*$wgt);
     my $result='<input type="hidden" name="WGT'.$counter.'_'.$partid.'" value="'.$wgt.'" />'."\n";
-
+    $result.='<br />'.$partid.' - '.$respid.'<br />';
     my $display_part=&get_display_part($partid,undef,$symb);
-
     my %last_resets = &get_last_resets($symb,$env{'request.course.id'},
 				       [$partid]);
     my $aggtries = $$record{'resource.'.$partid.'.tries'};
     if ($last_resets{$partid}) {
         $aggtries = &get_num_tries($record,$last_resets{$partid},$partid);
     }
-
     $result.='<table border="0"><tr><td>'.
 	'<b>Part: </b>'.$display_part.' <b>Points: </b></td><td>'."\n";
-
     my $ctr = 0;
     $result.='<table border="0"><tr>'."\n";  # display radio buttons in a nice table 10 across
     while ($ctr<=$wgt) {
@@ -1421,7 +1444,6 @@ sub gradeBox {
 	$ctr++;
     }
     $result.='</tr></table>';
-
     $result.='</td><td>&nbsp;<b>or</b>&nbsp;</td>'."\n";
     $result.='<td><input type="text" name="GD_BOX'.$counter.'_'.$partid.'"'.
 	($score ne ''? ' value = "'.$score.'"':'').' size="4" '.
@@ -1430,7 +1452,6 @@ sub gradeBox {
     $result.='<td>/'.$wgt.' '.$wgtmsg.
 	($$record{'resource.'.$partid.'.solved'} eq 'correct_by_student' ? '&nbsp;'.$checkIcon : '').
 	' </td><td>'."\n";
-
     $result.='<select name="GD_SEL'.$counter.'_'.$partid.'" '.
 	'onChange="javascript:clearRadBox(this.form,\''.$counter.'_'.$partid.'\')" >'."\n";
     if ($$record{'resource.'.$partid.'.solved'} eq 'excused') {
@@ -1451,8 +1472,24 @@ sub gradeBox {
         '<input type="hidden" name="aggtries'.$counter.'_'.$partid.'" value="'.
         $aggtries.'" />'."\n";
     $result.='</td></tr></table>'."\n";
+    $result.=&handbackBox($uname,$udom,$counter,$partid,$record,$respid);
     return $result;
 }
+sub handbackBox {
+    my ($uname,$udom,$counter,$partid,$record,$respid) = @_;
+    my $files=&get_submitted_files($udom,$uname,$partid,$respid,$record);
+    my $result;
+    if (@$files) {
+        my $file_counter = 0;
+	foreach my $file (@$files) {
+            $result.=' Return commented document to student. <input type="file" name="part'.$partid.'_returndoc';
+            $result.=$file_counter.'" />'."\n";
+            $result.='<input type="hidden" name="respid" value="'.$respid.'" />';
+            $result.='<input type="hidden" name="returndocorig'.$file_counter.'" value="'.$file.'" /><br />';
+        }
+    }
+    return $result;    
+}
 
 sub show_problem {
     my ($request,$symb,$uname,$udom,$removeform,$viewon,$mode) = @_;
@@ -1792,30 +1829,14 @@ KEYWORDS
 			$lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part:</b> '.
 			    $display_part.' <font color="#999999">( ID '.$respid.
 			    ' )</font>&nbsp; &nbsp;';
-			my @files;
-			if ($record{"resource.$partid.$respid.portfiles"}) {
-			    my $file_url = '/uploaded/'.$udom.'/'.$uname.'/portfolio';
-			    foreach my $file (split(',',$record{"resource.$partid.$respid.portfiles"})) {
-				push(@files,$file_url.$file);
-			    
-				&Apache::lonnet::logthis("found a portfolio file".$record{"resource.$partid.$respid.portfiles"});
-				&Apache::lonnet::logthis("uploaded URL file".$record{"resource.$partid.$respid.uploadedurl"});
-			    }
-			}
-			if ($record{"resource.$partid.$respid.uploadedurl"}) {
-			    push(@files,$record{"resource.$partid.$respid.uploadedurl"});
-			}
-			if (@files) {
+			my $files=&get_submitted_files($udom,$uname,$partid,$respid,\%record);
+			if (@$files) {
 			    $lastsubonly.='<br /><font color="red" size="1">Like all files provided by users, this file may contain virusses</font><br />';
 			    my $file_counter = 0;
-			    foreach my $file (@files) {
+			    foreach my $file (@$files) {
 			        $file_counter ++;
 				&Apache::lonnet::allowuploaded('/adm/grades',$file);
-				$lastsubonly.='<br /><a href="'.$file.'" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border=0"> '.$file.'</a>';
-				$lastsubonly.=' Return commented document to student. <input type="file" name="part'.$partid.'_returndoc';
-				$lastsubonly.=$file_counter.'" />'."\n";
-				$lastsubonly.='<input type="hidden" name="returndocorig'.$file_counter.'" value="'.$file.'" />';
-
+				$lastsubonly.='<br /><a href="'.$file.'" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border="0"> '.$file.'</a>';
 			    }
 			    $lastsubonly.='<br />';
 			}
@@ -1893,15 +1914,18 @@ KEYWORDS
     my %seen = ();
     my @partlist;
     my @gradePartRespid;
-    for (sort keys(%$handgrade)) {
-	my ($partid,$respid) = split(/_/);
-	next if ($seen{$partid} > 0);
+    for my $part_resp(sort keys(%$handgrade)) {
+	my ($partid,$respid) = split(/_/, $part_resp);
+	#next if ($seen{$partid} > 0);
+	if ($seen{$partid} > 0) {
+	    $request->print(&handbackBox($uname,$udom,$counter,$partid,\%record,$respid));
+	    next;
+	}
 	$seen{$partid}++;
-	next if ($$handgrade{$_} =~ /:no$/ && $env{'form.lastSub'} =~ /^(hdgrade)$/);
+	next if ($$handgrade{$part_resp} =~ /:no$/ && $env{'form.lastSub'} =~ /^(hdgrade)$/);
 	push @partlist,$partid;
 	push @gradePartRespid,$partid.'.'.$respid;
-
-	$request->print(&gradeBox($request,$symb,$uname,$udom,$counter,$partid,\%record));
+	$request->print(&gradeBox($request,$symb,$uname,$udom,$counter,$partid,\%record,$respid));
     }
     $result='<input type="hidden" name="partlist'.$counter.
 	'" value="'.(join ":",@partlist).'" />'."\n";
@@ -2224,7 +2248,6 @@ sub saveHandGrade {
     my @parts = split(/:/,$env{'form.partlist'.$newflg});
     foreach my $new_part (@parts) {
 	#collaborator may vary for different parts
-	$request->print('form.part'.$new_part.'_returndoc1');
 	if ($submitter && $new_part ne $part) { next; }
 	my $dropMenu = $env{'form.GD_SEL'.$newflg.'_'.$new_part};
 	if ($dropMenu eq 'excused') {
@@ -2305,9 +2328,10 @@ sub saveHandGrade {
     #	        	 'portfolio'.$env{'form.currentpath'});
     
             my $file_counter = 1;
+            my $respid = $env{'form.respid'};
             while ($env{'form.part'.$new_part.'_returndoc'.$file_counter}) {
                 my $fname=$env{'form.returndoc'.$file_counter.'.filename'};
-                $newrecord{'resource.'.$new_part.'.handback'} = $env{'form.returndocorig'.$file_counter};
+                $newrecord{"resource.$new_part.$respid.handback"} = $env{'form.returndocorig'.$file_counter};
                 $request->print("<br />".$fname." will be the uploaded file name");
                 $request->print("<font color=\"red\">Will upload document</font>".$env{'form.returndocorig'.$file_counter});
                 $file_counter++;
@@ -2350,7 +2374,20 @@ sub saveHandGrade {
     }
     return ('',$pts,$wgt);
 }
-
+sub get_submitted_files {
+    my ($udom,$uname,$partid,$respid,$record) = @_;
+    my @files;
+    if ($$record{"resource.$partid.$respid.portfiles"}) {
+        my $file_url = '/uploaded/'.$udom.'/'.$uname.'/portfolio';
+        foreach my $file (split(',',$$record{"resource.$partid.$respid.portfiles"})) {
+    	    push(@files,$file_url.$file);
+        }
+    }
+    if ($$record{"resource.$partid.$respid.uploadedurl"}) {
+        push(@files,$$record{"resource.$partid.$respid.uploadedurl"});
+    }
+    return (\@files);
+}
 # ----------- Provides number of tries since last reset.
 sub get_num_tries {
     my ($record,$last_reset,$part) = @_;