<?php
/**
 * webtrees: online genealogy
 * Copyright (C) 2017 webtrees development team
 * This program 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 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
namespace Fisharebest\Webtrees;

use Fisharebest\Webtrees\Controller\PageController;
use Fisharebest\Webtrees\Date\FrenchDate;
use Fisharebest\Webtrees\Date\GregorianDate;
use Fisharebest\Webtrees\Date\HijriDate;
use Fisharebest\Webtrees\Date\JalaliDate;
use Fisharebest\Webtrees\Date\JewishDate;
use Fisharebest\Webtrees\Date\JulianDate;
use Fisharebest\Webtrees\Functions\FunctionsDb;
use Fisharebest\Webtrees\Functions\FunctionsPrint;

/** @global Tree $WT_TREE */
global $WT_TREE;

require 'includes/session.php';

$CALENDAR_FORMAT = $WT_TREE->getPreference('CALENDAR_FORMAT');

$cal      = Filter::get('cal', '@#D[A-Z ]+@');
$day      = Filter::get('day', '\d\d?');
$month    = Filter::get('month', '[A-Z]{3,5}');
$year     = Filter::get('year', '\d{1,4}(?: B\.C\.)?|\d\d\d\d\/\d\d|\d+(-\d+|[?]+)?');
$view     = Filter::get('view', 'day|month|year', 'day');
$filterev = Filter::get('filterev', '[_A-Z-]*', 'BIRT-MARR-DEAT');
$filterof = Filter::get('filterof', 'all|living|recent', 'all');
$filtersx = Filter::get('filtersx', '[MF]', '');

if ($cal . $day . $month . $year === '') {
	// No date specified? Use the most likely calendar
	$cal = I18N::defaultCalendar()->gedcomCalendarEscape();
}

// Create a CalendarDate from the parameters

// We cannot display new-style/old-style years, so convert to new style
if (preg_match('/^(\d\d)\d\d\/(\d\d)$/', $year, $match)) {
	$year = $match[1] . $match[2];
}

// advanced-year "year range"
if (preg_match('/^(\d+)-(\d+)$/', $year, $match)) {
	if (strlen($match[1]) > strlen($match[2])) {
		$match[2] = substr($match[1], 0, strlen($match[1]) - strlen($match[2])) . $match[2];
	}
	$ged_date = new Date("FROM {$cal} {$match[1]} TO {$cal} {$match[2]}");
	$view     = 'year';
} else {
	// advanced-year "decade/century wildcard"
	if (preg_match('/^(\d+)(\?+)$/', $year, $match)) {
		$y1       = $match[1] . str_replace('?', '0', $match[2]);
		$y2       = $match[1] . str_replace('?', '9', $match[2]);
		$ged_date = new Date("FROM {$cal} {$y1} TO {$cal} {$y2}");
		$view     = 'year';
	} else {
		if ($year < 0) {
			$year = (-$year) . ' B.C.';
		} // need BC to parse date
		$ged_date = new Date("{$cal} {$day} {$month} {$year}");
		$year     = $ged_date->minimumDate()->y; // need negative year for year entry field.
	}
}
$cal_date = $ged_date->minimumDate();

// Fill in any missing bits with todays date
$today = $cal_date->today();
if ($cal_date->d === 0) {
	$cal_date->d = $today->d;
}
if ($cal_date->m === 0) {
	$cal_date->m = $today->m;
}
if ($cal_date->y === 0) {
	$cal_date->y = $today->y;
}

$cal_date->setJdFromYmd();

if ($year === 0) {
	$year = $cal_date->y;
}

// Extract values from date
$days_in_month = $cal_date->daysInMonth();
$days_in_week  = $cal_date->daysInWeek();
$cal_month     = $cal_date->format('%O');
$today_month   = $today->format('%O');

// Invalid dates? Go to monthly view, where they'll be found.
if ($cal_date->d > $days_in_month && $view === 'day') {
	$view = 'month';
}

// All further uses of $cal are to generate URLs
$cal = rawurlencode($cal);

$controller = new PageController;
$controller->setPageTitle(I18N::translate('Anniversary calendar'));

