#!/usr/bin/perl
#  Copyright 2001-2012 Leslie Richardson

#  This file is part of Open Admin for Schools.

#  Open Admin for Schools 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.

# Passed Values: Student Number and Password

# Script: studentview.pl - show student marks from gradebook, from
# report cards, and attendance.

# Changes: Parse input password and name for correct character
# classes. Also user is a read only user for the database. Cannot
# write data.

my %lex = ('Attendance' => 'Attendance',
	   'Bad Password or Student Number!' => 'Bad Password or Student Number!',
	   'Nothing selected to view!' => 'Nothing selected to view!',
	   'Enter Student Viewer' => 'Enter Student Viewer',
	   'Student Number' => 'Student Number',
	   'Password' => 'Password',
	   'Student' => 'Student',
	   'Average' => 'Average',
	   'Test Average' => 'Test Average',
	   'Test Weight' => 'Test Weight',
	   'Attendance' => 'Attendance',
	   'Report Card' => 'Report Card',
	   'Gradebook' => 'Gradebook',
	   'Marks for' => 'Marks for',
	   'NA' => 'NA',
	   'No Subject Enrollments' => 'No Subject Enrollments',
	   'Subject' => 'Subject',
	   'Objectives' => 'Objectives',
	   'Term' => 'Term',
	   'Error' => 'Error',
	   'for' => 'for',
	   'Assessment' => 'Assessment',
	   'Group' => 'Group',
	   'Weight' => 'Weight',
	   'Score' => 'Score',
	   'Comment' => 'Comment',
	   'Grp Avg' => 'Grp Avg',
	   'Additional Comments' => 'Additional Comments',
	   'Error' => 'Error',
	   'Current Year GPA' => 'Current Year GPA',
	   'GPA' => 'GPA',
	   'No Quality Score for' => 'No Quality Score for',
	   'Show' => 'Show',
	   'Continue' => 'Continue',
	   'Please Log In' => 'Please Log In',
	   'Parent' => 'Parent',
	   'Main' => 'Main',
	   'Homeroom' => 'Homeroom',
	   'Teacher' => 'Teacher',
	   'Grade' => 'Grade',

	   );

my $self = 'viewattgbook.pl';


# Get etc directory location
#  Not useful
#eval require "parbase.conf";
#if ( $@ ) {
#    print "$lex{Error}: $@<br>\n";
#    die "$lex{Error}: $@\n";
#}

# The location to load the config file from.
my $configlocation = '../etc';

my $specchar = '*';  # causes this test to be skipped in calculating avg.
my $altcolor = '#3B7'; #1B6 Complement to the 063 green of teacher site.
my $commentcolor = 'yellow';


use DBI;
use CGI;
use CGI::Session;
use Date::Business;

eval require "$configlocation/admin.conf";
if ( $@ ) {
    print $lex{Error}. ": $@<br>\n";
    die $lex{Error}. ": $@\n";
}

eval require "$configlocation/gbook.conf";
if ( $@ ) {
    print $lex{Error}. ": $@<br>\n";
    die $lex{Error}. ": $@\n";
}
# get $defaultItemWeight from gbook.conf for the correct multiplier view


my $dsn = "DBI:$dbtype:dbname=$dbase";
my $dbh = DBI->connect($dsn,$rouser,$ropassword);
# Note change in user and password above.
#---------------------------------------

my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $iddst) = localtime(time);
$year = $year + 1900;
$mon++;
$wday++;
$currdate = "$dow[$wday], $month[$mon] $mday, $year";

my $q = CGI->new;
my %arr = $q->Vars; # Get passed values


# Get Session
my $session = new CGI::Session("driver:$dbtype;serializer:FreezeThaw",
 undef,{Handle => $dbh}) or die CGI::Session->errstr;

if ( not $session->param('logged_in') ){

    my $userid = $session->param('userid');
    print $q->header( -charset, $charset );
    print "<h1>$title</h1>\n";

    print "<form action=\"plogin.pl\" method=\"post\" style=\"padding:0 2em;\">\n";
    print "<input type=\"hidden\" name=\"script\" value=\"$self\">\n";
    print "<input type=\"hidden\" name=\"userid\" value=\"$userid\">\n";
    print "<input type=\"submit\" value=\"$lex{'Please Log In'}\">\n";
    print "</form>\n";

    print "</body></hmtl>\n";
    exit;
}


my $userid = $session->param('userid');
my $duration = $session->param('duration');

$session->expire('logged_in', $duration );
print $session->header( -charset, $charset );

# print page header
my $title = "$lex{Student} $lex{Attendance}/$lex{'Report Card'}/$lex{Gradebook}";

print "$doctype\n<html><head><title>$title</title>
<link rel=\"stylesheet\" href=\"$parcss\" type=\"text/css\">\n";
print "<style type=\"text/css\">
    .nameheader { font-size:130%;font-weight:bold;}
</style>\n";
print "$chartype\n</head><body style=\"padding:1em;\">\n";

print "[ <a href=\"$g_parpage\">$lex{Parent} $lex{Main}</a> ]\n";



if ( not $arr{page} ) {
    showStartPage();

} else {
    delete $arr{page};
    showResults();
}




