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

#  This file is part of Open Admin for Schools.

# confperiods_teacher.pl - manage periods for a teacher

my %lex = ('Error' => 'Error',
	   'Continue' => 'Continue',
	   'Main' => 'Main',
	   'Edit' => 'Edit',
	   'Add' => 'Add',
	   'New' => 'New',
	   'Set' => 'Set',
	   'Please Log In' => 'Please Log In',
	   'User Id' => 'User Id',
	   'Password' => 'Password',
	   'Cookie Duration' => 'Cookie Duration',
	   'Not Found' => 'Not Found',
	   'Ending Time' => 'Ending Time',
	   'Length' => 'Length',
	   'Number of' => 'Number of',
	   'Period' => 'Period',
	   'Periods' => 'Periods',
	   'Start' => 'Start',
	   'Starting Time' => 'Starting Time',
	   'Times' => 'Times',
	   'Periods' => 'Periods',
	   'Select' => 'Select',
	   
	   );


my $self = 'confperiods_teacher.pl';

my $defaultEtcPath = '../../etc';

use DBI;
use CGI;
use Data::Dumper;
use Time::JulianDay;
use CGI::Session;


$Data::Dumper::Purity = 1;
$Data::Dumper::Indent = 0;

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

# Set Path to etc directory 
if ( not $g_EtcPath ) {
    $g_EtcPath = $defaultEtcPath;
}


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

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



# Load Configuration
my $sth = $dbh->prepare("select datavalue from conf_system where dataname = ?");
foreach my $var ( qw( doctype chartype tchcss tchpage g_jquery_url g_jquery_ui_url 
  g_AttendanceEntryMethod g_JqueryUiCss tchpage g_DaysPerCycle g_PeriodTime g_PeriodMap )) {
    $sth->execute( $var );
    my $datavalue = $sth->fetchrow;
    eval $datavalue;
    if ( $@ ) {
	print "$lex{Error}: $@<br>\n";
	die "$lex{Error}: $@\n";
    }
}


my $userid = $ENV{'REMOTE_USER'};

my $sth = $dbh->prepare("select lastname, firstname from staff where userid = ?");
$sth->execute( $userid );
if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
my ($ln,$fn) = $sth->fetchrow;


# Page Header
my $title = qq{$lex{Set} $lex{Period} $lex{Times}};
print qq{$doctype\n<html><head><title>$title</title>\n};
print qq{<link rel="stylesheet" href="$tchcss" type="text/css">\n};


if ( $arr{page} == 1 ) { # load jQuery libs for setPeriods

    print qq{<link rel="stylesheet" href="$g_JqueryUiCss">\n};
    print qq{<link rel="stylesheet" href="/js/jquery.ui.timepicker.css" type="text/css">\n};
    print qq{<script type="text/javascript" src="$g_jquery_url"></script>\n};
    print qq{<script type="text/javascript" src="$g_jquery_ui_url"></script>\n};
    print qq{<script type="text/javascript" src="/js/jquery.ui.timepicker.js"></script>\n};

}

    
print qq{$chartype\n</head><body>\n};

print qq{[ <a href="$tchpage">$lex{Main}</a> | $fn $ln ($userid)\n};

print qq{<h1>$title</h1>\n};
my $cycletext;
if ( $g_DaysPerCycle == 1 ) {
    $cycletext = "( Every Day is the same. )";
} elsif ( $g_DaysPerCycle == 5 or $g_DaysPerCycle eq 'w' or $g_DaysPerCycle eq 'W' ) {
    $cycletext = "( Weekly Cycle - Each monday the same, each tuesday, etc. )";
}
    
print qq{<h3>Days in a School Cycle - $g_DaysPerCycle</h3>\n};
if ( $cycletext ) {
    print qq{<span style="font-size:80%;">$cycletext</span></h3>\n};
}



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

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

} elsif ( $arr{page} == 1 ) {
    delete $arr{page};
    setPeriods();
    
} elsif ( $arr{page} == 2 ) {
    delete $arr{page};
    writeRecords();
}


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

    # load existing timesets (period groups), including this user.  If no userid
    # mapped timeset, then display these to allow teacher to select
    # one as a starting point.

    my %timedata;
    
    # Check for a user timeset.
    my $sth = $dbh->prepare("select timeset from period_map where timetype = 'userid' and timeval = ?");
    $sth->execute( $userid );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    my $usertimeset = $sth->fetchrow;

