#!/usr/local/bin/perl
# exam statistics for CAPA
#  Copyright (C) 1992-2000 Michigan State University
#
#  The CAPA system is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation; either version 2 of the
#  License, or (at your option) any later version.
#
#  The CAPA system is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public
#  License along with the CAPA system; see the file COPYING.  If not,
#  write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
#  Boston, MA 02111-1307, USA.
#
#  As a special exception, you have permission to link this program
#  with the TtH/TtM library and distribute executables, as long as you
#  follow the requirements of the GNU GPL in regard to all of the
#  software in the executable aside from TtH/TtM.


#
# June 17 1997 by Isaac Tsai
#

  require('getopts.pl');
  $Usage = "USAGE: examanalysis.pl [-s start_set][-t end_set]";
#
# ask user to enter the absolute path to the class
#
  sub  S_Enterpath {
    local($set,$to)=@_;
    local($notdone,$path);
    local($cfullpath);
    
    $notdone = 1;
    while ($notdone) {
      print "Please enter the CLASS absolute path:\n";
      $path = <>; chomp($path);
      if( $path =~ /\/$/ ) {            # check if the path entered contains a trailing /
        $Cfullpath = "$path" . "classl";
        $Rfullpath = "$path" . "records";
        $Sfullpath = "$path" . "records/set$set.db";
      } else {
        $Cfullpath = "$path" . "/classl";
        $Rfullpath = "$path" . "/records";
        $Sfullpath = "$path" . "/records/set$set.db";
      }
      if( -d $path ) {           # check if the class directory exists
        if( -d $Rfullpath ) {    # check if the records directory exists
          if( -f $Sfullpath ) {  # check if the setX.db file exists
            $notdone = 0;
          } else {
            print "File [$Sfullpath] does not exist!\n";
          }
        } else {
          print "Directory [$Rfullpath] does not exist!\n";
        }
      } else {
        print "Directory [$path] does not exist!\n";
      }
    
    }
    return ($path);
  }

#
#  scan the setX.db file
#
  sub S_ScanDB  {
    local($filename,$idx)=@_;
    local($line_cnt)=0;
    local($valid_cnt)=0;
    local($valid);
    local($ii);
    local($head,$s_num,$ans_str,$rest);
    local(@ans_char,@tries);
    local($score,$Snum);
    
    open(IN, "<$filename") || die "Cannot open $filename file!";
    while (<IN>) {
      $line_cnt++;             # line count in setX.db file
      if( $line_cnt == 2 ) {   # the second line is the weight information
        chomp();   
        (@Weight) = split(/ */);  # split the weight string into an integer array
      }
      if( $line_cnt > 3) {     # valid student record begins with the fourth line
        chomp();               # remove the trailing \n
        ($head,$rest) = split(/,/,$_,2); #  split the entry based on the first comma
        ($s_num,$ans_str) = split(/ /,$head,2); # split the head part based on space char
        
        (@ans_char) = split(/ */,$ans_str);   # split the answer string into an array of chars
        (@tries)    = split(/,/,$rest);       # split the number of tries string into an array of integer
        for($valid = 'N', $ii=0;$ii<=$#ans_char;$ii++) {  # if all char in the answer is '-', mark it as invalid
            $valid = 'Y'  if $ans_char[$ii] ne '-';
        }
        if( $valid eq 'Y' ) {                 # a valid entry, contains some scoring info  
          for($score=0,$ii=0;$ii<=$#ans_char;$ii++) {  # number of elements in the answer char array
            if($ans_char[$ii] eq 'Y') {       # big Y, score adds the weight of that problem
              $score += $Weight[$ii];
            }
            if($ans_char[$ii] eq 'y') {       # small y, score adds the weight of that problem
              $score += $Weight[$ii];
            }
            if( $ans_char[$ii] >= 0 && $ans_char[$ii] <= 9) { # hand graded problem has numerical value
              $score += $ans_char[$ii];
            }
          }
          $Snum = uc($s_num);     # uppercase the student number
          $$Snum[$idx] = $score;  # put the score into an array named as the student number and indexed by
          $valid_cnt++;           #   offset of set in the scoring report
        }
      }
    }
    close(IN) || die "Cannot close $filename file!";
    return ($#tries+1,$valid_cnt);
  }
#        1         2         3         4     -   5         6         7         8
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
#nnnnnnnnnnnnnnnnn aaaaaaaaa sec                 scor    scor    scor
#
# produce the scoring report based on entries from classl file
#
  sub S_ClassRpt {
    local($filename)=@_;
    local($code,$cn,$sec,$sid,$sname);
    local($a_line,$cnt,$i);
    local($score,$len,$pad);
    local($sm,$Snum);
    
    open(IN, "<$filename") || die "cannot open file $filename!\n";
    while(<IN>) { 
      $a_line = $_;    # each line in the classl file
      ($code,$cn,$sec,$sid,$sname) =  split(/\s+/,$a_line,5);  # use space to divide each field
      chomp($sname); # chop off the last \n
      $len = length($sname); # student name length
      if( $len < 18 ) {      # if name is less than 18 characters, padded to 18 chars
        $pad = 18 - $len;
        $sm = "$sname" . " " x $pad;
      } else {               # more than 18 chars, take the first 18 characters
        $sm = substr("$sname",0,18); # take the first 18 characters
      }
      printf "%s %s %03d             ", $sm,$sid,$sec; # print out student name, student number, section
      $Snum = uc($sid);  # uppercase the student number
      if( defined @{$Snum} ) { # if we have the scores for this student
        $cnt = $#{$Snum};      #   the number of sets in this scoring array
        for($i=0;$i<=$cnt;$i++) {  # loop through the number of sets
          $score = $$Snum[$i];     # assign the score to a variable, (extra step)
          printf "    %4d", $score;
        }
      }
      print "\n";   # at the end of the record, place an \n
    }
    close(IN) || die "cannot close file $filename!\n";
  }
  
  
  if(! &Getopts('s:t:') ) {
     print STDERR "$Usage\n";
     exit 2;
  }
  
  if( (!$opt_s) || ($opt_s <= 0 )  ) {
    $opt_s = 1;
  }
  if( (!$opt_t) || ($opt_t <= 0 ) ) {
    $opt_t = 1;
  }
  if( $opt_t < $opt_s ) {
    $tmp   = $opt_t;
    $opt_t = $opt_s;
    $opt_s = $tmp;
  }
  $CPath = S_Enterpath($opt_s,$opt_t);  # get the class path
  
  for($set_idx=$opt_s;$set_idx<=$opt_t;$set_idx++) {  # loop through each set
    $set_offset = $set_idx - $opt_s;
    $fullpath = "$CPath" . "/records/set$set_idx.db";
    S_ScanDB("$fullpath",$set_offset);
  }
  
  S_ClassRpt("$Cfullpath");   # produce the scoring report
  
  
  
  
