#!/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',
	   'Course' => 'Course',
	   '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';

my %nonstandardGrades = ('P3' => 1, 'K' => 1, 'PK' => 1);
# grades, that as homerooms, have nonstandard days closed(ie varying).


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);



# 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 ) {
	if ( $mo eq $months[0] ) { next; }
	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 $month ( @months ) {
	if ( $month eq $prevyrmo ) { next; }
	print qq{<option value="$month">$months{$month}</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 value=""></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{Course} $lex{Attendance} - $lex{Grade}</td>};
    print qq{<td class="la"><select name="grade"><option value=""></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
	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"; }
    # Passed: startmonth, endmonth, override (ovr) months, student numbers, grade,homeroom
    
    # 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 year-month 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";
    #    }

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

    # Mode to know if using what dates table.
    my $mode = 'homeroom'; # but only P3,PK,K grades will use dates_homeroom table.
    if ( $grade ) {
	$mode = 'grade';
    }

#    my $datetable = 'dates_periods'; # either dates_homeroom or dates_period
    my @grades; # if a split homeroom
    if ( $mode eq 'homeroom' ) {
	# find the grade that matches this homeroom; needed to figure
	 # out what table to use.
	my $sth = $dbh->prepare("select distinct grade from student 
				where homeroom = ? and grade is not null and grade != ''
				order by grade");
	$sth->execute( $homeroom );
	if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	while ( my $gr = $sth->fetchrow ) {
#	    if ( $nonstandardGrades{$gr} ) { # reset datetable to homeroom
#		$datetable = 'dates_homeroom';
#	    }
	    push @grades, $gr;
	}
	$grade = $grades[0];
    }
    
    
#    print "<br>Main - Mode:$mode<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"; }
    
    delete $arr{startmonth};
    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 ) { # should only a 1 or 0 value now; partial handled by dates_periods table
		$daysclosed{$ym}{$d} = $fraction;
		$closed += $fraction;
	    }
	}
	$daysclosedcount{$ym} = $closed;
	
    }

    # Test Days closed (fully)
    #    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"; 
    #	}
    #    }

    
    # Periods Closed - read both tables. homeroom will have HR:homeroom key
    my %pclosed; # pclosed{GR/HR}{ym}{day}{period} = type (type not really used currently)
    # $datetable is set above.
    
    # homeroom closed
    my $sth = $dbh->prepare("select * from dates_homeroom where 
			    month(date) = ? and year(date) = ?"); 

    # periods closed; partial day closure
    my $sth1 = $dbh->prepare("select * from dates_periods where 
			     month(date) = ? and year(date) = ?"); 

    
    foreach my $ym ( @yearmonth ) {

	my ($yr,$mo) = split '-', $ym;
	
	# Dates_Homeroom closed
	$sth->execute($mo, $yr);
	if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	
	while ( my $ref = $sth->fetchrow_hashref ) {
	    my %r = %$ref;
	    my ($y,$m,$d) = split('-',$r{date});
	    $d =~ s/^0//; # strip leading zeros from the day
	    $pclosed{"HR:$r{homeroom}"}{$ym}{$d}{$r{period}} = 1;
	}

	
	# Dates_Periods table
	$sth1->execute($mo, $yr);
	if ( DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	
	while ( my $ref = $sth1->fetchrow_hashref ) {
	    my %r = %$ref;
	    my ($y,$m,$d) = split('-',$r{date});
	    $d =~ s/^0//; # strip leading zeros from the day

	    # Get the grades

	    my $gref = parseGradesPeriod( $r{date}, $dbh);
	    my %temp = %$gref;
	    # {grades}{period} - more than one period possible in day.
	    foreach my $gr ( keys %temp ) {
		foreach my $per ( keys %{ $temp{$gr}} ) {
		    $pclosed{$gr}{$ym}{$d}{$per} = 1;
		}
	    }
	} # end of dates_periods loop
    } # end of ym loop

    # Testing Section for pclosed hash
#    foreach my $grp ( sort keys %pclosed ) {
#	foreach my $ym ( sort keys %{ $pclosed{$grp}} ) {
#	    foreach my $day ( sort {$a <=> $b} keys %{ $pclosed{$grp}{$ym} } ) {
#		foreach my $period (sort {$a <=> $b} keys %{ $pclosed{$grp}{$ym}{$day} } ) {
#		    print qq{Grp:$grp / $ym / $day / $period<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) Course/Subject (really Course)
With a course 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

#	    print "Y:$y M:$m D:$day P:$r{periods} S:$r{subjects}<br> \n";
	    
	    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 Course/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 ); # courses and local timetable for this student;
	# $localttb{$subjsec}{$day}{$period} = 1;
	
	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 from dates tables
		    $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 ( $pclosed{$grade}{$ym}{$day} or $pclosed{"HR:$homeroom"}{$ym}{$day} ) {
		    # OLD: exists $daysclosed{$ym}{$day} and  $daysclosed{$ym}{$day} == 0 ) {
		    # partially closed (zero fraction), periods set in dates_periods or dates_homeroom
		    my ($pcount,$tempcount);
		    # Grade of student
		    if ( $pclosed{$grade}{$ym}{$day} ) { # we have periods to do
			$tempcount = scalar %{ $pclosed{$grade}{$ym}{$day} };
			$pcount += $tempcount;
		    }
		    # Homeroom, if not grade already set closed
		    if ( not $tempcount ) {
			if ( $pclosed{"HR:$homeroom"}{$ym}{$day} ) { # we have periods to do
			    $tempcount = scalar %{ $pclosed{"HR:$homeroom"}{$ym}{$day} };
			    $pcount += $tempcount;
			}
		    }


		    #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);
		    if ( not $openfrac ) { # full day closed (openfrac is 0)
			print qq{<td title="School Closed" class="bcn">C</td>\n};
			next;
		    } else { # day is partially open for this student
			if ( $estatus eq 'e' ) { # enrolled!
			    $daysenrolled += $openfrac;
			}
		    }

		    
		} 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 ) { # the day is closed
		    
		    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 check
			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; }

			    # reset courses and timetable
			    @courses = ();   # courses
			    %localttb = ();  # local timetable
			
			    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; }
			} # end of term change


			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} } ) {
				    if ( $pclosed{$grade}{$ym}{$day}{$period} ) { # part day closed
					next;
				    }
				    $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


		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="9">Days Open: $totaldaysopen</th>\n};
	print qq{</tr>\n};
	
	print qq{</table>\n\n};


	# Enrollment Table.
	print qq{<table cellpadding="3" cellspacing="0" border="1" style="margin-top:1em;">\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