#----------------
sub showStartPage {
#----------------

    print "<form action=\"$self\" method=\"post\">\n";
    print "<input type=\"hidden\" name=\"page\" value=\"1\">\n";

    print "<table cellpadding=\"3\" cellspacing=\"0\" border=\"0\">\n";

    print "<tr><td></td><td><input type=\"submit\" value=\"$lex{Continue}\"></td></tr>\n";

    # Choices: Attendance, Report Card, Gradebook
    print "<tr><td class=\"bra\">$lex{Show} $lex{Attendance}</td>\n";
    print "<td><input type=\"checkbox\" name=\"attendance\" value=\"1\"></td></tr>\n";

    print "<tr><td class=\"bra\">$lex{Show} $lex{'Report Card'}</td>\n";
    print "<td><input type=\"checkbox\" name=\"reportcard\" value=\"1\"></td></tr>\n";

    print "<tr><td class=\"bra\">$lex{Show} $lex{'Gradebook'}</td>\n";
    print "<td><input type=\"checkbox\" name=\"gradebook\" value=\"1\"></td></tr>\n";

    print "<tr><td></td><td><input type=\"submit\" value=\"$lex{Continue}\"></td></tr>\n";

    print "</table></form></body></html>\n";

    exit;

} # end of showStartPage



#--------------
sub showResults {
#--------------


    if ( not $arr{attendance} and not $arr{reportcard} and not $arr{gradebook} ){
	print "<center><h1>". $lex{'Nothing selected to view!'}. "</h1>\n";
	print "</center></body></html>\n";
	exit;
    }


    if ( $arr{attendance} ){ # Show Child's Attendance
	print "<h1 style=\"border-bottom:1px solid gray;\">". $lex{Attendance}. "</h1>\n";
	showAttendance( $userid );
    }

    if ( $arr{reportcard} ){ # Show Report Card Marks
	print "<h1 style=\"border-bottom:1px solid gray;\">". $lex{'Report Card'}. "</h1>\n";
	showReportCard( $userid );
    }

    if ( $arr{gradebook} ){ # Show Gradebook Marks
	showGradebook( $userid );
    }

    print "</center></body></html>\n";

    exit;

} 


