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

#  This file is part of Open Admin for Schools.

#  Open Admin for Schools is free software; you can redistribute it 
#  and/or modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2 of 
#  the License, or (at your option) any later version.

# confperiods.pl - configure the period times for the grades that have subject attendance.


my %lex = ('Eoy' => 'Eoy',
	   'Periods' => 'Periods',
	   'Error' => 'Error',
	   'Set' => 'Set',
	   'Tracks' => 'Tracks',
	   'Number of' => 'Number of',
	   'Terms' => 'Terms',
	   'Start Date' => 'Start Date',
	   'End Date' => 'End Date',
	   'Continue' => 'Continue',
	   'Grades' => 'Grades',
	   'Separate with Spaces' => 'Separate with Spaces',
	   'Term Block' => 'Term Block',
	   'Term' => 'Term',
	   'Start' => 'Start',
	   'End' => 'End',
	   'Default' => 'Default',
	   'Track' => 'Track',
	   'Main' => 'Main',
	   'Description' => 'Description',
	   'Map' => 'Map',
	   'Desc' => 'Desc',
	   'File' => 'File',
	   'Updated' => 'Updated',
	   'Record(s) Stored' => 'Record(s) Stored',
	   'Save' => 'Save',
	   'Illegal' => 'Illegal',
	   'later than' => 'later than',
	   'Date' => 'Date',
	   'Sequence' => 'Sequence',
	   'Duplicate' => 'Duplicate',
	   'Missing' => 'Missing',
	   'Outside' => 'Outside',

	   'Period' => 'Period',
	   'Times' => 'Times',
	   'Timetable' => 'Timetable',
	   'for' => 'for',
	   'Values' => 'Values',

	   'Starting Time' => 'Starting Time',
	   'Ending Time' => 'Ending Time',
	   'Grade' => 'Grade',
	   'Group' => 'Group',
	   'Update' => 'Update',
	   'Edit' => 'Edit',
	   'Add' => 'Add',
	   'New' => 'New',
	   'Delete' => 'Delete',
	   'Deleted' => 'Deleted',
	   'Record Updated' => 'Record Updated',
	   'Length' => 'Length',
	   
	   );

my $self = 'confperiods.pl';

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

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

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

eval require "../../etc/admin.conf";
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 $dsn = "DBI:$dbtype:dbname=$dbase";
my $dbh = DBI->connect($dsn,$user,$password);



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


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



if ( $arr{page} == 2 ) { # 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">};
    print "</script>\n";

    print qq{<script type="text/javascript" src="$g_jquery_ui_url">};
    print "</script>\n";

    print qq{<script type="text/javascript" src="/js/jquery.ui.timepicker.js">};
    print "</script>\n";

}

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

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

print qq{<h1>$title</h1>\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};
    mapGrades();
    
} elsif ( $arr{page} == 2 ) {
    delete $arr{page};
    setPeriods();
    
} elsif ( $arr{page} == 3 ) {
    delete $arr{page};
    writeRecords();
    
} elsif ( $arr{page} == 4 ) {
    delete $arr{page};
    deletePeriods();
}


