#!/usr/local/bin/perl
#computes and prints histograms of class average numerals and Letters, output file
#in grades/finalLetters.lst with SID Letter  pairs
#Letter grade outputs only if $final is set to 1
#If first parameter is not a number, assumed to be a search string using grep -i
#will only compute values for THAT search string
#If next parameter is numerical, it turns on printing of seas names for class average
#histogram and if >5 sets width of # of names to print on a line

require "/w/class.01/cs/cs131/cs131ta/risc/grades/column_names";#has column labels and indexes
$final=0;       #if true, computes/prints letter grades and output file
$res=2;         #resolution of histogram
$names=shift @ARGV if ($ARGV[0] =~ m:^\d\d?$:); #width parameter for putting seas names
        #beside class averages distribution
$names=5 if ($names && $names <5);
%weights = (
  hw1pa   => .04,
  hw1wa	  => .01,
  hw2pa   => .05,
  hw2wa	  => .01,
  hw3pa   => .07,
  hw3wa	  => .01,
  hw4pa   => .05,
  hw4wa	  => .01,
  hw5pa   => .07,
  hw5wa	  => .01,
  hw6pa   => .06,
  hw6wa	  => .01,
  mid     => .3,
  final   => .3,
);
map {$sum+=$_} (values %weights);
if ($sum!=1) {	#check that weights sum to 1
  print "Sum=$sum\n";
  exit;
}
@letgrades=qw (A  B+ B  B- C+ C  C- D+ D  D- F); #spaces don't matter, just for visual
@cutoffs  =qw (90 85 80 74 72 70 68 63 60 55 0); #as long as indexing lines them up

@keys=keys %weights;
if (@ARGV) {#just those who match
  $names=5;
  $ARGV[0]=join ('|', @ARGV) if $#ARGV;
  @grades=`/usr/xpg4/bin/grep -i -E \"$ARGV[0]\" $grade_file`;
  @avgsline=split (/,/, `grep -i average $grade_file`);
}
else {#all students
  &readgrades;
  shift @grades;
  @avgsline=split (/,/, pop @grades, -1);
}
foreach $col (@keys) {  #determine how many points possible so far
  if ($avgsline[$columns{$col}] =~ m:\d:) {$possible+=$weights{$col};}
}
foreach $student (@grades) {
  $current=0;
  @sgrades=split (/,/, $student, -1);
  foreach $col (@keys) {
    if ($sgrades[$columns{$col}]=~m:\b(\d+(.\d+)?)\b:) {
      $value=$1;
      $value*=50 if ($col =~ m:wa:);	#wa graded out of 2 points, rest out of 100
      $current+=$weights{$col}*$value;
    }
  }
  if ($final) {
    $letter=&getletter($current);
    $letters{$letter}++;
    push @avgs, "$sgrades[$columns{'sid'}] $letter\n";
    push @{$letnames{$letter}}, $sgrades[$columns{'seas'}];
  }
  if (@ARGV) {printf "%10s %-12s raw=%3.2f of %3.1f, avg=%3.2f%%\n",  $sgrades[$columns{"fname"}],
	$sgrades[$columns{"lname"}], $current, 100*$possible, $current/$possible;}
  $overall+=$current;
  $count++ if $current>0;
  $scores{int $current/$res}++;
  push @scores, $current;
  push @{$names{int $current/$res}}, $sgrades[$columns{'seas'}];
}

exit if @ARGV;
printf "overall average for $count people is %.1f out of %.1f,  which is %.1f%%\n",
        $overall/$count, 100*$possible, $overall/$count/$possible if $count>0;

if ($names) { #find max width for alignment
  foreach $key (sort {$b <=> $a} keys %scores) {$width= $scores{$key} if ($scores{$key} >$width);}
  $width+=2;
}
$sofar=0;
foreach $key (sort {$b <=> $a} keys %scores) {  #sort decreasing
  $sofar+= 100*$scores{$key}/$count;
  printf (">= %2d  %4.1f%% (%5.1f%%)  %2d %-${width}s", $res*$key, 100*$scores{$key}/$count,
        $sofar, $scores{$key}, "x" x $scores{$key});
  if ($names) {
    $i=1;
    while ( $names*$i < $#{$names{$key}}) {
      $names{$key}[$i++*$names-1].="\n                          " . ' ' x $width . '| ';
    }
    print "|  @{$names{$key}}";
  }
  print "\n";
}

if ($final) {
  open (OUT, ">$home/grades/finalLetters.lst") or die "Can't create finalLetters.lst: $!\n";
  print OUT @avgs;
  close OUT;
  print "\n";
  foreach $key (@letgrades) {
    printf "%-2s:  %4.1f%%  %2d %-${width}s", $key, $letters{$key}/$count*100, $letters{$key}, 'x' x $letters{$key};
    if ($names) {print "   |  ", join (' ', @{$letnames{$key}});}
    print "\n";
  }
}

@scores=sort @scores;
print "@scores\n";

sub getletter {
#print "got $_[0], c2=$cutoffs[2], p=$possible, x=", $_[0]/$possible, "\n";
#  for ($i=0; $i<@cutoffs; $i++) {if ($_[0] >= $cutoffs[$i]) {return $letgrades[$i];}}
  for ($i=0; $i<@cutoffs; $i++) {if ($_[0]/$possible >= $cutoffs[$i]) {return 
$letgrades[$i];}}
}