#-----------------
sub showAttendance { # Show student attendance
#-----------------

    my $studnum = shift;

    $maxlines = 28;
    $shortname = "attprofile$$";
    $fileName = "$shortname.tex";

    # Set AM/PM Hash for use converting 2 period day to AM/PM
    %ampm = ( 1 =>'AM', 2 =>'PM');

    # date variables: start and end dates for period of interest. 
    # (start of year to date for this student.)
 
    my $startdate = $schoolstart; # global variable from admin.conf

    my ($syear,$smo,$sday) = split /-/,$startdate;
    $startdate = "$syear$smo$sday";

    # current date
    @tim = localtime(time);
    my $eyear = @tim[5] + 1900;
    my $emonth = @tim[4] + 1;
    my $eday = @tim[3];
    if (length($emonth) == 1){ $emonth = "0".$emonth;}
    if (length($eday) == 1){ $eday = "0".$eday;}
    $enddate = "$eyear$emonth$eday";
    
    # Format Year End date and compare.
    my ( $yeyear, $yemonth, $yeday ) = split /-/, $schoolend;
    if (length($yemonth) == 1){ $yemonth = "0".$yemonth;}
    if (length($yeday) == 1){ $yeday = "0".$yeday;}
    my $yearenddate = "$yeyear$yemonth$yeday";

    # Reset end date if past end of school year
    if ( $enddate > $yearenddate ) {
	$enddate = $yearenddate;
    }


    # Get student data; not needed until family groupings done.
    $sth = $dbh->prepare("select * from student where studnum = ?");
    $sth->execute( $studnum );
    if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
    my @student = $sth->fetchrow;


    #for ($st=1; $st<=$rows; $st++) {  # Loop through all students
    #while (@student = $sth->fetchrow){

    $tardyu = 0;
    $absentu = 0;
    $totalu = 0;
   

    # Done once per loop to carry updated start date from later enrollment.
    $loopstartdate = $startdate;
    $loopenddate = $enddate;
 
    # Fetch Enrollment/Withdrawal Changes
    $sth3 = $dbh->prepare("select * from transfer  where 
     studnum = '$student[4]' and 
     to_days(date) >= to_days('$loopstartdate') and 
     to_days(date) <= to_days('$loopenddate') 
     order by date desc");

    $sth3->execute;
    if ($DBI::errstr) { print $DBI::errstr; die; }
 
    while ( @entryrecord = $sth3->fetchrow ) {
	foreach  $rec (@entryrecord){
	    $rec =~ s/:/-/g;
	    $rec =~ s/&/\\&/g;
	    $rec =~ s/#//g;
	    $rec =~ s/$//g;
	}
	push @entries, "$entryrecord[2]:$entryrecord[3]:$entryrecord[4]";
	
	if ($entryrecord[3] eq "enrol" or $entryrecord[3] eq "re-enrol"){
	    # Change the start date, format in YYYY-MM-DD
	    ($year,$mo,$day) = split /-/,$entryrecord[2];
	    if (length($day)<2) { $day = "0".$day;}
	    if (length($mo)<2) { $mo = "0".$mo; }
	    $loopstartdate = "$year$mo$day";
	}
    } # End of Entry/Withdrawal Records  

    # Now figure out the number of schools days for this student
    $end = new Date::Business(DATE=>$loopenddate);
    $start = new Date::Business(DATE=>$loopstartdate);

    $schooldays = $end->diffb($start,'prev','next');
    $schooldays++; # Increment since we want number of days, not just diff.
    # These two settings are REQUIRED to get the elapsed day calculations.
    # I did a lot of head scratching on this one...(used lots of paper too...)

    # Now find number of holidays during this same period.
    $sth4 = $dbh->prepare("select * from dates 
     where to_days(date) >= to_days('$loopstartdate') and 
     to_days(date) <= to_days('$loopenddate')");
    $sth4->execute;
    if ($DBI::errstr) { print $DBI::errstr; die; }
    $holidays = $sth4->rows;

    $schooldays = $schooldays - $holidays;

    # Now format start and end dates.
    $year = substr($loopstartdate,0,4);   
    $mo = substr($loopstartdate,4,2);
    $day = substr($loopstartdate,-2,2);
    $fmtstartdate = "$month[$mo] $day, $year";

    $year = substr($loopenddate,0,4);   
    $mo = substr($loopenddate,4,2);
    $day = substr($loopenddate,-2,2);
    $fmtenddate = "$month[$mo] $day, $year";

    # Print School Days and Dates Info
    print "<table cellspacing=\"0\" cellpadding=\"3\" border=\"1\">\n";
    print "<tr><td class=\"bra\"><b>Start Date</b></td>
     <td> $fmtstartdate</td></tr>\n";
    print "<tr><td class=\"bra\"><b>Ending Date</b></td>
     <td>$fmtenddate</td></tr>\n";
    print "<tr><td class=\"bra\"><b>School Days</b></td>
     <td>$schooldays</td></tr>\n";
    print "</table><p></p>\n";

    # Print Any Enrollment Changes
    if (@entries){
	print "<table cellspacing=\"0\" cellpadding=\"3\" border=\"1\">\n";
	print "<caption>Enrollment Changes</caption>\n";
	print "<tr><th>Date</th><th>Type</th><th>Description</th></tr>\n";
	foreach my $entry (@entries){
	    my ($date,$type,$desc) = split /:/,$entry;
	    print "<tr><td>$date</td><td>$type</td><td>$desc</td></tr>\n";
	}
    }
    print "</table><p></p>\n";


    # Fetch Attendance Records by Days
    $sth1 = $dbh->prepare("select distinct absdate, count(absdate) 
     from attend  
     where studentid = '$student[4]' and 
     to_days(absdate) >= to_days('$startdate') and 
     to_days(absdate) <= to_days('$enddate') 
     group by absdate  order by absdate");

    $sth1->execute;
    if ($DBI::errstr) { print $DBI::errstr; die; }

    print "<table cellspacing=\"0\" cellpadding=\"3\" border=\"1\">\n";
    print "<caption>Attendance by Days</caption>\n";
    print "<tr><th>Date</th><th>Periods Missed</th></tr>\n";

    while (my ($absdate,$count) = $sth1->fetchrow){
	print "<tr><td>$absdate</td><td>$count</td></tr>\n";
    }
    print "</table><p></p>\n";


    # Fetch Attendance Records by Subjects
    $sth1 = $dbh->prepare("select distinct subjsec, count(subjsec) 
     from attend  
     where studentid = '$student[4]' and 
     to_days(absdate) >= to_days('$startdate') and 
     to_days(absdate) <= to_days('$enddate') 
     group by subjsec  order by subjsec");

    $sth1->execute;
    if ($DBI::errstr) { print $DBI::errstr; die; }

    print "<table cellspacing=\"0\" cellpadding=\"3\" border=\"1\">\n";
    print "<caption>Attendance by Subject</caption>\n";
    print "<tr><th>Subject</th><th>Periods Missed</th></tr>\n";

    while (my ($subject,$count) = $sth1->fetchrow){
	$sth2 = $dbh->prepare("select description from subject
         where subjsec = '$subject'");
	$sth2->execute;
	if ($DBI::errstr) { print $DBI::errstr; die; }
	my $description = $sth2->fetchrow;

	print "<tr><td>$description ($subject)</td><td>$count</td></tr>\n";
    }
    print "</table><p></p>\n";


    # Fetch Attendance Records
    $sth1 = $dbh->prepare("select * from attend  
     where studentid = '$student[4]' and 
     to_days(absdate) >= to_days('$startdate') and 
     to_days(absdate) <= to_days('$enddate') 
     order by absdate, period");

    $sth1->execute;
    if ($DBI::errstr) { print $DBI::errstr; die; }
    $absrows = $sth1->rows;

    # Get Teacher Values
    $sth2 = $dbh->prepare("select s.* from staff as s, staff_multi as sm 
      where s.userid = sm.userid and sm.field_name = 'homeroom' and sm.field_value = ?");
    $sth2->execute( $student[6] );
    if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
    @teacher = $sth2->fetchrow;
  


    if ($pdf){ # not defined.... yet.
	print TEX "\\center {\\sf\\huge $schoolname Attendance Profile} \\\\";
	print "\\bigskip\n\n {\\Large $student[2] $student[1]}\\\\ \n";
	print "\\bigskip\n \\begin{tabular}{r|l} \\hline\n";
	print "Teacher:& $teacher[1] $teacher[3] $teacher[2]\\\\ \n";
	print "Homeroom:& $student[6]\\\\ \n \\hline";
	print "Start Date:& $fmtstartdate \\\\\nEnd Date:& $fmtenddate \\\\";
	print "School Days: & $schooldays \\\\\n\\hline\n\\end{tabular}\\\\";
	print "\n\\bigskip";
    }

    
    if ($entryrecs > 0 and $pdf) {  # then print entry/withdrawals
	print TEX "\\hrulefill\\\\\n{\\large\\sf Enrollment Changes}\n\n";
	print TEX "\\begin{tabular}{lll}\n";
     
	foreach my $entryrec (@entries){
	    ($edate,$etype,$edesc) = split(/:/,$entryrec);
	    print TEX "$edate & $etype & $edesc \\\\ \n";   
	}
     
	print TEX "\\end{tabular}\n\n \\medskip \n";
    }

    # Now print the periods absent.
    # Calculate periods into days 
    $periods = $g_ppd{ $student[5] };
    if (not $periods){  
	# We don't have this grade's periods defined: fatal error
	print "<p>Error: The periods per day variable: g_ppd is not defined ";
	print "in the global configuration file for this student:</p><p>";
	print "$student[2] $student[1] in grade: $student[5]</p>\n";
	print "</body></html>\n";
	die;
    }
    
    if ($absrows > 0 ) {  # then we have absences.
	print TEX "\\hrulefill\n\n\\setlength{\\premulticols}{5pt}\n";
	print TEX "\\setlength{\\postmulticols}{5pt}\n\\begin{multicols}{2}";
	print TEX "\\raggedright";
     
	while (@abs = $sth1->fetchrow){

	    # Convert to AM/PM format if 2 periods per day
	    if ($periods == 2){  # $periods defined on line 399 above
		$abs[4] = $ampm{$abs[4]}; # ampm hash defined at top.
	    }

	    # Fixes for crud in reasons for attendance.
	    $abs[3] =~ s/[^A-Za-z\s]//g;
	    $abs[3] =~ s/(\w+)/\u\L$1/g;

	    if ($abs[3] eq '$g_LateUnexcused') {
		$tardyu++;
	    }
	    if ($abs[3] eq '$g_LateUnexcused' or 
		$abs[3] eq '$g_LateExcused') {
		$tardytot++;
	    }

	    if ($abs[3] eq '$g_AbsentUnexcused') {
		$absentu++;
	    }

	    if ($abs[3] ne '$g_LateUnexcused' and 
		$abs[3] ne '$g_Late Excused') {
		$absenttot++;
	    }

	    #print TEX "$abs[2]-$abs[4] $abs[3] \\\\ \n";
	    #print "$abs[2]-$abs[4] $abs[3] \\\\ \n";

	}

	$daysabsentu = $absentu/$periods;
	$daysabsenttot = $absenttot/$periods;
	
	$daysabsente = $daysabsenttot - $daysabsentu;
	$tardye = $tardytot - $tardyu;

	print TEX "\\end{multicols}\n\n\\hrulefill\n\n\\bigskip\n";
	print TEX "\\begin{tabular}{r|l}\\hline\n";
	print TEX "Late Unexcused & $tardyu times \\\\\n";
	print TEX "Late Excused & $tardye times \\\\\n";
	print TEX "Total Late & $tardytot times \\\\ \\hline\n";
	print TEX "Absent Unexcused & $daysabsentu days \\\\\n";
	print TEX "Absent Excused & $daysabsente days \\\\\n";
	print TEX "Total Absent & $daysabsenttot days \\\\\n";
	print TEX "\\hline\n \\end{tabular}\n\\newpage \n\n";
    } else {  # Perfect Attendance
	print TEX "\\bigskip {\\huge Perfect Attendance!} \\newpage \n\n";
    }


    # } # End of Student Loop - Family

    if ($pdf){
	print TEX "\\end{document}";
	close TEX;
	system("$pdflatex $fileName >/dev/null ");
	system("cp $shortname.pdf $downloaddir");
	system("rm $shortname.*");
	
	print "<h1><a href=\"/download/$shortname.pdf\">View/Download";
	print " Attendance Profiles</a></h1>";
    }


} # End of Show Attendance



#----------------
sub showGradebook {
#----------------

    my $studnum = shift;

    # Get Student Name
    my $sth = $dbh->prepare("select lastname, firstname from studentall where studnum = ?");
    $sth->execute($studnum);
    if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
    my ($lastname, $firstname) = $sth->fetchrow;


    # Get the Subjects this student takes (in eval table); put in %subject array.
    $sth = $dbh->prepare("select distinct eval.subjcode, subject.description
     from eval, subject where eval.subjcode = subject.subjsec and 
     eval.studnum = ? and  subject.visible = 'Y'");
    $sth->execute($studnum);
    if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
    my %subject;
    while ( my ($subjsec, $desc) = $sth->fetchrow ) { 
	$subject{$subjsec} = $desc; 
    }

    print "<h1 style=\"border-bottom:1px solid gray;\">". $lex{Gradebook};
    print " &ndash; $firstname $lastname</h1>\n";


    # loop through each subject
    foreach my $subjsec (keys %subject){

	# Lookup tests for this subject-section.
	my (@test, %weight, %maxscore);
	$sth = $dbh->prepare("select name, id, score, weight, description, grp 
          from gbtest where subjsec = ? order by grp, tdate desc");
	$sth->execute( $subjsec );
	if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
	while ( my ($name,$id,$score,$weight,$desc,$grp) = $sth->fetchrow ) {
	    if ($name eq 'sortorder'){ next; }  # skip the 'sortorder' test
	    $name =~ s/://g; # strip colons, if any.
	    $desc =~ s/://g;
	    push @test, "$name:$id:$score:$desc:$grp";
	    $weight{$id} = $weight; # used for calculating averages.
	    $maxscore{$id} = $score;
	}
	# Now done putting in the tests.

	# Skip to next subject if no tests.
	if ( not @test ){ next; }


	# Load the group weights from the current subject; define %groupweight
	my %groupweight;
	$sth = $dbh->prepare("select markscheme from subject where subjsec = ?");
	$sth->execute( $subjsec );
	if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr; }
	my $markscheme = $sth->fetchrow;

	# build a %groupweight hash from values in markscheme.
	my @fields = split (/[\n|\r]/, $markscheme);
	foreach my $fld (@fields) { 
	    if ($fld) {
		#print "F:$fld<br>\n";
		my ($grp, $percent) = split /=/, $fld;
		$groupweight{$grp} = $percent;
	    }
	}


	my $avg = calcAverage($studnum, $subjsec, \%maxscore, \%weight, \%groupweight);

	# Print the table header
	print "<table cellpadding=\"3\" cellspacing=\"0\" border=\"1\">\n";

	print "<tr style=\"font-size:120%;font-weight:bold;background-color:#063;";
	print "color:white;padding:0.3em;\">\n";
	print "<td><b>$subject{$subjsec} ($subjsec)</b></td><td colspan=\"2\" ";
	print "align=\"center\">". $lex{Average};
	print " <b>$avg</b></td></tr>\n";


	print "<tr style=\"background-color:#DDD\"><th>". $lex{Assessment}. "</th>";
	#print '<th>'. $lex{Group}. "</th>\n";
	print "<th>". $lex{Weight}. "</th>\n";
	print "<th>". $lex{Score}. "</th></tr>\n";


	my ($totalweight,$totalscore);
	my $count = 1;
	my $currgroup = -1;
	my $first = 1;

	foreach my $test ( @test ){

	    my ($name, $id, $maxscore, $desc, $grp) = split /:/, $test;

	    $oldgroup = $currgroup;
	    $currgroup = $grp;

	    if ( $currgroup ne $oldgroup and not $first) {
		print "<tr style=\"background-color:#084;color:white;\">\n";
		print "<td><b>". $lex{Group}. "</b> $oldgroup</td>\n";
		print "<td  align=\"center\">$groupweight{$oldgroup}\%</td><td>\n";
		if ( $totalweight ) {
		    print $lex{'Grp Avg'};
		    #print $lex{Average};
		    my $groupavg = sprintf("%3.1f",100 * $totalscore / $totalweight);
		    print " $groupavg\%</td>\n";
		} else {
		    print $lex{'Grp Avg'}. " ". $lex{NA}. "\n";
		}
		$totalweight = 0;
		$totalscore = 0;
		print "</tr>\n";
	    } else {
		$first = 0;
	    }



	    my $color;
	    if ($count % 2) { $color = qq{style="background-color:#EEE;"}; }
	    $count++;

	    # Calc the weight as multiplier...
	    my $wtmult;
	    if ($defaultItemWeight) {
		$wtmult = sprintf("%3.2f",($weight{$id} / $defaultItemWeight));
	    }

	    print "<tr $color><td>$name - $desc</td><td align=\"center\">$wtmult\X</td>\n";


	    $sth = $dbh->prepare("select score, comment from gbscore 
             where testid = ? and studnum = ?");
	    $sth->execute( $id, $studnum );
	    if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
	    my ($score, $comment) = $sth->fetchrow;

	    my $testaverage;
	    if ( $score ne $specchar ){ #ie. skip calcs for specialchar
		$totalweight += $weight{$id};
		$totalscore += ( $weight{$id} * $score / $maxscore );
		$testaverage = $score / $maxscore * 100;

		print "<td>";
		printf "%3.1f", $testaverage;  
		print "% ($score/$maxscore)</td>";

	    } else {
		$testaverage = $lex{NA};
		print "<td align=\"center\"><b>$score</b> (x/$maxscore)</td>";
	    }
	    print "</tr>\n";

	    if ($comment) {
		print "<tr><td colspan=\"4\" style=\"background-color:$commentcolor\"><b>";
		print $lex{Comment}. "</b>: $comment</td></tr>\n";
	    }


	} # End of test loop

	# Print the Last Group Values
	print "<tr style=\"background-color:#084;color:white;\"><td><b>";
	print $lex{Group}. "</b> $currgroup</td>\n";
	print "<td  align=\"center\">$groupweight{$currgroup}\%</td><td>\n";
	if ( $totalweight ) {
	    print $lex{'Grp Avg'};
	    my $groupavg = sprintf("%3.1f",100 * $totalscore / $totalweight);
	    print " $groupavg\%</td>\n";
	} else {
	    print $lex{'Grp Avg'}. " ". $lex{NA}. "\n";
	}
	print "</tr>\n";


	print "</table><p></p>\n";

    } # End of this subject.


} # End of showGradebook




#-----------------
sub showReportCard {
#-----------------

    my $studnum = shift;

    # Get Student Name
    my $sth = $dbh->prepare("select lastname,firstname, grade, homeroom 
     from student where studnum = ?");
    $sth->execute($studnum);
    if ($DBI::errstr){ print $DBI::errstr; die;}
    my ($lastname, $firstname, $grade, $homeroom ) = $sth->fetchrow;


    # Get homeroom teacher, if any
    $sth = $dbh->prepare("select s.sal, s.lastname, s.firstname from staff s, staff_multi sm
      where sm.field_name = 'homeroom' and sm.field_value = ? and s.userid = sm.userid");
    $sth->execute( $homeroom );
    my ($tsal, $tlastname, $tfirstname) = $sth->fetchrow;

    my $teachername;
    if ( $tlastname ) { # we have a homeroom teacher.
	if ( $tsal ) { # use salutation
	    $teachername = "$tsal $tlastname";
	} else { # use firstname
	    $teachername = "$tfirstname $tlastname";
	}
    }



    # Get All Subject Information and put into hash with key as subjsec
    #  and value is pointer to the array.
    my %subject = ();
    $sth = $dbh->prepare("select * from subject");
    $sth->execute;
    if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr; }
    while ( my $subjref = $sth->fetchrow_hashref ) {
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	$subject{ $subjref->{subjsec} } = $subjref;
    }

    # Load the SupressSubject, AdditionalComments data
    $sth = $dbh->prepare("select datavalue from conf_system
     where dataname = ?");

    foreach my $val qw(r_SupressSubject r_AdditionalComments r_CalcGPA ) {
	$sth->execute( $val );
	if ( $DBI::errstr ){ print $DBI::errstr; die $DBI::errstr; }
	my $dv = $sth->fetchrow;
	eval $dv;
    }


    # TEST: Loop through and print each student
    #foreach my $key ( keys %subject ) {
    #    print "K: $key V: ", $subject{$key}->{description},"<br>\n";
    #}


    # Get the number of terms from the eval table
    $sth = $dbh->prepare("select max(term) from eval");
    $sth->execute;
    if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr; }
    $maxterm = $sth->fetchrow;

    # Print Student Name and Homeroom Teacher
    print "<div class=\"nameheader\">$firstname $lastname ($studnum)";
    
    if ( $teachername ) { # homeroom teacher
	print "<br>$lex{Homeroom} $lex{Teacher} &ndash; $teachername\n";
    }
    print "</div><p></p>\n";


    # Print Table Header
    print "<table cellpadding=\"3\" cellspacing=\"0\" border=\"1\">";


#    print "<tr><th>$lex{Subject}/$lex{'Objectives'}</th>\n";
#    for my $t (1..$maxterm){ print "<th>$g_TermDisplay{$g_DefaultTrack}{$t}</th>";}
#    print "</tr>\n";
    

    my %eval = ();

    # a)Find his/her subjects in order
    $sth = $dbh->prepare("select distinct e.subjcode, s.description, s.teacher
      from eval as e, subject as s where e.subjcode = s.subjsec and 
      e.studnum = ? order by s.sequence, s.description,e.subjcode");
    $sth->execute( $studnum );
    if ( $DBI::errstr ){ print $DBI::errstr; die $DBI::errstr; }
    
    my $sth1 = $dbh->prepare("select * from eval where subjcode = ? and
      studnum = ? order by term");

    # Get Teacher Name
    my $sth2 = $dbh->prepare("select sal, lastname, firstname from staff where userid = ?");

    my $subjflag = 0; # flag in case of no subj enrollments.


    while ( my ($subjsec, $desc, $userid ) = $sth->fetchrow ) { # Loop through each subject.

	# Skip Additional Comments or Supressed Subjects
	my ($tsubjcode, $dud) = split(/-/, $subjsec ); 
	if ( $r_SupressSubject{$tsubjcode} or $r_SupressSubject{$subjsec} or
	     $r_AdditionalComments{$tsubjcode} or $r_AdditionalComments{$subjsec} ) {
	    next; 
	}

	$subjflag = 1;

	my @eval = ();
	my @gpa = ();

	# Get Objectives Count for this subject; also # of loops
	my $objcount; # objective count
	for my $i (1 .. 20){
	    my $idx = 'q'. $i;
	    if ( $subject{$subjsec}->{$idx} ){ $objcount++; } else { last; }
	}

	# Get Teacher Name
	$sth2->execute( $userid );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; };
	my ($tsal, $tlastname, $tfirstname) = $sth2->fetchrow;
	my $teachername;
	if ( $tsal ) {
	    $teachername = "$tsal $tlastname";
	} else {
	    $teachername = "$tfirstname $tlastname";
	}

	# Loop through records for this subject
	$sth1->execute( $subjsec, $studnum ); # Find the records for this subject.
	while ( my @evalrec = $sth1->fetchrow ){ # Loop through eval recs.

	    # Code to Check for Term Errors
	    $prevterm = $currterm;
	    $currterm = $evalrec[4];
	    if ( $prevterm == $currterm ){ # We have an error!
		print $lex{Error}. q{ }. $lex{for}. " $lastname, $firstname ($studnum) ";
		print $lex{Subject}. " $desc ($subjsec) - ". $lex{Term}. " $currterm.<br>\n";
		print "Multiple records for the same term in the same subject! Please Fix!<br>\n";
	    }
	    
	    $eval[ $evalrec[4] ] = [ @evalrec ]; # store record; evalrec[4] is term. 
	    $gpa[ $evalrec[4] ] = $evalrec[7]; # a1 field.

	} # End of Eval Creation Loop

	$eval{$subjsec} = [ @gpa ]; # store for GPA calcs.

 	if ( @eval ) { # we have records...   

	    # Print Terms Line
	    print "<tr><th>$lex{Subject}/$lex{'Objectives'}</th>\n";
	    for my $t (1..$#eval){ print "<th>$g_TermDisplay{$g_DefaultTrack}{$t}</th>";}
	    print "</tr>\n";

	    # Subject (and possibly objectives) Lines
	    print "<tr style=\"background-color:#DDD\">";
	    print "<td><b>$subject{$subjsec}->{description}</b><br>$teachername</td>";

	    if ( $objcount == 0 ){ # No objectives... just marks (1 line)

		for ( 1..$#eval ) {
		    print "<td align=\"center\"><b>$eval[$_]->[7]</b></td>";
		}
		print "</tr>\n";

	    } else { # We have objectives listed

		# blank line with subject
		for ( 1..$#eval ){ print "<td></td>"; }
		print "</tr>\n";

		for ( my $i = 1; $i <= $objcount; $i++){ # of lines/objectives
		    my $subjindex = 'q'. $i;
		    my $evalindex = $i + 6;
		    print "<tr><td>$subject{$subjsec}->{$subjindex}</td>";
		    for ( 1..$#eval ){
			print "<td align=\"center\">";
			print "<b>$eval[$_]->[$evalindex]</b></td>";
		    }
		    print "</tr>\n";
		}
	    } # End of 'Objectives listed' - ie. not just marks.

	    # Now Print Comments
	    my $colcount = $#eval + 1;
	    print "<tr><td colspan=\"$colcount\">";
	    for my $trm ( 1..$#eval ){
		if ($eval[$trm]->[6]){
		    print "<i>$g_TermDisplay{$g_DefaultTrack}{$trm}:</i> $eval[$trm]->[6]<br>";
		}
	    }
	    print "</td></tr>\n";
	    
	}  # End of 'Do we have eval records?'

    } # Next Subject

    # Do GPA calcs and Display
    if ( %eval and $r_CalcGPA ) { 
	calcGPA( \%eval, $maxterm );
    }


    if ( not $subjflag ){ # No subject enrollments for this student.
	my $colcount = $maxterm + 1;
	print "<tr><td colspan=\"$colcount\"><b>$lex{'No Subject Enrollments'}</b></td></tr>\n";
    }
    print "</table>\n";
    

} # End of showReportCard



#----------
sub calcGPA {
#----------

    my $gpa_ref = shift;
    my $maxterm = shift;

    use Number::Format qw(:subs);

    eval require "$configlocation/transcript.conf";
    if ( $@ ) {
	print $lex{Error}. ": $@<br>\n";
	die $lex{Error}. ": $@\n";
    }

    # Get credit and difficulty values for each subject.
    my $sth = $dbh->prepare("select credit, difficulty from subject where subjsec = ?");
    my ($totalGPQuality, $totalGPCredits); # needed for overall at end.

    print "<tr style=\"font-size:130%;font-weight:bold;\"><td>". $lex{GPA}. "</td>\n";

    # Loop through each term calculating the GPA for each term...
    foreach my $term ( 1..$maxterm )  { #loop through all terms

	my ( $termCreditTotal, $termGPTotal );
	my ( $termCredits, $termAttempts ); # not used, yet. TermCredits includes P/F courses.
	my ( $termGPCredits, $termGPQuality );

	foreach my $subjsec ( keys %{$gpa_ref} ) {

	    if ( $gpa_ref->{$subjsec}[$term] ) {  # If we have a value for this term..

		my $mark = $gpa_ref->{$subjsec}[$term]; # could be letter or number...

		# Get Subject Data
		$sth->execute( $subjsec );
		if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; };
		my ($credit, $difficulty) = $sth->fetchrow;
		$credit = 1 if not $credit;
		if ( not $difficulty ) { $difficulty = 0; }

		# Convert the mark to a letter (and then to a quality score below...
		my $letter; # letter grade.
		if ( $mark =~ /[a-zA-Z]/ ) { # We have a 'letter' mark, copy into $letter 
		    $letter = $mark;
		} else { # find the matching letter for this numeric value..
		    foreach my $threshold (reverse sort keys %markToLetter ) { # large to small
			if ($mark >= $threshold) {
			    $letter = $markToLetter{$threshold};
			    # print "Mark: $mark Letter: $letter<br>\n";
			    last;
			}
		    }
		}

		# Now convert $letter to a quality score.
		# letterToQual hash in transcript.conf; add up quality scores and credit counts.
		# Check for missing Quality value in transcript.conf
		if ( ( not defined $letterToQual{ $letter } ) and 
		     ( $letter ne $passletter ) ) { 
		    print "<br>". $lex{'No Quality Score for'}. " $letter\n";
		    next; # skip to next subject. 
		}

		my $quality = $letterToQual{ $letter } + $difficulty;
		
		$termGPQuality += $quality * $credit;
		$totalGPQuality += $quality * $credit;

		$termAttempts += $credit;

		if ( $letter ne $failletter ) {
		    $termCredits += $credit;
		    $totalCredits += $credit;
		}

		# If not a fail and also not a pass/fail course
		if ( $letter ne $passletter ) {
		    $totalGPCredits += $credit;
		    $termGPCredits += $credit;
		}

		 #print "$subjsec $term ". $gpa_ref->{$subjsec}[$term]. "<br>\n";
		
	    } # End of If mark exists
	} # End of Subject Loop for this term.

	my $gpa;
	if ($termGPCredits) {
	    $gpa = format_number( ($termGPQuality / $termGPCredits ), 2 );
	} 
	else { $gpa = 0; }

	print "<td>$gpa</td>"; # change to GPA value...
    
    } # End of terms loop

    print "</tr>\n"; 


    my $cumgpa;
    if ($totalGPCredits) {
	$cumgpa = format_number( ($totalGPQuality / $totalGPCredits), 2 );
    } 
    else { $cumgpa = 0; }

    my $colspan = $maxterm + 1;
    print "<tr><td colspan=\"$colspan\">". $lex{'Current Year GPA'}. " $cumgpa</td></tr>\n";



} # end of calcGPA



#-----------------
sub calcAverage { # Latest method for Gradebook
#-----------------

    require strict;
    # needed: $maxscore{$id}, $weight{$id}, $groupweight{$grp}, $specchar
    my $specchar = '*';

    # Get Passed values.
    my ($studnum, $subjsec, $maxscore_ref, $weight_ref, $groupweight_ref) = @_; 
    
    # Yes, this is ugly... but don't want to rewrite the rest...
    my %maxscore = %{$maxscore_ref};
    my %weight = %{$weight_ref};
    my %groupweight = %{$groupweight_ref};

    #print "SN: $studnum SUB: $subjsec MScore:",%maxscore, " Weight: ";
    #print %weight, "GWt:",%groupweight,"<br>\n";


    my $totalweight;
    my $totalscore;

    # Get test info and test score (of that item) at same time.
    my $sth = $dbh->prepare("select gs.id, gs.testid, gs.score, gt.grp 
      from gbscore as gs, gbtest as gt 
      where gs.testid = gt.id and gt.name != 'sortorder' and  
      gs.studnum = ? and gt.subjsec = ?
      order by gt.grp");
    $sth->execute( $studnum, $subjsec );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

    my $currgrp = -1;
    my $oldgrp;
    my $first = 1;
    my $totalscore; # running total for score; zeroed for each new group.
    my $totalweight; # running total for weight; zeroed for each new group.
    my %groupscore;

    while (my ( $id, $testid, $score, $grp ) = $sth->fetchrow ) {

	$score =~ s/\s//g; # strip any spaces in score;
	if ($score eq $specchar or $score eq '' or not defined $score ) { next; } # skip

	$oldgrp = $currgrp;
	$currgrp = $grp;
	if ($currgrp ne $oldgrp and not $first) {
	    # setup group values for the current group
	    if ( $totalweight ) {
		$groupscore{$oldgrp} = $totalscore / $totalweight;
	    } else {
		$groupscore{$oldgrp} = 0;
	    }
	    $totalscore = 0;
	    $totalweight = 0;
	}
	if ($first) { $first = 0; }


	if ($score =~ /\d/) { # if score is a digit... do it.
	    if ($maxscore{ $testid }) {
		$totalscore += $score / $maxscore{$testid} * $weight{$testid};
	    } else {
		$totalscore = 0;
	    }
	    $totalweight += $weight{$testid};
	} else {
	    # some sort of text score...count as zero... update total weight.
	    $totalweight += $weight{$testid};
	}	    

	#print "TS: $totalscore TW:$totalweight GP:$grp<br>\n";

    } # End of Scores Loop


    # Get Last group, if any;
    if ($totalweight) { 
	$groupscore{$currgrp} = $totalscore / $totalweight;
    }
    $totalscore = 0; # necessary?
    $totalweight = 0; # necessary?

    #foreach my $key (keys %groupscore) { print "K: $key GS: $groupscore{$key}<br>\n"; }

    # Add up the group scores and weight them for overall average
    foreach my $grp (keys %groupscore) {
	$totalscore += $groupscore{$grp} * $groupweight{$grp};
	#print "GS: $groupscore{$grp} GW:$groupweight{$grp}<br>\n";
	$totalweight += $groupweight{$grp};
    }

    #print "TS:$totalscore TW:$totalweight<br><br>\n";
    if ($totalweight) { 
	return sprintf("%3.1f", 100 * $totalscore / $totalweight). '%';
    } else {
	return 0;
    }


} # End of CalcAverage (new version)
