<?php
/**
 *----------------------------------------------------------------------------
 * iCagenda     Events Management Extension for Joomla!
 *----------------------------------------------------------------------------
 * @version     4.0.0 2026-01-12
 *
 * @package     iCagenda.Admin
 * @subpackage  src.Utilities.Registration
 * @link        https://www.joomlic.com
 *
 * @author      Cyril Reze
 * @copyright   (c) 2012-2026 Cyril Reze / JoomliC. All rights reserved.
 * @license     GNU General Public License version 3 or later; see LICENSE.txt
 *
 * @since       3.6
 *----------------------------------------------------------------------------
*/

namespace iCutilities\Registration;

\defined('_JEXEC') or die;

use iClib\Date\Date as iCDate;
use iClib\Date\Period as iCDatePeriod;
use iClib\Url\Url as iCUrl;
use iClib\String\StringHelper as iCString;
use iCutilities\Event\Event as icagendaEvent;
use iCutilities\Menus\Menus as icagendaMenus;
use iCutilities\Render\Render as icagendaRender;
use Joomla\CMS\Access\Access;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\ParameterType;
use Joomla\Registry\Registry;

/**
 * class icagendaRegistration
 */
class Registration
{
	/**
	 * Function to get total of registered people for one event/date
	 *
	 * @since   3.6.5
	 */
	public static function getRegisteredTotal($eventID, $regDate = null, $typeReg = '1')
	{
		$db = Factory::getContainer()->get('DatabaseDriver');

		$query = $db->createQuery()
			->select('SUM(' . $db->qn('r.people') . ') AS total')
			->from($db->qn('#__icagenda_registration', 'r'))
			->where($db->qn('r.eventid') . ' = :eventID')
			->where($db->qn('r.status') . ' = 1')
			->where($db->qn('r.state') . ' = 1')
			->bind(':eventID', $eventID, ParameterType::INTEGER);

		// Registration type: by single date/period (1)
		if ($regDate && $typeReg == 1) {
			// Single date or period split by day(s) of the week.
			$query->where('(' . $db->qn('r.date') . ' = ' . $db->q($regDate)
				. ' OR (' . $db->qn('r.date') . ' = "" AND ' . $db->qn('r.period') . ' = 1) )');
//			$query->where('r.date = ' . $db->q($regDate)); // This is the correct logic if correctly set
		} elseif ( ! $regDate && $typeReg == 1) {
			// Full period.
			$query->where($db->qn('r.date') . ' = ""');
//			$query->where('r.date = "" AND r.period = 0'); // This is the correct logic if correctly set
		}

		// Registration type: all dates (2)
//		else {
//			$query->where('r.date = "" AND r.period = 1');
//		}

		$db->setQuery($query);

		$total = $db->loadResult();

		return $total;
	}

	/**
	 * Function to get list of registered people per date/period for one event
	 * Not Use: BETA
	 *
	 * @since   3.6.6
	 */
	public static function getListRegisteredTotal($eventID)
	{
		$db    = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
		$query = $db->createQuery();

		$query->select('sum(' . $db->qn('r.people') . ') AS people, r.date AS date, r.period AS period')
			->from($db->qn('#__icagenda_registration', 'r'))
			->where($db->qn('r.eventid') . ' = ' . (int) $eventID)
			->where($db->qn('r.status') . ' = 1')
			->where($db->qn('r.state') . ' = 1')
			->group('r.date');

		$db->setQuery($query);

		$list = $db->loadObjectList();

		return $list;
	}

	/**
	 * Function to get available tickets for one event/date
	 *
	 * @since   3.6.5
	 */
	public static function getTicketsAvailable($eventID, $regDate, $typeReg = '1', $maxReg = '1000000')
	{
		$regDate          = ($typeReg == 1) ? $regDate : '';
		$registered       = self::getRegisteredTotal($eventID, $regDate, $typeReg);
		$ticketsAvailable = ($maxReg - $registered);

		if ($ticketsAvailable < 0) $ticketsAvailable = '0';

		return $ticketsAvailable;
	}

	/**
	 * Function to get list of available tickets per date/period for one event
	 * Not Use: BETA
	 *
	 * @since   3.6.6
	 */
	public static function getListTicketsAvailable($eventID, $typeReg = '1', $maxReg = '1000000')
	{
		$listDatesTicketsAvailable = array();

		$listRegisteredTotal = self::getListRegisteredTotal($eventID);

		foreach ($listRegisteredTotal as $k => $v)
		{
			$listDatesTicketsAvailable[$v->date] = ($maxReg - $v->people);
		}

		return $listDatesTicketsAvailable;
	}

	/**
	 * Function to get max number of tickets bookable (people) for one event/date
	 *
	 * @since   3.6.5
	 */
	public static function getTicketsBookable($eventID, $regDate, $typeReg = '1', $maxReg = '1000000', $tickets = '5')
	{
		$ticketsAvailable = self::getTicketsAvailable($eventID, $regDate, $typeReg, $maxReg);

		if ($ticketsAvailable > $tickets)
		{
			return $tickets;
		}
		else
		{
			return $ticketsAvailable;
		}
	}

