#! /usr/bin/perl
#  Copyright 2001-2023 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.

# Outline: Print the report cards for a single grade or homeroom.

# Customizations: Note ANY customizations for this school here
#  along with line numbers and/or markers to find them...

my %lex = ('Main' => 'Main',
	   'Report Cards' => 'Report Cards',
	   'Report Card' => 'Report Card',
	   'Report to Parents' => 'Report to Parents',
	   'Grade' => 'Grade',
	   'Teacher(s)' => 'Teacher(s)',
	   'Evaluation and Comment Key' => 'Evaluation Key',
	   'Class Average' => 'Class Average',
	   'Attendance' => 'Attendance',
	   'Days Enrolled' => 'Days Enrolled',
	   'Days Absent' => 'Days Absent',
	   'General Comments' => 'General Comments',
	   'Term' => 'Term',
	   'Teacher' => 'Teacher',
	   'Principal' => 'Principal',
	   'Please tear off this portion and return it to the school' =>
	     'Please tear off this portion and return it to the school',
	   'in the report envelope with any comments and your signature' =>
	     'in the report envelope with any comments and your signature',
	   'Parent/Guardian Signature' => 'Parent/Guardian Signature',
	   'Student' => 'Student',
	   'Comments' => 'Comments',
	   'Days per Month Override' => 'Days per Month Override',
	   'Homeroom' => 'Homeroom',
	   'Days Open' => 'Days Open',
	   'Month' => 'Month',
	   'Continue' => 'Continue',
	   'Duplicate Evaluation Record' => 
	      'Duplicate Evaluation Record',
	   'Average' => 'Average',
	   'No Quality Score' => 'No Quality Score',
	   'Error' => 'Error',
	   'Printed' => 'Printed',
	   'Override Term Days' => 'Override Term Days',
	   'Font Size' => 'Font Size',
	   'One Student per File' => 'One Student per File',
	   'GPA' => 'GPA',
	   'Current Year GPA' => 'Current Year GPA',
	   'Phone' => 'Phone',
	   'Fax' => 'Fax',
	   'Vice-Principal' => 'Vice-Principal',
	   'Periods' => 'Periods',
	   'Evaluation Key' => 'Evaluation Key',
	   'Select Subjects' => 'Select Subjects',
	   'For Duplexing/Stapling' => 'For Duplexing/Stapling',
	   'Show Withdrawn Students' => 'Show Withdrawn Students',
	   'Subject' => 'Subject',
	   'Mark' => 'Mark',
	   'Printing Date' => 'Printing Date',
	   'Absent' => 'Absent',
	   'Late' => 'Late',
	   'Paper Size' => 'Paper Size',
	   'Start Term' => 'Start Term',
	   'End Term' => 'End Term',
	   'Rank' => 'Rank',
	   'Demerits' => 'Demerits',
	   'Skipping' => 'Skipping',
	   'Undefined Value' => 'Undefined Value',
	   'Not Found' => 'Not Found',
	   'Picture' => 'Picture',
	   'Email' => 'Email',

	   'OR' => 'OR',
	   'Form' => 'Form',

	   );

use DBI;
use CGI;
use CGI::Session;
use Cwd;
use Number::Format qw(:all);
use Carp;
use Time::JulianDay;

my $deleteTeX = 1;
my $showwithdrawn = 0;

# Non School Day Grades
my %nonschoolgrades = ('K' => 1,'PK' => 1,'P3' => 1);


my $self = 'repcardCapture.pl';

# Get school list from central configuration
eval require "../admin.conf";
if ( $@ ) {
    print $lex{Error}. ": $@<br>\n";
    die $lex{Error}. ": $@\n";
}


my $q = new CGI;
my %arr = $q->Vars;
my $configpath;

print $q->header( -charset, $charset );


# Print HTML Page Header
my $title = "Capture $lex{'Report Cards'}";
print qq{$doctype\n<html><head><title>$title</title>\n};
print qq{<link rel="stylesheet" href="$css" type="text/css">\n};