switch ($view) {
	case 'day':
		$controller->setPageTitle(I18N::translate('On this day…') . ' ' . $ged_date->display(false));
		break;
	case 'month':
		$controller->setPageTitle(I18N::translate('In this month…') . ' ' . $ged_date->display(false, '%F %Y'));
		break;
	case 'year':
		$controller->setPageTitle(I18N::translate('In this year…') . ' ' . $ged_date->display(false, '%Y'));
		break;
}

// Only generate the content for interactive users (not search robots).
if (Filter::getBool('ajax') && Session::has('initiated')) {
	?>
	<div id="calendar-page">
	<h2 class="wt-page-title"><?= $controller->getPageTitle() ?></h2>

	<form name="dateform">
		<input type="hidden" name="cal" value="<?= $cal ?>">
		<input type="hidden" name="day" value="<?= $cal_date->d ?>">
		<input type="hidden" name="month" value="<?= $cal_month ?>">
		<input type="hidden" name="year" value="<?= $cal_date->y ?>">
		<input type="hidden" name="view" value="<?= $view ?>">
		<input type="hidden" name="filterev" value="<?= $filterev ?>">
		<input type="hidden" name="filtersx" value="<?= $filtersx ?>">
		<input type="hidden" name="filterof" value="<?= $filterof ?>">

		<table class="table-sm wt-page-options w-100" role="presentation">
			<tr>
				<th class="wt-page-options-label">
					<?= I18N::translate('Day') ?>
				</th>
				<td class="wt-page-options-value" colspan="3">
					<?php
					for ($d = 1; $d <= $days_in_month; $d++) {
						// Format the day number using the calendar
						$tmp   = new Date($cal_date->format("%@ {$d} %O %E"));
						$d_fmt = $tmp->minimumDate()->format('%j');
						if ($d === $cal_date->d) {
							echo '<span class="error">', $d_fmt, '</span>';
						} else {
							echo '<a href="?cal=', $cal, '&amp;day=', $d, '&amp;month=', $cal_month, '&amp;year=', $cal_date->y, '&amp;filterev=', $filterev, '&amp;filterof=', $filterof, '&amp;filtersx=', $filtersx, '&amp;view=', $view, '">', $d_fmt, '</a>';
						}
						echo ' | ';
					}
					?>
					<a href="?cal=<?= $cal ?>&amp;day=<?= $today->d ?>&amp;month=<?= $today_month ?>&amp;year=<?= $today->y ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;filtersx=<?= $filtersx ?>&amp;view=<?= $view ?>">
						<b><?php $tmp = new Date($today->format('%@ %A %O %E')); echo $tmp->display() ?></b>
					</a>
				</td>
			</tr>
			<tr>
				<th class="wt-page-options-label">
					<?= I18N::translate('Month') ?>
				</th>
				<td class="wt-page-options-value" colspan="3">
					<?php
					for ($n = 1, $months_in_year = $cal_date->monthsInYear(); $n <= $months_in_year; ++$n) {
						$month_name = $cal_date->monthNameNominativeCase($n, $cal_date->isLeapYear());
						$m          = array_search($n, $cal_date::$MONTH_ABBREV);
						if ($n === 6 && $cal_date instanceof JewishDate && !$cal_date->isLeapYear()) {
							// No month 6 in Jewish non-leap years.
							continue;
						}
						if ($n === 7 && $cal_date instanceof JewishDate && !$cal_date->isLeapYear()) {
							// Month 7 is ADR in Jewish non-leap years.
							$m = 'ADR';
						}
						if ($n === $cal_date->m) {
							$month_name = '<span class="error">' . $month_name . '</span>';
						}
						echo '<a href="?cal=', $cal, '&amp;day=', $cal_date->d, '&amp;month=', $m, '&amp;year=', $cal_date->y, '&amp;filterev=', $filterev, '&amp;filterof=', $filterof, '&amp;filtersx=', $filtersx, '&amp;view=', $view, '">', $month_name, '</a>';
						echo ' | ';
					}
					?>
					<a href="?cal=<?= $cal ?>&amp;day=<?= min($cal_date->d, $today->daysInMonth()) ?>&amp;month=<?= $today_month ?>&amp;year=<?= $today->y ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;filtersx=<?= $filtersx ?>&amp;view=<?= $view ?>">
						<b><?= $today->format('%F %Y') ?></b>
					</a>
				</td>
			</tr>
			<tr>
				<th class="wt-page-options-label">
					<label for="year"><?= I18N::translate('Year') ?></label>
				</th>
				<td class="wt-page-options-value">
					<a href="?cal=<?= $cal ?>&amp;day=<?= $cal_date->d ?>&amp;month=<?= $cal_month ?>&amp;year=<?= $cal_date->y === 1 ? -1 : $cal_date->y - 1 ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;filtersx=<?= $filtersx ?>&amp;view=<?= $view ?>">
						-1
					</a>
					<input type="text" id="year" name="year" value="<?= $year ?>" size="4">
					<a href="?cal=<?= $cal ?>&amp;day=<?= $cal_date->d ?>&amp;month=<?= $cal_month ?>&amp;year=<?= $cal_date->y === -1 ? 1 : $cal_date->y + 1 ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;filtersx=<?= $filtersx ?>&amp;view=<?= $view ?>">
						+1
					</a>
					|
					<a href="?cal=<?= $cal ?>&amp;day=<?= $cal_date->d ?>&amp;month=<?= $cal_month ?>&amp;year=<?= $today->y ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;filtersx=<?= $filtersx ?>&amp;view=<?= $view ?>">
						<?= $today->format('%Y') ?>
					</a>
					<?= FunctionsPrint::helpLink('annivers_year_select') ?>
				</td>

				<th class="wt-page-options-label">
					<?= I18N::translate('Show') ?>
				</th>

				<td class="wt-page-options-value">
					<?php if (!$WT_TREE->getPreference('HIDE_LIVE_PEOPLE') || Auth::check()): ?>
						<select class="list_value" name="filterof" onchange="document.dateform.submit();">
							<option value="all" <?= $filterof === 'all' ? 'selected' : '' ?>>
								<?= I18N::translate('All individuals') ?>
							</option>
							<option value="living" <?= $filterof === 'living' ? 'selected' : '' ?>>
								<?= I18N::translate('Living individuals') ?>
							</option>
							<option value="recent" <?= $filterof === 'recent' ? 'selected' : '' ?>>
								<?= I18N::translate('Recent years (&lt; 100 yrs)') ?>
							</option>
						</select>
					<?php endif ?>

					<a title="<?= I18N::translate('All individuals') ?>" href="?cal=<?= $cal ?>&amp;day=<?= $cal_date->d ?>&amp;month=<?= $cal_month ?>&amp;year=<?= $cal_date->y ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;view=<?= $view ?>">
						<i class="<?= $filtersx === '' ? 'icon-sex_m_15x15' : 'icon-sex_m_9x9' ?>"></i>
						<i class="<?= $filtersx === '' ? 'icon-sex_f_15x15' : 'icon-sex_f_9x9' ?>"></i>
					</a>
					|
					<a title="<?= I18N::translate('Males') ?>" href="?cal=<?= $cal ?>&amp;day=<?= $cal_date->d ?>&amp;month=<?= $cal_month ?>&amp;year=<?= $cal_date->y ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;filtersx=M&amp;view=<?= $view ?>">
						<i class="<?= $filtersx === 'M' ? 'icon-sex_m_15x15' : 'icon-sex_m_9x9' ?>"></i>
					</a>
					|
					<a title="<?= I18N::translate('Females') ?>" href="?cal=<?= $cal ?>&amp;day=<?= $cal_date->d ?>&amp;month=<?= $cal_month ?>&amp;year=<?= $cal_date->y ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;filtersx=F&amp;view=<?= $view ?>">
						<i class="<?= $filtersx === 'F' ? 'icon-sex_f_15x15' : 'icon-sex_f_9x9' ?>"></i>
					</a>

					<select class="list_value" name="filterev" onchange="document.dateform.submit();">
						<option value="BIRT-MARR-DEAT" <?= $filterev === 'BIRT-MARR-DEAT' ? 'selected' : '' ?>>
							<?= I18N::translate('Vital records') ?>
						</option>
						<option value="" <?= $filterev === '' ? 'selected' : '' ?>>
							<?= I18N::translate('All') ?>
						</option>
						<option value="BIRT" <?= $filterev === 'BIRT' ? 'selected' : '' ?>>
							<?= I18N::translate('Birth') ?>
						</option>
						<option value="BAPM-CHR-CHRA" <?= $filterev === 'BAPM-CHR-CHRA' ? 'selected' : '' ?>>
							<?= I18N::translate('Baptism') ?>
						</option>
						<option value="MARR-_COML-_NMR" <?= $filterev === 'MARR-_COML-_NMR' ? 'selected' : '' ?>>
							<?= I18N::translate('Marriage') ?>
						</option>
						<option value="DIV-_SEPR" <?= $filterev === 'DIV-_SEPR' ? 'selected' : '' ?>>
							<?= I18N::translate('Divorce') ?>
						</option>
						<option value="DEAT" <?= $filterev === 'DEAT' ? 'selected' : '' ?>>
							<?= I18N::translate('Death') ?>
						</option>
						<option value="BURI" <?= $filterev === 'BURI' ? 'selected' : '' ?>>
							<?= I18N::translate('Burial') ?>
						</option>
						<option value="IMMI,EMIG" <?= $filterev === 'IMMI,EMIG' ? 'selected' : '' ?>>
							<?= I18N::translate('Emigration') ?>
						</option>
						<option value="EVEN" <?= $filterev === 'EVEN' ? 'selected' : '' ?>>
							<?= I18N::translate('Custom event') ?>
						</option>
					</select>
				</td>
			</tr>
		</table>

		<table class="width100">
			<tr>
				<td class="topbottombar width50">
					<a class="<?= $view === 'day' ? 'error' : '' ?>" href="?cal=<?= $cal ?>&amp;day=<?= $cal_date->d ?>&amp;month=<?= $cal_month ?>&amp;year=<?= $cal_date->y ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;filtersx=<?= $filtersx ?>&amp;view=day">
						<?= I18N::translate('View this day') ?>
					</a>
					|
					<a class="<?= $view === 'month' ? 'error' : '' ?>" href="?cal=<?= $cal ?>&amp;day=<?= $cal_date->d ?>&amp;month=<?= $cal_month ?>&amp;year=<?= $cal_date->y ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;filtersx=<?= $filtersx ?>&amp;view=month">
						<?= I18N::translate('View this month') ?>
					</a>
					|
					<a class="<?= $view === 'year' ? 'error' : '' ?>" href="?cal=<?= $cal ?>&amp;day=<?= $cal_date->d ?>&amp;month=<?= $cal_month ?>&amp;year=<?= $cal_date->y ?>&amp;filterev=<?= $filterev ?>&amp;filterof=<?= $filterof ?>&amp;filtersx=<?= $filtersx ?>&amp;view=year">
						<?= I18N::translate('View this year') ?>
					</a>
				</td>
				<td class="topbottombar width50">
					<?php
					$n = 0;
	foreach (Date::calendarNames() as $newcal => $cal_name) {
		$tmp = $cal_date->convertToCalendar($newcal);
		if ($tmp->inValidRange()) {
			if ($n++) {
				echo ' | ';
			}
			if (get_class($tmp) === get_class($cal_date)) {
				echo '<span class="error">', $cal_name, '</span>';
			} else {
				$newcalesc = urlencode($tmp->format('%@'));
				$tmpmonth  = $tmp->format('%O');
				echo '<a href="?cal=', $newcalesc, '&amp;day=', $tmp->d, '&amp;month=', $tmpmonth, '&amp;year=', $tmp->y, '&amp;filterev=', $filterev, '&amp;filterof=', $filterof, '&amp;filtersx=', $filtersx, '&amp;view=', $view, '">', $cal_name, '</a>';
			}
		}
	} ?>
				</td>
			</tr>
		</table>
	</form>
	<?php

// Fetch data for day/month/year views
	$found_facts = [];

	switch ($view) {
		case 'day':
			$found_facts = apply_filter(FunctionsDb::getAnniversaryEvents($cal_date->minJD, $filterev, $WT_TREE), $filterof, $filtersx);
			break;
		case 'month':
			$cal_date->d = 0;
			$cal_date->setJdFromYmd();
			// Make a separate list for each day. Unspecified/invalid days go in day 0.
			for ($d = 0; $d <= $days_in_month; ++$d) {
				$found_facts[$d] = [];
			}
			// Fetch events for each day
			for ($jd = $cal_date->minJD; $jd <= $cal_date->maxJD; ++$jd) {
				foreach (apply_filter(FunctionsDb::getAnniversaryEvents($jd, $filterev, $WT_TREE), $filterof, $filtersx) as $fact) {
					$tmp = $fact->getDate()->minimumDate();
					if ($tmp->d >= 1 && $tmp->d <= $tmp->daysInMonth()) {
						// If the day is valid (for its own calendar), display it in the
						// anniversary day (for the display calendar).
						$found_facts[$jd - $cal_date->minJD + 1][] = $fact;
					} else {
						// Otherwise, display it in the "Day not set" box.
						$found_facts[0][] = $fact;
					}
				}
			}
			break;
		case 'year':
			$cal_date->m = 0;
			$cal_date->setJdFromYmd();
			$found_facts = apply_filter(FunctionsDb::getCalendarEvents($ged_date->minimumJulianDay(), $ged_date->maximumJulianDay(), $filterev, $WT_TREE), $filterof, $filtersx);
			// Eliminate duplicates (e.g. BET JUL 1900 AND SEP 1900 will appear twice in 1900)
			$found_facts = array_unique($found_facts);
			break;
	}

	// Group the facts by family/individual
	$indis     = [];
	$fams      = [];
	$cal_facts = [];

	switch ($view) {
		case 'year':
		case 'day':
			foreach ($found_facts as $fact) {
				$record = $fact->getParent();
				$xref   = $record->getXref();
				if ($record instanceof Individual) {
					if (empty($indis[$xref])) {
						$indis[$xref] = calendar_fact_text($fact, true);
					} else {
						$indis[$xref] .= '<br>' . calendar_fact_text($fact, true);
					}
				} elseif ($record instanceof Family) {
					if (empty($indis[$xref])) {
						$fams[$xref] = calendar_fact_text($fact, true);
					} else {
						$fams[$xref] .= '<br>' . calendar_fact_text($fact, true);
					}
				}
			}
			break;
		case 'month':
			foreach ($found_facts as $d => $facts) {
				$cal_facts[$d] = [];
				foreach ($facts as $fact) {
					$xref = $fact->getParent()->getXref();
					if (empty($cal_facts[$d][$xref])) {
						$cal_facts[$d][$xref] = calendar_fact_text($fact, false);
					} else {
						$cal_facts[$d][$xref] .= '<br>' . calendar_fact_text($fact, false);
					}
				}
			}
			break;
	}

	switch ($view) {
		case 'year':
		case 'day':
			$males   = 0;
			$females = 0;
			echo '<table class="width100"><tr>';
			echo '<td class="descriptionbox center width50"><i class="icon-indis"></i>', I18N::translate('Individuals'), '</td>';
			echo '<td class="descriptionbox center width50"><i class="icon-cfamily"></i>', I18N::translate('Families'), '</td>';
			echo '</tr><tr>';
			echo '<td class="optionbox wrap">';

			$content = calendar_list_text($indis, '<li>', '</li>', true);
			if ($content) {
				echo '<ul>', $content, '</ul>';
			}

			echo '</td>';
			echo '<td class="optionbox wrap">';

			$content = calendar_list_text($fams, '<li>', '</li>', true);
			if ($content) {
				echo '<ul>', $content, '</ul>';
			}

			echo '</td>';
			echo '</tr><tr>';
			echo '<td class="descriptionbox">', I18N::translate('Total individuals: %s', count($indis));
			echo '<br>';
			echo '<i class="icon-sex_m_15x15" title="', I18N::translate('Males'), '"></i> ', $males, ' ';
			echo '<i class="icon-sex_f_15x15" title="', I18N::translate('Females'), '"></i> ', $females, ' ';
			if (count($indis) !== $males + $females) {
				echo '<i class="icon-sex_u_15x15" title="', I18N::translate('All individuals'), '"></i> ', count($indis) - $males - $females;
			}
			echo '</td>';
			echo '<td class="descriptionbox">', I18N::translate('Total families: %s', count($fams)), '</td>';
			echo '</tr></table>';

			break;
		case 'month':
	// We use JD%7 = 0/Mon…6/Sun. Standard definitions use 0/Sun…6/Sat.
			$week_start    = (I18N::firstDay() + 6) % 7;
			$weekend_start = (I18N::weekendStart() + 6) % 7;
			$weekend_end   = (I18N::weekendEnd() + 6) % 7;
			// The french  calendar has a 10-day week, which starts on primidi
			if ($days_in_week === 10) {
				$week_start    = 0;
				$weekend_start = -1;
				$weekend_end   = -1;
			}
			echo '<table class="width100"><thead><tr>';
			for ($week_day = 0; $week_day < $days_in_week; ++$week_day) {
				$day_name = $cal_date->dayNames(($week_day + $week_start) % $days_in_week);
				if ($week_day == $weekend_start || $week_day == $weekend_end) {
					echo '<th class="descriptionbox weekend" width="' . (100 / $days_in_week) . '%">', $day_name, '</th>';
				} else {
					echo '<th class="descriptionbox" width="' . (100 / $days_in_week) . '%">', $day_name, '</th>';
				}
			}
			echo '</tr>';
			echo '</thead>';
			echo '<tbody>';
			// Print days 1 to n of the month, but extend to cover "empty" days before/after the month to make whole weeks.
			// e.g. instead of 1 -> 30 (=30 days), we might have -1 -> 33 (=35 days)
			$start_d = 1 - ($cal_date->minJD - $week_start) % $days_in_week;
			$end_d   = $days_in_month + ($days_in_week - ($cal_date->maxJD - $week_start + 1) % $days_in_week) % $days_in_week;
			// Make sure that there is an empty box for any leap/missing days
			if ($start_d === 1 && $end_d === $days_in_month && count($found_facts[0]) > 0) {
				$end_d += $days_in_week;
			}
			for ($d = $start_d; $d <= $end_d; ++$d) {
				if (($d + $cal_date->minJD - $week_start) % $days_in_week === 1) {
					echo '<tr>';
				}
				echo '<td class="optionbox wrap">';
				if ($d < 1 || $d > $days_in_month) {
					if (count($cal_facts[0]) > 0) {
						echo '<span class="cal_day">', I18N::translate('Day not set'), '</span><br style="clear: both;">';
						echo '<div class="details1" style="height: 180px; overflow: auto;">';
						echo calendar_list_text($cal_facts[0], '', '', false);
						echo '</div>';
						$cal_facts[0] = [];
					}
				} else {
					// Format the day number using the calendar
					$tmp   = new Date($cal_date->format("%@ {$d} %O %E"));
					$d_fmt = $tmp->minimumDate()->format('%j');
					if ($d === $today->d && $cal_date->m === $today->m) {
						echo '<span class="cal_day current_day">', $d_fmt, '</span>';
					} else {
						echo '<span class="cal_day">', $d_fmt, '</span>';
					}
					// Show a converted date
					foreach (explode('_and_', $CALENDAR_FORMAT) as $convcal) {
						switch ($convcal) {
							case 'french':
								$alt_date = new FrenchDate($cal_date->minJD + $d - 1);
								break;
							case 'gregorian':
								$alt_date = new GregorianDate($cal_date->minJD + $d - 1);
								break;
							case 'jewish':
								$alt_date = new JewishDate($cal_date->minJD + $d - 1);
								break;
							case 'julian':
								$alt_date = new JulianDate($cal_date->minJD + $d - 1);
								break;
							case 'hijri':
								$alt_date = new HijriDate($cal_date->minJD + $d - 1);
								break;
							case 'jalali':
								$alt_date = new JalaliDate($cal_date->minJD + $d - 1);
								break;
							default:
								break 2;
						}
					if (get_class($alt_date) !== get_class($cal_date) && $alt_date->inValidRange()) {
						echo '<span class="rtl_cal_day">' . $alt_date->format('%j %M') . '</span>';
						// Just show the first conversion
						break;
					}
				}
				echo '<br style="clear: both;"><div class="details1" style="height: 180px; overflow: auto;">';
				echo calendar_list_text($cal_facts[$d], '', '', false);
				echo '</div>';
			}
			echo '</td>';
			if (($d + $cal_date->minJD - $week_start) % $days_in_week === 0) {
				echo '</tr>';
			}
		}
		echo '</tbody>';
		echo '</table>';
		break;
	}
	echo '</div>'; //close "calendar-page"

	return;
}