	/**
	 * Function to get Deadline Interval.
	 *
	 * @since   3.8
	 */
	public static function getDeadlineInterval($item)
	{
		// Get Deadline for Registration
		$rdt = $item->params->get('reg_deadline_time', '');

		if ($rdt) {
			$rdt = \is_array($rdt) ? $rdt : json_decode($rdt, true);

			$deadline_month = $rdt['month'] ?: '0';
			$deadline_week  = $rdt['week'] ?: '0';
			$deadline_day   = $rdt['day'] ?: '0';
			$deadline_hour  = $rdt['hour'] ?: '0';
			$deadline_min   = $rdt['min'] ?: '0';

			if ($deadline_month == 0
				&& $deadline_week == 0
				&& $deadline_day == 0
				&& $deadline_hour == 0
				&& $deadline_min == 0
			) {
				$deadlineInterval = '';
			} else {
				$deadlineDays = $deadline_day + ($deadline_week * 7);
				$deadlineInterval = 'P' . $deadline_month . 'M' . $deadlineDays . 'DT' . $deadline_hour . 'H' . $deadline_min . 'M';
			}
		} else {
			$deadlineInterval = '';
		}

		return $deadlineInterval;
	}

	/**
	 * Function to get Deadline DateTime.
	 *
	 * @since   3.8
	 */
	public static function getDeadlineDateTime($date = 'now', $interval = null)
	{
		if ($interval) {
			$newDate = new \DateTime($date);
			$newDate->sub(new \DateInterval($interval));
			$deadlineDateTime = $newDate->format('Y-m-d H:i:s');
		} else {
			$deadlineDateTime = $date;
		}

		return $deadlineDateTime;
	}

	/**
	 * Function to return dates drop list for registrable dates
	 *
	 * @since   3.6.0 (Migrated from 3.5 - TO BE REVIEWED)
	 *          version 3.6.5
	 *
	 * @TODO    set option/value to array
	 * @TODO    migrate HTML rendering for options text to form field type getOptions ($type = registrationdates)
	 */
	public static function formDatesList($item)
	{
		$app      = Factory::getApplication();
		$params   = $app->getParams();
		$iCparams = ComponentHelper::getParams('com_icagenda');

		$eventTimeZone   = null;
		$date_today      = HTMLHelper::date('now', 'Y-m-d', false);
		$date_time_today = HTMLHelper::date('now', 'Y-m-d H:i', false);

		$allDates        = self::eventAllDates($item);
		$timeformat      = $params->get('timeformat', 1);
		$perioddates     = iCDatePeriod::listDates($item->startdate, $item->enddate, $eventTimeZone);

//		$evtParams   = icagendaEvent::evtParams($item->params);
		$typeReg     = $item->params->get('typeReg', '1');
		$max_tickets = $item->params->get('maxReg', '1000000');
		$regDeadline = $item->params->get('reg_deadline', 1);

		// Check the period if individual dates
		$fullPeriod = ($item->weekdays || $item->weekdays == '0') ? false : true;

		$lang_time = ($timeformat == 1) ? 'H:i' : 'h:i A';

		sort($allDates);

		$p = 0;

//		print_r(self::getListTicketsAvailable($item->id, $typeReg, $max_tickets));
// TEST	$listTicketsAvailable = $item->listTicketsAvailable;

		$upDays = array();

		foreach ($allDates as $k => $d)
		{
			// Get Deadline for Registration
			$deadlineInterval = self::getDeadlineInterval($item);

			$date_control = HTMLHelper::date($d, 'Y-m-d H:i', $eventTimeZone);

			if ($fullPeriod && in_array($date_control, $perioddates))
			{
				$is_full_period = true;
				$datetime_date  = ($regDeadline == 2)
//								? date('Y-m-d H:i:s', strtotime($item->enddate))
								? HTMLHelper::date($item->enddate, 'Y-m-d H:i:s', $eventTimeZone)
//								: date('Y-m-d H:i:s', strtotime($item->startdate));
								: HTMLHelper::date($item->startdate, 'Y-m-d H:i:s', $eventTimeZone);

				// Set Deadline to Limit Registration Date
				$DL_datetime_date = self::getDeadlineDateTime($datetime_date, $deadlineInterval);

				$datetime_check = $DL_datetime_date;
			}
			else
			{
				$is_full_period = false;
//				$datetime_date  = date('Y-m-d H:i:s', strtotime($d));
				$datetime_date  = HTMLHelper::date($d, 'Y-m-d H:i:s', $eventTimeZone);

				// Set Deadline to Limit Registration Date
				$DL_d = self::getDeadlineDateTime($d, $deadlineInterval);

				$datetime_check = ($regDeadline == 2)
								? date('Y-m-d', strtotime($DL_d)) . ' 23:59:59'
//								? HTMLHelper::date($DL_d, 'Y-m-d', $eventTimeZone) . ' 23:59:59'
								: date('Y-m-d H:i:s', strtotime($DL_d));
//								: HTMLHelper::date($DL_d, 'Y-m-d H:i:s', $eventTimeZone);
			}

			$regDate         = $is_full_period ? '' : $datetime_date;
			$nb_tickets_left = self::getTicketsBookable($item->id, $regDate, $typeReg, $max_tickets, $item->params->get('maxNbTicketsPerReg', 5));

// TEST		$nb_tickets_left = isset($listTicketsAvailable[$regDate]) ? $listTicketsAvailable[$regDate] : $max_tickets;

			$date_today_compare = ($item->displaytime == 1) ? $date_time_today : $date_today;

			if (strtotime($datetime_check) > strtotime($date_today_compare)
				&& $nb_tickets_left > 0)
			{
				// Removed for now, as gives confusion (nb of maximum tickets for one registration to selected date)
//				$tickets_left = ($max_tickets != '1000000') ? ' (&#10003;' . $nb_tickets_left . ')' : '';
				$tickets_left = '';

				if ($is_full_period)
				{
					if ($p == 0)
					{
						if (icagendaRender::dateToFormat($item->startdate) == icagendaRender::dateToFormat($item->enddate))
						{
							$upDays[$k] = 'period@@' . strip_tags(icagendaRender::dateToFormat($item->startdate)) . $tickets_left;
						}
						else
						{
							$upDays[$k] = 'period@@' . strip_tags(icagendaRender::dateToFormat($item->startdate)) . ' &#x279c; ' . strip_tags(icagendaRender::dateToFormat($item->enddate)) . $tickets_left;
						}

						$p = $p+1;
					}
				}
				else
				{
					$date = strip_tags(icagendaRender::dateToFormat($d));

					$event_time = ($item->displaytime == 1) ? ' - ' . date($lang_time, strtotime($datetime_date)) : '';

					$upDays[$k] = $datetime_date . '@@' . $date . $event_time . $tickets_left;
				}
			}
		}

		return $upDays;
	}