print qq{$chartype\n</head><body>\n};
print qq{[ <a href="$homepage">$lex{Main}</a> | \n};

print qq{<h1>$title</h1>\n};




# %alldbase have schools
# %alldbase = (%alldbase, %nontsec);

# Testing single school.
# %alldbase = ('chiefnapew' => 1);

foreach my $db ( sort keys %alldbase ) {

    print "\nDB:$db\n\n";
    sleep(5);
    
    $configpath = qq{/opt/openadmin/$db};
    my $repcardDir = qq{/opt/openadmin/$db/admin/reportcard};

# Uncomment this to remove existing values, rather than just add on.    
    system("rm -rf $repcardDir");
    
    if ( not -d $repcardDir ) { # create the report card directory
	use File::Path qw{make_path};
	my %options = ('owner' => 'www-data');
	eval { make_path($repcardDir, \%options) };
	if ( $@ ) {
	    print qq{Could not create $repcardDir: $!\n}; exit;
	}
    }

    
    # Setup all variables required to do full capture of report card.
    # Get all the grades;


    # main config file
    eval require "$configpath/etc/admin.conf";
    if ( $@ ) {
	print $lex{Error}. ": $@<br>\n";
	die $lex{Error}. ": $@\n";
    }


    my $dsn = "DBI:$dbtype:dbname=$dbase";
    $dbh = DBI->connect($dsn,$user,$password);

    
    # populate jdclosed with dates from dates table; used by calcTermDays;
    my %jdclosed;
    my $sth = $dbh->prepare("select date, dayfraction from dates 
			    where date is not NULL and date != ''");
    $sth->execute;
    if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
    
    while ( my ( $date, $dayfraction ) = $sth->fetchrow ) {
	my $jd = julian_day( split( '-', $date ) );
	$jdclosed{$jd} = $dayfraction;
    }


    # load report card configuration
    my $sth = $dbh->prepare("select id, datavalue from conf_system where filename = 'repcard' 
			    order by dataname");
    $sth->execute;
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    while (	my ($id, $datavalue) = $sth->fetchrow ) {
	eval $datavalue;
	if ( $@ ) {
	    print "$lex{Error}: $@<br>\n";
	    die "$lex{Error}: $@\n";
	}
    }


    # LaTeX filter function
    eval require "$configpath/lib/liblatex.pl";
    if ( $@ ) {
	print $lex{Error}. ": $@<br>\n";
	die $lex{Error}. ": $@\n";
    }

    # attendance library functions
    eval require "$configpath/lib/libattend.pl";
    if ( $@ ) {
	print $lex{Error}. ": $@<br>\n";
	die $lex{Error}. ": $@\n";
    }

    # Set Date
    # my ( $currsdate, $currdate);
    if ( not $arr{date} ) {
	my ($sec, $min, $hour, $mday, $mon, $year, $wday, 
	    $yday, $iddst) = localtime(time);
	$year = $year + 1900;
	$mon++;
	$wday++;
	if ( length($mon) == 1 ) { $mon = '0'. $mon; }
	if ( length($mday) == 1 ) { $mday = '0'. $mday; }
	$currdate = "$year-$mon-$mday";
	$currsdate = "$year-$mon-$mday";
	

    } else { # we have a passed value;
	my ( $yr, $mo, $da ) = split('-', $arr{date});
	if ( length($mo) == 1 ) { $mo = '0'. $mo; }
	if ( length($da) == 1 ) { $da = '0'. $da; }
	$currsdate = "$yr-$mo-$da";
	$currdate = "$month[$mo] $da, $yr";
    }
    
    # Get the Terms.
    my ($startterm, $endterm);
    my $sth = $dbh->prepare("select max(term) from eval");
    $sth->execute;
    if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
    my $maxterm = $sth->fetchrow;
    if ( not $maxterm ) { next; } # next school
#    print "Max Term:$maxterm\n";
    if ( $maxterm > 6 ) { # only do 4 or 5 terms
	$startterm = 4;
    } else {
	$startterm = 1;
    }
    $endterm = $maxterm;


    # Get the grades to print 
    my $sth = $dbh->prepare("select distinct grade, CAST(grade as SIGNED) as castgrade from student 
			    where grade is not NULL and grade != '' order by castgrade");
    $sth->execute;
    if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
    while ( my ($grade,$cast) = $sth->fetchrow ) { # loop through all grades

#	print "Grade:$grade Date:$currsdate STerm:$startterm ETerm:$endterm\n";

	my ($group, $groupid, $nsdflag );
	$group = 'grade';
	$groupid = $grade;

	delete $arr{grade};
	delete $arr{homeroom};

	$fontsize = '10pt';
	
#	my $showwithdrawn = $arr{showwithdrawn};
#	my $startterm = $arr{startterm};
#	my $endterm = $arr{endterm};

	$oneStudentPerFile = 1;


	# Set Paper Size, text width and height
	$papersize = 'letterpaper';
	$textwidth = $g_letterpaper_textwidth;
	$textheight = $g_letterpaper_textheight;
	

	# Set the Track.
	my $track;
	$track = $g_MTrackTermType{ $groupid };

	# Show withdrawn students, as well, if they have data.
	if ( $showwithdrawn ) {
	    $studenttable = 'studentall';
	} else {
	    $studenttable = 'student';
	}


	# Get a grade in order to get correct PPD (Periods per day that attendance is done).
	$periodsperday = $g_ppd{$groupid};


	my %homeroomTeachers; # homeroomTeachers{homeroom} = @names.
	if ( $r_ShowHomeroomTeacher ) {  # set in repcard.conf

	    # Get all homeroom userid values.....
	    my %rooms;
	    my $sth1 = $dbh->prepare("select sal, firstname, lastname from staff where userid = ?");
    
	    my $sth = $dbh->prepare("select id, userid, field_value from staff_multi 
				    where field_name = 'homeroom'");
	    $sth->execute;
	    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	    while ( my ($id, $userid, $hr) = $sth->fetchrow ) {
		if ( not $userid or not $hr ) { next; } # just in case....
		$rooms{$hr}{$userid} = 1;
	    }

	    foreach my $hr ( keys %rooms ) {
	
		my @tch;
		foreach my $userid ( keys %{ $rooms{$hr} } ) {
		    # Get Name
		    $sth1->execute( $userid );
		    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
		    my ($sal, $firstname, $lastname ) = $sth1->fetchrow;
		    push @tch, "$sal $firstname $lastname";
		} 
	
		if ( @tch ) {
		    $homeroomTeachers{$hr} = \@tch;
		}
	
	    }
    
	} # end of ShowHomeroomTeacher
    

	my $nsdhomeroom;
	if ( $nsdflag ) {
	    $nsdhomeroom = $groupid; # groupid IS a homeroom if nsdflag is set.
	}
	# IF nsdhomeroom is passed, then mkSchoolDays will also look for those days closed also.
	%schooldays = mkSchoolDays( $schoolstart, $currsdate, $dbh, $nsdhomeroom );
#	print qq{Days:}, %schooldays, qq{Start:$schoolstart Curr:$currsdate NSD:$nsdhomeroom\n};

	# print qq{School Days Hash<br>\n};
	# foreach my $key ( keys %schooldays ) { print "K: $key Val: $schooldays{$key}<br>\n"; }

	my ($shortname, $filename);

#	open( LOG,">", "pdflog-$db-$$.txt" ) || die "Can't open LOG file\n";

	# Get Students
	my %students;
	my $sth = $dbh->prepare("select studnum, lastname, firstname, homeroom
				from $studenttable where $group = ? 
				order by homeroom, lastname, firstname");
	$sth->execute( $groupid );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	while ( my ( $studnum, $lastname, $firstname, $homeroom ) = $sth->fetchrow ) {
	    $students{"$homeroom$lastname$firstname$studnum"} = $studnum;
	}


	my $sth = $dbh->prepare("select lastname, firstname, initial, grade, 
				homeroom, birthdate, provnum from $studenttable 
				where studnum = ?");


	# Loop through all students, one report card each.
	foreach my $key ( sort keys %students ) {
	    my $studnum = $students{$key};

	    # Get Student Info
	    $sth->execute( $studnum );
	    my ( $lastname, $firstname, $middlename, $grade, $homeroom, 
		 $birthdate, $provnum ) = $sth->fetchrow;

	    print qq{$firstname $lastname - $studnum - $grade\n};

	    
	    if ( $r_SkipBlankReportCard ) {

		# Check that she/he actually has some info in database.
		my $sth1 = $dbh->prepare("select count(*) from eval 
					 where term >= ? and term <= ? and studnum = ?"); # and a1 != ''
		$sth1->execute( $startterm, $endterm, $studnum );
		if ($DBI::errstr) {print $DBI::errstr; die $DBI::errstr; }

		my $evcount = $sth1->fetchrow;
		if ( not $evcount ) { next; } # skip kids with blank values for terms
	    }


	    if ( $oneStudentPerFile ) {

		# Create this student's filename
		my ($lname, $fname);
		$fname = $firstname; $lname = $lastname;
		$fname =~ s/\W|\-//g; # remove 'nonword' characters
		$lname =~ s/\W|\-//g;
		if ( length($lname) > 12 ) { $lname = substr $lname, 0, 12; }
		if ( length($fname) > 8 ) { $fname = substr $fname, 0, 8; }
		#print "LN: $lname  FN: $fname<br>\n";
		$shortname = "$lname$fname-$studnum-$currsdate";
		$filename = "$shortname.tex";

		open( TEX,">$filename" ) || die "Can't open tex file";
		prTexDocStart(); # print document preamble.
	
	    }


	    # Print the heading section for each new report card
	    prTexHead( $grade, $lastname, $firstname, $middlename, $birthdate, $provnum, $studnum );

	    # print a Note 1 - if set in repcard.conf
	    if ( $r_Note1 ) {
		print TEX "\\fbox{\\parbox[b]{\\textwidth}{ ";
		print TEX "\\begin{center}{\\it $r_Note1}\\end{center} }}\n\n";
	    }

	    # print homeroom teachers for this student (if any).
	    if ( $r_ShowHomeroomTeacher and $homeroomTeachers{$homeroom} ) {  # set in repcard.conf
		prHomeroomTeachers( $homeroom, @{ $homeroomTeachers{$homeroom}} );
	    }

	    # put in rule divider
	    print TEX "\\hrulefill \n\\smallskip\n\n";


	    # Attendance 1 - print block
	    if ( $r_ShowMonthlyAttendance == 1 ) {
		prMonthlyAttendance( $studnum );
	    }

	    
	    if ( $r_ShowGradeScheme ) {  # set in repcard.conf
		print_grade_scheme( $grade );
	    }
	    # End of head section for each new report card.

	    if ( $r_ShowMonthlyAttendance == 2 ) {
		prMonthlyAttendance( $studnum );
	    }


	    # print a Note 2 - if set in repcard.conf
	    if ( $r_Note2 ) {
		print TEX "\\begin{center}{\\it $r_Note2}\\end{center}\n\n";
	    }


	    my %mycourses;

	    my $sth2 = $dbh->prepare("select sequence from subject where subjsec = ?");

	    # Get Subjects for this student in this term range.
#	    print "SN:$studnum STerm:$startterm ETerm: $endterm\n";
	    
	    my $sth1 = $dbh->prepare("select distinct subjcode from eval where 
				     studnum = ? and term >= $startterm and term <= $endterm");
	    $sth1->execute( $studnum );
	    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	    while ( my  $subjsec = $sth1->fetchrow ) {

		# skip if member of %r_SupressSubject or %r_AdditionalComments
		my ($tsubjcode, $dud) = split('-', $subjsec ); 
		if ( $r_SupressSubject{$tsubjcode} or $r_SupressSubject{$subjsec} or
		     $r_AdditionalComments{$tsubjcode} or $r_AdditionalComments{$subjsec} ) {
		    
		    next; 
		}

	
		$sth2->execute( $subjsec );
		if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
		my $seq = $sth2->fetchrow;

		while ( length( $seq ) < 4 ) { # pad with leading zeros
		    $seq = '0'. $seq;
		}
		$mycourses{"$seq$subjsec"} = $subjsec;
	    }

	    #    print "SN: $studnum  SUB:", %mycourses, "<br>\n";
    

	    my $firstsubjectflag = 1; # mark if still at first subject

	    # Initialize the GPA hash.
	    my %gpa;
	    my $biggestterm; # track largest term values in subjects

	    if ( $r_CenterSubjects ) {
		print TEX "\\begin{center}\n";
	    }


	    my $sth1 = $dbh->prepare("select * from subject where subjsec = ?");
    
	    # Now Loop through all courses of this student
	    foreach  my $key ( sort keys %mycourses ) {

		my $subjsec = $mycourses{ $key }; # req'd since mycourses for sorting only
	
		# Get this subject's info...
		$sth1->execute( $subjsec );
		if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
		my $subjref = $sth1->fetchrow_hashref;
		my %s = %$subjref;
	
		#	my $sequence = $subjref->{sequence};
		#	my $startrptperiod = $subjref->{startrptperiod};
		#	my $endrptperiod = $subjref->{endrptperiod};
		#	my $subjcode = $subjref->{subjcode};


		#=== Various Skip Reasons
		# skip if this subject hasn't started yet.
		if ( $s{startrptperiod} > $endterm ) { next; }
		# skip if all done.
		if ( $startterm > $s{endrptperiod} ) { next; }

	

		my @objdesc; # objective descriptions
		my $objectivecount;
		for my $i ( 1 .. 20 ) {
		    my $fieldname = 'q'. $i;
		    if ( $s{$fieldname} ) {
			$objdesc[$i] = $s{$fieldname};
			$objectivecount = $i;
		    }
		}
		if ( not @objdesc ) { # no objectives, put in 1 for mark;
		    $objdesc[1] = $lex{Mark};
		    $objectivecount = 1;
		}


		# Start setting up eval data structure: array of arrays.
		my @eval;
		# Sets first column with description of objectives ( by q1, q2, etc)
		$eval[0] = [ @objdesc ];
		# Testing: foreach my $desc ( @{ $eval[0] } ) { print "$desc<br>\n"; }

		# Now pull in the records for this subject for this student
		# Pull in full records
		$sth2 = $dbh->prepare("select * from eval where studnum = ?
			      and subjcode = ? order by eval.term");
		$sth2->execute( $studnum, $subjsec ) ;
		if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

		# read eval records for each term of this subject.
		my $currtrm = 0; 
		my $prevtrm; # for error checking for redundant records below.
		my $lastterm; # last term value in @eval; used for trailing blank cells.

		while ( my $evalref = $sth2->fetchrow_hashref ){ # load temp eval record

		    my $evalterm = $lastterm = $evalref->{term};
		    if ( $evalterm > $endterm or $evalterm < $startterm ) { next; } 
		    # not there yet, or skipping earlier.

		    # Set values into GPA Hash
		    if ( defined $evalref->{$r_MarkField} ) { # markfield comes from repcard.conf
			$gpa{$subjsec}[$evalterm] = $evalref->{$r_MarkField};
		    }

		    # Check for largest term ( so know how many gpa calcs to do).
		    if ( $evalterm > $biggestterm ) { $biggestterm = $evalterm; }

		    # Error Checking for any mistakes in eval records
		    $prevtrm = $currtrm; $currtrm = $evalterm;
		    if ( $currtrm == $prevtrm){ 
			# Error! two eval records with the same term value.
			print $lex{'Duplicate Evaluation Record'}. ":\n";
			print "$lex{Student}: $studnum - $lex{Subject}:";
			print "$subjnum - $lex{Term}:$currtrm.\n";
			print "Contact Les Richardson\n";
		    }

		    # use array slice to put in eval record fields with possible values
		    my @temp = ();
		    push @temp, $evalterm;
		    for my $i ( 1 .. $objectivecount ) {
			$fieldname = 'a'. $i;
			push @temp, $evalref->{$fieldname};
		    }

		    push @eval, [ @temp ];

		} # Done stuffing eval recs into eval array (with reference).


		if ( $r_TermDisplayTrailing ) { # pad end of course, if necessary.
		    my $trailidx = $lastterm;  # lastterm is last term in @eval
		    while ( $trailidx < $s{endrptperiod} ) { # was $endterm
			my @temp = ();
			$temp[ $#objdesc ] = ''; # dimension that thar array.
			push @eval, [ @temp ];
			$trailidx++;
		    }
		}


		prCourse( $subjsec, $studnum, $currterm, $startterm, $endterm, \@eval ); # print course;

		prComment( $subjsec, $studnum, $startterm, $endterm ); # print the comments (all)


	    } # End of this course; loop to print the next.


	    # End Subject Centering, if turned on.
	    if ( $r_CenterSubjects ) {
		print TEX "\\end{center}\n";
	    }


	    # Start a new page for attendance, etc.
	    if ( $r_NewPageBeforeAttendance ) {
		print TEX "\\newpage\n";
	    }


	    # Attendance - print block
	    if ( $r_ShowMonthlyAttendance == 3) {
		prMonthlyAttendance( $studnum );
	    }


	    if ( $teachermode ) {
		print TEX "\\vspace{10mm}\n\n";
	    } else {
		print TEX "\n\n"; # to push over additional comments.
	    }

	    if ( $r_ShowAdditionalComments ) {
		prAddComments( $studnum, $startterm, $endterm ); # Additional comments
	    }

	    if ( $r_ShowMonthlyAttendance == 4 ) {
		prMonthlyAttendance( $studnum );
	    }

	    if ( $r_Note3 ) {
		print TEX "\\fbox{\\parbox[b]{\\textwidth}{ ";
		print TEX "\\begin{center}{\\it $r_Note3}\\end{center} }}\n";
		print TEX "\\vspace{6mm}\n\n";
	    }


	    # Now finish off the report card; last term gets the promotion format.
	    # There are 3 signature fns: Teacher, Principal, or Combo. Pick your mix.

	    # Placement Text block
	    my $blockFlag; # indicates if a placement block is used with this grade level
	    if ( $r_PlacementTex{ "$r_PlacementIndex{ $grade }" } ) {
		$blockFlag = 1; 
	    }

	    if ( $endterm != $r_FinalTerm{$grade} or not $blockFlag ){ 
		# not final term or no Placement Block ( even IF final term)

		# Also... if no $teachersign value, then not shown...
		if ( $r_TeacherSign eq 'teacher' ){
		    prTeacherSig();  #Teacher Signature

		} elsif ( $r_TeacherSign eq 'principal' ){
		    prPrincipalSig();  #Principal Signature

		} elsif ( $r_TeacherSign eq 'combo' ) {
		    prComboSig(); 
		    # Combination Signature (both teacher / principal side by side.)
		}
	
		# print if we have a showTearoff (or not updated)
		if ( $r_ShowTearoff ){
		    if ( $r_PrintParentSig ) { # block them together
			$tearoffblock = 1;
		    }
		    prTearoff(); 

		    # print a signature line for parents on tear off line.
		    if ( $r_PrintParentSig ) {
			prParentSig( $currdate, $lastname, $firstname, $middlename ); # Parent Signature
		    } elsif ( $tearoffblock ) { # close off the parbox
			print TEX "} \n ";
		    }
		}
    
	    } else { # we're in the last term; print graduation box, if set...
		if ( $r_PrintYearEnd ) {
		    prYearEnd("$firstname $middlename $lastname", $grade);
		}
	    }

	    if ( $r_Note4 ) {
		print TEX "\\fbox{\\parbox[b]{\\textwidth}{ ";
		print TEX "\\begin{center}{\\it $r_Note4}\\end{center} }}\n\n";
	    }

    
	    # End Section for this student.
	    if ( $oneStudentPerFile ) {
		# build pdf and put into tempdir; append to pdflog$$.txt
		#print TEX "\\end{center}\n";
		print TEX "\\end{document}\n";
		close TEX;

#		print LOG "\n\n$firstname $lastname ($studnum)\n-----------------\n";
		system("$pdflatex $filename >>pdflog$$.txt");
		system("mv $shortname.pdf $repcardDir");
		system("rm -f $shortname.*");
	    } else {
		print TEX "\\newpage\n"; # new page for next student.
	    }

	}  # End of Main Loop; Back to Next Student.


	# Final section
    
	if ( $oneStudentPerFile ) {

#	    my $repcardDir = qq{/opt/openadmin/$db/admin/reportcard};

	    #	    if ( not -d $repcardDir ) { # create the report card directory
#		use File::Path q2{make_path);
#		my %options = ('owner' => 'www-data');
#		eval { $make_path($repcardDir, \%options) };
#		if ( $@ ) {
#		    print qq{Could not create $repcardDir: $!\n}; exit;
#		}
#	    }
	    
	    # create single zip and copy all zip to webdownload dir; pdflog$$.txt too.
#	    $shortname = "repcard$$";
	    #	    system("zip $shortname.zip $tempdir/* >> pdflog$$.txt");
	    
#	    system("mv -f $tempdir $repcardDir");

	    system("mv pdflog$$.txt $repcardDir");
#	    system("rm -r $tempdir");


	}

    } # end of grade loop


    

    
#    system("mv -f $tempdir $repcardDir");
    
} # end of DB/School Loop

print "Done\n";

# ====== End of Main Section ================


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

    my ( @subjects, %subjdesc );
    
    if ( $teachermode ) { # we are running on teacher site
	# Get their subjects
	my $sth = $dbh->prepare("select subjsec, description from subject 
          where teacher = ? order by sequence, description ");
	$sth->execute( $userid );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	while ( my ( $subjsec, $description ) = $sth->fetchrow ) {
	    push @subjects, $subjsec;
	    $subjdesc{ $subjsec } = $description;
	}

    }


    # Get School Months for Override
    my %schoolmonths = mkSchoolDays( $schoolstart, $currsdate, $dbh );
    # Format: yyyy-mm; first record is blank (zeroth)
    

    # Form Start
    print qq{<form action="$self" method="post">\n};
    print qq{<input type="hidden" name="page" value="1">\n};

    
    # Get the grades
    my @grades;
    my $sth = $dbh->prepare("select distinct grade from student 
      where grade is not NULL and grade != ''");
    $sth->execute;
    if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    while ( my $gr = $sth->fetchrow ) {
	push @grades, $gr;
    }


    # Get the homerooms.
    my @homerooms;
    my $sth = $dbh->prepare("select distinct homeroom from student where 
     homeroom is not NULL and homeroom != ''");
    $sth->execute;
    if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    while ( my $hr = $sth->fetchrow ) {
	push @homerooms, $hr; # removed checking below
    }


    # Start Table.
    print qq{<table cellspacing="0" cellpadding="3" border="0" };
    print qq{style="padding:1em;margin:0.5em;border:1px solid gray;">\n};


    # Grades
    print qq{<tr><td class="bra">$lex{Grade}};
    if ( $schoolmode == 1 ) {
	print qq{/$lex{Form}};
    }
    print qq{</td>};
    print qq{<td class="la"><select name="grade"><option></option>\n}; 
    foreach my $gr ( sort {$a <=> $b} @grades ) {
	my $displaygrade = $gr;
	if ( $schoolmode == 1 ) { # British mode
	    my $val = $g_FormMap{$gr};
	    if ( not $val ) { $val = $gr; }
	    if ( $val =~ m/F|f/ ) { # we are adding form.
		$val =~ s/F|f/$lex{Form} /;
	    }
	    $displaygrade = $val;
	}
	print qq{<option value="$gr">$displaygrade</option>};
    }
    print qq{</select></td></tr>\n};

    print qq{<tr><td class="bcn" colspan="2">$lex{OR}</td><td></td></tr>\n};
    
    # Homeroom
    print qq{<tr><td class="bra">$lex{Homeroom}</td>};
    print qq{<td class="la"><select name="homeroom"><option></option>\n}; 
    foreach my $hr ( sort {$a <=> $b} @homerooms ) {
	print qq{<option>$hr</option>};
    }
    print qq{</select></td></tr>\n};
    
    print qq{<tr><td colspan="2"><hr></td></tr>\n};
    
    
    # Printing Date
    print qq{<tr><td class="bra">$lex{'Printing Date'}</td>\n<td>};
    print qq{<input type="text" name="date" id="date" size="10" value="$currsdate">\n};
    print qq{<button type="reset" id="start_trigger">...</button>\n};
    print qq{</td></tr>\n};

    
    # Terms  (to use to get courses during those term blocks).
    print qq{<tr><td class="bra">$lex{'Start Term'}</td>\n<td>};
    print qq{<input type="text" name="startterm" size="4"></td></tr>\n};
    print qq{<tr><td class="bra">$lex{'End Term'}</td>\n<td>};
    print qq{<input type="text" name="endterm" size="4"></td></tr>\n};


    # Paper Size
    $defaultpapersize =~ s/paper//; # strip out word paper so lex works; from admin.conf
    my $defpaper = ucfirst( $defaultpapersize );

    print qq{<tr><td class="bra">$lex{'Paper Size'}</td>\n};
    print qq{<td><select name="papersize"><option>$lex{$defpaper}</option>\n};
    my @sizes = qw(Letter A4 Legal);
    foreach my $size ( @sizes ) {
	if ( $size eq $defpaper ) { next; }
	print qq{<option>$lex{$size}</option>};
    }
    print qq{</select></td></tr>\n} ;

    # Font Size
    print qq{<tr><td class="bra">$lex{'Font Size'}</td>\n<td>};
    print qq{<select name="fontsize"><option>$r_FontSize</option>\n};
    print qq{<option>10pt</option><option>11pt</option><option>12pt</option></select></td></tr>\n};


    if ( $teachermode ) {
	print qq{<tr><td><b>$lex{'Select Subjects'}</b></td><td></td></tr>\n};
	foreach my $subjsec ( @subjects ) {
	    print qq{<tr><td class="bra" style="background-color:#DDD;">};
	    print qq{$subjdesc{$subjsec} ($subjsec)</td>\n};
	    print qq{<td><input type="checkbox" name="$subjsec" value="-1"></td></tr>\n};
	}
    }


    # Withdrawn Students
    print qq{<tr><td class="bra">$lex{'Show Withdrawn Students'}</td>\n<td>};
    print qq{<input type="checkbox" name="showwithdrawn" value="1"></td></tr>\n};

    # One Student per File
    print qq{<tr><td class="bra">$lex{'One Student per File'}</td>\n};
    print qq{<td><input type="checkbox" name="onestudentperfile" value="1">};
    print qq{$lex{'For Duplexing/Stapling'}</td></tr>\n};

    # Enable/Disable the email report card option from top of script.
    if ( $showEmailOption ) {
	# Email report card.
	print qq{<tr><td class="bra">$lex{Email} $lex{'Report Card'}</td>\n};
	print qq{<td><input type="checkbox" name="emailrepcard" value="1"></td></tr>\n};

	print qq{<tr><td class="bra">Check All Email Addresses</td>\n};
	print qq{<td><input type="checkbox" name="checknextpage" value="1"></td></tr>\n};
	
    }

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


    # Spacer
    print qq{<tr><td colspan="2"><hr></td></tr>\n};

    
    # Override for Days open in month
    print qq{<tr><td class="bra">$lex{'Override Term Days'}</td>};
    print qq{<td><input type="checkbox" name="override" value="1"></td></tr>\n};

    # Inner Table
    print qq{<tr><td colspan="2">\n};
    print qq{<table cellspacing="0" cellpadding="3" border="1">\n};
    print qq{<tr><th colspan="2">$lex{'Days per Month Override'}</th></tr>\n};
    print qq{<tr><th>$lex{Month}</th><th>$lex{'Days Open'}</th></tr>\n};

    
    for my $ym ( sort keys %schoolmonths ) { # keys are yyyy-mm format
	my ($y,$m) = split('-', $ym);
	print qq{<tr><td><b>$month[$m]</b> ($ym)</td>};
	print qq{<td><input type="text" name="$ym" size="4"></td></tr>\n};
    }
    print qq{</table></td></tr>\n};
    # End of Inner Table
    
    print qq{<tr><td></td><td><input type="submit" value="$lex{Continue}"></td></tr>\n};

    
    print qq{</table></form>\n};

    print qq{<script type="text/javascript">
    Calendar.setup({
    inputField     :    "date", // id of the input field
    ifFormat       :    "%Y-%m-%d", // format of the input field
    button         :    "start_trigger", // trigger for the calendar (button ID)
    singleClick    :    false,        // double-click mode
    step           :    1             // show all years in drop-down boxes (not every other year as default)
    });
    </script>\n};

    print qq{</body></html>\n};

    exit;

} # end of showStartPage


#----------------
sub prTexDocStart {
#----------------

# Preamble and Head of Document

    # $papersize, $textwidth and $textheight set at top of script.
    print TEX <<"EOS1";  
\\documentclass[ $fontsize, $papersize, oneside]{article}
\\usepackage{array,graphicx,multicol,colortbl,inputenc,fancyhdr}
$a_latex_header
\\renewcommand{\\familydefault}{\\sfdefault}

\\setlength{\\hoffset}{ $r_HOffset }
\\setlength{\\voffset}{ $r_VOffset }

\\setlength{\\headsep}{10pt}
\\setlength{\\headheight}{14pt}
\\setlength{\\topmargin}{0in}

\\setlength{\\textwidth}{ $textwidth }
\\setlength{\\textheight}{ $textheight }

\\setlength{\\parindent}{0pt}
\\setlength{\\evensidemargin}{0in}
\\setlength{\\oddsidemargin}{0in}
\\setlength{\\extrarowheight}{4pt}
\\pagestyle{headings}
\\newcolumntype{G}{>{\\columncolor[gray]{ $r_GrayScale }}p{$r_SubjSpace}}

\\pagestyle{fancy}
\\lhead{$schoolname -- $schoolyear}
\\rfoot{ $lex{Printed}: $currdate }
\\cfoot{ }

\\begin{document}
EOS1

}


#----------------------
sub showRankDemAvgBlock {
#----------------------

    my ($studnum, $grade)  = @_;

    print TEX "\\bigskip\n";

    # Start TeX head
    print TEX "\\begin{tabular}{|p{$r_SubjSpace}|";
    for ( $startterm .. $endterm ){ print TEX "p{$r_MarkSpace}|"; }
    print TEX "}\\hline\n";

    my $track = $g_MTrackTermType{ $grade };

    # Do Header
    print TEX "\\rowcolor[gray]{ $r_GrayScale }";
    foreach my $term ( $startterm .. $endterm )  { #loop through all terms
	my $title;
	if ( $g_TermDisplay{$track}{$term} ) {
	    $title = $g_TermDisplay{$track}{$term};
	} else { $title = $term; }
	print TEX "& \\hfil $title \\hfil"; 
    }
    print TEX "\\\\ \\hline\n";

    # Do Average
    if ( $r_ShowTermAverage ) {
	#print TEX "\\rowcolor[gray]{ $r_GrayScale }";
	print TEX "\\bf ". $lex{Average};
	# Loop through each term displaying the average
	foreach my $term ( $startterm .. $endterm )  { #loop through all terms
	    my $average = format_number( $termavg_ref->{$term}->{$studnum} , $r_AveragePrecision );
	    print TEX "&\\hfil $average \\hfil "; # change to GPA value...
	} # End of terms loop
	print TEX "\\\\ \\hline\n";
    }

    # Do Rank
    if ( $r_ShowRanking ) {
	#print TEX "\\rowcolor[gray]{ $r_GrayScale }";
	print TEX "\\bf ". $lex{Rank};
	# Loop through each term displaying the average
	foreach my $term ( $startterm .. $endterm )  { #loop through all terms
	    my $rank = $rank_ref->{$term}->{$studnum};
	    print TEX "&\\hfil $rank \\hfil "; # change to GPA value...
	} # End of terms loop
	print TEX "\\\\ \\hline\n";
    }


    # Do Grade Category
    if ( $r_ShowGradeCategory ) {
	#print TEX "\\rowcolor[gray]{ $r_GrayScale }";
	print TEX "\\bf ". $lex{Grade}; # really Grade Category

	foreach my $term ( $startterm .. $endterm )  { #loop through all terms
	    my $gradecategory = calcGradeCategory( $studnum, $term );
	    print TEX "&\\hfil $gradecategory \\hfil ";
	} # End of terms loop

	print TEX "\\\\ \\hline\n";

    } # end of showGradeCategory


    # Do Demerits
    if ( $r_ShowDemerits ) {
	#print TEX "\\rowcolor[gray]{ $r_GrayScale }";
	print TEX "\\bf ". $lex{Demerits};
	foreach my $term ( $startterm .. $endterm )  { #loop through all terms
	    my $start = $g_MTrackTerm{$track}{$term}{'start'};
	    my $end = $g_MTrackTerm{$track}{$term}{'end'};

	    my $sth = $dbh->prepare("select sum( demerit ) from disc_ident i, disc_event e where 
              e.id = i.eventid and studnum = ? and 
              to_days(e.date) >= to_days('$start') and 
              to_days(e.date) <= to_days('$end') ");           

	    $sth->execute( $studnum );
	    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	    my $demerits = $sth->fetchrow;
	    if ( not $demerits ) { $demerits = '0'; }

	    print TEX "&\\hfil $demerits \\hfil "; # change to GPA value...

	} # End of terms loop

	print TEX "\\\\ \\hline\n";
    } # end of showDemerits;

    print TEX "\\end{tabular}\n\n";


} # end of showRankDemAvgBlock



#--------------------
sub calcGradeCategory {
#--------------------

    my ( $studnum, $term ) = @_;

    # Now in configuration system.
    # my %r_GCDisplay = ( '1' => 'I', '2' => 'II', '3' => 'III', '4' => 'P', '5' => 'U' );
    
    my %dud; # just need a blank hash.

    # Find if any marks below a fail value; don't count blanks.
    my $failmark = 55;
    my $sth = $dbh->prepare("select count(*) from eval 
      where studnum = ? and term = ? and $r_MarkField is not null
      and $r_MarkField != '' and $r_MarkField < $failmark ");
    $sth->execute( $studnum, $term );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    my $failcount = $sth->fetchrow;

    my $sth1 = $dbh->prepare("select lastname, firstname from studentall where studnum = ?");
    
    if ( $failcount ) { # display the values

	# Get Name
	$sth1->execute( $studnum );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	my ($lastname, $firstname) = $sth1->fetchrow;

	# Display Courses and Marks
	my $sth = $dbh->prepare("select subjcode, $r_MarkField from eval 
          where studnum = ? and term = ?");
	$sth->execute( $studnum, $term );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	print qq{<h4>FAILURE for $firstname $lastname</h4>\n};
	while ( my ($subjcode, $mark )  = $sth->fetchrow ) {
	    print "<div>SN:$studnum TERM:$term COURSE:$subjcode MARK:$mark</div>\n";
	}
    }
    
    
    # Level 1
    my $avg1 = calcTopAverage( $studnum, $term );
#    my %names = ('English' => '1' );
#    my $count2 = calcTopCount( $studnum, $term, 70, \%names,1 );
#    my $count3 = calcTopCount( $studnum, $term, 55, \%dud, 1 );

    # print "Studnum:$studnum Level:1  A1:$avg1  C2:$count2 C3:$count3<br>\n";
    if ( $avg1 >= 85  and not $failcount ) { # and $count2 >= 5 and $count3 >= 7 ) {
	# print "Level 1 Return<br><br>\n";
	return $r_GCDisplay{1};
    }

    # Level 2
    $avg1 = calcTopAverage( $studnum, $term );
#    $count2 = calcTopCount( $studnum, $term, 70,\%dud,1 );
#    %names = ('English' => '1' );
#    $count3 = calcTopCount( $studnum, $term, 55, \%names, 1 );

    # print "Studnum:$studnum Level:2  A1:$avg1  C2:$count2 C3:$count3<br>\n";
    
    if ( $avg1 >= 75 and not $failcount ) { # and $count2 >= 4 and $count3 >= 6 ) {
	# print "Level 2 Return<br><br>\n";
	return $r_GCDisplay{2};
    }

    # otherwise just...
    
    return;
    
=head
    # Level 3
    $avg1 = calcTopAverage( $studnum, $term );
    $count2 = calcTopCount( $studnum, $term, 70,\%dud, 1);
    %names = ('English' => '1' );
    $count3 = calcTopCount( $studnum, $term, 55, \%names, 1);

    # print "Studnum:$studnum Level:3  A1:$avg1  C2:$count2 C3:$count3<br>\n";

    if ( $avg1 >= 60 and $count2 >= 2 and $count3 >= 6 and not $failcount ) {
	# print "Level 3 Return<br><br>\n";
	return $r_GCDisplay{3};
    }


    # Level 4 - Pass 
    $avg1 = calcTopAverage( $studnum, $term );
    $count2 = calcTopCount( $studnum, $term, 55,\%dud,1 );

    # print "Studnum:$studnum Level:4 (Pass)  A1:$avg1  C2:$count2<br>\n";
    if ( $avg1 >= 55 and $count2 >= 5 and not $failcount ) {
	# print "Level 4 (Pass) Return<br><br>\n";
	return $r_GCDisplay{4};
    }

    
    # Fail
    return $r_GCDisplay{5};
=cut


} # end of calcGradeCategory



#-----------------
sub calcTopAverage { # Find Averages for GradeCategory Results
#-----------------
    
    my ( $studnum, $term, $subjnum, $name_ref ) = @_; 
    # student number, term, number of subject to avg, names of subj to include in avg (hash ref)


    my $sth = $dbh->prepare("select $r_MarkField, subjcode from eval 
      where studnum = ? and term = ? order by $r_MarkField desc");
    $sth->execute( $studnum, $term );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

    my $sth1= $dbh->prepare("select description from subject where subjsec = ?");
    
    my ($subjcount, $marktotal );
    my (%marks, %found );

    while ( my ( $mark, $subjcode ) = $sth->fetchrow ) {

	# skip if member of %r_SupressSubject or AdditionalComments
	my ($tsubjcode, $dud) = split('-', $subjcode ); 
	if ( $r_SupressSubject{$tsubjcode} or $r_SupressSubject{$subjcode} or
	     $r_AdditionalComments{$tsubjcode} or $r_AdditionalComments{$subjcode} ) {

	    next; 
	}


	# Get course description.
	$sth1->execute( $subjcode );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	my $description = $sth1->fetchrow;

	if ( not defined $mark ) { # NULL value in table
	    print "$lex{Skipping}: $lex{'Undefined Value'}";
	    print " $description ($subjcode) - $studnum<br>\n";
	    next;
	}

	if ( $name_ref ) { # we have names to store and check against.
	    $marks{ $subjcode } = $mark; # store mark in hash.
	    foreach my $name ( keys  %{ $name_ref } ) {
		if ( $description =~ m/($name)/ ) { # subject match

		    $found{ $subjcode } = $mark;
		    delete $$name_ref{ $name };
		    last;
		}
	    }
	}

	$mark =~ s/\s+//g; # strip any spaces.
	if ( $mark =~ m/[^.0-9]/ or not $mark ) { # non-numeric mark or no value
	    print qq{$lex{Skipping}: $mark - $description ($subjcode) - $studnum<br>\n};
	    next;
	}

	$marktotal += $mark;
	$subjcount++;
	if ( not $name_ref and $subjcount == $subjnum ) { # no names and enough subjects
	    my $average;
	    if ( $subjcount ) { # not zero.
		$average = $marktotal / $subjcount;
		return $average;
	    } else {
		return undef;
	    }
	}
    } # end of data retrieval loop.

    # just find overall average for this term.
    if ( not defined $subjnum or $subjcount < $subjnum ) { 
	if ( $subjcount ) {
	    my $average = $marktotal / $subjcount;
	    return $average;

	} else {
	    return undef;
	}
    }


    # else here.... we should have some names, etc.
    # check %found and if anything left in %$name_ref
    $marktotal = 0;
    $subjcount = 0;
    $subjnum -= $subjcount = keys %found; #
    foreach my $subjsec ( keys %found ) {
	delete $marks{$subjsec}; # don't want to count twice.
	$marktotal += $found{ $subjsec };
    }

    my $count;
    foreach my $subjsec ( sort { $marks{$b} <=> $marks{$a} } keys %marks ) {
	$marktotal += $marks{ $subjsec };
	$subjcount++;
	$count++;
	if ( $count == $subjnum ) { last; }
    }

    my $average;
    if ( $subjcount ) {
	$average = $marktotal / $subjcount;
	return $average;
    } else { 
	return undef;
    }

} # end of calcTopAverage



#---------------
sub calcTopCount { # Find Count of subjects above certain value, including subject names;
#---------------
    
    # returned:  number of subjects above (or >= based on $eqmode ) mark limit, must include subject names.
    # EQMODE is new

    my ( $studnum, $term, $marklimit ,$name_ref, $eqmode ) = @_; 
    # student number, term, lower mark limit, names of subj to include
    # in $subjcount returned.

    # subjects that are required to be in this group.
    my %subjects = %$name_ref;


    my $sth = $dbh->prepare("select $r_MarkField, subjcode from eval 
      where studnum = ? and term = ? order by $r_MarkField desc");
    $sth->execute( $studnum, $term );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }


    my $sth1= $dbh->prepare("select description from subject where subjsec = ?");
    my $subjcount;

    while ( my ( $mark, $subjcode ) = $sth->fetchrow ) {

	# skip if member of %r_SupressSubject or AdditionalComments
	my ($tsubjcode, $dud) = split(/-/, $subjcode ); 
	if ( $r_SupressSubject{$tsubjcode} or $r_SupressSubject{$subjcode} or
	     $r_AdditionalComments{$tsubjcode} or $r_AdditionalComments{$subjcode} ) {

	    next; 
	}

	# Get subject description for skipping.
	$sth1->execute( $subjcode );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	my $description = $sth1->fetchrow;

	# skip NULL value in table
	if ( not defined $mark ) { 
	    print "$lex{Skipping}: $lex{'Undefined Value'}";
	    print " $description ($subjcode) - $studnum<br>\n";
	    next;
	}

	# skip non-numeric mark
	if ( $mark =~ m/[^.0-9]/ ) { 
	    print $lex{Skipping}. ": $mark - $description ($subjcode) - $studnum<br>\n";
	    next;
	}

	# Check if a certain subject
	if ( %subjects ) { # we have names to store and check against.
	    foreach my $name ( keys  %subjects ) {
		if ( $description =~ m/($name)/ ) { # subject match
		    if ( $eqmode ) { # >= mode
			if ( $mark >= $marklimit ) {
			    $subjects{$name} = 0; # set to zero, from 1.
			}
		    } else { # > mode
			if ( $mark > $marklimit ) {
			    $subjects{$name} = 0; # set to zero, from 1.
			} 
		    }

		} # end if subject match
	    } # name loop
	}


        if ( $eqmode ) { # >= mode
	    if ( $mark >= $marklimit ) {
		$subjcount++;
	    }
	} else { # > mode
	    if ( $mark > $marklimit ) {
		$subjcount++; 
	    } 
	}

	# print "SN:$studnum SUB:$subjcode Mark: $mark  Count:$subjcount<br>\n";

    } # end of data retrieval loop.

    # check to make sure %subjects all zeroed out (ie. matched)
    foreach my $key ( keys %subjects ) {
	if ( $subjects{$key} ) {
	    return 0;
	}
    }

    return $subjcount;

} # end of calcTopCount



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

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

    eval require "$configpath/etc/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 = ?");

    # Start TeX head
    print TEX "\\begin{tabular}{|p{$r_SubjSpace}|";
    for ( 1..$maxterm ){ print TEX "p{$r_MarkSpace}|";}

    print TEX "}\\hline\n";
    print TEX "\\rowcolor[gray]{ $r_GrayScale }";
    print TEX "\\bf $lex{Term} $lex{GPA}";

    my ($totalGPQuality, $totalGPCredits); # needed for overall at end.

    # 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 ( defined $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'}: $letter\n";
		    next; # skip to next subject. 
		}

		# Update Attempts
		$termAttempts += $credit;

		# Now do Pass Letter settings.
		if ( $letter eq $passletter ) {
		    $termCredits += $credit;
		    $totalCredits += $credit;

		} elsif ( $letter eq $failletter ) {
		    # No additions to credits, GP credits increase to bring down avg.
		    $totalGPCredits += $credit;
		    $termGPCredits += $credit;

		} else { # calculate passing grade settings.

		    my $quality = $letterToQual{ $letter };
		    if ( $quality ) { $quality += $difficulty; } # if non-zero add on difficulty factor.

		    # Update Quality scores for weighted average.
		    $termGPQuality += $quality * $credit;
		    $totalGPQuality += $quality * $credit;

		    # Update GP Credit totals for weighted average.
		    $totalGPCredits += $credit;
		    $termGPCredits += $credit;

		    # Update the credits
		    $termCredits += $credit;
		    $totalCredits += $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 ), $r_AveragePrecision );
	} 
	else { $gpa = 0; }

	print TEX "&\\hfil $gpa \\hfil "; # change to GPA value...
    
    } # End of terms loop


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

    print TEX "\\\\ \\hline\n";
    print TEX "\\hfil\\bf ". $lex{'Current Year GPA'}. " $cumgpa \\hfil ";
    for ( 1..$maxterm ){ print TEX "& ";}

    print TEX "\\\\ \\hline \\end{tabular}\n\n";


} # end of calcGPA


#---------------
sub calcTermDays {
#---------------

    # passed a start date and an end date for a term, and a ref to a
    # hash storing the closure dates in julian day format, it will
    # return a count of the days open in the month.

    # outline: convert start/end dates to jd. Loop over all days. Use
    # modulus function to ident weekend days.

    my ($startdate, $enddate, $closeref ) = @_;
    my %jdclosed = %$closeref;

=head
    print qq{JDClosed<br>\n";
    foreach my $key ( sort keys %jdclosed ) {
	print qq{K:$key V:$jdclosed{$key}<br>\n";
    }
    print qq{End JDClosed<br>\n";
=cut

    my $startjd = julian_day(split('-',$startdate));
    my $endjd = julian_day(split('-',$enddate));

    my %modclosed; # modulus for days closed
    foreach my $inc ( 0..6 ) {
	my $testjd = $startjd + $inc;
	my $dow = day_of_week($testjd);
	if ( $dowclosed{$dow} ) { # $testjd is a closed dow
	    my $mod = $testjd % 7;
	    $modclosed{$mod} = 1;
	}
    }

#    foreach my $d ( sort keys %modclosed ) {
#	print qq{Closed Mod: $d<br>\n";
#    }

    my ($daysopen, $daysclosed);
    foreach my $jd ( $startjd..$endjd ) {

	my $dow = day_of_week( $jd );
	my $mod = $jd % 7;

	if ( $modclosed{$mod} ) { # closed for weekend
	    next;
	}

	# check if a day closed
	my $cl = $jdclosed{ $jd };
	if ( $cl  ) { # this gives us the fraction closed
	    $daysclosed += $cl;
	    # only add on the fraction of day open
	    $daysopen += (1 - $cl );
#	    print qq{<br>INSIDE<br>\n";
	} else {
	    $daysopen += 1;
	}
#	print qq{JD:$jd Count:$daycount<br>\n";

    }

    print qq{ST:$startdate END:$enddate  Count:$daycount<br>\n};

    return "$daysopen:$daysclosed";

}


=head
#-----------------
sub calcAttendance {
#-----------------
    my ( $studnum, $startdate, $enddate, $periodsperday ) = @_;
    my $sth = $dbh->prepare("select * from attend 
     where studentid = ? and 
     to_days(absdate) >= to_days('$startdate') and 
     to_days(absdate) <= to_days('$enddate') 
     order by absdate,period");
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    $sth->execute( $studnum );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

    my $absent = 0; my $late = 0;
    while ( my @absence = $sth->fetchrow ) {
	print "Absent: @absence\n";
	if ( $absence[3] =~ /$lex{Absent}/) { $absent++; }
	if ( $absence[3] =~ /$lex{Late}/) { $late++; }
    }
    if ( $periodsperday ) {
	$absent = $absent / $periodsperday; #convert periods into days
    }
    return "$absent:$late";
}
=cut


#------------ 
sub prTexHead {  # Print the head of each new report card 
#------------

    # globals: schoolname, $schoolyear
    my ($grade, $lastname, $firstname, $middlename, $birthdate, $provnum, $studnum ) = @_;

    print TEX "\\thispagestyle{empty}\n\\setcounter{page}{1}\n";

    print TEX "\\rhead{$firstname $middlename $lastname -- \\thepage}\n\\begin{center}\n";

    if ( $r_ShowLogo ) {
	if ( not $r_LogoFile and $r_logoFile ) { $r_LogoFile = $r_logoFile; }
	print TEX "\\includegraphics[width=$r_LogoWidth]{";
	print TEX "$configpath/etc/$r_LogoFile}\\quad \n";
	print TEX "\\parbox[b]{$r_SchoolAddressWidth}{\\begin{center}{";
	print TEX "\\Large\\bf $schoolname}\\\\";
	if ( $schooladdr1 ) {
	    print TEX "$schooladdr1\\\\ \n";
	}
	if ( $schoolcity or $schoolprov ) {
	    print TEX "$schoolcity, $schoolprov $schoolpcode\\\\ \n";
	}

	# Phone / Fax Line
	if ( $schoolphone and $schoolfax ) {  # use an hfill
	    print TEX qq{$lex{Phone} $schoolphone \\hfill $lex{Fax} $schoolfax};
#	    if ( $r_ShowAdmins ) { print TEX "\\hfill ";}
#	    else { print TEX "\\qquad "; }
	} elsif ( $schoolphone ) {
	    print TEX "$lex{Phone} $schoolphone ";
	} elsif ( $schoolfax ) {
	    print TEX $lex{Fax}. " $schoolfax";
	}
	if ( $schoolphone or $schoolfax ) {
	    print TEX "\\\\\n\n";
	}
	# Note:\quad is eM horizontal width, \qquad is eMM's width. 
	
	# Administrator Lines
	if ( $r_ShowAdmins ) {
	    print TEX "$r_Principal \\hfill  $r_VicePrincipal \\\\\n\n";
	    print TEX "{\\footnotesize $lex{Principal} \\hfill ";
	    if ( $r_VicePrincipal ) { print TEX $lex{'Vice-Principal'}; }
	    print TEX "}\\\\\n\n";
	}

	print TEX "\\vspace{$r_AddressSpacer}\n\n";
	print TEX " \\end{center}}\\qquad\n";  # note extra parens to close parbox.

	my $sth = $dbh->prepare("select pic from studentall where studnum = ?");
	$sth->execute( $studnum );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	my $pic = $sth->fetchrow;

	if ( $r_ShowStudentPicture and $pic ) { # verify that file exists
	    my $fpath = $configpath. '/admin/pic-big/'. $studnum. '.jpg';
	    if ( not -e $fpath ) {
		print "<h3>$lex{Picture} $lex{'Not Found'}: $firstname $lastname ($studnum)</h3>\n";
		$pic = ''; # set to blank, so next section fails to try to print picture
	    }
	}

	if ( $r_ShowStudentPicture and $pic ) { # note: must have ShowLogo on...
	    print TEX "\\includegraphics[width=$r_StudentPictureWidth]{";
	    print TEX "$configpath/admin/pic-big/$studnum.jpg}\\\\\n";

	} elsif ( $r_DivLogoFile ) {
	    print TEX "\\includegraphics[width=$r_DivLogoWidth]{";
	    print TEX "$configpath/etc/$r_DivLogoFile}\\\\\n";
	}


    } else {
	print TEX "\n{\\sf\\Huge $schoolname}\n\n";
    }

    print TEX "\n\\smallskip\n{\\sf\\Large ";

    my $displaygrade = $grade;
    if ( $schoolmode == 1 ) { # British mode
	my $val = $g_FormMap{$grade};
	if ( not $val ) { $val = $grade; }
	if ( $val =~ m/F|f/ ) { # we are adding form.
	    $val =~ s/F|f/$lex{Form} /;
	} else { # put in grade text.
	    $val = "$lex{Grade} $val";
	}
	$displaygrade = $val;
	
    } else { # normal mode
	$displaygrade = qq{$lex{Grade} $displaygrade};
    }

	
    print TEX " $displaygrade ". $lex{'Report to Parents'};
    print TEX "}\n\n $currdate\n";
    print TEX "\n\\medskip\n{\\sf\\Large\\it $firstname $middlename $lastname} ";
    if ( $r_ShowProvNum and $provnum ) {
	print TEX "{\\sf($provnum)}";
    }
    print TEX "\n\n";


    print TEX "{\\sf ($birthdate)}\n\\smallskip\n\n";
    print TEX "\\end{center}\n";


} # End of prTexHead


#---------------------
sub prHomeroomTeachers {
#---------------------

    my $homeroom = shift;
    my @teachers = @_;
    print TEX "\\begin{center}\n";
    print TEX "\\setlength{\\extrarowheight}{0pt}\n";
    print TEX "\\begin{tabular}{ll}\n{\\small\\bf  ";
    print TEX "$lex{Homeroom} $homeroom $lex{'Teacher(s)'} }";
    foreach my $teach ( @teachers ){
	print TEX "& {\\it $teach} \\\\ \n";
    }
    print TEX "\\end{tabular}\n\\setlength{\\extrarowheight}{4pt}\n";
    print TEX "\\end{center}\n\n";

} # End of prHomeroomTeachers



#---------------------
sub print_grade_scheme {
#---------------------

    my $grade = shift;

    # Set Grading Scheme choice ( 'a', 'b', etc.)
    my $scheme = $r_EvalSch{$grade}; # is letter a,b,c, etc. from repcard configuration
    my $schemeAlt1 = $r_EvalSchAlt1{$grade};
    my $first;

    if ( $r_CenterSubjects ) {
	print TEX "\\begin{center}\n";
    }

    if ( @{$r_Eval{$scheme}} ) {

	# set width of section.
	my $width = $textwidth;
	$width =~ s/mm//; # strip 'mm'.
	$width -= 30;

	my $col1 = 10;
	my $col2 = $width - $col1; # rest of width;

	print TEX "\\begin{tabular}{|p{$col1 mm}|p{$col2 mm}|}\\hline\n";
	print TEX "\\multicolumn{2}{|c|}{\\sf\\large\\bf ". $lex{'Evaluation and Comment Key'};
	print TEX " }\\\\ \\hline\n";

	for my $item ( @{ $r_Eval{$scheme} } ){
	    ( $item ) = latex_filter( $item );
	    my ($itema, $itemb ) = split(/::/, $item);
	    if ( not $itemb ) { # no double colons::
		print TEX "\\multicolumn{2}{|p{$width mm}|}{$itema}\\\\ \\hline\n";
#		print TEX "\\multicolumn{2}{|l|}{$itema}\\\\ \\hline\n";
	    } else {
		print TEX "$itema &$itemb\\\\ \\hline\n";
	    }
	}
	print TEX "\\end{tabular}\n\\medskip\n\n";


#	$first = 1;
#	print TEX "\\begin{center}{\\sf\\Large ";
#	print TEX $lex{'Evaluation and Comment Key'}. "}\n\n";
#	print TEX "\\parbox[b]{$r_AssessKeyWidth}";
#	print TEX "{\\begin{multicols}{$r_AssessKeyCols}\n";

#	for my $item ( @{$r_Eval{$scheme}} ){
#	    if (not $first){ 
#		print TEX "\\\\\n";
#	    } else { 
#		$first = 0;
#	    }
#	    print TEX $item;
#	}
#	print TEX "\\end{multicols}}\n"; # Note parbox ending.
#	print TEX "\\end{center}\n";

    }


    # Now print Alt1 Eval keys, if any.
    if ( @{$r_EvalAlt1{$schemeAlt1}} ) { # assume we have something

	# set width of section.
	my $width = $textwidth;
	$width =~ s/mm//; # strip 'mm'.
	$width -= 30;
	
	my $col1 = 10;
	my $col2 = $width - $col1; # rest of width;

	print TEX "\\begin{tabular}{|p{$col1 mm}|p{$col2 mm}|}\\hline\n";
	print TEX "\\multicolumn{2}{|c|}{\\sf\\large\\bf $r_EvalAlt1Title ";
	print TEX " }\\\\ \\hline\n";

	for my $item ( @{ $r_EvalAlt1{$schemeAlt1} } ){
	    ( $item ) = latex_filter( $item );
	    my ($itema, $itemb ) = split(/::/, $item);
	    if ( not $itemb ) { # no double colons::
		print TEX "\\multicolumn{2}{|p{$width mm}|}{$itema}\\\\ \\hline\n";
#		print TEX "\\multicolumn{2}{|l|}{$itema}\\\\ \\hline\n";
	    } else {
		print TEX "$itema &$itemb\\\\ \\hline\n";
	    }
	}
	print TEX "\\end{tabular}\n\\medskip\n\n";


#	$first = 1;
#	print TEX "\\begin{center}{\\sf\\Large ";
#	print TEX $r_EvalAlt1Title. "}\n\n";
#	print TEX "\\parbox[b]{$r_AssessKeyWidth}";
#	print TEX "{\\begin{multicols}{$r_AssessKeyCols}\n";

#	for my $item ( @{$r_EvalAlt1{$schemeAlt1}} ) {
#	    if ( not $first ){
#		print TEX "\\\\\n";
#	    } else { 
#		$first = 0;
#	    }
#	    print TEX $item;
#	}
#	print TEX "\\end{multicols}}\n"; # Note parbox ending.
#	print TEX "\\end{center}\n";
 
   }

    if ( $r_CenterSubjects ) {
	print TEX "\\end{center}\n";
    }

} # end of print grade scheme



#------------
sub prCourse { # Print Course Results
#------------

    # @eval array set with current subjsec, and refs...
    # $startterm, and $endterm are starting and ending term for the report card display. 
    # This will be modified by $r_TermDisplayLeading and $r_TermDisplayTrailing values;
    my ( $subjsec, $studnum, $currterm, $startterm, $endterm, $evalref )  = @_;
    my @eval = @{ $evalref };
    

    # Get info for this course; 
    my $sth = $dbh->prepare("select description, teacher, startrptperiod, endrptperiod, calcavg,
     grade from subject where subjsec = ?");
    $sth->execute( $subjsec );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    my ( $description, $teacher, $startterm, $endterm, $calcavg, $subjgrade ) = $sth->fetchrow;
    if ( $calcavg eq 'N' ) { $calcavg = 0; } #

    # Set the Track for this course based on it's grade
    my $track = $g_MTrackTermType{ $subjgrade };

    
    # Set Personal Growth Flag before latex filtering/escaping.
    my $personal_growth_flag; # flag for printing keys to personal growth evals
    if ( $description eq $r_Personal_Growth ) {
	$personal_growth_flag = 1;
    } else {
	$personal_growth_flag = 0;
    }


    # LaTeX filter subject fields
    ( $description, $teacher ) = latex_filter( $description, $teacher );


    # calculate the average mark
    my $averagemark;
    if ( $calcavg ) {

	# Calculate the weighted average
	my $termPattern = $startterm. '-'. $endterm;
	my @weight;
	if ( $r_AverageWeight{$termPattern} ) {
	    @weight = @{ $r_AverageWeight{$termPattern} };
	} else {
	    @weight = ();
	}

	unshift @weight, 0; # put in a blank value.
	#foreach my $wt ( @weight ) { print "W:$wt "; }
	
	my ( $totalscore, $totalweight );
	my @tempeval = @eval; # in order to remove first column (objectives)
	shift @tempeval;

	foreach my $evalref ( @tempeval ) {
	    if ( my $wt = $weight[ $evalref->[0] ] ) { # The weight for this term of subj.
		$totalscore += ( $wt * $evalref->[1] );
		$totalweight += $wt;

	    } elsif ( defined $evalref->[1] && $evalref->[1] ne "" ) { 
		# if it's defined and not an empty string, count it
		$totalscore += $evalref->[1];
		$totalweight++;
	    }
	}

	if ( $totalweight ) {
	    $averagemark = $totalscore / $totalweight;
	} else {
	    $averagemark = 0;
	}
	$averagemark = format_number( $averagemark, $r_AveragePrecision, 0);
    }


    # Check if we should add the Personal Growth Key...
    if ( $personal_growth_flag ) {  # print row with objectives...

	# Figure out width of section.
	my $width = $textwidth;
	$width =~ s/mm//; # strip 'mm'.
	$width -= 30;

	$col1 = 10;
	$col2 = $width - $col1; # rest of width;

	print TEX "\\begin{tabular}{|p{$col1 mm}|p{$col2 mm}|}\\hline\n";

	my $key = $r_PDEvalGrp{$subjgrade};

	if ( @{ $r_PDEval{$key} } ) { # if we have a non blank objective group...
	    print TEX "\\multicolumn{2}{|c|}{\\sf\\large\\bf $description ";
	    print TEX $lex{'Evaluation Key'}. " }\\\\ \\hline\n";
	}
	for my $item ( @{ $r_PDEval{$key} } ){
	    ( $item ) = latex_filter( $item );
	    my ($itema, $itemb ) = split(/::/, $item);
	    print TEX "$itema &$itemb\\\\ \\hline\n";
	}
	print TEX "\\end{tabular}\\medskip\n\n";

    }

# Print Out Eval Table for viewing -------
#    print qq{Original Eval: $subjsec};
#    print qq{<table border="1" cellspacing="0" cellpadding="3">};
#
#    foreach my $idx ( 0.. $#eval ) {
#	print "<tr><td>$idx - $eval[$idx]</td>";
#	foreach my $val ( @{ $eval[$idx] } ) {
#	    print "<td>$val</td>\n";
#	}
#	print "</tr>\n";
#    }
#    print "</table>\n";
#--------


    print TEX "\\begin{tabular}{|p{$r_SubjSpace}|";
    foreach my $ref ( @eval ) {  print TEX "p{$r_MarkSpace}|"; }
    if ( $calcavg ){ print TEX "p{$r_MarkSpace}|"; }
    print TEX "}\\hline\n";


    # pull off first column of objectives
    my @objectives = @{ shift @eval };
    shift @objectives; # remove top blank one.
    @objectives = latex_filter( @objectives );


    # Get Teacher Information
    my $sth = $dbh->prepare("select sal, firstname, lastname 
      from staff where userid = ? ");
    $sth->execute( $teacher );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    my ($sal, $firstname, $lastname) = $sth->fetchrow;
    my $subjectteacher;
    if ( $lastname ) { 
	if ( $sal ) {
	    $subjectteacher = " ($sal $lastname)"; 
	} else { # fall back to using first name
	    $subjectteacher = " ($firstname $lastname)"; 
	}
    }


    # Print Term Line with Subject name, Teacher and term numbers.
    print TEX "\\rowcolor[gray]{ $r_GrayScale }";
    print TEX "{\\sf\\large\\bf $description}";
    if ( length( $description ) > 20 ) { print TEX "\n\n"; }
    print TEX "$subjectteacher";

    foreach my $ref ( @eval ) {
	my $title = $ref->[0]; # top of column 
	if ( $g_TermDisplay{$track}{ $title } ) { # if defined, reset
	    $title = $g_TermDisplay{$track}{ $title };
	}
	print TEX "& \\hfil $title \\hfil"; 
    }


    if ( $calcavg ){ print TEX "& \\hfil ". $lex{Average}. " \\hfil"; }
    print TEX "\\\\ \\hline\n";


    # LaTeX filter characters in @eval 2D array.
    foreach my $ref ( @eval ) {
	@{$ref} = latex_filter( @{$ref} );
    }


    my ($absents, $lates) = split(':', calcSubjectAttendance( $subjsec, $studnum ));
    
    
    my $objcount = 1;
    foreach my $objective ( @objectives ) {

	# Skip showing 'Mark' objective and show attendance
	if ( $r_ShowSubjectAttendance{$subjgrade} and $objcount == 1 ) { # only on line 1

	    print TEX qq{$lex{Periods} $lex{Absent} $absents $lex{Late} $lates};
	    if ( $objective ne $lex{Mark} ) { # print rest of line blank
		foreach my $ref ( @eval ) { print TEX "& "; }
		if ( $calcavg ) { print TEX "& "; }
		print TEX "\\\\ \\hline\n\n";
		print TEX $objective;
	    }

    	} else { # print objective
	    print TEX $objective;
	}

	# Print Rest of Line
	foreach my $ref ( @eval ) {
	    print TEX "& \\hfil $ref->[$objcount]\\hfil";
	}
	if ( $calcavg and $objcount == 1 ){ # only print average for first.
	    print TEX "& \\hfil $averagemark \\hfil";
	} elsif ( $calcavg ) { 
	    print TEX "& ";
	}
	print TEX "\\\\ \\hline\n\n";

	$objcount++;

    }

    print TEX "\\end{tabular}\\\\";


} # End of prCourse



#------------
sub prComment { # print all the comments.
#------------

    my ( $subjsec, $studnum, $startterm, $endterm ) = @_;
    
    # startterm since we use values from the subject table instead. We
    # use endterm in case not yet at end of the course.
    
    # print "Comment:$subjsec - $studnum - Start:$startterm END:$endterm<br>\n";

    
    print TEX "\n\\smallskip\n\n"; # small space
    if ( $r_ClassAvg and $classavg{$subjsec} ){ 
	print TEX "{\\bf ". $lex{'Class Average'}. ":} $classavg{$subjsec}\n\n";
    }

    # Load comments, if any.
    my %comments;
    my $sth = $dbh->prepare("select comment, term from eval where studnum = ?
      and subjcode = ? order by term"); 
    $sth->execute( $studnum, $subjsec );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    while ( my ($comment, $term ) = $sth->fetchrow ) {
	if ( $term >= $startterm and $term <= $endterm ) {
	    $comments{$term} = $comment;
	}
    }
    if ( not %comments ) { return; }

    my $sth = $dbh->prepare("select calcavg, grade, startrptperiod, endrptperiod from subject where subjsec = ?");
    $sth->execute( $subjsec );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    my ($calcavg,$subjgrade, $start, $end) = $sth->fetchrow;  # note 'start','end' are set in subject, not passed
    if ( $calcavg eq 'N' ) { $calcavg = 0; }

    my $track = $g_MTrackTermType{ $subjgrade };

    # Figure out Comment Width; assume 6pt tabcolsep (2.12mm); first 2 is subject cell
    my $subjspace  = $r_SubjSpace;
    $subjspace =~ s/mm//; # strip 'mm';
    my $markspace  = $r_MarkSpace;
    $markspace =~ s/mm//; # strip 'mm';

    if ( $endterm < $end ) { # not at end of course term.
	$end = $endterm;
    }

    
    # my $termcount = $endterm - $startterm + 1;
    my $termcount = $end - $start + 1; # now using values from the subject table (ie. course)
    if ( $termcount < 1 ) { $termcount = 1; }
    
    # OLD my $width = $subjspace + ($#eval * $markspace) + ( 2 + 2 * $#eval ) * 2.1;
    my $width = $subjspace + ($termcount * $markspace) + ( 2 + 2 * $termcount ) * 2.1;
    if ( $calcavg ){ $width = $width + $markspace;}


    print TEX "\n\\parbox{$width mm}{\n";

    foreach my $term ( sort keys %comments ) {
	if ( not $comments{$term} ) { next; }
	my $title = $g_TermDisplay{$track}{$term};

	my ($comment) = latex_filter ( $comments{$term} );
	$comment =~ s/\s*[\n|\r]/ /g;
	print TEX "\n{\\bf $title:} {\\it $comment }\n";
    }

    print TEX "\n}\\smallskip\n\n"; # Note: brace ends parbox.

    print TEX "\n\\medskip\n\n";

} # End of prComment



#----------------------
sub prMonthlyAttendance {  # Version with monthly attendance info
#----------------------

    my $studnum = shift;
 
    # Needs globals:
    #  %schooldays - days in each month in hash.
    #  $periodsperday - number of periods in the school day.

    # calculate attendance, one for each month; from library function.
    foreach my $yrmo ( sort keys %schooldays ) {
	my $absrec = calcMonthlyAttendance($studnum, $yrmo, $periodsperday, $currsdate, \%lex, $dbh );
#	print "$studnum YRMO:$yrmo REC:$absrec<br>\n";
	( $absent{$yrmo}, $tardy{$yrmo} ) = split(':',$absrec);
    }


    # calculate enrollment, one for each month
    my $ymref = calcMonthlyEnrollment( $studnum, $schoolstart, $currsdate, $dbh );
    my %ymenrol = %$ymref;  # yyyy-mm -> start,end,days


    # Print Start of Attendance Table
     print TEX "\\begin{center}\n";

    # Setup Table
    print TEX "\\medskip\n\\begin{tabular}{|p{32mm}|\n";
    foreach my $mo ( sort keys %schooldays ) { # $mo not used
	print TEX "p{9mm}|";
    }
    print TEX "}\n";


    # Print Heading Line
    my $colcount = scalar (keys %schooldays ) + 1;
    print TEX " \\multicolumn{$colcount}{\@{}c}{\\rule{0pt}{12pt} ";
    print TEX "\\sf\\bf\\Large ". $lex{Attendance}. "}\n\n";
    print TEX "\\\\\\hline\n";


    # Print Months Line
    print TEX "\\rowcolor[gray]{ $r_GrayScale }\n";
    foreach my $mo ( sort keys %schooldays ) {
	my ($yr,$mn) = split(/-/, $mo );
	print TEX "& \\hfil $s_month[$mn] \\hfil \n";
    }
    print TEX "\\\\\\hline\n";


    # Print Days Open
    print TEX "{\\large\\bf ". $lex{'Days Open'}. "}\n";
    foreach my $yrmon ( sort keys %schooldays ) {
	print TEX "& \\hfil $schooldays{$yrmon} \\hfil \n";
    }
    print TEX "\\\\\\hline\n";


    # Print Days Enrolled
    print TEX "{\\large\\bf ". $lex{'Days Enrolled'}. "}\n";
    foreach my $yrmo ( sort keys %schooldays ){

	if ( $override ) {
	    my $do = $schooldaysorig{ $yrmo }; # Days Open
	    my $ado = $schooldays{ $yrmo };  # Adjusted Days Open

	    my $de = $ymenrol{$yrmo}{'days'};  # Days Enrolled.
	    #print "<br>SCHOOL DAYS:",%schooldaysorig,"<br>\n";
	    #print "$student[1] $student[2] DO: $do  ADO: $ado DE: $de<br>\n";

	    my $ade; # adjusted days enrolled
	    if ( $do ) {
		$ade = format_number( ($de * $ado / $do), 2, 0);
	    } else {
		$ade = 0;
	    }

	    print TEX "& \\hfil $ade \\hfil \n";

	} else {
	    print TEX "& \\hfil $ymenrol{$yrmo}{'days'} \\hfil \n"; 
	}
    }
    print TEX "\\\\\\hline\n";


    # Print Days Absent
    print TEX "{\\large\\bf ". $lex{'Days Absent'}. "}\n";
    foreach my $yrmo ( sort keys %schooldays ){
	my $abs = format_number( $absent{$yrmo}, 2, 0);
	print TEX "& \\hfil $abs \\hfil\n"; 
    }
    print TEX "\\\\ \\hline\n";


    # Print Periods Late
    print TEX "{\\sf\\large\\bf $lex{Periods} $lex{Late} }\n";
    foreach my $yrmo ( sort keys %schooldays ){ 
	print TEX "& \\hfil $tardy{ $yrmo } \\hfil\n"; 
    }
    print TEX "\\\\ \\hline\n";


    # Finish Attendance Box
    print TEX "\\end{tabular}\n";
    print TEX "\\end{center}\n"; 
    print TEX "\\bigskip\n";

}



#----------------
sub prAddComments {
#----------------

    my ( $studnum, $startterm, $endterm ) = @_;

    # Updated to show additional comment data for each student.
    # $r_AdditionalComments{$tsubjcode} or $r_AdditionalComments{$subjcode} ) {
    # Get student information for this student for this term.

    # Get the student grade, and then the track for this grade (rather than subject based)
    my $sth = $dbh->prepare("select grade from studentall where studnum = ?");
    $sth->execute(  $studnum );
    if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr;}
    my $grade = $sth->fetchrow;
    my $track = $g_MTrackTermType{ $grade };


    $sth = $dbh->prepare("select count(*) from eval where subjcode = ? and studnum = ?");
    my $sth1 = $dbh->prepare("select subjcode from eval where subjcode like ? and studnum = ?");

    my @subjcodes; # codes for this student

    # Loop through subjects looking for records for this student.
    foreach my $subj ( keys %r_AdditionalComments ) {

	if ( $subj =~ m/-/ ) { # has dash, thus subjsec
	    $sth->execute( $subj, $studnum );
	    if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr;}
	    my $count = $sth->fetchrow;
	    if ( $count > 0 ) { # we have records
		push @subjcodes, $subj;
		next;
	    }

	} else { # no dash, a subject code, use 'like' match

	    $subj = $subj. '-%';
	    $sth1->execute( $subj, $studnum );
	    if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr;}
	    $subjcode = $sth1->fetchrow;
	    if ( $subjcode ) { # we have records
		push @subjcodes, $subjcode;
		next;
	    }
	}
    }
    # @subjcodes now defined if any additional comment subjects enrolled

    $sth = $dbh->prepare("select comment from eval 
      where subjcode = ? and studnum = ? and term = ?");

    print TEX "{\\bf\\Large $lex{'General Comments'}}\n\n";

    foreach my $term ( $startterm .. $endterm ) {
	my $first = 1;
	foreach my $subjcode ( @subjcodes ) {

	    $sth->execute( $subjcode, $studnum, $term );
	    if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr;}
	    my $comment = $sth->fetchrow;
	    if (not $comment) { next; }

	    $comment =~ s/\s*[\n\r]/ /g; # strip cr/lf
	    ($comment) = latex_filter(($comment)); # filter content

	    if ( $first ) {
		print TEX "{\\bf ". $g_TermDisplay{$track}{$term}. " $currterm:} ";
		$first = 0;
	    }

	    print TEX "$comment \n\n";
	}
    }

    print TEX "\\vspace{0.6in}\n\n";

}

 
#---------------
sub prTeacherSig {
#---------------
    print TEX "\\underline{\\hspace{2.5in}} \n\n";
    print TEX "{\\small $lex{Teacher}}\n\n \\medskip\n";
}

#-----------------
sub prPrincipalSig {
#-----------------
    print TEX "\\underline{\\hspace{2.5in}}\n\n";
    print TEX "{\\small $lex{'Principal'}}\n\n\\medskip\n";
}

#-------------
sub prComboSig { # both teacher and principal
#-------------
    print TEX "\\underline{\\hspace{2.5in}}";
    print TEX "\\hfill \\underline{\\hspace{2.5in}}\n\n";
    print TEX "{\\small $lex{Teacher}} \\hfill ";
    print TEX "{\\small $lex{'Principal'}}\n\n\\medskip\n";
}

#------------
sub prTearoff {  # print tearoff line.
#------------

    # block these 2 sections together over page breaks
    if ( $tearoffblock ) { print TEX "\\parbox{\\textwidth}{ "; } 

    print TEX "\\dotfill\n\n\\bigskip\n\n{\\bf Parents/Guardians:}\n";
    print TEX $lex{'Please tear off this portion and return it to the school'};
    print TEX " \n";
    print TEX $lex{'in the report envelope with any comments and your signature'}. ".\n";
}

#--------------
sub prParentSig { # print parent signature.
#--------------
    my ($currdate, $lastname, $firstname, $middlename) = @_;
    print TEX "\n\n\\vspace{0.5in}\n\n\\underline{\\hspace{2.5in}}\n\n";
    print TEX "{\\small $lex{'Parent/Guardian Signature'}}\n\n\\medskip\n";
    print TEX "{\\bf $lex{'Student'}:} {\\it $firstname $middlename $lastname}\n\n";
    print TEX "{\\bf $lex{Comments}:}\n\n";

    if ( $tearoffblock ) { print TEX "} \n "; } 

}


#------------
sub prYearEnd {
#------------

    my ($studentname, $grade)  = @_;

    my ($yearstart,$yearend) = split('-', $schoolyear); # global

    my ($nextgrade, $currgrade);
    
    if ($grade eq 'PK'){ $nextgrade = 'K';}
    elsif ($grade eq 'K'){ $nextgrade = 1;}
    else { $nextgrade = $grade + 1;}

    if ( $schoolmode == 1 ) { # British mode
	my $val = $g_FormMap{$nextgrade};
	if ( not $val ) { $val = $nextgrade; }
	if ( $val =~ m/F|f/ ) { # we are adding form.
	    $val =~ s/F|f/$lex{Form} /;
	} else {
	    $val = qq{$lex{Grade} $val};
	}
	$nextgrade = $val;

	# now do the same with grade to make currgrade values
	my $val = $g_FormMap{$grade};
	if ( not $val ) { $val = $grade; }
	if ( $val =~ m/F|f/ ) { # we are adding form.
	    $val =~ s/F|f/$lex{Form} /;
	} else {
	    $val = qq{$lex{Grade} $val};
	}
	$currgrade = $val;
    }
	
    
    my $key = $r_PlacementIndex{ $grade };
    my $tempTex = $r_PlacementTex{ $key };

    if ( $tempTex ) {
	# Replace variables.
	$tempTex =~ s/%studentname%/$studentname/;
	$tempTex =~ s/%nextgrade%/$nextgrade/g;
	$tempTex =~ s/%schoolyearend%/$yearend/;
	$tempTex =~ s/%currgrade%/$currgrade/;

	print TEX "\\begin{center}\n\\bigskip\n\n";
	print TEX "\\framebox[7in][c]{";
	print TEX $tempTex;  # Variable values found in repcard.conf.
	print TEX "}\\end{center}\n"; #End of Framebox also.
    }
}


#------------
sub calcFinal {
#------------
    # Passed values: ref to @eval array to do the calcs.
    my @localeval = ${shift};
    print @localeval; 
}


#------------------------
sub calcSubjectAttendance {
#------------------------

    my ( $subjsec, $studnum ) = @_; # pass subject and student.

    my ($periods,$lates); # periods absent/late

    my $sth = $dbh->prepare("select distinct reason, count(*) from attend 
      where subjsec = ? and studentid = ? group by reason");
    $sth->execute( $subjsec, $studnum );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

    while ( my ( $reason, $count ) = $sth->fetchrow ) {
	#print "Reason: $reason Count: $count<br>\n";

	if ( $reason =~ m/$absentString/ ) {
	    $periods += $count;
	} elsif ( $reason =~ m/$lateString/ ) {
	    #if ( $r_LateAbsentRatio ) {
	    #  $periods += ( $count / $r_LateAbsentRatio );
	    # } else {
	    # $periods += $count / 3; # default to 3 Late = 1 Absent
	    # }
	    $lates += $count;
	}
	# No other reasons affecting.

    }

    #print "P:$periods<br>\n";

    if ( not $periods ) {
	$periods = '0';
    }
    if ( not $latest ) {
	$lates = 0;
    }

    
    return "$periods:$lates" # format_number( $periods, 2);

}
