<?php

namespace Ig\IgReservations\Domain\Model;

use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use DateTime;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;
use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult;
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use Ig\IgReservations\Domain\Repository\ReservationRepository;
use Ig\IgReservations\Domain\Repository\StatusRepository;
use Ig\IgReservations\Utility\EventUtility;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Attribute\ORM\Cascade as ORMCascade;
use TYPO3\CMS\Extbase\Attribute\ORM\Lazy as ORMLazy;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;

/**
 * Event
 */
class Event extends AbstractEntity
{
    /**
     * language
     *
     * @var int
     */
    protected $language = 0;

    /**
     * createDate
     *
     * @var DateTime
     */
    protected $createDate = null;

    /**
     * isPublic
     * @var boolean
     */
    protected $isPublic = false;

    /**
     * startDate
     *
     * @var DateTime
     */
    protected $startDate = null;

    /**
     * startTime
     *
     * @var string
     */
    protected $startTime = null;

    /**
     * endDate
     *
     * @var DateTime
     */
    protected $endDate = null;

    /**
     * endTime
     *
     * @var string
     */
    protected $endTime = null;

    /**
     * timeslot
     *
     * @var Timeslot
     */
    protected $timeslot = null;

    /**
     * bookingType
     *
     * @var BookingType
     */
    #[ORMLazy]
    protected $bookingType = null;

    /**
     * name
     *
     * @var string
     */
    protected $name = '';

    /**
     * description
     *
     * @var string
     */
    protected $description = '';

    /**
     * notes
     *
     * @var string
     */
    protected $notes = '';

    /**
     * purpose
     *
     * @var string
     */
    protected $purpose = '';

    /**
     * numParticipants
     *
     * @var int
     */
    protected $numParticipants = 0;

    /**
     * category
     *
     * @var Category
     */
    #[ORMLazy]
    protected $category = null;

    /**
     * address
     *
     * @var Address
     */
    #[ORMLazy]
    protected $address = null;

    /**
     * status
     *
     * @var Status
     */
    protected $status = null;

    /**
     * calendar
     *
     * @var Calendar
     */
    protected $calendar = null;

    /**
     * owner
     *
     * @var FeUser
     */
    protected $owner = null;

    /**
     * additionalMember
     *
     * @var FeUser
     */
    protected $additionalMember = null;

    /**
     * teammembers (FrontendUsers)
     *
     * @var ObjectStorage<FeUser>
     */
    #[ORMLazy]
    protected $teammembers = null;

    /**
     * confirmationSent
     *
     * @var boolean
     */
    protected $confirmationSent = false;


    /**
     * virtual not stored in database
     *
     * @var string
     */
    protected $captcha;

    /**
     * @var array|null
     */
    protected $userReservation = null;

    /**
     * @var array|null
     */
    protected $freePlaces = null;

    /**
     * locationDescription
     *
     * @var string
     */
    protected $locationDescription = '';

    /**
     * calendarGroup
     *
     * @var CalendarGroup
     */
    #[ORMLazy]
    protected $calendarGroup = null;

    /**
     * eventGroup
     *
     * @var EventGroup
     */
    #[ORMLazy]
    protected $eventGroup = null;

    /**
     * mainEvent
     *
     * @var boolean
     */
    protected $mainEvent = true;

    /**
     * location
     *
     * @var Location
     */
    #[ORMLazy]
    protected $location = null;

    /**
     * reservationTypes (FrontendUsers)
     *
     * @var ObjectStorage<ReservationType>
     */
    #[ORMLazy]
    protected $reservationTypes = null;

    /**
     * files
     *
     * @var ObjectStorage<FileReference>
     */
    #[ORMCascade(['value' => 'remove'])]
    #[ORMLazy]
    protected $files = null;

    
    protected ?string $linkHash = null;

    /**
     * __construct
     */
    public function __construct()
    {
        $this->reservationTypes = new ObjectStorage();
        $this->teammembers = new ObjectStorage();
        $this->files = new ObjectStorage();
        //Do not remove the next line: It would break the functionality
    }
    public function reset(): void
    {
        //$this->reservations = null;
        $this->userReservation = null;
        $this->linkHash = null;
    }

    /**
     * Returns the startDate
     *
     * @return DateTime
     */
    public function getStartDate()
    {
        return $this->startDate;
    }
    /**
     * Sets the startDate
     */
    public function setStartDate(DateTime $startDate): void
    {
        $this->startDate = $startDate;
    }
    public function getDate()
    {
        return $this->startDate;
    }