	/**
	 * Function to get option setting for max nb of tickets per registration
	 *
	 * @since   3.6.0  (Migrated from 3.5)
	 */
	public static function maxNbTicketsPerReg($params)
	{
		$iCparams = ComponentHelper::getParams('com_icagenda');

		$useGlobal    = $params->get('maxRlistGlobal', '');
		$evt_maxRlist = $params->get('maxRlist', '5');

		// Control and edit param values to iCagenda v3
		if ($useGlobal == '1') $useGlobal = '';
		elseif ($useGlobal == '0') $useGlobal = '2';

		if ($useGlobal == '2')
		{
			$maxNbTicketsPerReg = $evt_maxRlist;
		}
		else
		{
			$maxNbTicketsPerReg = $iCparams->get('maxRlist', '5');
		}

		return $maxNbTicketsPerReg;
	}

	/**
	 * Function to get registrations by user id
	 *
	 * @since   3.8.0
	 */
	public static function getUserRegistrations($userID, $eventID = null)
	{
		$user = Factory::getUser($userID);

		$db = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
		$query = $db->createQuery();

		$query->select('r.*')
			->from($db->quoteName('#__icagenda_registration', 'r'))
			->where($db->quoteName('r.status') . ' = 1')
			->where($db->quoteName('r.state') . ' = 1')
			->where('(' . $db->quoteName('r.userid') . ' = ' . (int) $userID)
			->where($db->quoteName('r.email') . " = " . $db->quote($user->email) . ')');

		if ($eventID)
		{
			$query->where($db->quoteName('r.eventid') . ' = ' . (int) $eventID);
		}

		$db->setQuery($query);

		$list = $db->loadObjectList();

		return $list;
	}

	/**
	 * Function to get booked registrations by user email
	 *
	 * @since   3.8.0
	 */
	public static function getUserRegistrationsBooked($email, $eventID = null, $regDate = '')
	{
		$iCparams = ComponentHelper::getParams('com_icagenda');

		$limitRegEmail = $iCparams->get('limitRegEmail', 1);
		$limitRegDate  = $iCparams->get('limitRegDate', 1);

		$db    = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
		$query = $db->createQuery();

		$query->select('r.*')
			->from($db->qn('#__icagenda_registration', 'r'));

		$query->where($db->qn('r.email') . ' = ' . $db->q($email));

		if ($eventID) {
			$query->where($db->qn('r.eventid') . ' = ' . (int) $eventID);
		}

//		if ($limitRegEmail != 1 && $limitRegDate == 1)
		if ($limitRegDate == 1) {
			$query->where($db->qn('r.date') . ' = ' . $db->q($regDate));
		}

		$query->where($db->qn('r.status') . ' = 1');
		$query->where($db->qn('r.state') . ' = 1');

		$db->setQuery($query);

		$list = $db->loadObjectList();

		return $list;
	}

	/**
	 * Function to get registrations status by user for one event/date
	 *
	 * @since   3.8.0
	 */
	public static function getUserRegistrationsStatus($email, $eventID = null, $regDate = '')
	{
		$iCparams = ComponentHelper::getParams('com_icagenda');

		$limitRegEmail = $iCparams->get('limitRegEmail', 1);
		$limitRegDate  = $iCparams->get('limitRegDate', 1);

		$db    = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
		$query = $db->createQuery();

		$query->select('r.*')
			->from($db->qn('#__icagenda_registration', 'r'));

		$query->where($db->qn('r.email') . ' = ' . $db->q($email));

		if ($eventID) {
			$query->where($db->qn('r.eventid') . ' = ' . (int) $eventID);
		}

//		if ($limitRegEmail != 1 && $limitRegDate == 1)
		if ($limitRegDate == 1) {
			$query->where($db->qn('r.date') . ' = ' . $db->q($regDate));
		}

		$query->where($db->qn('r.state') . ' = 1');

		$db->setQuery($query);

		$list = $db->loadObjectList();

		$booked    = 0;
		$cancelled = 0;

		foreach ($list as $reg) {
			switch ($reg->status) {
				case 0:
					$cancelled++;
					break;

				case 1:
					$booked++;
					break;
			}
		}

		if ($limitRegEmail == 1 && $limitRegDate != 1 && $booked > 0) {
			return 'registered';
		} elseif ($limitRegDate == 1 && $booked > 0) {
			return 'registeredDate';
		} elseif ($booked > 0) {
			return 'ok';
		} elseif ($cancelled > 0) {
			return 'cancelled';
		}

		return 'ok';
	}

