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

#  This file is part of Open Admin for Schools.

# Get Grade and Year-Month and display attendance for each day.

my %lex = ('Teacher' => 'Teacher',
	   'Error' => 'Error',
	   'Main' => 'Main',
	   'Attendance' => 'Attendance',
	   'Report' => 'Report',
	   'Month' => 'Month',
	   'Start' => 'Start',
	   'Continue' => 'Continue',
	   'Select' => 'Select',
	   'Grade' => 'Grade',
	   'Student' => 'Student',
	   'Subject' => 'Subject',
	   'Show' => 'Show',
	   'Withdrawn' => 'Withdrawn',
	   'or' => 'or',
	   'Homeroom' => 'Homeroom',
	   'Missing' => 'Missing',
	   'Value' => 'Value',
	   'View' => 'View',
	   'Hover' => 'Hover',
	   'Students' => 'Students',
	   'Starting' => 'Starting',
	   'Ending' => 'Ending',
	   'Override' => 'Override',
	   'Days Open' => 'Days Open',
	   'No Students Selected' => 'No Students Selected',
	   'Open' => 'Open',
	   'End' => 'End',
	   'Yearly' => 'Yearly',
	   
	   );

my $self = 'rptattstud1.pl';

my $closedcolor = '#AAA';
my $partclosedcolor = '#EEE';
my $notenrolledcolor = '#DDD';

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


# Get current dir so know what path for config files.
my $configpath;
my $teachermode;
if ( getcwd() =~ /tcgi/ ){ # we are in tcgi
    $teachermode = 1;
    $configpath = '..'; # go back one to get to etc.
} else {
    $configpath = '../..'; # go back two to get to etc.
}

# only load passwords and users
eval require "$configpath/etc/admin.conf.root";
if ( $@ ) {
    print $lex{Error}. " $@<br>\n";
    die $lex{Error}. " $@\n";
}

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

eval require "$configpath/lib/libschedule.pl";
if ( $@ ) {
    print $lex{Error}. " $@<br>\n";
    die $lex{Error}. " $@\n";
}

# for parseGradesPeriod function
eval require "$configpath/lib/libDate.pl";
if ( $@ ) {
    print $lex{Error}. " $@<br>\n";
    die $lex{Error}. " $@\n";
}




my $dbtype = 'mysql';
my $dsn = "DBI:$dbtype:dbname=$dbase";
my $dbh = DBI->connect($dsn,$user,$password);
$dbh->{mysql_enable_utf8} = 1;


# Load Configuration Variables;
my $sth = $dbh->prepare("select id, datavalue from conf_system where filename = 'admin'");
$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";
    }
}


# Teachermode
if ( $teachermode ) { # running on teacher site
    $css = $tchcss;
    $homepage = $tchpage;
    $downloaddir = $tchdownloaddir;
    $webdownloaddir = $tchwebdownloaddir;
}


my $q = new CGI;
print $q->header( -charset, $charset );
my %arr = $q->Vars;



# Set Date
my @tim = localtime(time);
my $cyear = @tim[5] + 1900;
my $cmonth = @tim[4] + 1;
my $cday = @tim[3];
my $currdate = "$cyear-$cmonth-$cday";
my $currjd = julian_day( split('-', $currdate) );
if (length $cmonth == 1 ) { $cmonth = '0'. $cmonth; }
my $curryrmo = "$cyear-$cmonth";

my $prevyrmo;
if ( $cmonth == 1 ) {
    my $prevyr = $cyear - 1;
    $prevyrmo = "$prevyr-12";
} else {
    my $prevmo = $cmonth - 1;
    if (length $prevmo == 1 ) { $prevmo = '0'. $prevmo; }
    $prevyrmo = "$cyear-$prevmo";
}


my $title = "$lex{Yearly} $lex{Student} $lex{Attendance} $lex{Report} 1";
print qq{$doctype\n<html><head><title>$title</title>\n};
print qq{<link rel="stylesheet" href="$css" type="text/css">\n};
print qq{<style>th.dr, td.dr { border-right-style:double; border-right-width:3px; }</style>\n};

print qq{$chartype\n</head><body style="padding:1em;">\n};