    /**
     * Returns the startTime
     *
     * @return string
     */
    public function getStartTime()
    {
        return $this->startTime;
    }
    public function getStartTimeFormat()
    {
        return substr($this->startTime, 0, 5);
    }
    public function getStartTimeWithBufferFormat()
    {
        return $this->getStartDateTimeWithBuffer()->format('H:i');
    }

    public function getStartDateTime()
    {
        if (!$this->getStartDate()) {
            return null;
        }
        return new DateTime($this->getStartDate()->format('Y-m-d') . 'T' . $this->getStartTime());
    }

    public function getStartDateTimeWithBuffer()
    {
        return EventUtility::getStartDateTimeWithBuffer($this->getStartDateTime(), $this->getCalendar());
    }

    /**
     * Sets the startTime
     */
    public function setStartTime(string $startTime): void
    {
        $this->startTime = $startTime;
    }

    /**
     * Returns the endDate
     *
     * @return DateTime
     */
    public function getEndDate()
    {
        return $this->endDate;
    }
    /**
     * Sets the endDate
     */
    public function setEndDate(DateTime $endDate): void
    {
        $this->endDate = $endDate;
    }

    /**
     * Returns the endTime
     *
     * @return string
     */
    public function getEndTime()
    {
        return $this->endTime;
    }
    public function getEndTimeFormat()
    {
        return substr($this->endTime, 0, 5);
    }
    public function getEndTimeWithBufferFormat()
    {
        return $this->getEndDateTimeWithBuffer()
->format('H:i');
    }

    public function getEndDateTime()
    {
        if (!$this->getEndDate()) {
            return null;
        }
        return new DateTime($this->getEndDate()->format('Y-m-d') . 'T' . $this->getEndTime());
    }

    public function getEndDateTimeWithBuffer()
    {
        return EventUtility::getEndDateTimeWithBuffer(
            $this->getStartDateTime(),
            $this->getEndDateTime(),
            $this->getCalendar()
        );
    }


    public function getStartEndDateTime()
    {
        $ret = $this->getStartDate()
->format('d.m.Y') . ' / ' . $this->getStartTimeFormat() . ' - ';
        $ret .= ($this->getStartDate() && $this->getEndDate() && $this->getStartDate() != $this->getEndDate() ? $this->getEndDate()->format(
            'd.m.Y'
        ) . ' ' : '') . $this->getEndTimeFormat();
        return $ret;
    }


    /**
     * Sets the endTime
     */
    public function setEndTime(string $endTime): void
    {
        $this->endTime = $endTime;
    }

    /**
     * Returns the startDateTime
     *
     * @return DateTime
     */
    public function getDateTime()
    {
        $datetime = clone $this->startDate;
        $timeslot = $this->getTimeslot();
        if ($timeslot) {
            $timeStdMin = (int) ($this->getTimeslot()->getStartTimeInt() / 60);
            $datetime->setTime((int) ($timeStdMin / 60), ($timeStdMin % 60), 0);
        }

        return $datetime;
    }


    /**
     * Returns the name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Sets the name
     *
     * @param string $name
     */
    public function setName($name): void
    {
        $this->name = $name;
    }

    /**
     * Returns the address
     *
     * @return Address
     */
    public function getAddress()
    {
        if ($this->address instanceof LazyLoadingProxy) {
            $this->address->_loadRealInstance();
        }
        return $this->address;
    }

    /**
     * Sets the address
     */
    public function setAddress(?Address $address = null): void
    {
        $this->address = $address;
    }

    /**
     * Returns the status
     *
     * @return Status
     */
    public function getStatus()
    {
        return $this->status;
    }
    public function getStatusColor()
    {
        return $this->status ? $this->status->getColor() : 'none';
    }

    /**
     * Sets the status
     */
    public function setStatus(?Status $status = null): void
    {
        $this->status = $status;
    }

    /**
     * Returns the calendar
     *
     * @return Calendar
     */
    public function getCalendar()
    {
        return $this->calendar;
    }

    /**
     * Sets the calendar
     */
    public function setCalendar(Calendar $calendar): void
    {
        $this->calendar = $calendar;
    }

    /**
     * Returns the category
     *
     * @return Category
     */
    public function getCategory()
    {
        if ($this->category instanceof LazyLoadingProxy) {
            $this->category->_loadRealInstance();
        }
        return $this->category;
    }