	/**
	 * Function to return $displayData for Register Button Box
	 *
	 * @since   3.8
	 */
	static public function registerButton($item, $evt = '', $linkid = 0)
	{
		// Access Control
		$user       = Factory::getUser();
		$userLevels = $user->getAuthorisedViewLevels();
		$userGroups = Access::getGroupsByUser($user->get('id'), false);

		$accessReg            = self::accessReg($item);
		$availableDates       = self::upcomingDatesBooking($item);
		$ticketsCouldBeBooked = self::ticketsCouldBeBooked($item);

		// Get Event params
//		if (isset($item->params) && \is_array($item->params)) {
//			$evtParams = new Registry($item->params);
//		} else {
//			$evtParams = $item->params;
//		}
		if (!($item->params instanceof Registry)) {
			$item->params = new Registry($item->params);
		}

		$evtParams = $item->params;

		$statutReg   = $evtParams->get('statutReg', '1');
		$regDeadline = $evtParams->get('reg_deadline', 1);
		$typeReg     = $evtParams->get('typeReg', '1');

		// Initialize controls
		$eventTimeZone   = null;
		$date_today      = HTMLHelper::date('now', 'Y-m-d', false);
		$date_time_today = HTMLHelper::date('now', 'Y-m-d H:i', false);

		$period             = unserialize($item->period);
		$period             = is_array($period) ? $period : array();
		$fullPeriod         = ($item->weekdays || $item->weekdays == '0') ? false : true;
		$datetime_startdate = HTMLHelper::date($item->startdate, 'Y-m-d H:i', $eventTimeZone);

		// Get var event date alias if set or var 'event_date' set to session in event details view
		$session    = Factory::getSession();
		$event_date = $evt ? $evt : $session->get('event_date', '');

		if ($evt) {
			$get_date = date('Y-m-d-H-i', strtotime($event_date));
		} else {
			$get_date = Factory::getApplication()->input->get('date', ($event_date ? HTMLHelper::date($event_date, 'Y-m-d-H-i', $eventTimeZone) : ''));
		}

		// Get Deadline for Registration
		$deadlineInterval = self::getDeadlineInterval($item);

		if ($get_date && ! isset($item->date)) {
			// URL datetime var (legacy) or date $evt set (since 4.0)
			$registered = isset($item->registered) ? $item->registered : self::getRegisteredTotal($item->id, $get_date, $typeReg);
//			$registered = self::getRegisteredTotal($item->id, $get_date, $typeReg);

			// Convert to SQL datetime if set, or return empty.
			$dateday = icagendaEvent::convertDateAliasToSQLDatetime($get_date);

			// Set Deadline to Event Date (@todo: check if needed, after refactory)
			$DL_dateday = self::getDeadlineDateTime($dateday, $deadlineInterval);

			$date_is_upcoming = (strtotime($DL_dateday) > strtotime($date_time_today));

			// If registration until End Date
			if ($regDeadline == 2) {
				// Case Single Date from period (weekdays), else single date
				$endDatetime = (in_array($dateday, $period))
					? HTMLHelper::date($dateday, 'Y-m-d', $eventTimeZone) . ' ' . HTMLHelper::date($item->enddate, 'H:i:s', $eventTimeZone)
					: HTMLHelper::date($dateday, 'Y-m-d', $eventTimeZone) . ' 23:59:59';
			} else {
				$startDatetime  = HTMLHelper::date($dateday, 'Y-m-d H:i', $eventTimeZone);
			}

//		} elseif (isset($evt)) {
//			// Button in list of events
//			$registered = isset($item->registered) ? $item->registered : self::getRegisteredTotal($item->id, $evt, $typeReg);
//
//			$dateday = $evt;
//
//			// Set Deadline to Event Date (@todo: check if needed, after refactory)
//			$DL_dateday = self::getDeadlineDateTime($dateday, $deadlineInterval);
//
//			$date_is_upcoming = (strtotime($DL_dateday) > strtotime($date_time_today));
//
//			echo 'evt: ' . $evt;
//			echo 'date: ' . $date_is_upcoming;
//
//			// If registration until End Date
//			if ($regDeadline == 2) {
//				// Case Single Date from period (weekdays), else single date
//				$endDatetime    = (\in_array($dateday, $period))
//					? HTMLHelper::date($dateday, 'Y-m-d', $eventTimeZone) . ' ' . HTMLHelper::date($item->enddate, 'H:i:s', $eventTimeZone)
//					: HTMLHelper::date($dateday, 'Y-m-d', $eventTimeZone) . ' 23:59:59';
//			} else {
//				$startDatetime  = HTMLHelper::date($dateday, 'Y-m-d H:i', $eventTimeZone);
//			}

		} else {
			// No datetime var in URL (full period) (legacy) and date $evt not set (since 4.0)
//			$registered = isset($item->registered) ? $item->registered : self::getRegisteredTotal($item->id, null, $typeReg);
			$registered = self::getRegisteredTotal($item->id, null, $typeReg);

			$dateday = '';

			// Set Deadline to Period Start Date (@todo: check if needed, after refactory)
			$DL_startdate = self::getDeadlineDateTime($datetime_startdate, $deadlineInterval);

			if (\count($period) > 0
				&& $fullPeriod
				&& (strtotime($DL_startdate) < strtotime($date_time_today))
			) {
				$date_is_upcoming = false;
			} else {
				$date_is_upcoming = true;
			}

			// If registration until End Date
			if ($regDeadline == 2) {
				$endDatetime    = ($fullPeriod && in_array($datetime_startdate, $period))
					? HTMLHelper::date($item->enddate, 'Y-m-d H:i:s', $eventTimeZone)
					: HTMLHelper::date($date_today, 'Y-m-d', $eventTimeZone) . ' ' . HTMLHelper::date($item->enddate, 'H:i:s', $eventTimeZone);
			} else {
				$startDatetime = HTMLHelper::date($item->startdate, 'Y-m-d H:i', $eventTimeZone);
			}
		}

		if ($statutReg == 1) {
			$formDatesList  = self::formDatesList($item);
			$dates_bookable = $formDatesList ? $formDatesList : [];
			$this_event_url = Uri::getInstance()->toString();

			$cleanurl = preg_replace('/&date=[^&]*/', '', $this_event_url);
			$cleanurl = preg_replace('/\?date=[^\?]*/', '', $cleanurl);

			/* Set list of bookable dates */
			$iClistMenuItems = icagendaMenus::iClistMenuItemsInfo();
			
			$extraDates = [];

			foreach ($dates_bookable AS $d) {
				$ex_d     = explode('@@', $d);
				$date_url = iCDate::isDate($ex_d[0]) ? HTMLHelper::date($ex_d[0], 'Y-m-d-H-i', $eventTimeZone) : '';
				$date     = iCDate::isDate($ex_d[0]) ? HTMLHelper::date($ex_d[0], 'Y-m-d H:i', $eventTimeZone) : '';
				$Itemid   = icagendaMenus::thisEventItemid($date, $item->catid, $iClistMenuItems);

				$extraDates[icagendaEvent::url($item->id, $item->alias, $Itemid, ['date' => $date_url])] = $ex_d[1];
			}

			// Set Deadline to Registration Limit Date
			$deadlineDateStart = $deadlineDateEnd = '';

			if (isset($startDatetime)) {
				$DL_startDatetime   = $deadlineInterval ? self::getDeadlineDateTime($startDatetime, $deadlineInterval) : $startDatetime;
				$deadlineDateStart  = $deadlineInterval
					? icagendaRender::dateToFormat($DL_startDatetime) . ' ' . icagendaRender::dateToTime($DL_startDatetime)
					: '';
			}

			if (isset($endDatetime)) {
				$DL_endDatetime     = $deadlineInterval ? self::getDeadlineDateTime($endDatetime, $deadlineInterval) : $endDatetime;
				$deadlineDateEnd    = $deadlineInterval
					? icagendaRender::dateToFormat($DL_endDatetime) . ' ' . icagendaRender::dateToTime($DL_endDatetime)
					: '';
			}

			// Available date(s) (boolean) and ticket(s) available for this event (boolean)
			if ($availableDates
				&& $ticketsCouldBeBooked
			) {
				if (\in_array($accessReg, $userLevels)
					|| \in_array('8', $userGroups)
				) {
					$maxReg = $evtParams->get('maxReg', '1000000');

					if ($registered == $maxReg) {
						$status = ($typeReg != '2') ? 'select' : 'close';
					}

					elseif ($date_is_upcoming
						&& $regDeadline == 1
					) {
						$status = 'ok';

						$deadlineDate = $deadlineInterval ? $deadlineDateStart : '';

					} elseif ($regDeadline == 2
						&& (strtotime($DL_endDatetime) > strtotime($date_time_today) || $typeReg == 2)
					) {
						// Registration Until end date (if registration for all dates, allow to register to a past date)
						$status = 'ok';

						$deadlineDate = $deadlineInterval ? $deadlineDateEnd : '';

					} elseif ($regDeadline == 1
						&& strtotime($DL_startDatetime) < strtotime($date_time_today)
					) {
						$status = ($typeReg != '2' && $availableDates) ? 'select' : 'close';

					} else {
						$status = 'select';
					}

				} else {
					$status = 'private';
				}

			} elseif ($availableDates && ! $ticketsCouldBeBooked) {
				// Available date(s) (boolean) but no ticket left (boolean)
				if ( ! $date_is_upcoming && $typeReg == 2) {
					$status = 'close';
				} elseif ( ! $date_is_upcoming && $typeReg == 1) {
					$status = 'complete';
				} else {
					$status = 'select';
				}
			} elseif ( ! $availableDates) {
				$status = 'close';
			} else {
				return false;
			}

		} else {
			return false;
		}

		$regDate     = $evt ?: ($dateday ?: '');
		$thisDateUTC = $regDate ? date('Y-m-d H:i', strtotime($regDate)) : '';
		$periodDates = iCDatePeriod::listDates($item->startdate, $item->enddate); // UTC

		// Is it a full period and date is in the period array.
		if ($thisDateUTC && $fullPeriod && \in_array($thisDateUTC, $periodDates)) {
			$regDate = '';
		}

		$userRegStatus = !empty($user->id)
			? self::getUserRegistrationsStatus($user->email, $item->id, $regDate)
			: '';

		switch ($userRegStatus)
		{
			case 'registered':
				$status = 'booked';
				break;

			case 'registeredDate':
//				if (
//					($regDeadline == 1 && strtotime($DL_startDatetime) < strtotime($date_time_today))
//					||
//					($regDeadline == 2 && strtotime($DL_endDatetime) < strtotime($date_time_today))
//					)
//				{
//					$status = 'close';
//				}
//				else
//				{
					$status = 'select';
//				}
				break;

			case 'cancelled':
//				$status = 'ok'; // Don't change status after date cancelled, to let deadline works.
				break;
		}

//		if ($status == 'select' && $evt) {
//			$userRegStatus = '';
//		}

		$userBooked = !empty($user->id)
			? self::getUserRegistrationsBooked($user->email, $item->id, $regDate)
			: [];

		$input = Factory::getApplication()->input;

		$registerTarget = ($evtParams->get('RegButtonTarget', '0') == 1)
			? '_blank'
			: '_parent';

		if ($evt && !(\in_array(date('Y-m-d H:i', strtotime($evt)), $period) && $fullPeriod)) {
			if ($linkid) {
				$registerUrl = self::registrationLink($item, $evt, $linkid);
			} else {
				$registerUrl = self::registrationLink($item, $evt);
			}
//		} elseif ($evt) {
//			if ($linkid) {
//				$registerUrl = self::registrationLink($item, '*', $linkid);
//			} else {
//				$registerUrl = self::registrationLink($item, '*');
//			}
		} elseif ($event_date && !$evt) {
			if ($linkid) {
				$registerUrl = self::registrationLink($item, $event_date, $linkid);
			} else {
				$registerUrl = self::registrationLink($item, $event_date);
			}
		} else {
			if ($linkid) {
				$registerUrl = self::registrationLink($item, '*', $linkid);
			} else {
				$registerUrl = self::registrationLink($item, '*');
			}
		}

		// Data for layouts
		$displayData = [
			'basePath'       => JPATH_SITE . '/components/com_icagenda/themes/packs/' . $evtParams->get('template', 'default') . '/layouts',
			'cancelUrl'      => Route::_('index.php?option=com_icagenda&view=registration&layout=cancel&id=' . $input->getInt('id') . '&Itemid=' . $input->getInt('Itemid')),
			'customLink'     => $evtParams->get('RegButtonLink', ''),
			'extraDates'     => $extraDates,
			'registered'     => isset($registered) ? $registered : 0,
			'registerTarget' => $registerTarget,
			'registerUrl'    => $registerUrl,
			'status'         => ($date_is_upcoming || $user->id) ? $status : 'close',
			'textButton'     => $evtParams->get('RegButtonText', Text::_('COM_ICAGENDA_REGISTRATION_REGISTER')),
			'classButton'    => $evt ? 'btn btn-sm' : 'btn',
			'eventDetails'   => (bool) !$evt,
			'userBooked'     => $userBooked,
			'userRegStatus'  => $userRegStatus,
			'canCancel'      => $date_is_upcoming ? $evtParams->get('reg_cancellation', 0) : '',
			'deadlineDate'   => isset($deadlineDate) ? $deadlineDate : '',
		];

		$layout = new FileLayout('icagenda.registration.button.box');
		$layout->addIncludePaths(JPATH_SITE . '/components/com_icagenda/layouts');
		$layout->addIncludePaths(JPATH_SITE . '/components/com_icagenda/themes/packs/' . $evtParams->get('template', 'default') . '/layouts');

		$session->set('event_date', '');

		return $layout->render($displayData);
	}