#----------------
sub deletePeriods {
#----------------

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

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

    # Period Group to Delete
    print qq{<h3>$lex{Period} $lex{Group} $lex{Deleted}</h3>\n};
    print qq{<table cellpadding="3" cellspacing="0" border="1">};
    print qq{<tr><th>$lex{Period}</th><th>$lex{Times}</th></tr>\n};
    my %r = %{ $g_PeriodTime{$id}};
    foreach my $period ( sort keys %r ) {
	my $stime = conv24to12($r{$period}{s});
	my $etime = conv24to12($r{$period}{e});
	print qq{<tr><td>$period</td><td>$stime - $etime</td></tr>\n};
    }
    print qq{</table>\n};

    
    my %newhash = %g_PeriodTime; # to store the configured values.
    delete $newhash{$id};

    my $g_PeriodTimeEnc = setScalar('*g_PeriodTime', \%newhash);
    # print "g_PeriodTime: $g_PeriodTimeEnd<br>\n";
#    $save{'g_PeriodTime'} = $g_PeriodTimeEnc;

    # Save the record into conf_system
    my $sth = $dbh->prepare("update conf_system set datavalue = ? 
      where dataname = ? and filename = 'admin'");
    $sth->execute( $g_PeriodTimeEnc,'g_PeriodTime' );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
 
    print qq{<h3>$lex{'Record Updated'}</h3>\n};


    
    # Write the admin.conf file.
    my $filename = "$g_EtcPath/admin.conf";

    system("cp -f $g_EtcPath/admin.conf.root $g_EtcPath/admin.conf");
    # print "Result:", $? >> 8, "<br>\n";

    open(FH,">>$filename") or
	die "Cannot open file $filename: $!\n"; # open for append

    my $sth = $dbh->prepare("select id, datavalue from conf_system 
     where filename = 'admin' order by dataname");
    $sth->execute;
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

    while ( my ($id, $value) = $sth->fetchrow ) {
	print FH $value, "\n";
    }

    print FH "\n1;\n"; # put in correct file ending with a 1.
    close FH;
    print qq{<h3>$lex{Main} $lex{File} $lex{Updated}</h3>\n};


    
    print qq{<h3>[ <a href="$self">$lex{Start}</a> ]</h3>\n};
    print qq{</body></html>\n};

    exit;
    
} # end of deletePeriods




#------------
sub mapGrades {  # update the mapping variable g_PeriodMap;
#------------

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

    my %grades;
    foreach my $key ( sort keys %arr ) {
	my ($dud,$grade) = split(':', $key);
	$grades{$grade} = $arr{$key};
    }

    my $datavalue = setScalar('*g_PeriodMap', \%grades);

    # Save the record into conf_system
    my $sth = $dbh->prepare("update conf_system set datavalue = ? 
      where dataname = 'g_PeriodMap' and filename = 'admin'");
    $sth->execute( $datavalue );
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

    print qq{<h3>$lex{'Record(s) Stored'}</h3>\n};
    print qq{<h3>[ <a href="$self">$lex{Start}</a> ]</h3>\n};
    
    print qq{</body></html>\n};
    exit;
    
}



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

    # Grades with Subject Attendance.
    my @grades;
    foreach my $grade ( sort {$a <=> $b} keys %g_AttendanceEntryMethod ) {
	if ( $g_AttendanceEntryMethod{ $grade } eq 'subject' ) {
	    push @grades, $grade;
	}
    }
    
    print qq{<form action="$self" method="post">\n};
    print qq{<input type="hidden" name="page" value="1">\n};

    print qq{<table cellpadding="3" cellspacing="0" border="0" };
    print qq{style="padding:0.5em;border:1px solid gray;float:left; margin:0.2em;">\n};
    print qq{<tr><th>$lex{Grade}</th><th>$lex{Period}<br>$lex{Group} ID</th></tr>\n};

    
    # Display Grades, and Period Block ID
    foreach my $gr ( @grades ) {
	print qq{<tr><td class="bra">$lex{Grade} $gr</td>};
	print qq{<td><select name="gr:$gr"><option>$g_PeriodMap{$gr}</option>};
	foreach my $id ( sort keys %g_PeriodTime ) {
	    if ( $id eq $g_PeriodMap{$gr} ) { next; } # skip duplicate value
	    print qq{<option>$id</option>};
	}
	print qq{<option></option></select></td></tr>\n};	
    }

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

    

    # Display current values, floated
    print qq{<table style="float:left;border:1px solid black;padding:0.5em;margin:0.2em;">\n};
    print qq{<tr><th>ID</th><th>$lex{Period} $lex{Group}</th><th></th></tr>\n};
    
    foreach my $id ( sort keys %g_PeriodTime ) {
	my %r = %{ $g_PeriodTime{$id}};
	print qq{<tr><td>$id</td><td>\n};
	
	print qq{<table cellpadding="3" cellspacing="0" border="1">};
	print qq{<tr><th>$lex{Period}</th><th>$lex{Times}</th><th>$lex{Length}</th></tr>\n};

	foreach my $period ( sort {$a <=> $b} keys %{ $g_PeriodTime{$id} } ) {
	    my $stime = conv24to12($r{$period}{s});
	    my $etime = conv24to12($r{$period}{e});

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

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

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

	# Edit this Period Group
	print qq{<form action="$self" method="post">\n};
	print qq{<input type="hidden" name="page" value="2">\n};
	print qq{<input type="hidden" name="id" value="$id">\n};
	print qq{<input type="submit" value="$lex{Edit}"></form>\n};

	# Delete this Period Group
	print qq{<form action="$self" method="post">\n};
	print qq{<input type="hidden" name="page" value="4">\n};
	print qq{<input type="hidden" name="id" value="$id">\n};
	print qq{<input type="submit" value="$lex{Delete}"></form>\n};
	
	print qq{</td></tr>\n};
	
    }

    print qq{</table>\n};
    print qq{<br clear="left">\n};
    
    
    # Add new Period Group
    print qq{<form action="$self" method="post">\n};
    print qq{<input type="hidden" name="page" value="2">\n};
    print qq{<table style="float:left;border:1px solid black;padding:0.4em;">\n};
    print qq{<tr><td>\n};
    print qq{<input type="submit" value="$lex{Add} $lex{New} $lex{Period} $lex{Group}">\n};
    print qq{$lex{'Number of'} $lex{Timetable} $lex{Periods}\n};
    print qq{<select name="periods"><option></option>\n};
    foreach my $per (1..15) {
	print qq{<option>$per</option>};
    }

    print qq{\n</select></td></tr></table></form>\n};
    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, $id);
    my %r;

    if ( $arr{id} ) {
	$id = $arr{id};
	%r = %{ $g_PeriodTime{$id} }; # gives $r{period}{s/e times}
#	print "R:", %r, "<br>\n";

	$periods = (keys %r ) + 1;
    } else {
	$periods = $arr{periods};
    }

#    foreach my $period ( sort keys %r ) {
#	print "Per:$period S:$r{$period}{s} E:$r{$period}{e}<br>\n";
#    }

    # Convert to 12 hour clock.
    foreach my $period ( sort keys %r ) {
	$r{$period}{s} = conv24to12( $r{$period}{s} );
	$r{$period}{e} = conv24to12( $r{$period}{e} );
    }

    if ( not $periods or ( $periods < 0 or $periods > 15 )) {
	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="3">\n};
    print qq{<input type="hidden" name="id" value="$id">\n};

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

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

	print qq{<tr><td class="bcn">$lex{Period} $period</td>\n};
	print qq{<td class="la"><input type="text" size="8" id="S$period" name="s:$period" };
	print qq{value="$r{$period}{'s'}">\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="$r{$period}{'e'}">\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 "Entry Keys:<br>\n";
    # foreach my $key ( sort keys %arr ) { print "K:$key V:$arr{$key}<br>\n"; }
    

    my $id = $arr{id};
    delete $arr{id};
    
    my (%periods,%check);
    foreach my $key ( keys %arr ) {

	my $time = conv12to24( $arr{$key} );
	my ($type, $per) = split(':', $key);  # type is start 's' or end 'e'.
	$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{</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">};
    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><td>$length</td></tr>\n};
    }
    
    print qq{</table>\n};
        

    
    my %newhash = %g_PeriodTime; # to store the configured values.

    if ( not $id ) { # pick the next available character (alphabetic)
	$id = 'A'; 
	while ( exists $g_PeriodTime{$id} ) {
	    $id++;
	}
    }

    print qq{<h3>$lex{Period} $lex{Group} ID:$id</h3>\n};

    
    # Set g_PeriodsTime   ( g_PeriodsTime{a} = {1 => {s => '9:00', e => '10:00'}, etc )
    my $dref = {};
    foreach my $period ( sort keys %periods ) {

	if ( not $periods{$period}{'s'} ) { next; }

	$dref->{$period}{'s'} = $periods{$period}{s};
	$dref->{$period}{'e'} = $periods{$period}{e};

    }
    $newhash{$id} = $dref;

    
    my $g_PeriodTimeEnc = setScalar('*g_PeriodTime', \%newhash);
    # print "g_PeriodTime: $g_PeriodTimeEnd<br>\n";

    # Save the records into conf_system
    my $sth = $dbh->prepare("update conf_system set datavalue = ? 
      where dataname = ? and filename = 'admin'");
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
    $sth->execute( $g_PeriodTimeEnc, 'g_PeriodTime');
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

    print qq{<h3>$lex{'Record(s) Stored'}</h3>\n};

    print qq{<h3>[ <a href="$self">$lex{Start}</a> ]</h3>\n};
    

    # Write the admin.conf file.
    my $filename = "$g_EtcPath/admin.conf";

    system("cp -f $g_EtcPath/admin.conf.root $g_EtcPath/admin.conf");
    # print "Result:", $? >> 8, "<br>\n";

    open(FH,">>$filename") or
	die "Cannot open file $filename: $!\n"; # open for append

    my $sth = $dbh->prepare("select id, datavalue from conf_system 
     where filename = 'admin' order by dataname");
    $sth->execute;
    if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }

    while ( my ($id, $value) = $sth->fetchrow ) {
	print FH $value, "\n";
    }

    print FH "\n1;\n"; # put in correct file ending with a 1.
    close FH;

    print qq{<h3>$lex{Main} $lex{File} $lex{Updated}</h3>\n};

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

    exit;
}


#------------
sub setScalar {
#------------

    my ($dataname, $datavalue) = @_;

    my $name_ref = [ ];
    my $value_ref = [ ];
    push @$name_ref, $dataname;
    push @$value_ref, $datavalue;
    my $d = Data::Dumper->new( $value_ref, $name_ref );
    return $d->Dump;

}


#-------------
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;
    }

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

}