    /**
     * Sets the category
     */
    public function setCategory(?Category $category = null): void
    {
        $this->category = $category;
    }

    /**
     * Returns the createDate
     *
     * @return DateTime createDate
     */
    public function getCreateDate()
    {
        return $this->createDate;
    }

    /**
     * Sets the createDate
     */
    public function setCreateDate(DateTime $createDate): void
    {
        $this->createDate = $createDate;
    }

    /**
     * Returns the notes
     *
     * @return string
     */
    public function getNotes()
    {
        return $this->notes;
    }

    /**
     * Sets the notes
     *
     * @param string $notes
     */
    public function setNotes($notes): void
    {
        $this->notes = $notes;
    }

    /**
     * Returns the numParticipants
     *
     * @return int
     */
    public function getNumParticipants()
    {
        return $this->numParticipants;
    }

    /**
     * Sets the numParticipants
     *
     * @param int $numParticipants
     */
    public function setNumParticipants($numParticipants): void
    {
        $this->numParticipants = (int)$numParticipants;
    }

    /**
     * Get the value of language
     *
     * @return int
     */
    public function getLanguage()
    {
        return $this->language;
    }

    /**
     * Set the value of language
     *
     * @param int $language
     *
     * @return self
     */
    public function setLanguage($language)
    {
        $this->language = $language;

        return $this;
    }

    /**
     * Get the value of confirmationSent
     *
     * @return boolean
     */
    public function getConfirmationSent()
    {
        return $this->confirmationSent;
    }

    /**
     * Set the value of confirmationSent
     *
     * @param boolean $confirmationSent
     *
     * @return self
     */
    public function setConfirmationSent($confirmationSent)
    {
        $this->confirmationSent = $confirmationSent;

        return $this;
    }

    /**
     * Returns the site language for the language of this Event
     *
     * @return SiteLanguage
     */
    public function getLanguageConfig()
    {
        $site = $GLOBALS['TYPO3_REQUEST']->getAttribute('site');
        return $site->getLanguageById($this->getLanguage());
    }


    /**
     * Get the value of virtual not stored in database
     *
     * @return string
     */
    public function getCaptcha()
    {
        return $this->captcha;
    }

    /**
     * Set the value of virtual not stored in database
     *
     * @param string $captcha
     *
     * @return self
     */
    public function setCaptcha($captcha)
    {
        $this->captcha = $captcha;

        return $this;
    }

    /**
     * Get the value of Reservations
     *
     * @return QueryResult
     */
    public function getReservations()
    {
        // var_dump($this);die();
        //if($this->reservations===null) {
        // bugfix for wrong reservation inserts without event
        $eventUid = $this->getUid() > 0 ? $this->getUid() : -1;
        $reservationRepository = GeneralUtility::makeInstance(ReservationRepository::class);
        $reservations = $reservationRepository->findBy(['event' => $eventUid]);
        //}
        /*
          if( $this->getUid()==16) {
          die('r=' . count( $this->reservations ));
          }
        */
        return $reservations;
    }
    /**
     * Get the value of Reservations
     *
     * @return array
     */
    public function getReservationsSortedByName()
    {
        $reservations = $this->getReservations()
->toArray();
        uasort($reservations, fn ($a, $b) => strcmp((string) $a->getSort(), (string) $b->getSort()));

        return $reservations;
    }

    /**
     * Set the value of Reservations
     *
     * @return self
     */
    public function setReservations(QueryResult $reservations)
    {
        //$this->reservations = $reservations;

        return $this;
    }

    public function getUserReservation()
    {
        if ($this->userReservation === null) {
            $context = GeneralUtility::makeInstance(Context::class);
            $userId = $context->getPropertyFromAspect('frontend.user', 'id');
            $this->userReservation = [];
            foreach ($this->getReservations() as $reservation) {
                if ($reservation->getFrontendUser() && $reservation->getFrontendUser()->getUid() == $userId) {
                    $this->userReservation[] = $reservation;
                }
            }
        }
        return $this->userReservation;
    }
    public function getFreePlaces()
    {
        if ($this->freePlaces === null) {
            $maxReservations = $this->calendar->getMaxReservations();
            $reservationsCount = $this->getReservations()
->count();

            $this->freePlaces = $reservationsCount < $maxReservations ? range(
                $reservationsCount + 1,
                $maxReservations
            ) : [];
        }
        return $this->freePlaces;
    }
    public function getPartial()
    {
        if (empty($this->timeslot)) {
            return 'Empty';
        }
        return 'Default';
    }