	/**
	 * Function to return Registration Status for this event
	 *
	 * @todo               check and remove from utilities, as not needed in modules and list
	 * DEPRECATED 3.6.0 :  use now $item->params (global + event params merged)
	 */
//	static public function statutReg($item)
//	{
//		$params       = Factory::getApplication()->getParams();
//		$gstatutReg   = $params->get('statutReg', '');

//		$evtParams    = icagendaEvent::evtParams($item->params);
//		$evtstatutReg = $evtParams->get('statutReg', '');

		// Control and edit param values to iCagenda v3
//		if ($evtstatutReg == '2')
//		{
//			$evtstatutReg = '0';
//		}

//		$statutReg = ($evtstatutReg != '') ? $evtstatutReg : $gstatutReg;

//		return $statutReg;
//	}


	/* TO BE REVIEWED */

	/**
	 * Function to return Registration Access Level for this event
	 *
	 * @since   3.6.0 (Migrated from 3.5 - TO BE REVIEWED)
	 */
	static public function accessReg($item)
	{
		$reg_form_access = ComponentHelper::getParams('com_icagenda')->get('reg_form_access', 2);

		$accessReg = $item->params->get('accessReg', $reg_form_access);

		return $accessReg;
	}

	/**
	 * Function return true if upcoming dates for Booking
	 *
	 * @since   3.6.0 (Migrated from 3.5 - TO BE REVIEWED)
	 */
	public static function upcomingDatesBooking($item)
	{
		if (count(self::formDatesList($item)) > 0)
		{
			return true;
		}

		return false;
	}