#    print "usertimeset: $usertimeset<br>\n";
    
    my $sth1 = $dbh->prepare("select period,starttime,endtime from period_data where timeset = ?");
    
    # if we have a timeset for this user, then allow for an edit.
    if ( $usertimeset ) {
	my (%pstart,%pend);
	# Load this period data
	$sth1->execute( $usertimeset );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	while ( my ($per,$st,$et) = $sth1->fetchrow ) {
	    my ($h,$m,$s) = split(':', $st);
	    $st = qq{$h:$m};
	    my ($h,$m,$s) = split(':', $et);
	    $et = qq{$h:$m};

#	    print qq{Per:$per ST:$st ET:$et<br>};

	    $pstart{$per} = $st;
	    $pend{$per} = $et;
	}

	print qq{<p style="width:60ch;">Remove Start/End times to delete a period. Only
	remove periods from the end (highest numbered ) periods,
	unless you want "holes" in your period group.</p>\n};

	
	print qq{<table cellpadding="3" cellspacing="0" border="1" style="margin:1em;">\n};
	print qq{<caption style="font-weight:bold;">Your Periods };
	print qq{<span style="font-weight:normal;font-size:80%;">(Timeset $usertimeset)</span>};
	print qq{</caption>\n};
	print qq{<tr><th>$lex{Period}</th><th>$lex{Times}</th><th>$lex{Length}</th></tr>\n};

	foreach my $period ( sort {$a <=> $b} keys  %pstart  ) {

	    my $stime = conv24to12( $pstart{$period} );
	    my $etime = conv24to12( $pend{$period} );

#	    print "Period:$period Start:$stime<br>\n";

	    my ($shr,$smin) = split(':', $pstart{$period} );
	    $smin = $shr * 60 + $smin;

	    my ($ehr,$emin) = split(':', $pend{$period} );
	    $emin = $ehr * 60 + $emin;

	    my $length = $emin - $smin;
	    
	    print qq{<tr><td class="cn">$period</td><td class="la">};
	    print qq{$stime - $etime</td><td class="cn">$length</td></tr>\n};
	}
	
	# Edit this Timeset
	print qq{<tr><td colspan="3" class="cn">};
	print qq{<form action="$self" method="post">\n};
	print qq{<input type="hidden" name="page" value="1">\n};
	print qq{<input type="hidden" name="timeset" value="$usertimeset">\n};
	print qq{<input type="submit" value="$lex{Edit} $lex{Periods}"></form>\n};
	print qq{</td></tr>\n};
	print qq{</table>\n};

    } else { # add a new timeset (period group)

        
	# Load Any Values in period_data
	$sth = $dbh->prepare("select * from period_data");
	$sth->execute;
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

	while ( my $ref = $sth->fetchrow_hashref ) {
	    my %r = %$ref;
	    $timedata{ $r{timeset} }{ $r{period} } = { start => $r{starttime}, end => $r{endtime} };
	}
	
	print qq{<h3>Select A Period Group or make your own</h3>\n};
	print qq{<hr style="width:40ch;margin-left:0;">\n};


	# Display current values, floated
	foreach my $timeset ( sort keys %timedata ) {
	    my %r = %{ $timedata{$timeset}};
	    
	    print qq{<table cellpadding="3" cellspacing="0" border="1" style="margin:1em;">\n};
	    print qq{<caption style="font-weight:bold;">Period Group $timeset</caption>\n};
	    print qq{<tr><th>$lex{Period}</th><th>$lex{Times}</th><th>$lex{Length}</th></tr>\n};

	    foreach my $period ( sort {$a <=> $b} keys %{ $timedata{$timeset} } ) {
		my $stime = conv24to12($r{$period}{start});
		my $etime = conv24to12($r{$period}{end});
	    
		my ($shr,$smin) = split(':', $r{$period}{'start'} );
		$smin = $shr * 60 + $smin;
		
		my ($ehr,$emin) = split(':', $r{$period}{'end'} );
		$emin = $ehr * 60 + $emin;

		my $length = $emin - $smin;
	    
		print qq{<tr><td class="cn">$period</td><td class="la">};
		print qq{$stime - $etime</td><td class="cn">$length</td></tr>\n};
	    }
	
	    print qq{</table>\n};

	
	} # end of display current timeset for selection

   
	# select a Timeset to copy
	print qq{<form action="$self" method="post" style="margin:1em;">\n};
	print qq{<input type="hidden" name="page" value="1">\n};

	print qq{<table style="border:1px solid black;padding:0.4em;margin:1em 0 2em 0;width:60ch;">\n};
	
	print qq{<tr><td class="bla">Select a Period Group to Copy\n};
	print qq{<select name="timeset"><option value=""></option>\n};
	foreach my $timeset ( sort keys %timedata ) {
	    print qq{<option>$timeset</option>\n};
	}
	print qq{</select></td></tr>\n};

	# OR
	print qq{<tr><td><hr></td></tr>\n};

	# Make your own
	print qq{<tr><td class="bla">Make your own Period Group</td></tr>\n};
	print qq{<tr><td>$lex{'Number of'} $lex{Periods}\n};
	print qq{<select name="periods"><option value=""></option>\n};
	foreach my $per (1..16) {
	    print qq{<option>$per</option>};
	}
	print qq{\n</select></td></tr>\n};

	print qq{<tr><td><input type="submit" value="Continue"></td></tr>\n};
	
	print qq{</table></form>\n};

    } # end of add new timeset.

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

    exit;

} # end of showStartPage