print qq{[ <a href="$homepage">$lex{Main}</a> |\n};
print qq{ <a href="$attpage">$lex{Attendance}</a> ]\n};
print qq{<h1>$title</h1>\n};


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

} elsif ( $arr{page} == 1 ) {
    delete $arr{page};
    selectStudents();
    
} elsif ( $arr{page} == 2 ) {
    delete $arr{page};
    showReport();
}


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

    # Setup Year-Months.
    my @months;
    my %months;


    my ($sy, $sm, $sd) = split('-', $schoolstart); # schoolstart is global var from config.
    if ( length( $sm ) == 1 ) { $sm = '0'. $sm; }
    my $yrmo = "$sy-$sm";
    push @months, $yrmo;
    $months{$yrmo} = "$s_month[$sm]-$sy";

    for my $i (1..10) {
	my $mo = $sm + $i;
	if ( length( $mo ) == 1 ) { $mo = '0'. $mo; }
	my $yr = $sy;
	if ( $mo > 12 ) {
	    $mo = $mo - 12;
	    if ( length( $mo ) == 1 ) { $mo = '0'. $mo; }
	    $yr++;
	}
	my $yrmo = "$yr-$mo";
	push @months, $yrmo;
	$months{$yrmo} = "$s_month[$mo]-$yr";
    }


    # Get the grades, for subject attendance.
    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 ) {
	if ( $g_AttendanceEntryMethod{$gr} eq 'subject' ) {
	    push @grades, $gr;
	}
    }


    # Get the homerooms.
    my @homerooms;

    my $sth1 = $dbh->prepare("select distinct grade from student where homeroom = ? 
      and grade != '' and grade is not NULL");

    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
    }


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

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

    
    # Starting Month
    print qq{<tr><td class="bra">$lex{Starting} $lex{Month}</td>};
    print qq{<td class="la"><select name="startmonth"><option value="$months[0]">};
    print qq{$months{$months[0]}</option>\n}; 

    foreach my $mo ( @months ) {
	print qq{<option value="$mo">$months{$mo}</option>\n};
    }
    print qq{</select></td></tr>\n};


    # Ending Month
    print qq{<tr><td class="bra">$lex{Ending} $lex{Month}</td>};
    print qq{<td class="la"><select name="endmonth"><option value="$prevyrmo">};
    print qq{$months{$prevyrmo}</option>\n}; 

    foreach my $mo ( @months ) {
	print qq{<option value="$mo">$months{$mo}</option>\n};
    }
    print qq{</select></td></tr>\n};


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

    
    # Homerooms
    print qq{<tr><td class="bra">$lex{Homeroom} $lex{Attendance}</td>};
    print qq{<td class="la"><select name="homeroom"><option></option>\n}; 

    foreach my $hr ( sort {$a <=> $b} @homerooms ) {
	print qq{<option>$hr</option>\n};
    }
    print qq{</select></td></tr>\n};



    # Grades
    print qq{<tr><td class="bra"><span style="font-weight:normal;">$lex{or}</span>&nbsp;};
    print qq{$lex{Subject} $lex{Attendance} - $lex{Grade}</td>};
    print qq{<td class="la"><select name="grade"><option></option>\n}; 

    foreach my $gr ( sort {$a <=> $b} @grades ) {
	print qq{<option>$gr</option>\n};
    }
    print qq{</select></td></tr>\n};

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



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

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

    
    # Override Days Open
    print qq{<tr><td class="bra">$lex{Override} $lex{'Days Open'}</td>};
    print qq{<td><input type="checkbox" name="override" value="1">};
    print qq{ For Kindergarten or Pre-Kindergarten; partial/alternate days</td></tr>\n};

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

    foreach  my $mo ( @months ) {
	my ($y,$m) = split('-', $mo );
	print qq{<tr><td><b>$month[$m]</b> ($mo)</td><td>};
	print qq{<input type="text" name="ovr:$mo" size="4">};
	print qq{</td></tr>\n};
	if ( $mo eq $curryrmo ) {
	    last;
	}
    }

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


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

    exit;

}


