<?php
namespace App\Controller;
use App\Entity\TennisBookings;
use App\Entity\TennisCoachCalendar;
use App\Entity\TennisCourtAvailability;
use App\Entity\User;
use App\Entity\Weather;
use App\Form\SearchOnPeriodType;
use App\Form\TennisBookingsType;
use App\Form\TennisCourtAvailabilityType;
use App\Form\UserType;
use App\Repository\ClientCourtTimesRepository;
use App\Repository\CmsRepository;
use App\Repository\CourtSurfaceRepository;
use App\Repository\DefaultTennisPlayerAvailabilityHoursRepository;
use App\Repository\PaymentsRepository;
use App\Repository\SettingsRepository;
use App\Repository\TennisBookingsRepository;
use App\Repository\TennisCourtAvailabilityRepository;
use App\Repository\TennisVenuesDistancesRepository;
use App\Repository\TennisVenuesRepository;
use App\Repository\UserRepository;
use App\Repository\WeatherRepository;
use App\Services\ActiveAceifyClient;
use App\Services\CourtLeadTime;
use App\Services\CourtSurfaceAndFloodlights;
use App\Services\CourtUsageStatistics;
use App\Services\FindUnreleasedCourtsByVenueByDate;
use App\Services\GoogleApiDistanceCount;
use App\Services\LatestScrapeTime;
use App\Services\ScrapeService;
use App\Services\TowerHamletBookingEngine;
use App\Services\UnreleasedCourtsByVenueByDate;
use App\Services\Venues;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Security;
/**
* @Route("/tenniscourt/availability")
*/
class TennisCourtAvailabilityController extends AbstractController
{
/**
* @Route("/index/{sort}", name="tennis_court_availability_index", methods={"GET"},defaults={"sort"=null})
*/
public function index(Request $request, ActiveAceifyClient $activeAceifyClient, UnreleasedCourtsByVenueByDate $unreleasedCourtsByVenueByDate,
TennisVenuesDistancesRepository $tennisVenuesDistancesRepository, $sort,
TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository, TennisVenuesRepository $tennisVenuesRepository,
CourtSurfaceAndFloodlights $courtSurfaceAndFloodlights,
Security $security, GoogleApiDistanceCount $googleApiDistanceCount, ClientCourtTimesRepository $clientCourtTimesRepository): Response
{
$client_court_times = $clientCourtTimesRepository->findAll();
$logged_user = $security->getUser();
$week = 'week1';
if ($request->query->get('week')) {
$week = $request->query->get('week');
}
$message = '';
if ($request->query->get('message')) {
$message = $request->query->get('message');
}
$hours = [];
for ($i = 7; $i <= 23; $i++) {
$hours[$i]['hour'] = $i . ':00';
$hours[$i]['sort'] = $i;
}
$minDate = $request->query->get('minDate');
$maxDate = $request->query->get('maxDate');
$today = new \DateTime('now');
$todayHour = $today->format('H') + 3 - 1;
$tomorrow = new \DateTime('tomorrow');
$weekday = $today->format('N') - 1;
$lastMonday = new \DateTime($today->format('Y-m-d'));
$lastMonday->modify('-' . $weekday . ' days');
$nextSunday = new \DateTime($lastMonday->format('Y-m-d'));
$nextSunday->modify('+6 days');
$daysRemainingThisWeek = 7 - $weekday;
$dateRange = '';
$monday2 = new \DateTime($lastMonday->format('Y-m-d'));
$monday3 = new \DateTime($lastMonday->format('Y-m-d'));
$sunday2 = new \DateTime($nextSunday->format('Y-m-d'));
$sunday3 = new \DateTime($nextSunday->format('Y-m-d'));
$monday2->modify('+7 days');
$monday3->modify('+14 days');
$sunday2->modify('+7 days');
$sunday3->modify('+14 days');
if ($minDate && $maxDate) {
if (date_diff(new \DateTime($minDate), new \DateTime($maxDate))->days <= 1) {
if ($minDate == $today->format('Y-m-d')) {
$dateRange = 'Today';
} else {
$dateRange = 'Tomorrow';
}
$dates = [];
for ($i = 0; $i < 1; $i++) {
$next_date = new \DateTime($minDate);
$next_date->modify($i . 'days');
$dates[$i] = $next_date;
}
} else {
if ($minDate == $today->format('Y-m-d')) {
$dates = [];
$dates[0] = new \DateTime($minDate);
$dateRange = "This Week";
for ($i = 1; $i < $daysRemainingThisWeek; $i++) {
$next_date = new \DateTime($minDate);
$next_date->modify($i . 'days');
$dates[$i] = $next_date;
}
} else {
if ($monday2->format('Y-m-d') == $minDate) {
$dateRange = 'Next Week';
} elseif ($monday3->format('Y-m-d') == $minDate) {
$dateRange = 'Following Week';
}
$dates = [];
$dates[0] = new \DateTime($minDate);
for ($i = 1; $i <= 6; $i++) {
$next_date = new \DateTime($minDate);
$next_date->modify($i . 'days');
$dates[$i] = $next_date;
}
}
}
} else {
$dates = [];
for ($i = 0; $i < 1; $i++) {
$next_date = new \DateTime($today->format('Y-m-d'));
$next_date->modify($i . 'days');
$dates[$i] = $next_date;
}
}
$tennis_venues = $tennisVenuesRepository->findBy([
'isActive' => true
]);
if ($sort == 'Home') {
$tennis_venues = [];
$venuesbyUserdistance = $tennisVenuesDistancesRepository->getSortedVenueByUserAndDistanceHome($activeAceifyClient->findClient($logged_user));
foreach ($venuesbyUserdistance as $venue) {
$tennis_venues[] = $venue->getVenue();
}
}
if ($sort == 'Work') {
$tennis_venues = [];
$venuesbyUserdistance = $tennisVenuesDistancesRepository->getSortedVenueByUserAndDistanceWork($activeAceifyClient->findClient($logged_user));
foreach ($venuesbyUserdistance as $venue) {
$tennis_venues[] = $venue->getVenue();
}
}
return $this->render('tennis_court_availability/index.html.twig', [
'tennis_venues' => $tennis_venues,
'sample_venue' => $tennisVenuesRepository->findOneBy([
'venue' => 'Bethnal Green Gardens'
]),
'tennis_court_availabilities' => $tennisCourtAvailabilityRepository->findAll(),
'client_court_times' => $client_court_times,
'dates' => $dates,
'hours' => $hours,
'today' => $today,
'minDate' => $request->query->get('minDate'),
'maxDate' => $request->query->get('maxDate'),
'lastMonday' => $lastMonday,
'nextSunday' => $nextSunday,
'monday2' => $monday2,
'monday3' => $monday3,
'sunday2' => $sunday2,
'sunday3' => $sunday3,
'week' => $week,
'now' => $today,
'show_icon' => 'Yes',
'tomorrow' => $tomorrow,
'todayHour' => $todayHour,
'dateRange' => $dateRange
]);
}
/**
* @Route("/tennis_court_availability_daily_detail/index/{venue}/{date}", name="tennis_court_availability_daily_detail", methods={"GET"} )
*/
public function indexDailyDetail(int $venue, string $date, ActiveAceifyClient $activeAceifyClient, UnreleasedCourtsByVenueByDate $unreleasedCourtsByVenueByDate, Request $request, TennisVenuesDistancesRepository $tennisVenuesDistancesRepository, TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository, TennisVenuesRepository $tennisVenuesRepository, Security $security, GoogleApiDistanceCount $googleApiDistanceCount, ClientCourtTimesRepository $clientCourtTimesRepository): Response
{
$tennis_venue = $tennisVenuesRepository->find($venue);
$number_of_courts = $tennis_venue->getNumberOfCourts();
$client_court_times = $clientCourtTimesRepository->findAll();
$hours = [];
for ($i = 7; $i <= 23; $i++) {
$hours[$i]['hour'] = $i . ':00';
$hours[$i]['sort'] = $i;
}
$today = new \DateTime('now');
$todayHour = (int)($today->format('H')) + 2;
$date = new \DateTime($date);
return $this->render('tennis_court_availability/indexSingleVenue.html.twig', [
'tennis_venue' => $tennis_venue,
'number_of_courts' => $number_of_courts,
'tennis_court_availabilities' => $tennisCourtAvailabilityRepository->findBy([
'venue' => $venue,
'date' => $date,
]),
'client_court_times' => $client_court_times,
'hours' => $hours,
'today' => $today,
'now' => $today,
'show_icon' => 'Yes',
'date' => $date,
'todayHour' => $todayHour
]);
}
/**
* @Route("/usage/statistics", name="tennis_court_availability_usage_statistics", methods={"GET"},defaults={"sort"=null})
*/
public function usageStatistics(Request $request, CourtUsageStatistics $courtUsageStatistics, TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository, TennisVenuesRepository $tennisVenuesRepository): Response
{
$filterStart = null;
$filterEnd = null;
if (!empty($request->query->get('search_on_period')['startAt']) &&
!empty($request->query->get('search_on_period')['endAt'])
) {
$filterStart = new \DateTime($request->query->get('search_on_period')['startAt']);
$filterEnd = new \DateTime($request->query->get('search_on_period')['endAt']);
}
$form = $this->createForm(SearchOnPeriodType::class);
$form->handleRequest($request);
$now = new \DateTime();
$dateStartAt = '2023-01-01';
$dateEndtAt = $now->format('Y') . '-01-01';
$startAt = new \DateTime($dateStartAt);
$endAt = new \DateTime($dateEndtAt);
$endAt->modify('+1 year');
$interval = new \DateInterval('P1Y');
$annualDatePeriod = new \DatePeriod($startAt, $interval, $endAt);
$lastYear = new \DateTime('now');
$lastYear->modify('- 1 year');
$interval = new \DateInterval('P1M');
$monthlyDatePeriod = new \DatePeriod(new \DateTime('2023-01-01'), $interval, new \DateTime('2023-12-31'));
$days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
$hours = [];
for ($i = 7; $i <= 23; $i++) {
$hours[$i]['hour'] = $i;
$hours[$i]['sort'] = $i;
}
$tennis_venues = $tennisVenuesRepository->findBy([
'isActive' => true
]);
return $this->render('tennis_court_availability/usage_statistics_index.html.twig', [
'annual_date_period' => $annualDatePeriod,
'monthly_date_period' => $monthlyDatePeriod,
'tennis_venues' => $tennis_venues,
'tennis_court_availabilities' => $tennisCourtAvailabilityRepository->findAll(),
'days' => $days,
'hours' => $hours,
'form' => $form->createView(),
'filterStart' => $filterStart,
'filterEnd' => $filterEnd
]);
}
/**
* @Route("/leadtime/statistics", name="tennis_court_availability_leadtime_statistics", methods={"GET"},defaults={"sort"=null})
*/
public function leadTimeStatistics(Request $request, CourtLeadTime $courtLeadTime, CourtUsageStatistics $courtUsageStatistics, TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository, TennisVenuesRepository $tennisVenuesRepository): Response
{
$filterStart = null;
$filterEnd = null;
if (!empty($request->query->get('search_on_period')['startAt']) &&
!empty($request->query->get('search_on_period')['endAt'])
) {
$filterStart = new \DateTime($request->query->get('search_on_period')['startAt']);
$filterEnd = new \DateTime($request->query->get('search_on_period')['endAt']);
}
$form = $this->createForm(SearchOnPeriodType::class);
$form->handleRequest($request);
$now = new \DateTime();
$dateStartAt = '2023-01-01';
$dateEndtAt = $now->format('Y') . '-01-01';
$startAt = new \DateTime($dateStartAt);
$endAt = new \DateTime($dateEndtAt);
$endAt->modify('+1 year');
$interval = new \DateInterval('P1Y');
$annualDatePeriod = new \DatePeriod($startAt, $interval, $endAt);
$lastYear = new \DateTime('now');
$lastYear->modify('- 1 year');
$interval = new \DateInterval('P1M');
$monthlyDatePeriod = new \DatePeriod(new \DateTime('2023-01-01'), $interval, new \DateTime('2023-12-31'));
$days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
$hours = [];
for ($i = 7; $i <= 23; $i++) {
$hours[$i]['hour'] = $i;
$hours[$i]['sort'] = $i;
}
$tennis_venues = $tennisVenuesRepository->findBy([
'isActive' => true
]);
return $this->render('tennis_court_availability/leadtime_statistics_index.html.twig', [
'annual_date_period' => $annualDatePeriod,
'monthly_date_period' => $monthlyDatePeriod,
'tennis_venues' => $tennis_venues,
'tennis_court_availabilities' => $tennisCourtAvailabilityRepository->findAll(),
'days' => $days,
'hours' => $hours,
'form' => $form->createView(),
'filterStart' => $filterStart,
'filterEnd' => $filterEnd
]);
}
/**
* @Route("/leadtimes/calculate/leadtimes", name="tennis_court_availability_calculate_leadtime_statistics", methods={"GET"},defaults={"sort"=null})
*/
public function calculateLeadTimeStatistics(CourtLeadTime $courtLeadTime): Response
{
$courtLeadTime->returnCourtLeadTime();
return $this->redirectToRoute('tennis_court_availability_leadtime_statistics');
}
/**
* @Route("/leadtimes/delete/leadtimes", name="tennis_court_availability_delete_leadtime_statistics", methods={"GET"},defaults={"sort"=null})
*/
public function deleteLeadTimeStatistics(TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository, EntityManagerInterface $manager): Response
{
$courts = $tennisCourtAvailabilityRepository->findAll();
foreach ($courts as $court) {
$court->setLeadTime(null);
$court->setSnapUpTime(null);
}
$manager->flush();
return $this->redirectToRoute('tennis_court_availability_leadtime_statistics');
}
/**
* @Route("/add/future/slots", name="tennis_court_availability_add_future_slots", methods={"GET","POST"})
*/
public function addFutureSlots(Request $request, SettingsRepository $settingsRepository, TennisVenuesRepository $tennisVenuesRepository, TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository): Response
{
$venues = $tennisVenuesRepository->findBy([
'isActive' => true
]);
$futureCourtAvailabilityDaysCount = $settingsRepository->find('1')->getFutureCourtAvailabilityDaysCount();
foreach ($venues as $venue) {
$number_of_courts_at_venue = $venue->getNumberOfCourts();
$startDate = new \DateTime('now');
for ($dateCounter = 1; $dateCounter <= $futureCourtAvailabilityDaysCount; $dateCounter++) {
if ($dateCounter == 1) {
$date = clone $startDate;
} else {
$startDate = $startDate->modify("+1 day");
$date = clone $startDate;
}
for ($courtNumber = 1; $courtNumber <= $number_of_courts_at_venue; $courtNumber++) {
for ($i = 7; $i <= 23; $i++) {
$previousRecord = $tennisCourtAvailabilityRepository->findBy([
'date' => $date,
'hour' => $i,
'venue' => $venue,
'courtNumber' => $courtNumber
]);
if (!$previousRecord) {
$tennisCourtAvailability = new TennisCourtAvailability();
$tennisCourtAvailability->setScrapedAt(null)
->setAvailable(0)
->setDate($date)
->setHour($i)
->setVenue($venue)
->setCourtNumber($courtNumber);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($tennisCourtAvailability);
$entityManager->flush();
}
}
}
}
}
return $this->redirectToRoute('tennis_court_availability_index');
}
/**
* @Route("/add/past/slots", name="tennis_court_availability_populate_history", methods={"GET","POST"})
*/
public function addPastSlots(Request $request, TennisVenuesRepository $tennisVenuesRepository, TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository): Response
{
$venues = $tennisVenuesRepository->findBy([
'isActive' => true
]);
foreach ($venues as $venue) {
$today = new \DateTime('now');
$today2 = new \DateTime('now');
$startDate = $today->modify('-30 days');
$scrapeStartDate = $today2->modify('-35 days');
for ($dateCounter = 1; $dateCounter <= 40; $dateCounter++) {
$date = $startDate->modify(+1 . ' days');
$scraped_date = $scrapeStartDate->modify(+1 . ' days');
for ($i = 7; $i <= 22; $i++) {
for ($j = 1; $j < 5; $j++) {
$previousRecord = $tennisCourtAvailabilityRepository->findBy([
'date' => $date,
'hour' => $i,
'venue' => $venue,
'courtNumber' => $j
]);
if (!$previousRecord) {
$available = rand(0, 3);
$cost = null;
if ($available == 1) {
$cost = rand(4, 12);
}
$tennisCourtAvailability = new TennisCourtAvailability();
$tennisCourtAvailability->setScrapedAt(null)
->setAvailable($available)
->setCourtCost($cost)
->setDate($date)
->setHour($i)
->setVenue($venue)
->setCourtNumber($j)
->setScrapedAt($scraped_date);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($tennisCourtAvailability);
$entityManager->flush();
}
}
}
}
}
return $this->redirectToRoute('tennis_court_availability_index');
}
/**
* @Route("/delete/all", name="tennis_court_availability_delete_all", methods={"GET"})
*/
public
function deleteAll(TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository): Response
{
$allEntries = $tennisCourtAvailabilityRepository->findAll();
foreach ($allEntries as $allEntry) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($allEntry);
$entityManager->flush();
}
return $this->redirectToRoute('tennis_court_availability_index');
}
/**
* @Route("/scrape/{venue}/{date}", name="tennis_court_availability_scrape", methods={"GET"})
*/
public
function scrapeCourtAvailability(Request $request, $venue, string $date, TennisVenuesRepository $tennisVenuesRepository, TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository, ScrapeService $scrapeService): Response
{
$referer = $request->headers->get('referer');
if ($venue == 'All') {
if ($date == 'All') {
$scrapeService->CreateCourtAvailability();
} else {
$scrapeService->CreateCourtAvailability(null, $date);
}
} else {
if ($date == 'All') {
$scrapeService->CreateCourtAvailability($venue, null);
} else {
$scrapeService->CreateCourtAvailability($venue, $date);
}
}
return $this->redirect($referer);
}
/**
* @Route("/{id}", name="tennis_court_availability_show", methods={"GET"})
*/
public
function show(TennisCourtAvailability $tennisCourtAvailability): Response
{
return $this->render('tennis_court_availability/show.html.twig', [
'tennis_court_availability' => $tennisCourtAvailability,
]);
}
/**
* @Route("/{id}/edit", name="tennis_court_availability_edit", methods={"GET","POST"})
*/
public
function edit(Request $request, TennisCourtAvailability $tennisCourtAvailability): Response
{
$form = $this->createForm(TennisCourtAvailabilityType::class, $tennisCourtAvailability);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('tennis_court_availability_index');
}
return $this->render('tennis_court_availability/edit.html.twig', [
'tennis_court_availability' => $tennisCourtAvailability,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}", name="tennis_court_availability_delete", methods={"POST"})
*/
public
function delete(Request $request, TennisCourtAvailability $tennisCourtAvailability): Response
{
if ($this->isCsrfTokenValid('delete' . $tennisCourtAvailability->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($tennisCourtAvailability);
$entityManager->flush();
}
return $this->redirectToRoute('tennis_court_availability_index');
}
/**
* @Route("/courtcalendarstatusrainedoff/{date}/{hour}/{action}", name="tennis_court_calendar_set_status_rained_off", methods={"GET","POST"})
*/
public
function courtstatusRainedOff(string $date, int $hour, Request $request, string $action, TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository, EntityManagerInterface $manager): Response
{
$referer = $request->headers->get('Referer');
$sessions = $tennisCourtAvailabilityRepository->findBy([
'date' => new \DateTime($date),
'hour' => $hour
]);
foreach ($sessions as $session) {
if ($session->getPlayer()) {
$session->setStatus($action);
}
}
$manager->flush();
return $this->redirect($referer);
}
/**
* @Route("/email/reminders", name="court_bookings_email_reminders", methods={"GET","POST"})
*/
public
function emailReminders(CmsRepository $cmsRepository, TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository, MailerInterface $mailer)
{
$tomorrow = new \DateTime('tomorrow');
$bookings = $tennisCourtAvailabilityRepository->findBy([
'date' => $tomorrow
]);
foreach ($bookings as $booking) {
if ($booking->getPlayer()) {
$Sendto = $booking->getPlayer()->getUser()->getEmail();
$date = $booking->getDate();
$hour = $booking->getHour();
$courtNumber = $booking->getCourtNumber();
$html = $this->renderView('court_booked_confirmed_email.html.twig', [
'booking' => $booking
]);
$email = (new Email())
->from($cmsRepository->find('1')->getCompanyEmail())
->to('sjwn71@gmail.com')
->subject("Court booked. Date: " . $date->format('D d-M-y') . " at " . $hour . ":00h. Court: " . $courtNumber)
->html($html);
$mailer->send($email);
}
}
return $this->redirectToRoute('tennis_court_availability_index');
}
/**
* @Route("/delete/delete_all", name="court_times_delete_all", methods={"GET"})
*/
public
function deleteAllCourtTime(TennisCourtAvailabilityRepository $tennisCourtAvailabilityRepository, EntityManagerInterface $entityManager): Response
{
$allCourtTimes = $tennisCourtAvailabilityRepository->findAll();
foreach ($allCourtTimes as $allCourtTime) {
$entityManager->remove($allCourtTime);
$entityManager->flush();
}
return $this->redirectToRoute('tennis_court_availability_index');
}
}