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

#  This file is part of Open Admin for Schools.

# Staff Absent - Weekly - A weekly entry form for staff absences.


my %lex = ('Staff' => 'Staff',
	   'Main' => 'Main',
	   'Staff Member' => 'Staff Member',
	   'User Id' => 'User Id',
	   'Error' => 'Error',
	   'Position' => 'Position',
	   'Absence' => 'Absence',
	   'Reason' => 'Reason',
	   'Day' => 'Day',
	   'Part' => 'Part',
	   'Save' => 'Save',
	   'Date' => 'Date',
	   'AM' => 'AM',
	   'PM' => 'PM',
	   'All Day' => 'All Day',
	   'Record Exists' => 'Record Exists',
	   'Skipping' => 'Skipping',
	   'Record Stored' => 'Record Stored',
	   'Continue' => 'Continue',
	   'No Entry' => 'No Entry',
	   'Out of Range' => 'Out of Range',
	   'Invalid Date' => 'Invalid Date',
	   'Missing' => 'Missing',
	   'Other' => 'Other',
	   'Late' => 'Late',
	   'Audit' => 'Audit',
	   
	   
	   );


my $self = 'staffAbsWeekly.pl';

my @dayparts; # put in translated values, if necessary.
foreach my $dp ( 'AM', 'PM', 'All Day' ) {
    push @dayparts, $lex{$dp};
}


use DBI;
use CGI;
use Time::JulianDay;

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

# Load audit write function
eval require "../../lib/libaudit.pl";
if ( $@ ) {
    print $lex{Error}. ": $@<br>\n";
    die $lex{Error}. ": $@\n";
}


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


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



my @tim = localtime(time);
my $year = $tim[5] + 1900;
my $month = $tim[4] + 1;
my $day = $tim[3];
if (length($month) == 1){ $month = "0".$month;}
if (length($day) == 1){ $day = "0".$day;}
my $currdate = "$year-$month-$day";


# Print Page Header
my $title = "Weekly $lex{Staff} $lex{Absence} Entry";

print qq{$doctype\n<html><head><title>$title</title>
<link rel="stylesheet" href="$css" type="text/css">
$chartype\n};

if ( not $arr{page} ) { # date function
    print qq{<link rel="stylesheet" type="text/css" media="all" };
    print qq{href="/js/calendar-blue.css" title="blue">\n};
    print qq{<script type="text/javascript" src="/js/calendar.js"></script>\n};
    print qq{<script type="text/javascript" src="/js/lang/calendar-en.js"></script>\n};
    print qq{<script type="text/javascript" src="/js/calendar-setup.js"></script>\n};
}


print qq{</head>\n<body style="padding:1.5em;">[ <a href="$homepage">$lex{Main}</a> ]\n};

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


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

} elsif ( $arr{page} == 1 ) {
    delete $arr{page};
    displayEntry();

} elsif ( $arr{page} == 2 ) {
    delete $arr{page};
    confirmEntry();

} elsif ( $arr{page} == 3 ) {
    delete $arr{page};
    writeRecords();
}


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

    # Prep for position values
    my $sth1 = $dbh->prepare("select field_value from staff_multi
     where field_name = ? and userid = ?");

    # Dates closed
    my %closed;
    my $sth = $dbh->prepare("select date from dates where dayfraction > 0.99");
    $sth->execute;
    if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
    while ( my $date = $sth->fetchrow ) {  # Note will have leading zeros!
#	print "Date Closed: $date<br>\n";
	$closed{$date} = 1;
    }


    
    # select values from staff table.
    my $sth = $dbh->prepare("select id, lastname, firstname, userid
			    from staff order by lastname, firstname");
    $sth->execute;
    if (DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }



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

    
    # Get the Current date
    print qq{<table style="padding:1em;font-size:120%;border:1px solid black;">\n};
    print qq{<tr><td class="bra">Current $lex{Date}</td>\n};
    print qq{<td class="bla"><input type="text" name="date" id="date" size="10" value="$currdate">\n};
    print qq{<button type="reset" id="start_trigger">...</button></td></tr>\n};

    
    # Get the Number of Days in Sequence (default to 5) for a week.
    # Copy more than one date.
    print qq{<tr><td class="bra">Add Extra Days</td>\n};
    print qq{<td><select name="extradays"><option>4</option>\n};
    foreach my $day (1..5) {
	if ( $day == 4 ) { next; }
	print qq{<option>$day</option>\n};
    }
    print qq{<option value=""></option></select></td></tr>\n};

    # Select the Staff Members
    print qq{<tr><th>Select Staff Members</th><th>$lex{'User Id'}</th>};
    print qq{<th>$lex{Position}</th></tr>\n};
    
    while ( my ( $id, $lastname, $firstname, $userid ) = $sth->fetchrow) {

	# Load Positions (Jobs)
	$sth1->execute( 'position', $userid );
	if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
	my $positions;
	my $first = 1;
	while ( $pos = $sth1->fetchrow ) {
	    if ( not $first ) { $positions .= ', '; } else { $first = 0; }
	    $positions .= $pos;
	}

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

    }
    
    print qq{<tr><td colspan="7" class="la"><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
      });
     </script>\n};

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

    exit;
} # end of showStartPage



