--- loncom/homework/grades.pm	2007/06/11 21:36:18	1.401
+++ loncom/homework/grades.pm	2007/06/15 22:16:13	1.409
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.401 2007/06/11 21:36:18 albertel Exp $
+# $Id: grades.pm,v 1.409 2007/06/15 22:16:13 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -41,7 +41,6 @@ use Apache::Constants qw(:common);
 use Apache::lonlocal;
 use Apache::lonenc;
 use String::Similarity;
-use lib '/home/httpd/lib/perl';
 use LONCAPA;
 
 use POSIX qw(floor);
@@ -1959,8 +1958,8 @@ KEYWORDS
 			($env{'form.lastSub'} eq 'hdgrade' && 
 			 $$handgrade{$$part[0].'_'.$$part[1]} eq 'yes')) {
 			my $display_part=&get_display_part($partid,$symb);
-			$lastsubonly.='<tr><td bgcolor="#ffffe6">Debug -'.'<b>Part:</b> '.
-			    $display_part.' <span class="LC_internal_info">( hhhh ID '.$respid.
+			$lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part:</b> '.
+			    $display_part.' <span class="LC_internal_info">( ID '.$respid.
 			    ' )</span>&nbsp; &nbsp;';
 			my $files=&get_submitted_files($udom,$uname,$partid,$respid,\%record);
 			if (@$files) {
@@ -6078,10 +6077,9 @@ GRADINGMENUJS
 	'<input type="button" onClick="javascript:checkChoice(this.form,\'3\',\'csvform\');" value="'.&mt('Upload').'" />'.
 	' '.&mt('scores from file').' </td></tr>'."\n";
 
-#    $result.='<tr bgcolor="#ffffe6"><td>'.
-#        '<input type="button" onClick="javascript:checkChoice(this.form,\'6\',\'processclicker\');" value="'.&mt('Process').'" />'.
-#        ' '.&mt('clicker file').' </td></tr>'."\n";
-
+    $result.='<tr bgcolor="#ffffe6"><td>'.
+        '<input type="button" onClick="javascript:checkChoice(this.form,\'6\',\'processclicker\');" value="'.&mt('Process').'" />'.
+        ' '.&mt('clicker file').' </td></tr>'."\n";
 
     $result.='<tr bgcolor="#ffffe6"valign="top"><td colspan="2">'.
 	'<input type="button" onClick="javascript:checkChoice(this.form,\'4\',\'scantron_selectphase\');'.
@@ -6131,29 +6129,53 @@ sub init_perm {
 }
 
 sub gather_clicker_ids {
-    my %clickerids=();
+    my %clicker_ids;
 
     my $classlist = &Apache::loncoursedata::get_classlist();
 
     # Set up a couple variables.
-    my $usernameidx = &Apache::loncoursedata::CL_SNAME();
-    my $domainidx   = &Apache::loncoursedata::CL_SDOM();
+    my $username_idx = &Apache::loncoursedata::CL_SNAME();
+    my $domain_idx   = &Apache::loncoursedata::CL_SDOM();
 
-    foreach my $student (keys %$classlist) {
+    foreach my $student (keys(%$classlist)) {
 
-        my $username = $classlist->{$student}->[$usernameidx];
-        my $domain   = $classlist->{$student}->[$domainidx];
+        my $username = $classlist->{$student}->[$username_idx];
+        my $domain   = $classlist->{$student}->[$domain_idx];
         my $clickers =
-	   (&Apache::lonnet::userenvironment($domain,$username,'clickers'))[1];
+	    (&Apache::lonnet::userenvironment($domain,$username,'clickers'))[1];
         foreach my $id (split(/\,/,$clickers)) {
-            if (exists($clickerids{$id})) {
-               $clickerids{$id}.=','.$username.':'.$domain;
+            $id=~s/^0+//;
+            if (exists($clicker_ids{$id})) {
+		$clicker_ids{$id}.=','.$username.':'.$domain;
             } else {
-               $clickerids{$id}=$username.':'.$domain;
+		$clicker_ids{$id}=$username.':'.$domain;
             }
         }
     }
-    return %clickerids;
+    return %clicker_ids;
+}
+
+sub gather_adv_clicker_ids {
+    my %clicker_ids;
+    my $cnum=$env{'course.'.$env{'request.course.id'}.'.num'};
+    my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
+    my %coursepersonnel=&Apache::lonnet::get_course_adv_roles($cdom.'/'.$cnum);
+    foreach my $element (sort(keys(%coursepersonnel))) {
+        foreach my $person (split(/\,/,$coursepersonnel{$element})) {
+            my ($puname,$pudom)=split(/\:/,$person);
+            my $clickers =
+		(&Apache::lonnet::userenvironment($pudom,$puname,'clickers'))[1];
+            foreach my $id (split(/\,/,$clickers)) {
+		$id=~s/^0+//;
+		if (exists($clicker_ids{$id})) {
+		    $clicker_ids{$id}.=','.$puname.':'.$pudom;
+		} else {
+		    $clicker_ids{$id}=$puname.':'.$pudom;
+		}
+            }
+        }
+    }
+    return %clicker_ids;
 }
 
 sub process_clicker {
@@ -6171,10 +6193,54 @@ sub process_clicker {
     $result.='<tr bgcolor=#ffffe6><td>'."\n";
     my $upload=&mt("Upload File");
     my $type=&mt("Type");
+    my $attendance=&mt("Award points just for participation");
+    my $personnel=&mt("Correctness determined from response by course personnel");
+    my $specific=&mt("Correctness determined from response with clicker ID"); 
+    my $pcorrect=&mt("Percentage points for correct solution");
+    my $pincorrect=&mt("Percentage points for incorrect solution");
     my $selectform=&Apache::loncommon::select_form('iclicker','upfiletype',
-                                  ('iclicker' => 'iClicker'));
+						   ('iclicker' => 'i>clicker'));
 
     $result.=<<ENDUPFORM;
+<script type="text/javascript">
+function sanitycheck() {
+// Accept only integer percentages
+   document.forms.gradesupload.pcorrect.value=Math.round(document.forms.gradesupload.pcorrect.value);
+   document.forms.gradesupload.pincorrect.value=Math.round(document.forms.gradesupload.pincorrect.value);
+// Find out grading choice
+   for (i=0; i<document.forms.gradesupload.gradingmechanism.length; i++) {
+      if (document.forms.gradesupload.gradingmechanism[i].checked) {
+         gradingchoice=document.forms.gradesupload.gradingmechanism[i].value;
+      }
+   }
+// By default, new choice equals user selection
+   newgradingchoice=gradingchoice;
+// Not good to give more points for false answers than correct ones
+   if (Math.round(document.forms.gradesupload.pcorrect.value)<Math.round(document.forms.gradesupload.pincorrect.value)) {
+      document.forms.gradesupload.pcorrect.value=document.forms.gradesupload.pincorrect.value;
+   }
+// If new choice is attendance only, and old choice was correctness-based, restore defaults
+   if ((gradingchoice=='attendance') && (document.forms.gradesupload.waschecked.value!='attendance')) {
+      document.forms.gradesupload.pcorrect.value=100;
+      document.forms.gradesupload.pincorrect.value=100;
+   }
+// If the values are different, cannot be attendance only
+   if ((Math.round(document.forms.gradesupload.pcorrect.value)!=Math.round(document.forms.gradesupload.pincorrect.value)) &&
+       (gradingchoice=='attendance')) {
+       newgradingchoice='personnel';
+   }
+// Change grading choice to new one
+   for (i=0; i<document.forms.gradesupload.gradingmechanism.length; i++) {
+      if (document.forms.gradesupload.gradingmechanism[i].value==newgradingchoice) {
+         document.forms.gradesupload.gradingmechanism[i].checked=true;
+      } else {
+         document.forms.gradesupload.gradingmechanism[i].checked=false;
+      }
+   }
+// Remember the old state
+   document.forms.gradesupload.waschecked.value=newgradingchoice;
+}
+</script>
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
 <input type="hidden" name="symb" value="$symb" />
 <input type="hidden" name="command" value="processclickerfile" />
@@ -6182,6 +6248,13 @@ sub process_clicker {
 <input type="hidden" name="saveState"  value="$env{'form.saveState'}" />
 <input type="file" name="upfile" size="50" />
 <br /><label>$type: $selectform</label>
+<br /><label>$attendance: <input type="radio" name="gradingmechanism" value="attendance" checked="checked" onClick="sanitycheck()" /></label>
+<br /><label>$personnel: <input type="radio" name="gradingmechanism" value="personnel" onClick="sanitycheck()" /></label>
+<br /><label>$specific: <input type="radio" name="gradingmechanism" value="specific" onClick="sanitycheck()" /></label>
+<input type="text" name="specificid" size="15" />
+<input type="hidden" name="waschecked" value="attendance" />
+<br /><label>$pcorrect: <input type="text" name="pcorrect" size="4" value="100" onChange="sanitycheck()" /></label>
+<br /><label>$pincorrect: <input type="text" name="pincorrect" size="4" value="100" onChange="sanitycheck()" /></label>
 <br /><input type="button" onClick="javascript:checkUpload(this.form);" value="$upload" />
 </form>
 ENDUPFORM
@@ -6196,12 +6269,95 @@ sub process_clicker_file {
     my ($symb)=&get_symb($r);
     if (!$symb) {return '';}
     my ($result) = &showResourceInfo($symb,$env{'form.probTitle'});
-    $result.=&show_grading_menu_form($symb);
-    my %clickerids=&gather_clicker_ids();
-    foreach my $key (keys %clickerids) {
-       $result.='<br />'.$key.' - '.$clickerids{$key};
+    if (($env{'form.gradingmechanism'} eq 'specific') && ($env{'form.specificid'}!~/\w/)) {
+	$result.='<span class="LC_error">'.&mt('You need to specify a clicker ID for the correct answer').'</span>';
+	return $result.&show_grading_menu_form($symb);
+    }
+    my %clicker_ids=&gather_clicker_ids();
+    my %correct_ids;
+    if ($env{'form.gradingmechanism'} eq 'personnel') {
+	%correct_ids=&gather_adv_clicker_ids();
+    }
+    if ($env{'form.gradingmechanism'} eq 'specific') {
+	my $correct_id=$env{'form.specificid'};
+	$correct_id=~tr/a-z/A-Z/;
+	$correct_id=~s/\s//gs;
+	$correct_id=~s/^0+//;
+	$correct_ids{$correct_id}='specified';
     }
-    return $result;
+    if ($env{'form.gradingmechanism'} eq 'attendance') {
+	$result.=&mt('Score based on attendance only');
+    } else {
+	my $number=0;
+	$result.='<h3>'.&mt('Correctness determined by the following IDs').'</h3>';
+	foreach my $id (sort(keys(%correct_ids))) {
+	    $result.='<tt>'.$id.'</tt> - ';
+	    if ($correct_ids{$id} eq 'specified') {
+		$result.=&mt('specified');
+	    } else {
+		my ($uname,$udom)=split(/\:/,$correct_ids{$id});
+		$result.=&Apache::loncommon::plainname($uname,$udom);
+	    }
+	    $result.='<br />';
+	    $number++;
+	}
+	if ($number==0) {
+	    $result.='<span class="LC_error">'.&mt('No IDs found to determine correct answer').'</span>';
+	    return $result.&show_grading_menu_form($symb);
+	}
+    }
+    if (length($env{'form.upfile'}) < 2) {
+        $result.=&mt('[_1] Error: [_2] The file you attempted to upload, [_3] contained no information. Please check that you entered the correct filename.',
+		     '<span class="LC_error">',
+		     '</span>',
+		     '<span class="LC_filename">'.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'</span>');
+        return $result.&show_grading_menu_form($symb);
+    }
+    my %responses;
+    my @questiontitles;
+    my $errormsg='';
+    my $number=0;
+    if ($env{'form.upfiletype'} eq 'iclicker') {
+	($errormsg,$number)=&iclicker_eval(\@questiontitles,\%responses);
+    }
+    $result.='<br />'.&mt('Found [_1] questions',$number).'<br />';
+    foreach my $id (keys(%responses)) {
+	$result.='<br />'.$id.' - '.$responses{$id};
+    }
+    return $result.&show_grading_menu_form($symb);
+}
+
+sub iclicker_eval {
+    my ($questiontitles,$responses)=@_;
+    my $number=0;
+    my $errormsg='';
+    foreach my $line (split(/[\n\r]/,$env{'form.upfile'})) {
+	chomp($line);
+	foreach my $quoted ($line=~/\,\s*\"([^\"]*)\"\s*\,/g) {
+	    my $replace=$quoted;
+	    $replace=~s/\,//g;
+	    &Apache::lonnet::logthis($quoted.' - '.$replace.'<br />');
+	    $line=~s/\,\s*\"\Q$quoted\E\"\s*\,/,$replace,/gs;
+	}
+	my @entries=split(/\,/,$line);
+	if ($entries[0] eq 'Question') {
+	    for (my $i=3;$i<$#entries;$i+=6) {
+		$$questiontitles[$number]=$entries[$i];
+		$number++;
+	    }
+	}
+	if ($entries[0]=~/^\#/) {
+	    my $id=$entries[0];
+	    my @idresponses;
+	    $id=~s/^[\#0]+//;
+	    for (my $i=0;$i<$number;$i++) {
+		my $idx=3+$i*6;
+		push(@idresponses,$entries[$idx]);
+	    }
+	    $$responses{$id}=join(',',@idresponses);
+	}
+    }
+    return ($errormsg,$number);
 }
 
 sub handler {