$ajax_url = Html::url('calendar.php', [
	'ged'      => $WT_TREE->getName(),
	'cal'      => $cal,
	'day'      => $day,
	'month'    => $month,
	'year'     => $year,
	'view'     => $view,
	'filterev' => $filterev,
	'filterof' => $filterof,
	'filtersx' => $filtersx,
	'ajax'     => 1,
]);

$controller->pageHeader();

?>
	<div class="wt-ajax-load wt-page-content" data-ajax-url="<?= e($ajax_url) ?>"></div>
	<?php

/**
 * Filter a list of anniversaries
 *
 * @param Fact[] $facts
 * @param string $filterof
 * @param string $filtersx
 *
 * @return array
 */
function apply_filter($facts, $filterof, $filtersx) {
	$filtered      = [];
	$hundred_years = WT_CLIENT_JD - 36525;
	foreach ($facts as $fact) {
		$record = $fact->getParent();
		if ($filtersx) {
			// Filter on sex
			if ($record instanceof Individual && $filtersx !== $record->getSex()) {
				continue;
			}
			// Can't display families if the sex filter is on.
			if ($record instanceof Family) {
				continue;
			}
		}
		// Filter living individuals
		if ($filterof === 'living') {
			if ($record instanceof Individual && $record->isDead()) {
				continue;
			}
			if ($record instanceof Family) {
				$husb = $record->getHusband();
				$wife = $record->getWife();
				if ($husb && $husb->isDead() || $wife && $wife->isDead()) {
					continue;
				}
			}
		}
		// Filter on recent events
		if ($filterof === 'recent' && $fact->getDate()->maximumJulianDay() < $hundred_years) {
			continue;
		}
		$filtered[] = $fact;
	}

	return $filtered;
}