#-----------------
sub selectStudents {
#-----------------

    my $studtable = 'student';
    my $showwithdrawn;
    if ( $arr{showwithdrawn} ) {
	$studtable = 'studentall';
	$showwithdrawn = 1;
	delete $arr{showwithdrawn};
    }


    # Check end month vs current month (can't go into future month...)
    my ($y, $m) = split('-', $arr{endmonth});
    if ( ($y == $cyear and $m > $cmonth ) or $y > $cyear ) { #Error
	print "<h3>Ending Month Not Allowed</h3>\n";
	print "</body></html>\n";
	exit;
    }

    
    # foreach my $key ( sort keys %arr ) { print "K:$key V:$arr{$key}<br>\n"; }
    
    
    # Start Form
    print qq{<form action="$self" method="post">\n};
    print qq{<input type="hidden" name="page" value="2">\n};
    foreach my $key ( sort keys %arr ) {  # pass arguments through
	if ( $key eq 'grade' or $key eq 'homeroom' ) { next; } # not needed since selct by student
	print qq{<input type="hidden" name="$key" value="$arr{$key}">\n};
    }


    my $sth1 = $dbh->prepare("select count(*) from studentwd where studnum = ?");
    
    my $sth;
    if ( $arr{homeroom} and $arr{grade} ) { # Error
	print qq{<h3>Error: Select Only Grade or Homeroom</h3>\n};
	print qq{</body></html>\n};
	exit;
	
    } elsif ( $arr{homeroom} ) {
	$sth = $dbh->prepare("select lastname, firstname, studnum from $studtable
          where homeroom = ? order by lastname, firstname");
	$sth->execute( $arr{homeroom} );
			     
    } elsif ( $arr{grade} ) {
	$sth = $dbh->prepare("select lastname, firstname, studnum from $studtable
          where grade = ? order by lastname, firstname");
	$sth->execute( $arr{grade} );


    } else { # all students selected
	$sth = $dbh->prepare("select lastname, firstname, studnum from $studtable
          order by lastname, firstname");
	$sth->execute;
    }

    my $first = 1;
    if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    while ( my ($lastname, $firstname, $studnum ) = $sth->fetchrow ) {

	my $wd;
	if ( $showwithdrawn ) {
	    $sth1->execute( $studnum );
	    if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	    
	    if ( $sth1->fetchrow ) { # we have a WD student
		$wd = qq{<span style="color:red;font-weight:bold;">WD</span>\n};
	    }
	}
	

	if ( $first ) {
	    if ( $arr{grade} ) { 
		print qq{<h3>$lex{Grade} $arr{grade}</h3>\n};
	    } elsif ( $arr{homeroom} ) { 
		print qq{<h3>$lex{Homeroom} $arr{homeroom}</h3>\n};
	    } else { # all students
		print qq{<h3>All $lex{Students}</h3>\n};
	    }
				 
	    print qq{<table cellpadding="3" border="1" cellspacing="0">\n};
	    print qq{<tr><th>$lex{Select} $lex{Students}</th></tr>\n};
	    print qq{<tr><td><input type="submit" value="$lex{Continue}"></td></tr>\n};
	    $first = 0;
	}

	print qq{<tr><td><input type="checkbox" name="$studnum" value="1"> };
	print qq{$wd <b>$lastname</b>, $firstname</td></tr>\n};
    }

    print qq{<tr><td><input type="submit" value="$lex{Continue}"></td></tr>\n};
    
    if ( not $first ) {
	print qq{</table>\n};
    }

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

    exit;

}


#-------------
sub showReport {
#-------------

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

    # Put Override days open in a month into hash and remove from %arr
    my %override;  # override days open per month.
    foreach my $key ( sort keys %arr ) {
	my ($txt,$ym) = split(':', $key );
	if ( $txt eq 'ovr' and $ym ) {  # it's override and we have a value.
	    $override{$ym} = $arr{$key};
	    delete $arr{$key};
	}
    }


    
# Check override    
#    foreach my $key ( sort keys %override ) {
#	print "OVR:K:$key  V:$override{$key}<br>\n";
#    }

    
#     print "<br>Main<br>\n";  # remaining values in %arr
#     foreach my $key ( sort keys %arr ) { print "K:$key V:$arr{$key}<br>\n"; }


   # Check for missing month entry
    if ( not $arr{startmonth} or ( not $arr{endmonth} ) ) {
	print qq{<h3>$lex{Missing} $lex{Value}</h3>\n};
	print qq{</body></html>\n};
	exit;
    }

    
    # Create hash of year-month values
    my @yearmonth;
    my ($yr, $mo ) = split('-', $arr{startmonth});
    my ($ey, $em ) = split('-', $arr{endmonth});
    
    # increment end month so we can get last days correctly.
    if ( $em == 12 ) {
	$em = '01';
	$ey++;
    } else {
	$em ++;
    };
    if ( length $em == 1 ) { $em = '0'. $em; };
    $arr{endmonth} = "$ey-$em";
	

    my $ym = $arr{startmonth};

    while ( $ym ne $arr{endmonth} ) {
	push @yearmonth, $ym;
	$mo++;
	if ( $mo > 12 ) {
	    $mo = 1;
	    $yr++;
	}
	if ( length $mo == 1 ) { $mo = '0'. $mo; }
	$ym = qq{$yr-$mo};
    }
    push @yearmonth, $ym; # final month push

   
    
    # Hash to store last days of the month.
    my %lastdays;
    my ($currym, $prevym);

    foreach my $ym ( @yearmonth ) {
	if (not $currym ) { $currym = $ym; next; } # skip first element
	$prevym = $currym;
	$currym = $ym;

	my $startjd = julian_day( split('-',$currym),1);
	my $prevjd = $startjd - 1; # end of previous month.
	my @date =  inverse_julian_day( $prevjd );
	$lastdays{$prevym} = $date[2];
    }
    pop @yearmonth;  # remove extra month added to get last day in last month.

#   foreach my $key ( sort keys %lastdays ) { print "YM:$key V:$lastdays{$key}<br>\n"; }
    
    
#    my $startmonth = $arr{startmonth};
    delete $arr{startmonth};
#    my $endmonth = $arr{endmonth};
    delete $arr{endmonth};
    # should only be student numbers left in %arr at this point.

    
    # Check for Students
    if ( not %arr ) {
	print qq{<h3>$lex{'No Students Selected'}</h3>\n};
	print qq{</body></html>\n};
	exit;
    }

    
#    foreach my $key ( sort keys %arr ) { print "K:$key V:$arr{$key}<br>\n"; }
    
    
    # Load student info and create sorting hash.
    my (%student, %sort );    # $student{studnum}{all fields} = value;
    my $sth = $dbh->prepare("select * from studentall where studnum = ?");
    foreach my $studnum ( keys %arr ) {
	$sth->execute($studnum);
	if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	while ( my $ref = $sth->fetchrow_hashref ) {
	    $student{$studnum} = $ref;
	    $sort{"$ref->{lastname}$ref->{firstname}$studnum"} = $studnum;
	}
    }

    
    # Get days closed for the year or year fraction.
    my %daysclosed; # daysclosed{ym}{day} = fraction
    my %daysclosedcount; # daysclosedcount{ym} = total

    # Populate DaysClosed hashes
    my $sth = $dbh->prepare("select date, dayfraction from dates where 
        month(date) = ? and year(date) = ?"); 
    foreach my $ym ( @yearmonth ) {

	my ($yr,$mo) = split '-', $ym;
	$sth->execute($mo, $yr);
	if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	
	my $closed; # sum of days closed fraction
	
	while ( my ($dt, $fraction ) = $sth->fetchrow ) {
	    my ($y,$m,$d) = split('-',$dt);
	    $d =~ s/^0//; # strip leading zeros from the day
#	    if ( $fraction == 0 ) {
#		# Check for partial day closed. 
#		print "No fraction for $dt<br>\n";
#	    }
	    $daysclosed{$ym}{$d} = $fraction;
	    $closed += $fraction;
	}
	$daysclosedcount{$ym} = $closed;
	
    }


# Testing Section.

#    foreach my $ym ( sort keys %daysclosed ) {
#	print "<br>YM:$ym $daysopen{$ym}<br>\n";
#	foreach my $day ( sort {$a <=> $b} keys %{ $daysclosed{$ym} } ) {
#	    print "K:$day V:$daysclosed{$ym}{$day}<br>\n"; 
#	}
#    }



=head  # Outline for teacher attendance checking.    

The teacher information in tattend has:
userid - teacher userid
attdate - date of attendance entry
subjects - (singular) subject subjsec OR homeroom in format HR:5/6
periods - again, now singular, the period that it was done for....


In order to check if a particular student's attendance was done, we have to:
a) Homeroom

Get students grade and homeroom and get attendance entry method.

If homeroom method, then get the teacher associated with this homeroom (only 1, check 'does attendance, too?). 
Then use this userid to check records with value: this userid, this subjects field (HR:homeroom),
Use tAttendHomeroom{ym}{day}{period} {userid}

This will give the attdate, and periods that attendance was done.

b) Subject (really Course)
With a subject entry method for a grade, we need the student timetable, 
and then find the matching teacher attendance table.
1) Get Day in Cycle, find courses student took.
2) Check if teacher attendance was done for that attdate, for that period, for that subjsec (subjects field).  
We don't care about userid, since student linkage is via subjsec not homeroom assignment.

create tAttendCourse{ym}{day}{period} {subjsec}

Checking for a particular date, period, we first need the day in cycle in order to get 
the timetable values for the student, which gives: Period->subjsec. Looping over the periods, 
we get the subjsec (course identifier),  we then check for this entry in tAttendCourse.

=cut



    # Teacher Attendance
    my (%tAttendHomeroom, %tAttendCourse);   
    # tAttendHomeroom{ym}{day}{period} {userid}    tAttendCourse{ym}{day}{period} {subjsec}

    
    my $sth = $dbh->prepare("select * from tattend where year(attdate) = ? and month(attdate) = ?"); 

    foreach my $ym ( @yearmonth ) {
	my ($yr,$mo) = split '-', $ym;
	$sth->execute($yr, $mo);
	if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

	while ( my $ref = $sth->fetchrow_hashref ) {
	    
	    my %r = %$ref;
	    
	    my ($y,$m,$day) = split('-', $r{attdate});
	    $day =~ s/^0//; # strip leading zero

	    if ( $r{subjects} =~ m/HR:.+/ ) {  # or not $r{subjects} ) { # if a homeroom
		my $hr = $r{subjects};
		$hr =~ s/HR://; 
		$tAttendHomeroom{$ym}{$day}{ $r{periods} }{ $hr } = 1; # students linked by homeroom; # was userid
	    
	    } elsif ( $r{subjects} ) {
		$tAttendCourse{$ym}{$day}{ $r{periods} }{ $r{subjects} } = 1; # students linked by course.
		
	    } else { # blank 'subjects' field
		print qq{<div><b>Missing Teacher Attendance Subject/Homeroom field</b>};
		print qq{ Date:$r{attdate} Userid:$r{userid} Period:$r{periods}</div>\n};
	    } 
		
	} # get dates loop
    } # ym loop
          

#    use Data::Dumper;
#    print "Homeroom<br><pre>\n";
#    print Dumper %tAttendHomeroom;
#    print "</pre><br>\n";


#    print "Course<br><pre>\n";
#    print Dumper %tAttendCourse;
#    print "</pre><br>\n";


    
# For Subject based attendance, create a termjd{track}{start:end} = term to look up term of current date;
# MTrackTerm{$track}{$term}{ start => startdate, end => $enddate }
    
    my %termjd;
    foreach my $track ( keys %g_MTrackTerm ) {
	foreach my $term ( keys %{ $g_MTrackTerm{$track}} ) {
	    my $sdate = $g_MTrackTerm{$track}{$term}{start};
	    my $edate = $g_MTrackTerm{$track}{$term}{end};
	    my $sdatejd = julian_day( split('-',$sdate));
	    my $edatejd = julian_day( split('-',$edate));
	    $termjd{$track}{"$sdatejd:$edatejd"} = $term;
	}
    }

#    use Data::Dumper;
#    print "termjd<br><pre>\n";
#    print Dumper %termjd;
#    print "</pre><br>\n";



    # Global Timetable - load this and then each student will use a subset for their courses.
    my %ttb; # ttb{term}{subjsec}{dayincycle}{period}
    my $sth = $dbh->prepare("select * from schedat");
    $sth->execute;
    if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    my $ref = $sth->fetchall_hashref('id');
    foreach my $key ( sort keys %{ $ref } ) {
	foreach my $hkey ( sort keys %{ $ref->{$key}} ) {
	    my %r = %{ $ref->{$key} };
	    $ttb{ $r{term} }{ $r{subjsec} }{ $r{day} }{ $r{period} } = 1;
	}
    }
    
#    use Data::Dumper;
#    print "Timetable (%ttb)<br><pre>\n";
#    print Dumper %ttb;
#    print "</pre><br>\n";

    
    my $schoolstartjd = julian_day(split('-', $schoolstart));

    
    # get homerooms of teachers (in order to link to children by homeroom for tattend.
    my (%homeroom, %teachername); # %homeroom{homeroom} = $userid; # OLD:%homeroom{homeroom}{userid} = 1
    
    my $sth1 = $dbh->prepare("select lastname, firstname from staff where userid = ?");

    my $sth = $dbh->prepare("select userid, field_value from staff_multi where field_name = 'homeroom'");
    $sth->execute;
    if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    while ( my ($userid, $rm ) = $sth->fetchrow ) {

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

	
	# $homeroom{$rm}{$userid} = 1; # in case of more than one teacher in same homeroom...?
	$teachername{$userid} = "$firstname $lastname";
	$homeroom{$rm} = $userid; # only one teacher doing attendance. Too ugly otherwise
    }

    
    
    # Main Student Loop
    foreach my $key ( sort keys %sort ) { 

	my $studnum = $sort{$key};
	my %r = %{ $student{$studnum}}; # student record.
	my $teacher = $homeroom{ $r{homeroom}};
	my $homeroom = $r{homeroom};
	my $grade = $r{grade};

	my ( @courses, %localttb ); # for this student;
	my ( $totaldaysopen, $totaldaysenrolled, $totaldaysabsent ); # total for statistics line.
    
        # Set Attendance Entry Method
	my $attmethod = $g_AttendanceEntryMethod{ $r{grade} };
	# Track
	my $track = $g_MTrackTermType{ $r{grade} };
	# PPD (Periods per Day attendance is taken
	my $ppd = $g_ppd{ $r{grade} };
	
#	print "Method: $attmethod Track:$track Grade:$r{grade}<br>\n";

	# Heading
	print qq{<h3>$r{firstname} $r{lastname}};
	if ( $attmethod eq 'homeroom' ) { # show homeroom teacher
	    print qq{ - Teacher $teachername{$teacher}};
	}
	print qq{</h3>\n};

	
	# get their enrollment for the year, and populate status 
	my @enrolblocks = findEnrollmentBlocks($studnum, $schoolstart, $schoolend, $dbh);

	# populate status keys (ym values)
	my %enrol;
	foreach my $ym ( @yearmonth ) {  # enter all months, keys only, so far.
	    $enrol{$ym};
	}

	# Put in the trigger points (enrollment status change).
	foreach my $blockref ( @enrolblocks ) {
	    my ($sy,$sm,$sd) = split('-', $blockref->{start} );
	    $sd =~ s/^0//;
	    $enrol{"$sy-$sm"}{$sd} = 'e';
    
	    my ($ey,$em,$ed) = split('-', $blockref->{end} );
	    $ed =~ s/^0//;
	    $enrol{"$ey-$em"}{$ed} = 'w';
	}

	# Update the first day of each month with the enrollment status
	my $estatus;
	foreach my $ym ( @yearmonth ) {
	    my $first = 1;
	    foreach my $day (1..31) {
		
		# Logic to populate the first day of the month with an
		# estatus value, if no value already on the first.
		# This is the first value in the month;
		if ( $enrol{$ym}{$day} and $first ) { # if we have a trigger value.
		    if ( $day != 1 ) { # if this is not on the first, then put in the day 1 value
			# if an 'e'(enrol), then must have been withdrawn to that point
			if ($enrol{$ym}{$day} eq 'e' ) { 
			    $enrol{$ym}{1} = 'w';
			    $estatus = 'e';
			} else {
			    $enrol{$ym}{1} = 'e';
			    $estatus = 'w'
			}
		    }
		    $first = 0;
		}

		# The normal situation: if an enrollment, estatus is 'e'; if a withdraw, estatus is 'w'.
		if ( $enrol{$ym}{$day} ) {
		    $estatus = $enrol{$ym}{$day};
		}

	    } # end of days;

	    if ( $first ) { # no enrollment change;
		$enrol{$ym}{1} = $estatus;
	    }
	} # end of ym update loop

=head
	# Test the %enrol hash
	foreach my $ym ( sort keys %enrol ) {
	    foreach my $day ( sort keys %{ $enrol{$ym} } ) {
		print qq{YM:$ym Day:$day VAL:$enrol{$ym}{$day}<br>\n};
	    }
	}
=cut

	# Start the Main Table
	print qq{<table cellpadding="3" cellspacing="0" border="1">\n};
	print qq{<caption style="font-weight:bold;font-size:120%;text-align:left;">};
	print qq{$lex{Hover} = $lex{View}, C = Closed, X = Weekend/Not Started, };
	print qq{NE = No Teacher Attendance Entry</caption\n};

	
	# Heading;
	print qq{<tr><th>$lex{Month}</th>};
	foreach my $day (1..31) {
	    print qq{<th class="cn">$day</th>};
	}
	print qq{<th title="Days Open">$lex{Open}</th>};
	print qq{<th title="Days Attended / Days Enrolled = %Attendance">$lex{Attendance}</th></tr>\n};

	my $sth = $dbh->prepare("select * from attend where absdate = ? and studentid = ?");

	my ($currterm, $prevterm);
	
	# Loop through each month.
	foreach my $ym ( @yearmonth ) {

	    my ($y,$m) = split('-', $ym);
	    print qq{<tr><td>$month[$m], $y</td>};

	    my $lastday = $lastdays{$ym};

	    # IF subject attendance, create a hash for day in cycle for this month.
	    my %dayincycle;
	    if ( $attmethod eq 'subject' ) {
		for my $d ( 1..$lastday ) {
		    my $dic = findDayInCycle( "$ym-$d", $dbh );
		    #print "Day of Month:$d  Cycle Day:$dic<br>\n";
		    $dayincycle{$d} = $dic;
		}
	    }

	    my $daysabsent; # total count of days absent for the month.
	    my $daysenrolled; # total count of days enrolled for the month.
	    my $daysopen; # days school is open for the month
	    
	    my $estatus = $enrol{$ym}{1}; # daily value for enrollment status
	    my $tAttendMonthlyFlag;

	    
	    # Day Loop
	    foreach my $day ( 1..31 ) {

		my $tAttendFlag; # flag to indicate if teacher has missed attendance today
		my $tAttendMsg = "$lex{Missing} $lex{Teacher} $lex{Attendance}:";

		if ( $day > $lastday ) {
		    print qq{<td></td>\n};
		    next;
		}

		my $date = qq{$ym-$day};
		my $currjd = julian_day(split('-', $date));
		my $dow = day_of_week( $currjd );

		
		# Weekend or School Not Started Yet
		if ( $dow == 0 or $dow == 6 or $currjd < $schoolstartjd ) {
		    print qq{<td class="cn" style="font-size:150%;">X</td>\n};
		    next;
		}

	
		# Get Current Term, for subject attendance checking.
		my $term;
		if ( $attmethod eq 'subject' ) {
		    foreach my $key ( keys %{ $termjd{$track}} ) {
			my ($startjd, $endjd ) = split(':', $key);
			if ( $currjd >= $startjd and $currjd <= $endjd ) {
			    $term = $termjd{$track}{$key};
			    last;
			}
		    }

#		    if ( not $term ) { 
#			print qq{<h3>$lex{Error}: Term not found for $date</h3>\n};
#		    }
		}

		if ( $term ) {
		    $prevterm = $currterm;
		    $currterm = $term;
		}
#		print "Date:$date CT:$currterm PV:$prevterm<br>\n";		

		
		# Updated Enrollment status
		if ( $enrol{$ym}{$day} ) { # we have an enrollment change trigger
		    $estatus = $enrol{$ym}{$day};
		}
		

		# Fully Closed / Partially Closed PLUS Update Days enrolled (partial or complete)
		my $openfrac;  # fraction of the day open, to check below on attendance
		if ( $daysclosed{$ym}{$day} >0.99 ) { # full day closed
		    print qq{<td title="School Closed" class="bcn">C</td>\n};
		    next;
		} elsif ( $daysclosed{$ym}{$day} > 0.01 ) { # partially closed
		    $openfrac = round( 1 - $daysclosed{$ym}{$day}, 2);
		    $daysopen += $openfrac;
		    if ( $estatus eq 'e' ) { # enrolled!
			$daysenrolled += $openfrac;
		    }
		    # Note: no next here since we are going to print attendance for partial day open.
		} elsif ( exists $daysclosed{$ym}{$day} and  $daysclosed{$ym}{$day} == 0 ) {
		    # partially closed (zero fraction), periods set in dates_periods;
		    my $date = qq{$ym-$day};
		    my $ref = parseGradesPeriod($date,$dbh);
		    # We know $grade and $ppd for the student.
		    my %periods = %{ $ref->{$grade}};
		    my $pcount; # count of periods closed
		    foreach my $period ( sort keys %periods ) {
			$pcount++;  # we could be more complicated if periods not same length, etc.
		    }
		    
		    $openfrac = round( 1 - ($pcount / $ppd), 2);
		    
		} else {  # full day open/enrolled
		    $daysopen++;
		    if ( $estatus eq 'e' ) { # enrolled!
			$daysenrolled++;
		    }
		}


		if ( $estatus ne 'e' ) { # not enrolled!
		    print qq{<td style="background-color:$notenrolledcolor;"></td>\n};
		    next;
		}


		
		# Check for teacher attendance entry
	       
		if ( not $openfrac ) { # we don't want to mess with partial days open, 
		    # since we don't know which periods are 'off'
		    if ( $attmethod eq 'homeroom' ) {
			my $aflag;
			foreach my $period ( 1..$ppd ) {
			    if ( not $tAttendHomeroom{$ym}{$day}{$period}{$homeroom} ) {
				# print qq{YM:$ym D:$day P:$period HR:$homeroom<br>\n};
				#print "Missing Attendance:$ym - $day - $period - $teacher<br>\n";
				$tAttendFlag = 1;
				$tAttendMonthlyFlag = 1;
				$aflag = 1;
			    }
			}
		    
			if ( $aflag ) { 
			    print qq{<td>NE</td>\n};
			    next;
			}
		    
		    } else { # subject attendance
			if ( $currterm != $prevterm and $prevterm ) {  # we have a term change....
			
			    # Get Courses Student is enrolled in for this term.
			    my $sth = $dbh->prepare("select subjcode from eval 
						    where studnum = ? and term = ?");
			    $sth->execute( $studnum, $term );
			    if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

			    @courses;
			    %localttb;
			
			    while ( my $subjsec = $sth->fetchrow ) {
				push @courses, $subjsec;

				if ( $ttb{$term}{$subjsec} ) {
				    # we have a timetable entry for this subject
				    foreach my $day ( keys %{ $ttb{$term}{$subjsec} } ) {
					foreach my $period ( keys %{ $ttb{$term}{$subjsec}{$day} } ) {
					    $localttb{$subjsec}{$day}{$period} = 1;
					}
				    }
				}
			    }

			    if ( not @courses or not %localttb ) { $tAttendFlag = 1; }
			}


			my $dayincycle = $dayincycle{$day};
			# print "Date:$date  Day:$day DIC:$dayincycle<br>\n";

			my $sth = $dbh->prepare("select id from tattend 
                          where attdate = ? and subjects = ? and periods = ?");
		    
			# Get todays courses and their periods. (may be more than 1 or same...)
			my $firstatt = 1;
			foreach my $subjsec ( @courses ) {
			    if ( $localttb{$subjsec}{$dayincycle} ) {
				foreach my $period ( sort keys %{ $localttb{$subjsec}{$dayincycle} } ) {
				    $sth->execute( $date, $subjsec, $period );
				    if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
				    my $id = $sth->fetchrow;
				    if ( not $id ) { # no entry
					$tAttendFlag = 1;
					$tAttendMonthlyFlag = 1;
					$tAttendMsg .= " $subjsec P$period,";
				    }
				}
			    } # end of timetable entry exists loop for this subject today
			} # end of courses loop
		    
		    } # end of subject attendance teacher entry check
		} # end of not fractional day open conditional.

		if ( $tAttendFlag ) {
		    print qq{<td title="$tAttendMsg">NE</td>\n};
		    next; # day
		}
		
		# Get Attendance for today
		$sth->execute( $date, $studnum );
		if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
		my $abscount;
		while ( my $ref = $sth->fetchrow_hashref ) {
		    if ( $ref->{reason} =~ m/Absent/ ) {
			$abscount++;
		    }
		}
		
		my $absent = round($abscount / $ppd, 2);
		$daysabsent += $absent;

		if ( $openfrac and $absent > $openfrac ) {
		    $absent = $openfrac;  # because we can't be more absent than school is open!
		}
		
		my $display;
		if ( $absent < 0.01 ) { 
		    $display = 'P';
		} elsif ( $absent > 0.99 ) {
		    $display = 'A';
		} else {
		    $display = $absent. 'A';
		}

		my $partdaystyle;
		if ( $openfrac ) {
		    $partdaystyle = qq{style="background-color:$partclosedcolor;"};
		}
		print qq{<td class="cn" $partdaystyle >$display</td>\n};

	    }

	    if ( $override{$ym} ) {
		$daysopen = $override{$ym};
		if ( $daysenrolled > $daysopen ) {
		    $daysenrolled = $override{$ym};
		}
	    }
	    
	    print qq{\n<td class="cn">$daysopen</td>\n};

	    if ( $tAttendMonthlyFlag ) { # no stats shown, since missing attendance entry at some point.
		print qq{<td>$lex{Error}</td></tr>\n};
		next;
	    }
	    
	    my ($percentattend, $dayspresent, $ratio);
	    if ( $daysenrolled ) {
		$dayspresent = $daysenrolled - $daysabsent;
		$ratio = $dayspresent .' / '. $daysenrolled;
		$percentattend = '('. round( $dayspresent * 100 / $daysenrolled, 1). '%)';

		$totaldaysenrolled += $daysenrolled;
	
	    }
	    
	    $totaldaysopen += $daysopen;
	    $totaldaysabsent += $daysabsent;
	    
	    print qq{<td>$ratio $percentattend</td>};
	    print qq{</tr>\n};
	    
	} # year month loop

	# Statistics Line
	my $totaldayspresent = $totaldaysenrolled - $totaldaysabsent;
	
	my $totalpercentattend;
	if ( $totaldaysenrolled ) {
	    $totalpercentattend = round( $totaldayspresent * 100 / $totaldaysenrolled, 1);
	}

	print qq{<tr><th>Statistics</th><th colspan="10">Percent Attendance: };
	print qq{$totalpercentattend%</th>\n};
	print qq{<th colspan="14">Days Present / Absent / Enrolled: };
	print qq{$totaldayspresent / $totaldaysabsent };
	print qq{/ $totaldaysenrolled</th>\n};;
	print qq{<th colspan="7">Days Open: $totaldaysopen</th>\n};
	print qq{</tr>\n};
	
	print qq{</table><p></p>\n\n};


	# Enrollment Table.
	print qq{<table cellpadding="3" cellspacing="0" border="1">\n};
	print qq{<caption>Enrollment</caption>\n};
	print qq{<tr><th>$lex{Start}</th><th>$lex{End}</th></tr>\n};
	foreach my $ref ( @enrolblocks ) {
	    print qq{<tr><td>$ref->{start}</td><td>$ref->{end}</td></tr>\n};
	}
	print qq{</table>\n};
	# foreach my $key ( sort keys %{ $ref } ) { print "K:$key V:$ref->{$key}<br>\n";  }

	# Page Break
	print qq{<div style="page-break-after:always;"></div>\n};
	

    } # student loop


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

    exit;

} # end of showReport