	/**
	 * Ticket(s) could be booked
	 *
	 * @since   3.6.0 (Migrated from 3.5 - TO BE REVIEWED)
	 */
	static public function ticketsCouldBeBooked($i)
	{
		$eventTimeZone  = null;
		$date_today     = HTMLHelper::date('now', 'Y-m-d', false);
		$datetime_today = HTMLHelper::date('now', 'Y-m-d H:i', false);
		$allDates       = self::eventAllDates($i);
		$maxReg         = $i->params->get('maxReg', '1000000');
		$typeReg        = $i->params->get('typeReg', '1');
		$perioddates    = iCDatePeriod::listDates($i->startdate, $i->enddate, $eventTimeZone);
		$regDeadline    = $i->params->get('reg_deadline', 1);

		// Check the period if individual dates
		$fullPeriod = ($i->weekdays || $i->weekdays == '0') ? false : true;

		sort($allDates);

		// If registration for all dates, and not registration until end of event, no registration if past date(s)
		if ($typeReg ==  '2' && $regDeadline != 2) {
			foreach ($allDates as $k => $d) {
				if (strtotime(HTMLHelper::date($d, 'Y-m-d H:i', $eventTimeZone)) < strtotime($datetime_today)) {
					return false;
				}
			}
		}

		$total_tickets_bookable = 0;

		foreach ($allDates as $k => $d) {
			$date_control = HTMLHelper::date($d, 'Y-m-d H:i', $eventTimeZone);
			$is_in_period = in_array($date_control, $perioddates) ? true : false;

			if ($fullPeriod && $is_in_period) {
				$is_full_period = true;
			} else {
				$is_full_period = false;
			}

			$datetime_date      = date('Y-m-d H:i:s', strtotime($d));
			$datetime_startdate = date('Y-m-d H:i:s', strtotime($i->startdate));
			$datetime_enddate   = date('Y-m-d H:i:s', strtotime($i->enddate));

			// Nb of tickets left
//			$registered = isset($i->registered) ? $i->registered : self::getRegisteredTotal($i->id, $d, $typeReg);
			$registered = self::getRegisteredTotal($i->id, $d, $typeReg);
			$nb_tickets_left = $maxReg - $registered;

			// is Full period (& reg.type for all dates) & reg.limit until start date
			if ($is_full_period
				&& $typeReg == 2
				&& $regDeadline == 1
				&& (strtotime($datetime_startdate) < strtotime($date_today))
			) {
				$total_tickets_bookable = 0;
			}

			// is Full period & reg.limit until end dates
			elseif ($is_full_period
				&& $regDeadline == 2
				&& (strtotime($datetime_enddate) <= strtotime($datetime_today))
			) {
				$total_tickets_bookable = 0;
			}

			// timestamp datetime > timestamp today date & reg.limit until start date
			elseif ($regDeadline == 1
				&& strtotime($d) > strtotime($date_today)
			) {
				if ($nb_tickets_left > 0) {
					$total_tickets_bookable = $total_tickets_bookable + $nb_tickets_left;
				}
			}

			// is in period & timestamp datetime > timestamp today date & reg.limit until end date
			elseif ($regDeadline == 2
				&& $is_in_period
				&& strtotime(date('Y-m-d', strtotime($d)) . ' ' . date('H:i', strtotime($datetime_enddate))) > strtotime($datetime_today)
			) {
				if ($nb_tickets_left > 0) {
					$total_tickets_bookable = $total_tickets_bookable + $nb_tickets_left;
				}
			}

			// is single date & timestamp date > timestamp today date & reg.limit until end date
			elseif ($regDeadline == 2
				&& ! $is_in_period
//				&& strtotime(date('Y-m-d', strtotime($d))) > strtotime($date_today)
				&& strtotime(date('Y-m-d', strtotime($d))) >= strtotime($date_today)
			) {
				if ($nb_tickets_left > 0) {
					$total_tickets_bookable = $total_tickets_bookable + $nb_tickets_left;
				}
			}
		}

		if ($total_tickets_bookable > 0) {
			return true;
		}

		return false;
	}

