--- loncom/interface/Attic/lonspreadsheet.pm	2001/03/20 21:34:34	1.48
+++ loncom/interface/Attic/lonspreadsheet.pm	2001/09/13 15:55:40	1.63
@@ -5,7 +5,8 @@
 # 12/08,12/09,12/11,12/12,12/15,12/16,12/18,12/19,12/30,
 # 01/01/01,02/01,03/01,19/01,20/01,22/01,
 # 03/05,03/08,03/10,03/12,03/13,03/15,03/17,
-# 03/19,03/20 Gerd Kortemeyer
+# 03/19,03/20,03/21,03/27,04/05,04/09,
+# 07/09,07/14,07/21,09/01,09/10,9/11,9/12,9/13 Gerd Kortemeyer
 
 package Apache::lonspreadsheet;
             
@@ -77,12 +78,14 @@ sub initsheet {
 # v: output values
 # c: preloaded constants (A-column)
 # rl: row label
+# os: other spreadsheets (for student spreadsheet only)
 
 undef %v; 
 undef %t;
 undef %f;
 undef %c;
 undef %rl;
+undef @os;
 
 $maxrow=0;
 $sheettype='';
@@ -305,6 +308,42 @@ sub SUMMIN {
     return $sum;   
 }
 
+sub expandnamed {
+    my $expression=shift;
+    if ($expression=~/^\&/) {
+	my ($func,$var,$formula)=($expression=~/^\&(\w+)\(([^\;]+)\;(.*)\)/);
+	my @vars=split(/\W+/,$formula);
+        my %values=();
+        undef %values;
+        map {
+            my $varname=$_;
+            if ($varname=~/\D/) {
+               $formula=~s/$varname/'$c{\''.$varname.'\'}'/ge;
+               $varname=~s/$var/\(\\w\+\)/g;
+	       map {
+		  if ($_=~/$varname/) {
+		      $values{$1}=1;
+                  }
+               } keys %c;
+	    }
+        } @vars;
+        if ($func eq 'EXPANDSUM') {
+            my $result='';
+	    map {
+                my $thissum=$formula;
+                $thissum=~s/$var/$_/g;
+                $result.=$thissum.'+';
+            } keys %values;
+            $result=~s/\+$//;
+            return $result;
+        } else {
+	    return 0;
+        }
+    } else {
+        return '$c{\''.$expression.'\'}';
+    }
+}
+
 sub sett {
     %t=();
     my $pattern='';
@@ -326,7 +365,7 @@ sub sett {
                     $t{$lb}=~s/\#/$trow/g;
                     $t{$lb}=~s/\.\.+/\,/g;
                     $t{$lb}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g;
-                    $t{$lb}=~s/(^|[^\"\'])\[(\w+)\]/$1\$c\{\'$2\'\}/g;
+                    $t{$lb}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
                 }
 	      }
             } keys %f;
@@ -344,14 +383,14 @@ sub sett {
 	       $t{$_}=$f{$_};
                $t{$_}=~s/\.\.+/\,/g;
                $t{$_}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g;
-               $t{$_}=~s/(^|[^\"\'])\[([\w\.]+)\]/$1\$c\{\'$2\'\}/g;
+               $t{$_}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
             }
         }
     } keys %f;
     $t{'A0'}=$f{'A0'};
     $t{'A0'}=~s/\.\.+/\,/g;
     $t{'A0'}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g;
-    $t{'A0'}=~s/(^|[^\"\'])\[([\w\.]+)\]/$1\$c\{\'$2\'\}/g;
+    $t{'A0'}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
 }
 
 sub calc {
@@ -397,7 +436,18 @@ sub outrowassess {
     my $n=shift;
     my @cols=();
     if ($n) {
-       $cols[0]=$rl{$f{'A'.$n}};
+       my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{'A'.$n});
+       $cols[0]=$rl{$usy}.'<br>'.
+                '<select name="sel_'.$n.'" onChange="changesheet('.$n.
+                ')"><option name="default">Default</option>';
+       map {
+           $cols[0].='<option name="'.$_.'"';
+            if ($ufn eq $_) {
+               $cols[0].=' selected';
+            }
+            $cols[0].='>'.$_.'</option>';
+       } @os;
+       $cols[0].='</select>';
     } else {
        $cols[0]='<b><font size=+1>Export</font></b>';
     }
@@ -460,6 +510,13 @@ sub setconstants {
     %{$safeeval->varglob('c')}=%c;
 }
 
+# --------------------------------------------- Set names of other spreadsheets
+
+sub setothersheets {
+    my ($safeeval,@os)=@_;
+    @{$safeeval->varglob('os')}=@os;
+}
+
 # ------------------------------------------------ Add or change formula values
 
 sub setrowlabels {
@@ -600,6 +657,7 @@ sub exportdata {
     return $safeeval->reval('&exportrowa()');
 }
 
+
 # ========================================================== End of Spreadsheet
 # =============================================================================
 
@@ -612,43 +670,34 @@ sub rown {
     my ($safeeval,$n)=@_;
     my $defaultbg;
     my $rowdata='';
+    my $dataflag=0;
     unless ($n eq '-') {
        $defaultbg=((($n-1)/5)==int(($n-1)/5))?'#E0E0':'#FFFF';
     } else {
        $defaultbg='#E0FF';
     }
-    if ((($n-1)/25)==int(($n-1)/25)) {
-        my $what='Student';
-        if (&gettype($safeeval) eq 'assesscalc') {
-	    $what='Item';
-	} elsif (&gettype($safeeval) eq 'studentcalc') {
-            $what='Assessment';
-        }
-	$rowdata.="</table>\n<br><table border=2>".
-        '<tr><td>&nbsp;<td>'.$what.'</td>';
-        map {
-           $rowdata.='<td>'.$_.'</td>';
-        } ('A','B','C','D','E','F','G','H','I','J','K','L','M',
-           'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
-           'a','b','c','d','e','f','g','h','i','j','k','l','m',
-           'n','o','p','q','r','s','t','u','v','w','x','y','z');
-        $rowdata.='</tr>';
-    }
     $rowdata.="\n<tr><td><b><font size=+1>$n</font></b></td>";
     my $showf=0;
     my $proc;
     my $maxred;
-    if (&gettype($safeeval) eq 'assesscalc') {
+    my $sheettype=&gettype($safeeval);
+    if ($sheettype eq 'studentcalc') {
         $proc='&outrowassess';
-        $maxred=1;
+        $maxred=26;
     } else {
         $proc='&outrow';
+    }
+    if ($sheettype eq 'assesscalc') {
+        $maxred=1;
+    } else {
         $maxred=26;
     }
-    if ($n eq '-') { $proc='&templaterow'; $n=-1; }
+    if ($n eq '-') { $proc='&templaterow'; $n=-1; $dataflag=1; }
     map {
        my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD');
        my ($fm,$vl)=split(/\_\_\_eq\_\_\_/,$_);
+       if ((($vl ne '') || ($vl eq '0')) &&
+           (($showf==1) || ($sheettype ne 'studentcalc'))) { $dataflag=1; }
        if ($showf==0) { $vl=$_; }
        if ($showf<=$maxred) { $bgcolor='#FFDDDD'; }
        if (($n==0) && ($showf<=26)) { $bgcolor='#CCCCFF'; } 
@@ -664,7 +713,11 @@ sub rown {
        }
        $showf++;
     } $safeeval->reval($proc.'('.$n.')');
-    return $rowdata.'</tr>';
+    if ($ENV{'form.showall'} || ($dataflag)) {
+       return $rowdata.'</tr>';
+    } else {
+       return '';
+    }
 }
 
 # ------------------------------------------------------------- Print out sheet
@@ -709,10 +762,59 @@ sub outsheet {
     my $maxrow=&getmaxrow($safeeval);
     $tabledata.=&rown($safeeval,'-');
     $r->print($tabledata);
+    my @rowprt=();
     for ($row=0;$row<=$maxrow;$row++) {
-        $r->print(&rown($safeeval,$row));
+        $rowprt[$row]=&rown($safeeval,$row);
+    }
+    my $n=0;
+    for ($row=0;$row<=$maxrow;$row++) {
+     if ($rowprt[$row]) {
+      if ((($n-1)/25)==int(($n-1)/25)) {
+        my $what='Student';
+        if (&gettype($safeeval) eq 'assesscalc') {
+	    $what='Item';
+	} elsif (&gettype($safeeval) eq 'studentcalc') {
+            $what='Assessment';
+        }
+	$r->print("</table>\n<br><table border=2>".
+        '<tr><td>&nbsp;<td>'.$what.'</td>');
+        map {
+           $r->print('<td>'.$_.'</td>');
+        } ('A','B','C','D','E','F','G','H','I','J','K','L','M',
+           'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
+           'a','b','c','d','e','f','g','h','i','j','k','l','m',
+           'n','o','p','q','r','s','t','u','v','w','x','y','z');
+        $r->print('</tr>');
+       }
+         $n++;
+         $r->print($rowprt[$row]);
+      }
     }
     $r->print('</table>');
+    undef @rowprt;
+}
+
+#
+# ----------------------------------------------- Read list of available sheets
+# 
+
+sub othersheets {
+    my ($safeeval,$stype)=@_;
+
+    my $cnum=&getcnum($safeeval);
+    my $cdom=&getcdom($safeeval);
+    my $chome=&getchome($safeeval);
+
+    my @alternatives=();
+    my $result=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.':'.
+                                      $stype.'_spreadsheets',$chome);
+    if ($result!~/^error\:/) {
+	map {
+            $alternatives[$#alternatives+1]=
+            &Apache::lonnet::unescape((split(/\=/,$_))[0]);
+        } split(/\&/,$result);
+    } 
+    return @alternatives; 
 }
 
 #
@@ -835,8 +937,10 @@ sub writesheet {
 # ----------------------------------------------------------------- Write sheet
     my $sheetdata='';
     map {
+     unless ($f{$_} eq 'import') {
        $sheetdata.=&Apache::lonnet::escape($_).'='.
 	   &Apache::lonnet::escape($f{$_}).'&';
+     }
     } keys %f;
     $sheetdata=~s/\&$//;
     my $reply=&Apache::lonnet::reply('put:'.$cdom.':'.$cnum.':'.$fn.':'.
@@ -844,7 +948,8 @@ sub writesheet {
     if ($reply eq 'ok') {
           $reply=&Apache::lonnet::reply('put:'.$cdom.':'.$cnum.':'.
               $stype.'_spreadsheets:'.
-              &Apache::lonnet::escape($fn).'='.$ENV{'user.name'},
+              &Apache::lonnet::escape($fn).'='.$ENV{'user.name'}.'@'.
+                                               $ENV{'user.domain'},
               $chome);
           if ($reply eq 'ok') {
               if ($makedef) { 
@@ -902,7 +1007,14 @@ sub tmpread {
             $fo{$name}=$value;
         }
     }
-    if ($nfield) { $fo{$nfield}=$nform; }
+    if ($nform eq 'changesheet') {
+        $fo{'A'.$nfield}=(split(/\_\_\&\&\&\_\_/,$fo{'A'.$nfield}))[0];
+        unless ($ENV{'form.sel_'.$nfield} eq 'Default') {
+	    $fo{'A'.$nfield}.='__&&&__'.$ENV{'form.sel_'.$nfield};
+        }
+    } else {
+       if ($nfield) { $fo{$nfield}=$nform; }
+    }
     &setformulas($safeeval,%fo);
 }
 
@@ -1093,9 +1205,17 @@ sub updatestudentassesssheet {
                        &GDBM_READER,0640)) {
 # --------------------------------------------------------- Get all assessments
 
-	my %allkeys=();
+	my %allkeys=('timestamp' => 
+                     'Timestamp of Last Transaction<br>timestamp');
         my %allassess=();
 
+        my $adduserstr='';
+        if ((&getuname($safeeval) ne $ENV{'user.name'}) ||
+            (&getudom($safeeval) ne $ENV{'user.domain'})) {
+            $adduserstr='&uname='.&getuname($safeeval).
+		'&udom='.&getudom($safeeval);
+        }
+
         map {
 	    if ($_=~/^src\_(\d+)\.(\d+)$/) {
 	       my $mapid=$1;
@@ -1108,7 +1228,8 @@ sub updatestudentassesssheet {
 			    '___'.$resid.'___'.
 			    &Apache::lonnet::declutter($srcf);
 		 $allassess{$symb}=
-    '<a href="/adm/assesscalc?usymb='.$symb.'">'.$bighash{'title_'.$id}.'</a>';
+	            '<a href="/adm/assesscalc?usymb='.$symb.$adduserstr.'">'.
+                     $bighash{'title_'.$id}.'</a>';
                  if ($stype eq 'assesscalc') {
                    map {
                        if (($_=~/^stores\_(.*)/) || ($_=~/^parameter\_(.*)/)) {
@@ -1161,10 +1282,14 @@ sub updatestudentassesssheet {
 	map {
 	    if ($_=~/^A(\d+)/) {
                 $maxrow=($1>$maxrow)?$1:$maxrow;
-                $existing{$f{$_}}=1;
-		unless ((defined($current{$f{$_}})) || (!$1)) {
+                my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{$_});
+                $existing{$usy}=1;
+		unless ((defined($current{$usy})) || (!$1)) {
 		   $f{$_}='!!! Obsolete';
                    $changed=1;
+	        } elsif ($ufn) {
+		    $current{$usy}
+                       =~s/assesscalc\?usymb\=/assesscalc\?ufn\=$ufn\&usymb\=/;
                 }
             }
         } keys %f;
@@ -1214,9 +1339,10 @@ sub loadstudent {
 	if ($_=~/^A(\d+)/) {
 	   my $row=$1;
            unless (($f{$_}=~/^\!/) || ($row==0)) {
+	      my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{$_});
 	      @assessdata=&exportsheet(&getuname($safeeval),
                                        &getudom($safeeval),
-                                       'assesscalc',$f{$_});
+                                       'assesscalc',$usy,$ufn);
               my $index=0;
               map {
                   if ($assessdata[$index]) {
@@ -1260,7 +1386,7 @@ sub loadcourse {
 <script>
     popwin=open('','popwin','width=400,height=100');
     popwin.document.writeln('<html><body bgcolor="#FFFFFF">'+
-      '<h1>Spreadsheet Calculation Progress</h1>'+
+      '<h3>Spreadsheet Calculation Progress</h3>'+
       '<form name=popremain>'+
       '<input type=text size=35 name=remaining value=Starting></form>'+
       '</body></html>');
@@ -1404,6 +1530,18 @@ sub loadassessment {
 # ----------------- now courseopt, useropt initialized for this user and course
 # (used by parmval)
 
+#
+# Load keys for this assessment only
+#
+    my %thisassess=();
+    my ($symap,$syid,$srcf)=split(/\_\_\_/,$symb);
+    
+    map {
+        $thisassess{$_}=1;
+    } split(/\,/,&Apache::lonnet::metadata($srcf,'keys'));
+#
+# Load parameters
+#
    my %c=();
 
    if (tie(%parmhash,'GDBM_File',
@@ -1413,9 +1551,11 @@ sub loadassessment {
 	if ($_=~/^A/) {
             unless ($f{$_}=~/^\!/) {
   	       if ($f{$_}=~/^parameter/) {
+		if ($thisassess{$f{$_}}) {
                   my $val=&parmval($f{$_},$safeeval);
                   $c{$_}=$val;
                   $c{$f{$_}}=$val;
+	        }
 	       } else {
 		  my $key=$f{$_};
                   my $ckey=$key;
@@ -1498,18 +1638,21 @@ sub forcedrecalc {
     my ($uname,$udom,$stype,$usymb)=@_;
     my $key=$uname.':'.$udom.':'.$stype.':'.$usymb;
     my $time=$oldsheets{$key.'.time'};
+    if ($ENV{'form.forcerecalc'}) { return 1; }
     unless ($time) { return 1; }
     if ($stype eq 'assesscalc') {
         my $map=(split(/\_\_\_/,$usymb))[0];
         if (&checkthis('::assesscalc:',$time) ||
             &checkthis('::assesscalc:'.$map,$time) ||
             &checkthis('::assesscalc:'.$usymb,$time) ||
-            &checkthis($uname.':'.$udom.':assesscalc:',$time)) {
+            &checkthis($uname.':'.$udom.':assesscalc:',$time) ||
+            &checkthis($uname.':'.$udom.':assesscalc:'.$map,$time) ||
+            &checkthis($uname.':'.$udom.':assesscalc:'.$usymb,$time)) {
             return 1;
         } 
     } else {
         if (&checkthis('::studentcalc:',$time) || 
-            &checkthis($uname.':'.$udom.':studencalc:',$time)) {
+            &checkthis($uname.':'.$udom.':studentcalc:',$time)) {
 	    return 1;
         }
     }
@@ -1748,6 +1891,10 @@ $tmpdir=$r->dir_config('lonDaemons').'/t
        }
     } (split(/&/,$ENV{'QUERY_STRING'}));
 
+# -------------------------------------- Interactive loading of specific sheet?
+    if (($ENV{'form.load'}) && ($ENV{'form.loadthissheet'} ne 'Default')) {
+	$ENV{'form.ufn'}=$ENV{'form.loadthissheet'};
+    }
 # ------------------------------------------- Nothing there? Must be login user
 
     my $aname;
@@ -1783,6 +1930,12 @@ $tmpdir=$r->dir_config('lonDaemons').'/t
         }
     }
 
+    function changesheet(cn) {
+	document.sheet.unewfield.value=cn;
+        document.sheet.unewformula.value='changesheet';
+        document.sheet.submit();
+    }
+
 </script>
 ENDSCRIPT
     $r->print('</head><body bgcolor="#FFFFFF">'.
@@ -1799,6 +1952,18 @@ ENDSCRIPT
 
     $r->rflush();
 
+# ---------------------------------------------------------------- Full recalc?
+
+
+    if ($ENV{'form.forcerecalc'}) {
+	$r->print('<h4>Completely Recalculating Sheet ...</h4>');
+        undef %spreadsheets;
+        undef %courserdatas;
+        undef %userrdatas;
+        undef %defaultsheets;
+        undef %updatedata;
+   }
+ 
 # ---------------------------------------- Read new sheet or modified worksheet
 
     $r->uri=~/\/(\w+)$/;
@@ -1839,29 +2004,40 @@ ENDSCRIPT
 # ---------------------------------------------------------------- Course title
 
     $r->print('<h1>'.
-            $ENV{'course.'.$ENV{'request.course.id'}.'.description'}.'</h1>');
-
+            $ENV{'course.'.$ENV{'request.course.id'}.'.description'}.
+             '</h1><h3>'.localtime().'</h3>');
 
-# ---------------------------------------------------- See if something to save
+# ---------------------------------------------------- See if user can see this
 
-    if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
-        my $fname='';
-	if ($ENV{'form.saveas'} && ($fname=$ENV{'form.newfn'})) {
-            $fname=~s/\W/\_/g;
-            if ($fname eq 'default') { $fname='course_default'; }
-            $fname.='_'.&gettype($asheet);
-            &setfilename($asheet,$fname);
-            $ENV{'form.ufn'}=$fname;
-	    $r->print('<p>Saving spreadsheet: '.
-                         &writesheet($asheet,$ENV{'form.makedefufn'}).'<p>');
-	}
+    if ((&gettype($asheet) eq 'classcalc') || 
+        (&getuname($asheet) ne $ENV{'user.name'}) ||
+        (&getudom($asheet) ne $ENV{'user.domain'})) {
+        unless (&Apache::lonnet::allowed('vgr',&getcid($asheet))) {
+	    $r->print(
+           '<h1>Access Permission Denied</h1></form></body></html>');
+            return OK;
+        }
     }
 
-# ------------------------------------------------ Write the modified worksheet
-
-   $r->print('<b>Current sheet:</b> '.&getfilename($asheet).'<p>');
+# ---------------------------------------------------------- Additional options
 
-   &tmpwrite($asheet);
+    $r->print(
+ '<input type=submit name=forcerecalc value="Completely Recalculate Sheet"><p>'
+		 );
+    if (&gettype($asheet) eq 'assesscalc') {
+       $r->print ('<p><font size=+2><a href="/adm/studentcalc?uname='.
+                                               &getuname($asheet).
+                                               '&udom='.&getudom($asheet).
+                  '">Level up: Student Sheet</a></font><p>');
+    }
+    
+    if ((&gettype($asheet) eq 'studentcalc') && 
+        (&Apache::lonnet::allowed('vgr',&getcid($asheet)))) {
+       $r->print (
+                   '<p><font size=+2><a href="/adm/classcalc">'.
+                   'Level up: Course Sheet</a></font><p>');
+    }
+    
 
 # ----------------------------------------------------------------- Save dialog
 
@@ -1877,6 +2053,24 @@ ENDSCRIPT
 
     $r->print(&hiddenfield('ufn',&getfilename($asheet)));
 
+# ----------------------------------------------------------------- Load dialog
+    if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
+	$r->print('<p><input type=submit name=load value="Load ...">'.
+                  '<select name="loadthissheet">'.
+                  '<option name="default">Default</option>');
+        map {
+	    $r->print('<option name="'.$_.'"');
+            if ($ENV{'form.ufn'} eq $_) {
+               $r->print(' selected');
+            }
+            $r->print('>'.$_.'</option>');
+        } &othersheets($asheet,&gettype($asheet));
+        $r->print('</select><p>');
+        if (&gettype($asheet) eq 'studentcalc') {
+	    &setothersheets($asheet,&othersheets($asheet,'assesscalc'));
+        }
+    }
+
 # --------------------------------------------------------------- Cached sheets
 
     &expirationdates();
@@ -1913,6 +2107,38 @@ ENDSCRIPT
     my $calcoutput=&calcsheet($asheet);
     $r->print('<h3><font color=red>'.$calcoutput.'</h3></font>');
 
+# ---------------------------------------------------- See if something to save
+
+    if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
+        my $fname='';
+	if ($ENV{'form.saveas'} && ($fname=$ENV{'form.newfn'})) {
+            $fname=~s/\W/\_/g;
+            if ($fname eq 'default') { $fname='course_default'; }
+            $fname.='_'.&gettype($asheet);
+            &setfilename($asheet,$fname);
+            $ENV{'form.ufn'}=$fname;
+	    $r->print('<p>Saving spreadsheet: '.
+                         &writesheet($asheet,$ENV{'form.makedefufn'}).'<p>');
+	}
+    }
+
+# ------------------------------------------------ Write the modified worksheet
+
+   $r->print('<b>Current sheet:</b> '.&getfilename($asheet).'<p>');
+
+   &tmpwrite($asheet);
+
+    if (&gettype($asheet) eq 'studentcalc') {
+	$r->print('<br>Show rows with empty A column: ');
+    } else {
+        $r->print('<br>Show empty rows: ');
+    } 
+    $r->print('<input type=checkbox name=showall onClick="submit()"');
+    if ($ENV{'form.showall'}) { $r->print(' checked'); }
+    $r->print('>');
+
+# ------------------------------------------------------------- Print out sheet
+
     &outsheet($r,$asheet);
     $r->print('</form></body></html>');