#!/usr/bin/perl
#

#  Mike Ward  mward@cs.utah.edu
#  CGI Statistics Script for time logs for entire class
# ---------------------------------------------------------------------

&readStuff;

$data_file_path = $stuff{'data_file_path'};

print "Content-type: text/html\n\n";

print "<HTML>\n";

print "<HEAD><TITLE>Time-log data for $stuff{'course'}\n";
print "</TITLE></HEAD>\n";
print "<BODY BGCOLOR=\"white\">\n";
print "<h1 align=center>Time-log data for $stuff{'course'}</h1>\n";

$directory = $stuff{'data_file_path'} . "unsafe";

chdir $directory ||
  print "Unable to cd to $directory!\n";


# print "Changed directories to $directory.<br>\n";

# Find all the plan files in the directory
opendir (DIR, $directory) || print "Unable to open dir $directory!";
@filenames = grep {/\.time$/} readdir(DIR);
closedir DIR;

if ($#filenames < 0) {
   print "No time-log plan files found.</body></html>\n";
   exit;
   }


$numFiles = 0;

# The following hashes are indexed by program name.  Since program name
# can now be any string, e.g. "4a", they've become hashes rather than
# arrays.  And instead of the 0 entry indicating the total-of-totals,
# each hash will have a "total" entry.  BUG: what if somebody uses
# "total" as a program name?  Better solution: each of these things is a
# struct with a "total" field and a hash indexed by program name.
# Unfortunately, perl doesn't do structs.  I hate perl....

%totalStudents = ( total => 0 );
%totalPlanning = ( total => 0 );
%totalDesign = ( total => 0 );
%totalCode = ( total => 0 );
%totalCodeReview = ( total => 0 );
%totalCompile = ( total => 0 );
%totalTest = ( total => 0 );
%totalPostMortem = ( total => 0 );
%totalTotal = ( total => 0 );
# @totalStudents = (0,0,0,0,0,0,0,0,0,0,0,0);
# @totalPlanning = (0,0,0,0,0,0,0,0,0,0,0,0);
# @totalDesign = (0,0,0,0,0,0,0,0,0,0,0,0);
# @totalCode = (0,0,0,0,0,0,0,0,0,0,0,0);
# @totalCodeReview = (0,0,0,0,0,0,0,0,0,0,0,0);
# @totalCompile = (0,0,0,0,0,0,0,0,0,0,0,0);
# @totalTest = (0,0,0,0,0,0,0,0,0,0,0,0);
# @totalPostMortem = (0,0,0,0,0,0,0,0,0,0,0,0);
# @totalTotal = (0,0,0,0,0,0,0,0,0,0,0,0);
 
 
@whichArray = (0,
	       \%totalPlanning,
               \%totalDesign,
               \%totalCode,
	       \%totalCodeReview,
	       \%totalCompile,
	       \%totalTest,
	       \%totalPostMortem,
	       );


# print "Examining files: @filenames \n";

# 
# print "Tracing...\n";
# print "<table border=1>\n";
# print "<tr><th>filename</th><th>prog_num</th><th>estLOC</th><th>estHours</th><th>estMinutes</th><th>estTime</th><th>estLOCPerHour</th><th>estDefects</th><th>estDefectsPerKLOC</th></tr>\n";

foreach $name (@filenames) {
  ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat($name);
  if ($mode & 020000) {
    next; # it's a symlink
    }

#  print "<h2>$name</h2>\n";
  open(THISFILE, "$name") || next;

  $numFiles++;

  %seenThisProgram = ( );

  while (<THISFILE>)  {

     @data = split(' ', $_);
## Note: data[0]=prog_num, data[1]= month, data[2]=day, data[3]=time spent,
## data[4]=development phase,
## data[5]=month recorded, data[6]="/", data[7]=day recorded,
## data[8]=hour recorded, data[9]=":", data[10]=minute recorded
   
     $prog_num = $data[0];
     $time = $data[3];
     $phase = $data[4];

     if ($phase == 0) {
        next;
	# just ignore entries with no phase, although 
	# they shouldn't be in the database anyway
        }

     # Increment number of students who entered data for this program,
     # but not if we've already done so for this student.
     unless (defined $seenThisProgram{$prog_num}) {
        $totalStudents{$prog_num} ++;
        # treats undefined as zero, right?
        $totalStudents{"total"} ++;
	$seenThisProgram{$prog_num} = 1;
	}

     $whichArray[$phase]{$prog_num} += $time;
     $whichArray[$phase]{"total"} += $time;
     $totalTotal{$prog_num} += $time;
     $totalTotal{"total"} += $time;
     
#      print "</tr>\n";
     } 
# end while (<THISFILE>)
     close(THISFILE);
  }
# end foreach $name (@filenames)
# print "</table>\n";

if ($numFiles == 0) {
   print "Didn't find any time logs.</body></html>\n";
   exit;
   }

print "<h2>Average actual times:</h2>\n";
print "<p><table border=1>\n";
print "<tr><th>Program<br>number</th><th>Number of<br>students</th><th>Average<br>planning</th><th>Average<br>design</th><th>Average<br>coding</th><th>Average<br>code review</th><th>Average<br>compiling</th><th>Average<br>test &amp; debug</th><th>Average<br>post-mortem</th><th>Average<br>total</th></tr>\n";