	/**
	 * Function to list all dates of an event
	 *
	 * @since   3.6.0 (Migrated from 3.5 - TO BE REVIEWED)
	 *          version 3.6.6
	 */
	static public function eventAllDates($i)
	{
		// Declare eventAllDates array
		$eventAllDates = array();
		$eventTimeZone = null;

		// Get WeekDays Array
		$WeeksDays = iCDatePeriod::weekdaysToArray($i->weekdays);

		// If Single Dates, added each one to All Dates for this event
		$singledates = iCString::isSerialized($i->dates) ? unserialize($i->dates) : array();

		foreach ($singledates as $sd)
		{
			$isValid = iCDate::isDate($sd);

			if ( $isValid )
			{
				array_push($eventAllDates, HTMLHelper::date($sd, 'Y-m-d H:i:s', $eventTimeZone));
			}
		}

		$perioddates = iCDatePeriod::listDates($i->startdate, $i->enddate);

		if ( (isset ($perioddates))
			&& ($perioddates != NULL) )
		{
			foreach ($perioddates as $Dat)
			{
//				if (in_array(date('w', strtotime($Dat)), $WeeksDays))
				if (in_array(HTMLHelper::date($Dat, 'w', $eventTimeZone), $WeeksDays))
				{
					$isValid = iCDate::isDate($Dat);

					if ($isValid)
					{
//						$SingleDate = date('Y-m-d H:i:s', strtotime($Dat));
						$SingleDate = HTMLHelper::date($Dat, 'Y-m-d H:i:s', $eventTimeZone);

						array_push($eventAllDates, $SingleDate);
					}
				}
			}
		}

		return $eventAllDates;
	}

	/**
	 * Function to get number of tickets booked (for one date of the event)
	 *
	 * @since   3.6.0 (Migrated from 3.5 - TO BE REVIEWED)
	 */
	public static function nbTicketsBooked($event_id, $date = null, $typeReg = 1, $is_full_period = false)
	{
		// Registrations total
		$db    = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
		$query = $db->createQuery();
		$query->select('sum(r.people) AS count');
		$query->from('#__icagenda_registration AS r');
		$query->where('r.status = 1');
		$query->where('r.state = 1');

		$query->where('r.eventid = ' . $db->q($event_id));

		// Get nb of tickets booked for the date only if registration per date
		if ($typeReg != 2)
		{
			// Single date
			if ($date && ! $is_full_period)
			{
				$query->where('r.date = ' . $db->q($date));
			}

			// Full Period (DEPRECATED 3.7)
			else
			{
				$query->where('r.date = "" AND r.period = 0');
			}
		}

		$db->setQuery($query);

		$result = $db->loadResult();

		return $result;
	}