#---------------
sub displayEntry {
#---------------

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

    
    my $date = $arr{date};
    delete $arr{date};

    my $extradays = $arr{extradays};
    delete $arr{extradays};
    # values left in %arr are userids of staff

    if (not %arr ) {
	print qq{<h3>No Staff Selected</h3>\n};
	print qq{</body></html>\n};
	exit;
    }

    
    # Check Date for not in future and within current school year, and validity.
    if ( not checkdate( $date ) ) { 
	print qq{<h3>$lex{'Invalid Date'}</h3>\n};
	print qq{</body></html>\n};
	exit;
    }

    # Check that we are within school year.
    my $schoolstartjd = julian_day( split('-', $schoolstart)); # global var
    my $datejd = julian_day( split('-', $date));
    # Need current jd so we can stop before going into future.
    my $currjd = julian_day( split('-', $currdate));
    
    if ( $datejd < $schoolstartjd ) {
	print qq{<h3>$lex{Error}: $lex{Date} $lex{'Out of Range'}</h3>\n};
	print qq{</body></html>\n};
	exit;
    }

    # we want to get to a Monday.
    my $dow = day_of_week( $datejd );
    my $diff; # amount to back up.
    if ( $dow < 2 ) { # 
	$diff = $dow + 6;
    } else {
	$diff = $dow - 1;
    }

    my $startjd = $datejd - $diff;

    my $startdow = day_of_week( $startjd );
    my $startdate = join('-',inverse_julian_day( $startjd ));
    
#    print qq{Start Date: $startdate DOW:$startdow<br>\n};

   
    # Prep for names, position values
    my (%names, %positions);
    my $sth1 = $dbh->prepare("select field_value from staff_multi
			     where field_name = ? and userid = ?");
	
    # select values from staff table.
    my $sth = $dbh->prepare("select lastname, firstname from staff where userid = ?");
    
    foreach  my $userid ( keys %arr ) {
	
	$sth->execute($userid);;
	if (DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
	my ( $lastname, $firstname ) = $sth->fetchrow;

#	print qq{$firstname $lastname ($userid)<br>\n};
	
	$names{$userid} = qq{<b>$lastname</b>, $firstname};

	# Load Positions (Jobs)
	$sth1->execute( 'position', $userid );
	if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
	my $positions;
	my $first = 1;
	while ( $pos = $sth1->fetchrow ) {
	    if ( not $first ) { $positions .= ', '; } else { $first = 0; }
	    $positions .= $pos;
	}
	    
	$positions{$userid} = $positions
    }

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

    
    # Continue
    print qq{<div><input type="submit" value="$lex{Continue}"></div>};
    
    
    foreach my $jd ( $startjd .. $startjd + $extradays ) {

	# Check if going into the future.
	if ( $jd > $currjd ) {
	    last;
	}
	

	my $loopdow = day_of_week($jd);

	# Skip over weekends
	if ( $loopdow == 6  ) {
	    $jd += 2;
	    $loopdow = day_of_week($jd); # recalc
	}
	elsif ( $loopdow == 0 ) {
	    $jd += 1;
	    $loopdow = 1;
	}
	my $loopdate = join('-',inverse_julian_day( $jd ));
	
	# Check if this date is closed
	if ( $closed{$loopdate} ) {
	    print qq{<h3>$loopdate Closed</h3>\n};
	    next;
	}

	my $fdate = fmtdate($loopdate);

	
	print qq{\n\n<h3 style="margin-bottom:0.3em;">$fdate</h3>\n}; #$dowstd[$loopdow] ($loopdate)
    
	print qq{<table cellpadding="3" border="1" cellspacing="0">\n};
	print qq{<tr><th>$lex{'Staff Member'}</th><th>$lex{'User Id'}</th><th>$lex{Position}</th>\n};
	print qq{<th>$lex{Day}<br>$lex{Part}</th><th>$lex{Reason}</th>};
	print qq{<th>$lex{Reason}<br>$lex{Other}</th><th>$lex{Late}<br>(minutes)</th></tr>\n};

	foreach  my $userid ( keys %arr ) {
	
	    print qq{<tr><td>$names{$userid}</td><td>$userid</td><td>$positions{$userid}</td>\n};

	    # Day Parts
	    print qq{<td><select name="F:$loopdate:$userid"><option value=""></option>\n};
	    foreach my $part ( @dayparts ) { # defined at top; also translated.
		print qq{<option>$part</option>};
	    }
	    print qq{</select></td>\n};


	    # Absence Reasons
	    print qq{<td><select name="R:$loopdate:$userid"><option value=""></option>\n};
	    foreach my $rsn ( @g_StaffAbsReason ) {
		print qq{<option>$rsn</option>};
	    }
	    print qq{</select></td>\n};

	    # Other Reason
	    print qq{<td><input type="text" name="O:$loopdate:$userid" style="width:12ch;"></td>};
    
	    # Late Minutes
	    print qq{<td><input type="text" name="L:$loopdate:$userid" style="width:5ch;"></td>};
	
	    print qq{</tr>\n};
	}
    
	print qq{</table>\n};

    } # end of multiple days loop

    print qq{<div style="margin:1em 0;"><input type="submit" value="$lex{Continue}"></div>};
    
    print qq{</form>\n};
    print qq{</body></html>\n};

    exit;

}



#---------------
sub confirmEntry {
#---------------

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

    # Checking for existing records.
    my $sth1 = $dbh->prepare("select count(*) from staff_absent where 
			     adate = ? and daypart = ? and userid = ?");

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


    my $first = 1;

    foreach my $key ( sort keys %arr ) {
	if ( not $arr{$key} ) { next; } # skip if no value

	my ( $type, $date, $userid ) = split(':', $key);
	if ( $type ne 'R' ) { next; } # skip if not a reason field

	my $latekey = qq{L:$date:$userid};
	my $otherkey = qq{O:$date:$userid};
	my $daypartkey = qq{F:$date:$userid};

	my $daypart = $arr{$daypartkey};
	my $other = $arr{$otherkey};
	my $late = $arr{$latekey};


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


	# Check each userid group for completeness
	if ( not $daypart ) { 
	    print qq{<h3>$lex{Error}: $lex{Missing} $lex{Day} $lex{Part}; $firstname $lastname</h3>\n};
	    next;
	}

	if ( $arr{$key} eq 'Other (specify)' and not $other ) { 
	    print qq{<h3>$lex{Error}: $lex{Missing} $lex{Reason}: $firstname $lastname</h3>\n};
	    next;
	}


	# Check for an existing record for this userid for this date and for this day part.
	$sth1->execute($date, $lex{AM}, $userid );
	if (DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
	my $amcount = $sth1->fetchrow;

	$sth1->execute($date, $lex{PM}, $userid );
	if (DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
	my $pmcount = $sth1->fetchrow;

	$sth1->execute($date, $lex{'All Day'}, $userid );
	if (DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
	my $alldaycount = $sth1->fetchrow;

	# print qq{AM:$amcount PM:$pmcount ALL DAY:$alldaycount<br>\n};

	# not efficient but easier to understand.
	if ( $daypart eq $lex{AM} and ($amcount or $alldaycount) ) {
	    print qq{<h3>$lex{Error}: $lex{'Record Exists'}; };
	    print qq{$date - $userid - $daypart; $lex{Skipping}</h3>\n};
	    next;
	}

	if ( $daypart eq $lex{PM} and ($pmcount or $alldaycount) ) {
	    print qq{<h3>$lex{Error}: $lex{'Record Exists'}; };
	    print qq{$date - $userid - $daypart; $lex{Skipping}</h3>\n};
	    next;
	}

	if ( $daypart eq $lex{'All Day'} and ($amcount or $alldaycount or $pmcount) ) {
	    print qq{<h3>$lex{Error}: $lex{'Record Exists'}; };
	    print qq{$date - $userid - $daypart; $lex{Skipping}</h3>\n};
	    next;
	}

	if ( $first ) {
	    print qq{<table cellpadding="3" border="1" cellspacing="0">\n};
	    print qq{<tr><th>$lex{'Staff Member'}</th><th>$lex{Date}</th>};
	    print qq{<th>$lex{Day}<br>$lex{Part}</th><th>$lex{Reason}</th></tr>\n};
	    $first = 0;
	}


	print qq{<tr><td>$firstname $lastname ($userid)</td><td>$date</td>};
	print qq{<td>$daypart</td><td>$arr{$key}</td></tr>\n};

    }

    if ( $first ) {
	print qq{<h3>$lex{'No Entry'}</h3>\n};
	print qq{</body></html>\n};
	exit;

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


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

    # Write the hidden values for next page
    # print qq{<input type="hidden" name="date" value="$date">\n};
    foreach my $key ( sort keys %arr ) {
	if ( not $arr{$key} ) { next; } # skip if no value
	print qq{<input type="hidden" name="$key" value="$arr{$key}">\n};
    }

    print qq{<input type="submit" value="$lex{Save}">\n};
    print qq{</form>\n};

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

    exit;

}




#---------------
sub writeRecords {
#---------------

#    print qq{<div>Write Records</div>\n};
#    foreach my $key ( sort keys %arr ) { print qq{K:$key V:$arr{$key}<br>\n}; }
#    exit;


    my $fields = qq{userid, lastname, firstname, adate, reason, daypart, other, late, comment};
    my $qst = "?,?,?,?,?,?,?,?,?";
    my $sth = $dbh->prepare("insert into staff_absent ( $fields ) values( $qst )");

    my $sth1 = $dbh->prepare("select lastname, firstname from staff where userid = ?");
    my $sth2 = $dbh->prepare("select * from staff_absent where userid = ? and adate = ?");
    
    foreach my $key ( sort keys %arr ) {
	if ( not $arr{$key} ) { next; } # skip if no value

	my ( $type, $date, $userid ) = split(':', $key);
	if ( $type ne 'R' ) { next; } # skip if not a reason field

	my $latekey = qq{L:$date:$userid};
	my $otherkey = qq{O:$date:$userid};
	my $daypartkey = qq{F:$date:$userid};

	my $daypart = $arr{$daypartkey};
	my $other = $arr{$otherkey};
	my $late = $arr{$latekey};

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

	# Insert Record ( staff absent )
	$sth->execute( $userid, $lastname, $firstname, $date, $arr{$key}, $daypart,
		       $other, $late, NULL ); # no comment yet.
	
	if (DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
	print qq{<div>$lex{'Record Stored'}: $firstname $lastname / $date  $daypart / };
	print qq{$arr{$key}</div>\n};

	# Load Current Record for audit
	$sth2->execute( $userid,$date );
	if (DBI::errstr) { print $DBI::errstr; die $DBI::errstr; }
	my $startref = $sth2->fetchrow_hashref;
	my $recid = $startref->{id};
	my %r = %$startref;
	
	# print "StartREF:$startref\n";
	#foreach my $key ( sort keys %r ) {
	#    print "K:$key VAL:$r{$key}<br>\n";
	#}
	
	
	my %audit;
	$audit{userid} = $ENV{REMOTE_USER};
	$audit{ipaddr} = $ENV{REMOTE_ADDR};
	$audit{scriptname} = $self;
	$audit{tablename} = 'staff_absent';
	$audit{tableid} = $startref->{id};
	#$audit{startval} = $startref; # nothing to start, data to end
	$audit{endval} = $startref;

	addAudit( \%audit, $dbh );

	# print qq{<h3>$lex{Audit} $lex{'Record Stored'}</h3>\n};
    }

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

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

    exit;

} # End of writeRecords



#------------
sub checkdate {  # check date for validity
#------------

    my @mdays = (0,31,28,31,30,31,30,31,31,30,31,30,31);
    my $maxyear = 2100;

    my $val = shift;

    if ( not $val =~ m/-/ ) {  # fail if no hyphens
	return undef;
    }

    # Strip Spaces
    $val =~ s/^\s+//g;
    $val =~ s/\s+$//g;

    my ( $year, $month, $day) = split(/-/, $val);


    # Check for non-digits
    if ($year =~ m/\D/) { return undef; }
    if ($month =~ m/\D/) { return undef; }
    if ($day =~ m/\D/) { return undef; }

    # reset Feb max days, if leap years
    if ($month == 2) {
	if ($year % 4 != 0) { $mdays[2] = 28; }
	elsif ($year % 400 == 0) { $mdays[2] = 29; }
	elsif ($year % 100 == 0) { $mdays[2] = 28; }
	else { $mdays[2] = 29; }
    }

    # check ranges
    if ( $day < 0 or $day > $mdays[$month] ) { # days out of range
	return undef;
    } elsif ( $month < 0 or $month > 12 ) { # month error
	return undef;
    } elsif ( $year < 0 or $year > $maxyear ) {
	return undef;
    }

    return $val;

}


#----------
sub fmtdate {
#----------

    my $date = shift;
    my ($yr, $mo, $da) = split(/-/, $date);

    my $month = $month[$mo];

    my $jd = julian_day( $yr, $mo,$da );
    my $dow = day_of_week( $jd ) + 1;
    my $day = $dow[$dow];

    my $rv = qq{$day, $month $da, $yr};

    return $rv;

}