@keys = sort(keys %total_plans);
# print "Keys in sorted order:",@keys,"<br>\n";
foreach $i (sort(keys %totalStudents)) {
# for ($i = 1; $i <= $#totalStudents; $i++) {
  if ($i == "total") { next; }
  my $n = $totalStudents{$i};
  unless ($n == 0) {
     $avgPlanning = $totalPlanning{$i}/$n;
     $avgDesign = $totalDesign{$i}/$n;
     $avgCode = $totalCode{$i}/$n;
     $avgCodeReview = $totalCodeReview{$i}/$n;
     $avgCompile = $totalCompile{$i}/$n;
     $avgTest = $totalTest{$i}/$n;
     $avgPostMortem = $totalPostMortem{$i}/$n;
     $avgTotal = $totalTotal{$i}/$n;
     print "<tr><td align=right>$i</td>";
     print "<td align=right>$n</td>";
     printf "<td align=right>%8.1f</td>",$avgPlanning;
     printf "<td align=right>%8.1f</td>",$avgDesign;
     printf "<td align=right>%8.1f</td>",$avgCode;
     printf "<td align=right>%8.1f</td>",$avgCodeReview;
     printf "<td align=right>%8.1f</td>",$avgCompile;
     printf "<td align=right>%8.1f</td>",$avgTest;
     printf "<td align=right>%8.1f</td>",$avgPostMortem;
     printf "<td align=right>%8.1f</td>",$avgTotal;
     print "</tr>\n";
     }
  }

$n = $totalStudents{"total"};

unless ($n == 0) {
   $avgPlanning = $totalPlanning{"total"}/$n;
   $avgDesign = $totalDesign{"total"}/$n;
   $avgCode = $totalCode{"total"}/$n;
   $avgCodeReview = $totalCodeReview{"total"}/$n;
   $avgCompile = $totalCompile{"total"}/$n;
   $avgTest = $totalTest{"total"}/$n;
   $avgPostMortem = $totalPostMortem{"total"}/$n;
   $avgTotal = $totalTotal{"total"}/$n;
   print "<tr><td align=right>Total</td>";
   print "<td align=right>$n</td>";
   printf "<td align=right>%8.1f</td>",$avgPlanning;
   printf "<td align=right>%8.1f</td>",$avgDesign;
   printf "<td align=right>%8.1f</td>",$avgCode;
   printf "<td align=right>%8.1f</td>",$avgCodeReview;
   printf "<td align=right>%8.1f</td>",$avgCompile;
   printf "<td align=right>%8.1f</td>",$avgTest;
   printf "<td align=right>%8.1f</td>",$avgPostMortem;
   printf "<td align=right>%8.1f</td>",$avgTotal;
   print "</tr>\n";

   print "<tr><td align=right>Percentage</td>";
   print "<td align=right>&nbsp;</td>";
   printf "<td align=right>%8.1f%%</td>",100*$avgPlanning/$avgTotal;
   printf "<td align=right>%8.1f%%</td>",100*$avgDesign/$avgTotal;
   printf "<td align=right>%8.1f%%</td>",100*$avgCode/$avgTotal;
   printf "<td align=right>%8.1f%%</td>",100*$avgCodeReview/$avgTotal;
   printf "<td align=right>%8.1f%%</td>",100*$avgCompile/$avgTotal;
   printf "<td align=right>%8.1f%%</td>",100*$avgTest/$avgTotal;
   printf "<td align=right>%8.1f%%</td>",100*$avgPostMortem/$avgTotal;
   printf "<td align=right>%8.1f%%</td>",100*$avgTotal/$avgTotal;
   print "</tr>\n";
   }
print "</table>\n";

print "</BODY>", "\n";
print "</HTML>", "\n";
 




#!/usr/bin/perl
#
#&readStuff;
#
#while (($key,$value) = each %stuff) {
#    print "$key=$value\n";
#    }


sub readStuff {
  my @cookie_pairs = split (/;\s/, $ENV{'HTTP_COOKIE'});
  parse_pairs(@cookie_pairs);

  my $buffer;
  # read cookies first, so GET, POST, etc. can override cookies

  if ( $ENV{'REQUEST_METHOD'} eq "GET" ) {
    $buffer = $ENV{'QUERY_STRING'};
  } elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
    read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'});
  } else {
        # Added for command line debugging
        # Supply name/value form data as a command line argument
        # Format: name1=value1\&name2=value2\&...
        # (need to escape & for shell)
        # Find the first argument that's not a switch (-)
        $buffer = ( grep( !/^-/, @ARGV )) [0];
        $buffer =~ s/\\&/&/g;
  }

  my @pairs = split(/&/,$buffer);
  parse_pairs(@pairs);
  }

sub parse_pairs {
  my $pair;
  foreach $pair (@_) {
     my ($name, $value) = split(/=/, $pair);
	 # replace plus signs with spaces
         $value =~ tr/+/ /;
	 # convert escape characters to ASCII form 
	 $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

	 # Stop people from using subshells to execute commands
	 $value =~ s/~!/ ~!/g;

	 # Uncomment for debugging purposes
         # print "Setting $name to $value<P>";
 
         # place name/value pair into array $stuff 
         $stuff{$name} = $value;
  }
}