	/**
	 * Function to get link to registration page
	 *
	 * @param   $item    Event object.
	 * @param   $date    Date of the event.
	 * @param   $Itemid  Menu Itemid to be used to display the registration form.
	 *
	 * @return  string   URL to the registration form.
	 *
	 * @since   4.0.0
	 */
	public static function registrationLink($item, $date = '', $Itemid = 0)
	{
		$app         = Factory::getApplication();
		$lang        = Factory::getLanguage();
		$menu        = $app->getMenu();
		$isSef       = $app->getCfg('sef');
		$params      = $app->getParams();
		$Itemid      = $Itemid ?: $app->input->get('Itemid');
		$date        = $date ?: $app->input->get('date', '*');
		$this_itemid = $params->get('itemid', $Itemid);

		$event_slug  = empty($item->alias)
			? $item->id
			: $item->id . ':' . $item->alias;

		$itemid_slug = ((int) $Itemid === $menu->getDefault($lang->getTag())->id)
			? ''
			: '&Itemid=' . (int) $this_itemid;

		$dateAlias = ($date != '*')
			? iCDate::dateToAlias($date, 'Y-m-d-H-i')
			: ($isSef ? '' : 'period');

		$date_slug = '&date=' . $dateAlias;

		$defaultForm = Route::_('index.php?option=com_icagenda&view=registration&id=' . $event_slug . $itemid_slug . $date_slug);

		$regLink        = $item->params->get('RegButtonLink', '');
		$regLinkArticle = $item->params->get('RegButtonLink_Article', $defaultForm);
		$regLinkUrl     = $item->params->get('RegButtonLink_Url', $defaultForm);

		if ($regLink == 1 && is_numeric($regLinkArticle)) {
			$registrationLink = Route::_('index.php?option=com_content&view=article&id=' . $regLinkArticle);
		} elseif ($regLink == 2) {
			$registrationLink = iCUrl::urlParsed($regLinkUrl);
		} else {
			$registrationLink = $defaultForm;
		}

		return $registrationLink;
	}

	/**
	 * Function to get link to registration page
	 *
	 * @since   3.6.0 (Migrated from 3.5 - DEPRECATED; To be removed)
	 */
	public static function regUrl($i)
	{
		$app         = Factory::getApplication();
		$lang        = Factory::getLanguage();
		$menu        = $app->getMenu();
		$isSef       = $app->getCfg('sef');
		$params      = $app->getParams();
		$Itemid      = $app->input->get('Itemid');
		$date        = $app->input->get('date', '');
		$this_itemid = $params->get('itemid', $Itemid);

		$event_slug  = empty($i->alias) ? $i->id : $i->id . ':' . $i->alias;
		$itemid_slug = ((int) $Itemid === $menu->getDefault($lang->getTag())->id) ? '' : '&Itemid=' . (int) $this_itemid;
//		$date_var    = ($isSef == '1') ? '?date=' : '&amp;date=';
//		$date_slug   = $date ? $date_var . $date : '';

		$icagenda_form = Route::_('index.php?option=com_icagenda&view=registration&id=' . $event_slug . $itemid_slug);

		$regLink         = $i->params->get('RegButtonLink', '');
		$regLinkArticle  = $i->params->get('RegButtonLink_Article', $icagenda_form);
		$regLinkUrl      = $i->params->get('RegButtonLink_Url', $icagenda_form);
//		$RegButtonTarget = $i->params->get('RegButtonTarget', '0');

//		if ($RegButtonTarget == 1)
//		{
//			$browserTarget = '_blank';
//		}
//		else
//		{
//			$browserTarget = '_parent';
//		}

		if ($regLink == 1 && is_numeric($regLinkArticle))
		{
//			$regUrl = Route::_('index.php?option=com_content&view=article&id=' . $regLinkArticle) . '" rel="nofollow" target="' . $browserTarget;
			$regUrl = Route::_('index.php?option=com_content&view=article&id=' . $regLinkArticle);
		}
		elseif ($regLink == 2)
		{
//			$regUrl = iCUrl::urlParsed($regLinkUrl) . '" rel="nofollow" target="' . $browserTarget;
			$regUrl = iCUrl::urlParsed($regLinkUrl);
		}
		else
		{
//			$regUrl = $icagenda_form . '" rel="nofollow" target="' . $browserTarget;
			$regUrl = $icagenda_form;
		}

		return $regUrl;
	}

	/**
	 * Function to check a valid email address
	 *
	 * @since   3.6.0 (Migrated from 3.5 - TO BE REVIEWED)
	 */
	static public function validEmail($email)
	{
		$isValid = true;
		$atIndex = strrpos($email, "@");

		if (is_bool($atIndex) && !$atIndex)
		{
			$isValid = false;
		}
		else
		{
			$domain    = substr($email, $atIndex+1);
			$local     = substr($email, 0, $atIndex);
			$localLen  = strlen($local);
			$domainLen = strlen($domain);

			if ($localLen < 1 || $localLen > 64)
			{
				// local part length exceeded
				$isValid = false;
			}
			elseif ($domainLen < 1 || $domainLen > 255)
			{
				// domain part length exceeded
				$isValid = false;
			}
			elseif ($local[0] == '.' || $local[$localLen-1] == '.')
			{
				// local part starts or ends with '.'
				$isValid = false;
			}
			elseif (preg_match('/\\.\\./', $local))
			{
				// local part has two consecutive dots
				$isValid = false;
			}
			elseif (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain))
			{
				// character not valid in domain part
				$isValid = false;
			}
			elseif (preg_match('/\\.\\./', $domain))
			{
				// domain part has two consecutive dots
				$isValid = false;
			}
			elseif (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\","",$local)))
			{
				// character not valid in local part unless
				// local part is quoted
				if (!preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\","",$local)))
				{
					$isValid = false;
				}
			}

			// Check the domain name
			if ($isValid
				&& ! self::is_valid_domain_name($domain))
			{
				return false;
			}
		}

		return $isValid;
	}

	/**
	 * Function to check if a domain is valid
	 *
	 * @since   3.6.0 (Migrated from 3.5 - TO BE REVIEWED)
	 */
	static public function is_valid_domain_name($domain_name)
	{
		$pieces = explode(".", $domain_name);

		foreach ($pieces as $piece)
		{
			if (!preg_match('/^[a-z\d][a-z\d-]{0,62}$/i', $piece)
				|| preg_match('/-$/', $piece))
			{
				return false;
			}
		}

		return true;
	}
}
