# Lib Schedule

%lex = ('Term' => 'Term',
	'Not Found' => 'Not Found',
	'not defined' => 'not defined',
	'Grade' => 'Grade',
    );

# Functions:
# findCurrentSubjects(teacher,date,dbh);
# Returns hash of subjsec and periods in the day.

# findDayInCycle - IN: date  OUT: an integer for DayInCycle

# fillDate - IN: isodate(2005-1-1) OUT: full isodate (2005-01-01)

# findFutureClass - find a future class (subjsec)
#   IN - date, subjsec, classtimes,
#    RETURN - period, date.

# prTeacherTimetable - IN: term,subjectref(ref to subjsec array)

# mkTimetable - mk 2D strucutre for teacher and term.


#----------------------
sub findCurrentSubjects {
#----------------------

    use Time::JulianDay;

    my ($userid, $date, $dbh ) = @_; # passed teacher, date to check, dic, db handle;

    my $currjd = julian_day( split(/-/, $date));

    # Read in values from conf_system;
    my $sth = $dbh->prepare("select datavalue from conf_system
      where dataname = ?");
    foreach my $dataname ( qw( g_MTrackTermType g_MTrackTerm 
       r_AdditionalComments g_AttendanceEntryMethod )) {
	$sth->execute( $dataname );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	my $datavalue = $sth->fetchrow;
	eval $datavalue;
	if ( $@ ) {
	    print "$lex{Error} $@<br>\n";
	    die "$lex{Error} $@\n";
	}
    }

    # now find if any scheduled periods on this date
    my $dayincycle = findDayInCycle( $date, $dbh );
    # print "Day:$day<br>\n";


    # Get subjects taught by this teacher
    my $sth= $dbh->prepare("select subjcode, subjsec, smdesc, description, 
     grade, startrptperiod, endrptperiod from subject
     where subject.teacher = ?");
    $sth->execute( $userid );
    if ( $DBI::errstr ){ print $DBI::errstr; die $DBI::errstr; }

    my $sth1 = $dbh->prepare("select count(*) from eval where subjcode = ?");

    my %subjects;


    while ( my ( $subjcode, $subjsec, $smdesc, $description, $grade, $sterm, $eterm )
	    = $sth->fetchrow ) {

	# skip AdditionalComments - not subjects used for attendance
	if ( $r_AdditionalComments{$subjcode} or
	     $r_AdditionalComments{$subjsec} ) { next; } #skip 

	# Check for student enrollments
	$sth1->execute( $subjsec );
	if ( $DBI::errstr ){ print $DBI::errstr; die $DBI::errstr; }
	my $count = $sth1->fetchrow;
	if ( $count < 1) { next; } # skip if no enrolled students.


	# find term, to see if current.
	if ( not $grade ) {
	    print "<h3>$lex{Grade} $lex{'Not Found'} - $subjsec</h3>\n";
	}

	my $track = $g_MTrackTermType{$grade}; 

	my $term;
	foreach my $trm ( keys %{ $g_MTrackTerm{$track} } ) {
	    my $ref = $g_MTrackTerm{$track}{$trm};
	   # my $startdate = $ref->{start};
	   # my $enddate = $ref->{end};
	    my $startjd = julian_day(split(/-/, $ref->{start}) );
	    my $endjd = julian_day(split(/-/, $ref->{end}) );
	    if ( $currjd >= $startjd and $currjd <= $endjd ) { 
		$term = $trm;
		last; 
	    }
	}
	if ( not $term ) {
	    print "<h3>$lex{Term} $lex{'Not Found'} - $description ($subjsec)</h3>\n";
	    next;
	}

#	print "Track:$track Term:$term<br>\n";
#	print "SUBJSEC:$subjsec ST:$sterm END:$eterm TRM:$term<br>\n";

	# Skip if not a current subject
	if ( $term > $eterm or $term < $sterm ) {
	    next; # skip
	}


	# Skip if a homeroom entry method, no subjects done.
	if ( $g_AttendanceEntryMethod{ $grade } eq 'homeroom' ) {
	    next; # skip any subjects that are done in homeroom entry method grades.
	}


	# Now get timetable period(s). May be MORE than 1 per day;
	my $sth2= $dbh->prepare("select period from schedat where
         subjsec = ? and term = ? and day = ?");
	$sth2->execute( $subjsec, $term, $dayincycle );
	if ( $DBI::errstr ){ print $DBI::errstr; die $DBI::errstr; }
	my $period;
	while ( my $per = $sth2->fetchrow ) {
	    $period .= "$per ";
	}

	if ( not $g_MTrackTermType{$grade} ) { $period = ''; } # bad grade = bad track = bad period
	# print "SUB:$subjsec - TRM:$term - DAY:$dayincycle - PER:$period<br>\n";

	$subjects{$subjsec} = $period;
    }


    return %subjects;

} # end of findCurrentSubjects (Courses);



#-----------------
sub findDayInCycle {
#-----------------

    # Passed date, dbh
    my ($date, $tempdbh) = @_;

    # print qq{<div>Date:$date DBH:$tempdbh</div>\n};

    use Time::JulianDay;

    my $givendate = fillDate( $date ); # Passed a date to find day in cycle.
    my $givenjd = julian_day( split('-',$givendate));

    # If database handle not available, look for passed value...
    if ( not $dbh) {
	$dbh = $tempdbh;
    }


    # Read in values from conf_system;
    my $sth = $dbh->prepare("select datavalue from conf_system where dataname = ?");
    foreach my $dataname ( qw( g_DaysPerCycle g_ResetCycleDate schoolstart )) {
	$sth->execute( $dataname );
	if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; }
	my $datavalue = $sth->fetchrow;
	eval $datavalue;
	if ( $@ ) {
	    print "$lex{Error} $@<br>\n";
	    die "$lex{Error} $@\n";
	}
    }

    if ( not $g_DaysPerCycle){
	print "<h3>g_DaysPerCycle $lex{'not defined'}</h3>";
	print "</body></hmtl>\n";
	exit;
    }


    # Check if given date is a non cycle day. If so return 0.
    my $sth = $dbh->prepare("select count(id) from dates where 
     dayincycle = 'N' and to_days(date) = to_days('$givendate')");
    $sth->execute;
    if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr; }
    if ( my $count = $sth->fetchrow){
	return 0;
    }

    
    # Check for a weekend; return 0
    my $dow = day_of_week( $givenjd );
    if ( $dow == 6 or $dow == 0 ) { # weekend
	return 0;
    }
    
    
    # Check for a weekly timetable (ie. 'w' );
    if ( $g_DaysPerCycle eq 'W' or $g_DaysPerCycle eq 'w' ) {
	my $dow = day_of_week( $givenjd );
	if ( $dow == 6 ) { $dow = 0; }  # make it return a 0 for Sat.
	return $dow;  # note will return 0 for Sunday,Saturday.
    }


    # Check for a daily timetable (ie. 'd' );
    if ( $g_DaysPerCycle eq 'D' or $g_DaysPerCycle eq 'd' or $g_DaysPerCycle eq '1' ) {
	return 1; # always day 1.
    }

    # Load closed dates; store in jd format.
    my %closed;
    $sth = $dbh->prepare("select date, dayincycle from dates");
    $sth->execute;
    if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr; }
    while  ( my ( $date,$dayincycle ) = $sth->fetchrow ) {
	my $jd = julian_day( split ('-',$date));
	$closed{$jd} = $dayincycle;
    }

    
    # Check for starting value... first day of school
    my $startdate = fillDate($schoolstart);

    
    # Bump the start date over any PD days during school start.
    my $sth = $dbh->prepare("select count(id) from dates where 
     dayincycle = '0' and to_days(date) = to_days(?)");
    
    my $flag = 1;
    do {

	$sth->execute( $startdate );
	if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr; }
	$count = $sth->fetchrow;
	# Do we have a record of this date.... if so go to the next date.

	# Check for a weekend
	my $startjd = julian_day( split ('-',$startdate));
	my $dow = day_of_week( $startjd );
	
	if ( $count or $dow == 0 or $dow == 6 ) {
	    # we have a closed day, and not a day in cycle OR a weekend
	    my $jd = julian_day( split ('-',$startdate));
	    $jd++;
	    my @d = inverse_julian_day($jd);
	    $startdate = fillDate(join('-',@d));
	    $flag = 1;
	} else {
	    $flag = 0;
	}
	
    } until ( not $flag  ); # no record of closure for that date

#    print qq{<div>Start Date: $startdate</div>\n};
    

    # Check for Resets
    my ($resetdate, $resetvalue);
    
    # Use the $startdate value as Day 1
    $resetdate = $startdate; 
    $dayincycle = 1;

    my $resetdatejd = julian_day(split '-',$resetdate);
    my $givendatejd = julian_day( split '-',$givendate);

    foreach my $rdate (sort {$b cmp $a} keys %g_ResetCycleDate){
	$rdatejd = julian_day(split '-',$rdate);
	# now sorted, not needeif ($rdatejd > $resetdatejd and $rdatejd <= $givendatejd){
	if ($rdatejd <= $givendatejd) {
	    $resetdate = $rdate;
	    $dayincycle = $g_ResetCycleDate{"$resetdate"};
#	    print "RDate:$rdate Reset: $resetdate V:$dayincycle<br>\n";
	    last;
	}
    }

#    print qq{<div>Final Reset Date: $resetdate  Reset Value: $dayincycle</div>\n};
    # my $gd = join('-', inverse_julian_day($givendatejd));
    # print "Given Date:$gd<br>\n";
	
    
    $resetdatejd = julian_day(split '-',$resetdate);  # since reset date may have changed.
    $resetdatejd++;
    # we are going to start on the next day, since day in cycle
    # already has the correct value for the current day;
    
    foreach my $jd ( $resetdatejd .. $givendatejd ) {

	my $dow = day_of_week( $jd );
	my $date = join('-',inverse_julian_day($jd));
	if ( $dow == 0 or $dow == 6 ) { # skip weekend
#	    print "Skip Weekend - $dow<br>\n";
	    next;
	}
	if ( exists $closed{$jd} ) { # it is a closed day
#	    print "$jd / $date closed, Not Day in Cycle - DOW:$dow<br>\n";
	    if ( $closed{$jd} ) {
		$dayincycle++;
#		print "Add:$jd /$date closed, but is DIC: $dayincycle - DOW:$dow<br>\n";
	    }
	} else { # not closed
	    $dayincycle++;
#	    print "Add:$jd / $date - $dayincycle  DOW:$dow<br>\n";
	}

	if ( $dayincycle > $g_DaysPerCycle ) {
	    $dayincycle = $dayincycle - $g_DaysPerCycle; # remove extra cycles;
	}
	
    }

#    print qq{<div>Given:$givendate DayInCycle:$dayincycle</div>\n};
    
    return $dayincycle;


} # End of findDayInCycle



#-----------
sub fillDate {  # Fill in date values of form: 2006-1-1 into 2006-01-01
#-----------
    my $fulldate = shift;
    my ($year, $month, $day) = split '-',$fulldate;
    if (length($month) == 1){ $month = '0'.$month;}
    if (length($day) == 1){ $day = '0'.$day;}
    return "$year-$month-$day";
}


#------------------
sub findFutureClass {
#------------------

    # passed startdate, startperiod, userid, term, subjsec, $skipclasses
    # return futuredate (fdate), fperiod(fperiod)

    my ($startdate, $startperiod, $userid, $term, $subjsec, $skipclasses) = @_;

    my $subjref = &mkTimetable($userid, $term);
    my $days = $#{$subjref};
    my $periods = $#{$subjref->[1]};
    my $day = &findDayInCycle($startdate);

    # Loops to construct array of periods, @slots
    for my $d (1..$days) {
	for my $p (1..$periods){
	    #print "Sub: ${$subjref}[$p][$d]Subjsec: $subjsec\n";
	    if ( $subjref->[$p]->[$d] eq $subjsec ){
	        push @slots, "$d:$p";
	    }
	    #print "$d:$p ${$subjref}[$p][$d] ";
        }
    }

    # test @slots
    # foreach my $slot (@slots){ print "$slot\n"; }
    
    # Find starting point in array
    for (0..$#slots){
	if ($slots[$_] eq "$day:$startperiod"){
	  #  print "Match for $slots[$_]\n";
	    $currindex = $_;
	    last;
	}
    }
    if (not defined $currindex){ 
	print "No match for Day $day Period $startperiod";
	exit;
    }

    my $cyclesize = $#slots + 1;
    my $nextindex = $currindex + 1;
    my $totaldays;

#    print "DpC: $g_DaysPerCycle Classes per Cycle: $cyclesize\n";
#    print "SkipClasses: $skipclasses\n";

    # Loop through to calc the number of days to skip.
    for ( 1..$skipclasses){ # how many jumps
	my ($currday,$cp) = split /:/,$slots[$currindex];
	my ($nextday,$np) = split /:/,$slots[$nextindex];
     	my $jumps = $nextday - $currday;
	if ($jumps < 0){ $jumps += $g_DaysPerCycle;}
	$totaldays += $jumps;
	$currindex++;
	if ($currindex > $cyclesize){ $currindex = 0;}
	$nextindex++;
	if ($nextindex > $cyclesize){ $nextindex = 0;}
    }


    my $sth = $dbh->prepare("select count(id) from dates where 
     (dayincycle = 'N' or dayincycle = '0') and to_days(date) = to_days(?)");

    my ($nd,$i);
    my $startjd = julian_day( split ('-',$startdate));
    my $nextjd = $startjd;
    
    while ($i < $totaldays){
	# Find the next date
	$nextjd++;
	my @d = inverse_julian_day($nextjd);
	$nextdate = fillDate(join('-',@d));
	
	$sth->execute($nextdate);
	$count = $sth->fetchrow;
	if (not $count){ $i++;}
    }

#    print "Final:$nextdate\n";
    
    return $nextdate;

}



#---------------------
sub prTeacherTimetable { # print timetable for 1 teacher for 1 term.
#---------------------

    my ($term, $subjref) = @_;  # passed term and ref to subjects.
    
    # Prep for loop finding the subjects
    my $sth = $dbh->prepare("select day, period from schedat 
      where term = '$term' and subjsec = ? ");

    my @subject;
    #loop through all subject-sections
    foreach my $subjsec (@{$subjref}){
	$sth->execute($subjsec);
	if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr;}

	# Create 2D subject array (of [period][day] indexes)
	while (my ($day, $period) = $sth->fetchrow){
	    if ($subject[$period][$day] != $subjsec){
		$subject[$period][$day] .= "$subjsec ";
	    }
	}

    }

    my $tblrows = $#subject;
    my $tblcols;
    for $i (1..$tblrows){
	if ($#{$subject[$i]} > $tblcols){ $tblcols = $#{$subject[$i]};}
    }

    $sth = $dbh->prepare("select description,smdesc from subject 
       where subjsec = ?");

    print "<table cellpadding=\"3\" cellspacing=\"0\" border=\"1\">\n";
    # heading
    print "<tr><th></th>";
    for (1..$tblcols){ print "<th>Day $_</th>"; }
    print "</tr>\n";
    
    # Main body of table.
    for $i (1..$tblrows){
	print "<tr><td>Period $i</td>";
	for (1..$tblcols){
	    if ($subject[$i][$_]){ # if we have a subjsec value;
		my $firstflag = 1;
		@subjval = split /\s/,$subject[$i][$_];
		print "<td>";
		foreach my $sv (@subjval){
		    if (not $firstflag){ print "<br>";} else { $firstflag = 0;}
		    $sth->execute($sv);
		    if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr;}
		    my ($description,$smdesc) = $sth->fetchrow;
		    if (not $smdesc){ $smdesc = substr($description,0,8);}
		    print "$smdesc ($sv)";
		}
		print "</td>";
	    } else {
		print "<td style=\"color: red;\">No Value</td>";
	    }
	}
	print "</tr>\n";
    }
    print "</table>\n";

}  # End of prTeacherTimetable


#--------------
sub mkTimetable { 
#--------------
    # make timetable structure (2D array), passed teacher userid, and term.

    my ($userid, $term) = @_;

    my (@subjects, @bigsubjects);
    # Get the subject info; stuff into 'subjects' array.
    my $sth = $dbh->prepare("select description,smdesc,subjsec from subject 
      where teacher $sql{like} '%($userid%' order by description");
    $sth->execute;
    if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr;}

    # Prep for loop finding the subjects
    my $sth1 = $dbh->prepare("select day, period from schedat 
     where term = '$term' and subjsec = ? ");

    while (my ($description,$smdesc,$subjsec) = $sth->fetchrow){
	push @bigsubjects,"$description ($subjsec)";
	push @subjects,$subjsec;

	$sth1->execute($subjsec);
	if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr;}

	# Create 2D subject array (of [period][day] indexes)
	while (my ($day, $period) = $sth1->fetchrow){
	    if (not $subject[$period][$day]){ # if empty, fill it.
		$subject[$period][$day] = $subjsec;
	    } elsif ($subject[$period][$day] eq $subjsec){
		# Do nothing if it matches...
	    } else { # Add one on.
		$subject[$period][$day] .= " $subjsec";
	    }
	}
	
    }
    return \@subject; # pass ref to 2D subject array.

} # End of mkTimetable




1;