/**
 * Format an anniversary display.
 *
 * @param Fact $fact
 * @param bool $show_places
 *
 * @return string
 */
function calendar_fact_text(Fact $fact, $show_places) {
	$text = $fact->getLabel() . ' — ' . $fact->getDate()->display(true, null, false);
	if ($fact->anniv) {
		$text .= ' (' . I18N::translate('%s year anniversary', $fact->anniv) . ')';
	}
	if ($show_places && $fact->getAttribute('PLAC')) {
		$text .= ' — ' . $fact->getAttribute('PLAC');
	}

	return $text;
}

/**
 * Format a list of facts for display
 *
 * @param Fact[] $list
 * @param string $tag1
 * @param string $tag2
 * @param bool   $show_sex_symbols
 *
 * @return string
 */
function calendar_list_text($list, $tag1, $tag2, $show_sex_symbols) {
	global $males, $females, $WT_TREE;

	$html = '';

	foreach ($list as $id => $facts) {
		$tmp = GedcomRecord::getInstance($id, $WT_TREE);
		$html .= $tag1 . '<a href="' . e($tmp->url()) . '">' . $tmp->getFullName() . '</a> ';
		if ($show_sex_symbols && $tmp instanceof Individual) {
			switch ($tmp->getSex()) {
				case 'M':
					$html .= '<i class="icon-sex_m_9x9" title="' . I18N::translate('Male') . '"></i>';
					++$males;
					break;
				case 'F':
					$html .= '<i class="icon-sex_f_9x9" title="' . I18N::translate('Female') . '"></i>';
					++$females;
					break;
				default:
					$html .= '<i class="icon-sex_u_9x9" title="' . I18N::translateContext('unknown gender', 'Unknown') . '"></i>';
					break;
			}
		}
		$html .= '<div class="indent">' . $facts . '</div>' . $tag2;
	}

	return $html;
}