    public function getTimeslot()
    {
        return $this->timeslot;
    }

    public function setTimeslot($timeslot): void
    {
        $this->timeslot = $timeslot;
    }

    public function getTimeslotTitle()
    {
        return $this->timeslot && $this->timeslot->getName();

        //return substr($timeslot->getStartTime(), 0, -3) . ' - ' . substr($timeslot->getEndTime(), 0, -3);
    }

    public function getLinkHash()
    {
        if (!$this->linkHash) {
            $encryptionKey = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];

            $this->linkHash = sha1(
                $this->getUid() . $this->getPid() . $this->getStartDate()->format('Y-m-d') . $encryptionKey
            );
        }
        return $this->linkHash;
    }
    public function getJs()
    {
        $title = '';
        $reservations = $this->getReservationsSortedByName();
        foreach ($reservations as $reservation) {
            $title .= $reservation->getLastName() . ' ' . $reservation->getFirstName() . "\n";
            if ($reservation->getAddress()) {
                $title .= $reservation->getAddress() . "\n";
            }
            if ($reservation->getZip() || $reservation->getCity()) {
                $title .= $reservation->getZip() . ' ' . $reservation->getCity() . "\n";
            }
        }
        $startTimeslot = $this->timeslot;
        $endTimeslot = $this->timeslot;

        return '		  {
		      title: ' . json_encode($title, JSON_THROW_ON_ERROR) . ',
		      start: ' . json_encode($this->getStartDate()->format('Y-m-d') . 'T' . $this->getStartTime()) . ',
		      end: ' . json_encode($this->getEndDate()->format('Y-m-d') . 'T' . $this->getEndTime()) . '
		  },