#-------------
sub setPeriods {
#-------------

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

    my $periods = $arr{periods};  # passed in %arr if no records yet.
    my $timeset = $arr{timeset};
    
    if ( not $timeset and not $periods ) {
	print qq{<h3>No Settings Found!</h3>\n};
	print qq{</body></html>\n};
	exit;
    }

    # Calc Mode: check owner of this timeset to see whether an update or a new user's add.
    my $sth = $dbh->prepare("select count(*) from period_map where timetype = 'userid' and 
			    timeval = ?");
    $sth->execute( $userid );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    my $mode = $sth->fetchrow;
    if ( $mode == 1 ) { # then update, otherwise an add.
        $mode = 'update';
    } else {
	$mode = 'insert';
    }

    print qq{<p style="width:60ch;">Remove Start/End times to delete a
	period. Only remove periods from the end (highest numbered )
	periods, unless you want "holes" in your period group. Use the
	<b>tab</b> key to move ahead to the next box.</p>\n};

    
    print qq{<h3>Mode:$mode</h3>\n};
    
    my %timedata;
    
    if ( $timeset ) {

	# Load Period time records
	my $sth = $dbh->prepare("select * from period_data where timeset = ?");
	$sth->execute( $timeset );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	while ( my $ref = $sth->fetchrow_hashref ) {
	    my %r = %$ref;
	    $timedata{ $r{period} } = { start => $r{starttime}, end => $r{endtime}, id => $r{id} };
	}

	$periods = (keys %timedata );
	
    } else { # no timeset data
	
	$periods = $arr{periods};
    }
    
#    foreach my $period ( sort keys %timedata ) {
#	print "Per:$period S:$timedata{$period}{start} E:$timedata{$period}{end} ID:$timedata{$period}{id}<br>\n";
#    }

    # Convert to 12 hour clock.
    foreach my $period ( sort keys %timedata ) {
	$timedata{$period}{start} = conv24to12( $timedata{$period}{start} );
	$timedata{$period}{end} = conv24to12( $timedata{$period}{end} );
    }

    # Check Periods value
    if ( not $periods or ( $periods < 0 or $periods > 16 )) {
	print qq{<h3>$lex{Error} - $lex{Periods}:$periods</h3>\n};
	print qq{</body></html>\n};
	exit;
    }

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

    
    print qq{<table cellpadding="3" cellspacing="0" border="0">\n};
    print qq{<tr><th>$lex{Period}</th><th>$lex{'Starting Time'}</th>};
    print qq{<th>$lex{'Ending Time'}</th></tr>\n}; 

    my $periodsPlus = $periods + 2;

    foreach my $period ( 1..$periodsPlus ) {

	if ( $period > $periods ) {
	    print qq{<tr><td class="bcn">Extra $lex{Periods} $period</td>\n};
	} else {
	    print qq{<tr><td class="bcn">$lex{Period} $period</td>\n};
	}

	
	print qq{<td class="la"><input type="text" size="8" };
	print qq{id="S$period" name="s:$period:$timedata{$period}{id}" };
	print qq{value="$timedata{$period}{'start'}">\n};
	print qq{<script type="text/javascript">
	    \$(document).ready(function() {
		\$('#S$period').timepicker({showPeriod:true, onHourShow:OnHourShowCallback});
	    });
	    function OnHourShowCallback(hour) {
               if ((hour > 17 ) || (hour < 7 )) {
                   return false;
               }
               return true;
	    }
        </script></td>\n};

	
    	print qq{<td class="la"><input type="text" size="8" id="E$period" name="e:$period" };
	print qq{value="$timedata{$period}{'end'}">\n};
	print qq{<script type="text/javascript">
	    \$(document).ready(function() {
		\$('#E$period').timepicker({showPeriod:true, onHourShow:OnHourShowCallback});
	    });
	    function OnHourShowCallback(hour) {
               if ((hour > 17 ) || (hour < 7 )) {
                   return false;
               }
               return true;
	    }
        </script></td>\n};
	print qq{</tr>\n};

    }

    
    print qq{<tr><td colspan="2" class="ra"><input type="submit" value="$lex{Continue}"></td></tr>\n};
    print qq{</table></form>\n};

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

}


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

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

    
    # Identifier whether to update or add new
    my $mode = $arr{mode};
    delete $arr{mode};

    print qq{<div>Mode: $mode</div>\n};
    
    my (%periods,%check, %recid);  # $recid{period} = id of record in db.
    foreach my $key ( keys %arr ) {

	my $time = conv12to24( $arr{$key} );
	my ($type, $per, $id) = split(':', $key);  # type is start 's' or end 'e'.
	if ( $id and $mode eq 'update' ) { # store the record holding this info for this period.
	    $recid{$per} = $id;
	}

	$periods{$per}{$type} = $time;
	
	my ($h,$m) = split(':', $time);
	my $minutes = $h * 60 + $m;
	if ( not $minutes ) { next; } # not checking blanks.
	my $idx = $per;
	if ( $type eq 'e' ) { # add on .5
	    $idx += 0.5;
	}
	$check{$idx} = $minutes; # these will be total minutes from start of the day.
    }

    
=head    
    # Display values for periods
    foreach my $period ( sort keys %periods ) {
	foreach my $type ( sort keys %{ $periods{$period} } ) {
	    print qq{Period:$period Type:$type Val:$periods{$period}{$type}<br>\n};
	}
    }
=cut


    
    # Check values for length, sequence, and overlap.
    my ($curr, $prev);
    foreach my $key ( sort {$a <=> $b} keys %check ) {

	$prev = $curr;
	$curr = $key;
	if ( $prev ) { # not at first;
	    if ( $check{$curr} < $check{$prev}  ) { # error;
		my ($currerr, $preverr );
		$currerr = "Start";
		if ( $curr =~ m/\./ ) { # is it a decimal value, if so, an end time
		    $currerr = "End";
		    $curr =~ s/\..+//g;
		}
		$currerr = "Period $curr ". $currerr;

		$preverr = "Start";
		if ( $prev =~ m/\./ ) { # is it a decimal value, if so, an end time
		    $preverr = "End";
		    $prev =~ s/\..+//g;
		}
		$preverr = "Period $prev ". $preverr;

		print qq{<h3>$lex{Error}: $currerr < $preverr</h3>\n};
		print qq{<h3>Go Back and Fix</h3>\n</body></html>\n};
		exit;
	    }
	}
	
#	print "K:$key V:$check{$key}<br>\n";
    }

   
   
    # Now get period lengths.
    my %lengths; # of periods in minutes.
    print qq{<table cellpadding="3" cellspacing="0" border="1" style="margin:1em;">};
    print qq{<caption style="font-weight:bold;">Period Times to Insert</caption>\n};
    print qq{<tr><th>$lex{Period}</th><th>$lex{Times}</th><th>$lex{Length}</th></tr>\n};

    foreach my $period ( sort {$a <=> $b} keys %periods ) {
	my ($shr,$smin) = split(':', $periods{$period}{'s'} );
	$smin = $shr * 60 + $smin;

	my ($ehr,$emin) = split(':', $periods{$period}{'e'} );
	$emin = $ehr * 60 + $emin;

	my $length = $emin - $smin;
	$lengths{$period} = $length;

	if ( not $length ) { next; }
	
	print qq{<tr><td>$period</td><td>$periods{$period}{s} - $periods{$period}{e}</td>};
	print qq{<td>$length</td></tr>\n};
    }
    
    print qq{</table>\n};

    
    # Get new timeset if insert mode
    my ($newtimeset, $timeset);
    if ( $mode eq 'insert' ) { # pick the next available number from the period_data table.
	my $sth = $dbh->prepare("select max(timeset) from period_data");
	$sth->execute;
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	$newtimeset = $sth->fetchrow;
	$newtimeset++;
    } else { # get an existing timeset value
	my $sth = $dbh->prepare("select timeset from period_map where timeval = ?");
	$sth->execute( $userid );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	$timeset = $sth->fetchrow;
    }
	
#    print qq{Timeset:$newtimeset<br>\n};
    
    # Insert
    my $sth = $dbh->prepare("insert into period_data (timeset, period, starttime, endtime) 
			    values(?,?,?,?) ");

    # Update
    my $sth1 = $dbh->prepare("update period_data set starttime = ?, endtime = ? where id = ?");

    # Delete record if the time value is blank.
    my $sth2 = $dbh->prepare("delete from period_data where id = ?");

    
    foreach my $period ( sort {$a <=> $b} keys %periods ) {
	my $recid = $recid{$period};
	if ( $recid ) { # we have an existing record. Update or Delete?
	    # Do we have values for time?
	    if ( $periods{$period}{s} and $periods{$period}{e} ) { 
		# both a start and end, update the record
		$sth1->execute( $periods{$period}{'s'}, $periods{$period}{'e'}, $recid );
		if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
		print qq{<div>Period $period Updated</div>\n};
		
	    } elsif ( not $periods{$period}{s} or not $periods{$period}{e} ) { 
		# start or end times not found, delete the rec
		$sth2->execute( $recid );
		if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
		print qq{<div>Period $period Deleted</div>\n};
		
	    } else { # an error in start/end times
		print qq{<div style="color:red;font-weight:bold;">};
		print qq{$lex{Error} in Period $period times. No Change</div>\n};
	    }
	    
	} else { # no record id.... add a record, if we have values.
	    if ( $periods{$period}{s} and $periods{$period}{e} ) { # both a start and end time
		if ($newtimeset ) {
		    $sth->execute( $newtimeset,$period,$periods{$period}{'s'},$periods{$period}{'e'} );
		    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
		} else {
		    $sth->execute( $timeset,$period,$periods{$period}{'s'},$periods{$period}{'e'} );
		    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
		}
		print qq{<div>New Period Added: $period</div>\n};
	    }
	}
    } # end of periods loop

    # insert userid into map table if newtimeset
    if ( $newtimeset ) {
	my $sth = $dbh->prepare("insert into period_map (timeset, timetype, timeval) 
             values($newtimeset,'userid',?) ");
	$sth->execute($userid);
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	print qq{<div>Userid Record Added for $userid</div>\n};
	
    }

    # else { # update the period_map value to this
#	my $sth = $dbh->prepare("update period_map set timeset = ? where timeval = ?");
#	$sth->execute($timeset, $userid);
#	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
#    }
    
    print qq{<p>[ <a href="$self">$lex{Edit} $lex{Periods} (Start)</a> ]</p>\n};

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

    exit;
}



#-------------
sub conv12to24 {
#-------------

    my $time = shift;
    if ( not $time ) { return }

    $time =~ s/(AM|PM|am|pm)//; # strip am/pm.
    $ampm = $1; 
    $ampm = uc $ampm; # uppercase value
    
    my ($hr, $min) = split(':', $time);
    if ( $ampm eq 'PM' and $hr < 12 ) {
	$hr += 12;
    } elsif ( not $ampm and $hr < 7 ) { # manually typed.
	$hr += 12;
    }

    if ( $hr > 24 or $hr < 0  or  $min < 0 or $min > 60 ) {
	print qq{<h3>$lex{Error}: $time</h3>\n};
	print qq{</body></html>\n};
	exit;
    }

    return qq{$hr:$min};

}



#-------------
sub conv24to12 {
#-------------

    my $time = shift;
    if ( not $time ) { return }
    my ($hr, $min) = split(':', $time);
    my $ampm = 'AM';
    if ( $hr == 12 ) { $ampm = 'PM'; }
    if ( $hr == 0 ) { $hr = 12; };

    if ( $hr > 12 ) { 
	$hr -= 12;
	$ampm = 'PM';
    }

    return qq{$hr:$min $ampm};

}