';
        /*
              start: ' . json_encode($this->getStartDate()->format('Y-m-d') .'T' . $startTimeslot->getStartTime()) . ',
              end: ' . json_encode($this->getEndDate()->format('Y-m-d') .'T' . $endTimeslot->getEndTime()) . '
        */
    }

    public function getRawWithInfo()
    {
        return $this->getRaw(true, false);
    }
    public function getRawPublic()
    {
        return $this->getRaw(false, true);
    }


    public function getRaw($showTitle, $useBuffers)
    {
        $context = GeneralUtility::makeInstance(Context::class);
        $title = '';
        $hasReservationForUser = $this->hasReservationForUser();
        $userId = $context->getPropertyFromAspect('frontend.user', 'id');
        $reservations = $this->getReservationsSortedByName();
        $openReservationForm = false;
        $calendar = $this->getCalendar();
        $acl = $calendar->getAcl();

        if ($this->owner && $userId && $this->owner->getUid() == $userId) {
            $hasReservationForUser = true;
        }

        if ($hasReservationForUser || $showTitle || !(is_countable($reservations) ? count($reservations) : 0)) {
            //$title = $this->getName() ?: '';
            $title = '';
            if ($hasReservationForUser || ($acl && ($acl->getIsAdmin() || $acl->hasPermission('team')))) {
                $classNames = ['event-status event-status-' . $this->getStatusColor()];
            } else {
                $statusRepository = GeneralUtility::makeInstance(StatusRepository::class);
                
                /** @var Status $standardStatus */
                $standardStatus = $statusRepository->findOneBy(['showPublic' => 1]);

                if ($standardStatus) {
                    $classNames = ['event-status event-status-' . $standardStatus->getColor()];
                //$title .= $standardStatus->getName();
                } else {
                    $classNames = ['event-status event-status-reserved'];
                }
            }
            if ($this->bookingType) {
                if ($title) {
                    $title .= "\n";
                }
                $title .= $this->bookingType->getName();
            }
            if ($this->status && ($hasReservationForUser || ($acl && ($acl->getIsAdmin() || $acl->hasPermission(
                'team'
            ))))) {
                if ($title) {
                    $title .= "\n";
                }
                $title .= $this->status->getName();
            }
            if ($this->owner && $acl && $acl->hasPermission('team')) {
                if ($title) {
                    $title .= "\n";
                }
                $title .= LocalizationUtility::translate(
                    'tx_igreservations_domain_model_event.owner',
                    'IgReservations'
                ) . ': ' . $this->owner->getUsernameAndName();
            }
            $now = new DateTime();
            $bookBeginModifier = $acl ? $acl->getBookBeginDateTimeModifier() : null;
            $bookEndModifier = $acl ? $acl->getBookEndDateTimeModifier() : null;

            $bookBegin = clone $now;
            $bookEnd = clone $now;
            if ($bookBeginModifier) {
                $bookBegin->modify($bookBeginModifier);
            }
            if ($bookEndModifier) {
                $bookEnd->modify($bookEndModifier);
            }
            if (
                $userId && !(is_countable($reservations) ? count($reservations) : 0)
                && $acl && !$acl->getIsAdmin() && !$acl->hasPermission('team')
                && $this->getStartDateTime() > $bookBegin && $this->getStartDateTime() < $bookEnd
            ) {
                // is reservation allowd in status
                $status = $this->getStatus();
                if ($status && $status->getNoReservationAllowed()) {
                    $openReservationForm = false;
                } else {
                    $openReservationForm = true;
                }
            }

            foreach ($reservations as $reservation) {
                $frontendUser = $reservation->getFrontendUser();
                if (
                    ($acl && ($acl->getIsAdmin() || $acl->hasPermission('team' )))
                    || ($userId && $frontendUser && $frontendUser->getUid() == $userId)
                ) {
                    if ($reservation->getReservationType()) {
                        if ($title) {
                            $title .= "\n";
                        }
                        $title .= $reservation->getReservationType()->getName();
                    }
                    if ($this->getPurpose()) {
                        if ($title) {
                            $title .= "\n";
                        }
                        $title .= $this->getPurpose();
                    }
                    if ($reservation->getRawAddress()) {
                        if ($title) {
                            $title .= "\n";
                        }
                        $title .= $reservation->getRawAddress();
                    }
                    if ($this->getNotes()) {
                        if ($title) {
                            $title .= "\n";
                        }
                        $title .= $this->getNotes();
                    }
                    if ($reservation->getPurpose()) {
                        if ($title) {
                            $title .= "\n";
                        }
                        $title .= $reservation->getPurpose()->getName();
                    }
                }
            }

            // TODO: Was wird wann ausgegeben? Allgemeine Lösung finden!
            if ($acl && !$acl->getIsAdmin() && ($this->getStartDateTime() < $bookBegin || $this->getStartDateTime() > $bookEnd)) {
                $classNames = ['event-status event-status-over'];
                // $title = 'Nicht buchbar';
                //$title = $this->getName() ?: '';
                $title = '';
            }
        } else {
            $classNames = ['event-status-red'];
            //$title = $this->getName() ?: 'Reserviert';
        }

        $start = $this->getStartDateTime()->format('Y-m-d\TH:i:s');
        $end = $this->getEndDateTime()->format('Y-m-d\TH:i:s');

        if ($useBuffers) {
            $start = $this->getStartDateTimeWithBuffer()->format('Y-m-d\TH:i:s');
            $end = $this->getEndDateTimeWithBuffer()->format('Y-m-d\TH:i:s');
        }

        if ($hasReservationForUser) {
            $classNames[] = 'event-my';
        }

        if ($userId && $acl && $acl->hasPermission('user') && !$acl->hasPermission('team') && !$acl->getIsAdmin()) {
            $classNames[] = 'user-event';
        }

        if ($acl && $acl->hasPermission('read')) {
            $openReservationForm = false;
        }

        return [
            'id' => $this->getUid(),
            'title' => $title,
            'start' => $start,
            'end' => $end,
            'classNames' => $classNames,
            'hasReservationForUser' => $hasReservationForUser,
            'openReservationForm' => $openReservationForm,
            //'backgroundColor' => 'rgb(255, 255, 0)',
        ];
        //substr($this->getStartTime(),0,5) . ' - ' . substr($this->getEndTime(),0,5),
        /*
        if($this->getCalendar()->getType()=='dsafsdfa') {
        }else {

        $timeslots = $this->getTimeslots();
        if($timeslots->count() == 0) {
            return '';
            }
        $startTimeslot = $timeslots[0];
        $endTimeslot = $timeslots[$timeslots->count() - 1];
        return [
            'id' => $this->getUid(),
            'title' => $title,
            'start' => $this->getDate()->format('Y-m-d') .'T' . $startTimeslot->getStartTime(),
            'end' => $this->getDate()->format('Y-m-d') .'T' . $endTimeslot->getEndTime(),
            'classNames' => $classNames,
            //'backgroundColor' => 'rgb(255, 255, 0)',
        ];

        }
        */
        /*
            'start' => $this->getDate()->format('Y-m-d') .'T' . $startTimeslot->getStartTime(),
            'end' => $this->getDate()->format('Y-m-d') .'T' . $endTimeslot->getEndTime(),
            */
    }

    public function hasReservationForUser()
    {
        $context = GeneralUtility::makeInstance(Context::class);
        $userId = $context->getPropertyFromAspect('frontend.user', 'id');

        $reservations = null;
        if ($userId) {
            $reservations = $this->getReservationsSortedByName();
            foreach ($reservations as $reservation) {
                if ($reservation->getFrontendUser() && $reservation->getFrontendUser()->getUid() == $userId) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Get the value of bookingType
     *
     * @return BookingType
     */
    public function getBookingType()
    {
        if ($this->bookingType instanceof LazyLoadingProxy) {
            $this->bookingType->_loadRealInstance();
        }
        return $this->bookingType;
    }

    /**
     * Set the value of bookingType
     *
     * @return self
     */
    public function setBookingType(?BookingType $bookingType = null)
    {
        $this->bookingType = $bookingType;

        return $this;
    }


    /**
     * Get the value of purpose
     *
     * @return string
     */
    public function getPurpose()
    {
        return $this->purpose;
    }

    /**
     * Set the value of purpose
     *
     * @param string $purpose
     *
     * @return self
     */
    public function setPurpose($purpose)
    {
        $this->purpose = $purpose;

        return $this;
    }

    /**
     * Merge two events if they overlap eachother
     *
     * @param  Event $event [description]
     * @return boolean True if a merge was needed
     */
    public function merge($event, $useBuffers = true)
    {
        $merge = false;
        $startDate = $this->getStartDate();
        $startTime = $this->getStartTime();
        $endDate = $this->getEndDate();
        $endTime = $this->getEndTime();

        $thisStartDateTime = $this->getStartDateTime();
        $thisEndDateTime = $this->getEndDateTime();
        $eventStartDateTime = $event->getStartDateTime();
        $eventEndDateTime = $event->getEndDateTime();

        if ($useBuffers) {
            $thisStartDateTime = $this->getStartDateTimeWithBuffer();
            $thisEndDateTime = $this->getEndDateTimeWithBuffer();
            $eventStartDateTime = $event->getStartDateTimeWithBuffer();
            $eventEndDateTime = $event->getEndDateTimeWithBuffer();
        }

        // Check for all kinds of collision
        if (
            $thisStartDateTime <= $eventStartDateTime
            && $thisEndDateTime >= $eventStartDateTime
            && $thisEndDateTime <= $eventEndDateTime
        ) {
            $endDate = $event->getEndDate();
            $endTime = $event->getEndTime();
            $merge = true;
        } elseif (
            $thisStartDateTime <= $eventStartDateTime
            && $thisEndDateTime >= $eventStartDateTime
            && $thisEndDateTime >= $eventEndDateTime
        ) {
            $merge = true;
        } elseif (
            $thisStartDateTime >= $eventStartDateTime
            && $thisStartDateTime <= $eventEndDateTime
            && $thisEndDateTime >= $eventEndDateTime
        ) {
            $startDate = $event->getStartDate();
            $startTime = $event->getStartTime();
            $merge = true;
        } elseif (
            $thisStartDateTime >= $eventStartDateTime
            && $thisStartDateTime <= $eventEndDateTime
            && $thisEndDateTime <= $eventEndDateTime
        ) {
            $merge = true;
        }

        $this->setStartDate($startDate);
        $this->setStartTime($startTime);

        $this->setEndDate($endDate);
        $this->setEndTime($endTime);

        return $merge;
    }

    public function getIsBlocked()
    {
        if ($this->getTimeslot() === null) {
            return false;
        }
        $eventStartDateTime = new DateTime($this->getStartDate()->format(
            'Y-m-d'
        ) . 'T' . $this->getTimeslot()->getStartTime());
        $eventEndDateTime = new DateTime($this->getStartDate()->format(
            'Y-m-d'
        ) . 'T' . $this->getTimeslot()->getEndTime());
        foreach ($this->getCalendar()->getBlockingTimes() as $blockingTime) {
            $startDateTime = $blockingTime->getStartDateTime();
            $endDateTime = $blockingTime->getEndDateTime();
            if (($startDateTime === null || $eventStartDateTime >= $startDateTime) && ($endDateTime === null || $eventEndDateTime <= $endDateTime)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Get the value of locationDescription
     *
     * @return string
     */
    public function getLocationDescription()
    {
        return $this->locationDescription;
    }

    /**
     * Set the value of locationDescription
     *
     * @param string $locationDescription
     *
     * @return self
     */
    public function setLocationDescription($locationDescription)
    {
        $this->locationDescription = $locationDescription;

        return $this;
    }


    /**
     * Get the value of isPublic
     *
     * @return boolean
     */
    public function getIsPublic()
    {
        return $this->isPublic;
    }

    /**
     * Set the value of isPublic
     *
     * @param boolean $isPublic
     *
     * @return self
     */
    public function setIsPublic($isPublic)
    {
        $this->isPublic = $isPublic;

        return $this;
    }


    /**
     * Get the value of calendarGroup
     *
     * @return CalendarGroup
     */
    public function getCalendarGroup()
    {
        if ($this->calendarGroup instanceof LazyLoadingProxy) {
            $this->calendarGroup->_loadRealInstance();
        }
        return $this->calendarGroup;
    }

    /**
     * Set the value of calendarGroup
     *
     * @return self
     */
    public function setCalendarGroup(?CalendarGroup $calendarGroup = null)
    {
        $this->calendarGroup = $calendarGroup;

        return $this;
    }

    /**
     * Get the value of eventGroup
     *
     * @return EventGroup
     */
    public function getEventGroup()
    {
        if ($this->eventGroup instanceof LazyLoadingProxy) {
            $this->eventGroup->_loadRealInstance();
        }
        return $this->eventGroup;
    }

    /**
     * Set the value of eventGroup
     *
     * @return self
     */
    public function setEventGroup(?EventGroup $eventGroup = null)
    {
        $this->eventGroup = $eventGroup;

        return $this;
    }


    /**
     * Get the value of mainEvent
     *
     * @return boolean
     */
    public function getMainEvent()
    {
        return $this->mainEvent;
    }

    /**
     * Set the value of mainEvent
     *
     * @param boolean $mainEvent
     *
     * @return self
     */
    public function setMainEvent($mainEvent)
    {
        $this->mainEvent = $mainEvent;

        return $this;
    }

    public function setUpdateProperties($event): void
    {
        $this->isPublic = $event->getIsPublic();
        $this->purpose = $event->getPurpose();
        $this->status = $event->getStatus();
        $this->notes = $event->getNotes();
        $this->owner = $event->getOwner();
    }


    /**
     * Get the value of description
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Set the value of description
     *
     * @param string $description
     *
     * @return self
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }


    /**
     * Get the value of owner
     *
     * @return FeUser
     */
    public function getOwner()
    {
        if ($this->owner instanceof LazyLoadingProxy) {
            $this->owner->_loadRealInstance();
        }
        return $this->owner;
    }

    /**
     * Set the value of owner
     *
     * @return self
     */
    public function setOwner(?FeUser $owner = null)
    {
        $this->owner = $owner;

        return $this;
    }

    /**
     * Get the value of teammembers (FrontendUsers)
     *
     * @return ObjectStorage<FeUser>
     */
    public function getTeammembers()
    {
        if ($this->teammembers instanceof LazyLoadingProxy) {
            $this->teammembers->_loadRealInstance();
        }
        return $this->teammembers;
    }

    /**
     * Set the value of teammembers (FrontendUsers)
     *
     * @param ObjectStorage<FeUser> $teammembers
     *
     * @return self
     */
    public function setTeammembers(ObjectStorage $teammembers)
    {
        $this->teammembers = $teammembers;

        return $this;
    }

    /**
     * Adds a Team Member (FrontendUser)
     */
    public function addTeammember(FeUser $teammember): void
    {
        $this->teammembers->attach($teammember);
    }

    /**
     * Removes a Team Member (FrontendUser)
     *
     * @param FeUser $teammemberToRemove The FeUser to be removed
     */
    public function removeTeammember(FeUser $teammemberToRemove): void
    {
        $this->teammembers->detach($teammemberToRemove);
    }

    /**
     * Get the value of location
     *
     * @return Location
     */
    public function getLocation()
    {
        if ($this->location instanceof LazyLoadingProxy) {
            $this->location->_loadRealInstance();
        }
        return $this->location;
    }

    /**
     * Set the value of location
     *
     * @return self
     */
    public function setLocation(?Location $location = null)
    {
        $this->location = $location;

        return $this;
    }

    /**
     * Get the value of teammembers (FrontendUsers)
     *
     * @return ObjectStorage<ReservationType>
     */
    public function getReservationTypes()
    {
        if ($this->reservationTypes instanceof LazyLoadingProxy) {
            $this->reservationTypes->_loadRealInstance();
        }
        return $this->reservationTypes;
    }

    /**
     * Set the value of teammembers (FrontendUsers)
     *
     * @param ObjectStorage<ReservationType> $reservationTypes
     *
     * @return self
     */
    public function setReservationTypes(ObjectStorage $reservationTypes)
    {
        $this->reservationTypes = $reservationTypes;

        return $this;
    }

    /**
     * Adds a Team Member (FrontendUser)
     */
    public function addReservationType(ReservationType $reservationType): void
    {
        $this->reservationTypes->attach($reservationType);
    }

    /**
     * Removes a Team Member (FrontendUser)
     *
     * @param ReservationType $reservationTypeToRemove The FeUser to be removed
     */
    public function removeReservationType(ReservationType $reservationTypeToRemove): void
    {
        $this->reservationTypes->detach($reservationTypeToRemove);
    }

    public function getClone()
    {
        $clone = GeneralUtility::makeInstance(static::class);
        $properties = ObjectAccess::getGettableProperties($this);
        foreach ($properties as $propertyName => $propertyValue) {
            if ($propertyValue instanceof ObjectStorage) {
                $v = GeneralUtility::makeInstance(ObjectStorage::class);
                foreach ($propertyValue as $subObject) {
                    $v->attach($subObject);
                }
            } else {
                $v = $propertyValue;
            }
            if ($v !== null) {
                ObjectAccess::setProperty($clone, $propertyName, $v);
            }
        }
        return $clone;
    }

    /**
     * Adds a FileReference
     */
    public function addFile(FileReference $file): void
    {
        $this->files->attach($file);
    }

    /**
     * Removes a FileReference
     *
     * @param FileReference $fileToRemove The FileReference to be removed
     */
    public function removeFile(FileReference $fileToRemove): void
    {
        $this->files->detach($fileToRemove);
    }

    /**
     * Returns the files
     *
     * @return ObjectStorage<FileReference> $files
     */
    public function getFiles()
    {
        return $this->files;
    }

    /**
     * Sets the files
     *
     * @param ObjectStorage<FileReference> $files
     */
    public function setFiles(ObjectStorage $files): void
    {
        $this->files = $files;
    }


    /**
     * Get the value of additionalMember
     *
     * @return FeUser
     */
    public function getAdditionalMember()
    {
        return $this->additionalMember;
    }

    /**
     * Set the value of additionalMember
     *
     * @return self
     */
    public function setAdditionalMember(FeUser $additionalMember)
    {
        $this->additionalMember = $additionalMember;

        return $this;
    }

    public function getPurposesCommaSeparated()
    {
        $purposes = [];
        if ($this->owner && $this->owner->getPurposes()->count() > 0) {
            foreach ($this->owner->getPurposes() as $purpose) {
                if (!in_array($purpose->getUid(), $purposes)) {
                    $purposes[] = $purpose->getUid();
                }
            }
        }
        if ($this->bookingType && $this->bookingType->getPurposes()->count() > 0) {
            foreach ($this->bookingType->getPurposes() as $purpose) {
                if (!in_array($purpose->getUid(), $purposes)) {
                    $purposes[] = $purpose->getUid();
                }
            }
        }
        if (empty($purposes)) {
            return '';
        }
        return implode(',', $purposes);
    }

    public function getPurposes()
    {
        $purposes = [];
        if ($this->owner && $this->owner->getPurposes()->count() > 0) {
            foreach ($this->owner->getPurposes() as $purpose) {
                if (!isset($purposes[$purpose->getUid()])) {
                    $purposes[$purpose->getUid()] = $purpose;
                }
            }
        }
        if ($this->bookingType && $this->bookingType->getPurposes()->count() > 0) {
            foreach ($this->bookingType->getPurposes() as $purpose) {
                if (!isset($purposes[$purpose->getUid()])) {
                    $purposes[$purpose->getUid()] = $purpose;
                }
            }
        }
        return $purposes;
    }
}
