<?php
namespace App\Obs\Service;
use App\Core\Entity\Scene;
use App\Core\Repository\SceneRepository;
use App\Core\Repository\TournamentRepository;
use Doctrine\ORM\EntityManagerInterface;
define('P_USR', 100, true);
define('P_EVENT', 90, true);
define('P_INTERRUPT_BORDER', 70, true);
define('P_IMPORTANT_SPONSORED', 60, true);
define('P_INTERESTING', 50, true);
define('P_SPONSORED', 40, true);
define('P_FILL_UP', 30, true);
define('P_UNKNOWN', 0, true);
class ActiveSceneResolver
{
private Scene $currentScene;
private int $commercialMinShow = 3600; // 1 hour
private int $commercialMaxNotShow = 7200; // 2 hours
private int $funMinShow = 3600; // 1 hour
private TournamentRepository $tournamentRepository;
private SceneRepository $sceneRepository;
private EntityManagerInterface $entityManager;
public function __construct(
TournamentRepository $tournamentRepository,
SceneRepository $sceneRepository,
EntityManagerInterface $entityManager
) {
$this->tournamentRepository = $tournamentRepository;
$this->sceneRepository = $sceneRepository;
$this->entityManager = $entityManager;
}
private function getSceneTypePriority(string $sceneType)
{
/* TODO Temporary solution - get mapping from DB */
switch ($sceneType) {
case 'user':
{
return P_USR;
}
case 'event':
{
return P_EVENT;
}
case 'important_sponsored':
{
return P_IMPORTANT_SPONSORED;
}
case 'interesting':
{
return P_INTERESTING;
}
case 'sponsored':
{
return P_SPONSORED;
}
case 'fill_up':
{
return P_FILL_UP;
}
default:
{
return P_UNKNOWN;
}
}
}
private function isTimePassed(\DateTime $from, int $duration): bool
{
$now = new \DateTime();
$endTime = (clone $from)->modify("+$duration seconds");
return $endTime < $now;
}
// -----------------------
private function getCurrentScene(): Scene
{
return $this->sceneRepository->getCurrentScene();
}
private function getUserSceneQueue()
{
return $this->sceneRepository->getUserSceneQueue();
}
private function getAvailableEventScene()
{
return $this->sceneRepository->getAvailableEventScene();
}
private function getFillUpSceneList()
{
return $this->sceneRepository->getFillUpSceneList();
}
private function getFunSceneList()
{
return $this->sceneRepository->getFunSceneList();
}
private function getSponsoredSceneList()
{
return $this->sceneRepository->getSponsoredSceneList();
}
// -----------------------
private function fetchCurrentScene()
{
$this->currentScene = $this->getCurrentScene();
$this->entityManager->persist($this->currentScene);
}
private function currentSceneEnded()
{
$duration = $this->currentScene->getDuration();
$started = $this->currentScene->getStartedAt();
return $this->isTimePassed($started, $duration);
}
private function canOverrideCurrentScene($priority)
{
$currentSceneType = $this->currentScene->getType();
$currentScenePriority = $this->getSceneTypePriority($currentSceneType);
if ($this->currentSceneEnded()) {
return true;
} else {
if ($priority > P_INTERRUPT_BORDER && $currentScenePriority < P_INTERRUPT_BORDER) {
return true;
} else {
return false;
}
}
}
private function saveScene(Scene $scene)
{
$now = new \DateTime();
$this->currentScene->setLastShownAt($now);
if ($scene->getId() !== $this->currentScene->getId()) {
$this->currentScene->setIsCurrent(false);
//$this->entityManager->flush();
$this->currentScene = $scene;
$this->currentScene->setStartedAt($now);
$this->currentScene->setIsCurrent(true);
$this->currentScene->setLastShownAt($now);
}
$this->entityManager->flush();
}
// -----------------------
private function getEventScene()
{
if (!$this->canOverrideCurrentScene(P_EVENT)) {
return false;
}
$scenes = $this->getAvailableEventScene();
if ($scenes) {
reset($scenes);
return current($scenes);
}
return false;
}
private function getOnDemandScene(): ?Scene
{
if (!$this->canOverrideCurrentScene(P_USR)) {
return null;
}
$scenes = $this->getUserSceneQueue();
if ($scenes) {
reset($scenes);
return current($scenes);
}
return null;
}
private function getImportantSponsoredScene(): ?Scene
{
if (!$this->canOverrideCurrentScene(P_IMPORTANT_SPONSORED)) {
return null;
}
$scenes = $this->getSponsoredSceneList();
if ($scenes) {
reset($scenes);
$rv = current($scenes);
if ($this->isTimePassed($rv->getLastShownAt(), $this->commercialMaxNotShow)) {
return $rv;
} else {
return null;
}
}
return null;
}
private function getFunScene(): ?Scene
{
if (!$this->canOverrideCurrentScene(P_INTERESTING)) {
return null;
}
$scenes = $this->getFunSceneList();
if ($scenes) {
reset($scenes);
$rv = current($scenes);
if ($this->isTimePassed($rv->getLastShownAt(), $this->funMinShow)) {
return $rv;
} else {
return null;
}
}
return null;
}
private function getSponsoredScene(): ?Scene
{
if (!$this->canOverrideCurrentScene(P_IMPORTANT_SPONSORED)) {
return null;
}
$scenes = $this->getSponsoredSceneList();
if ($scenes) {
reset($scenes);
$rv = current($scenes);
if ($this->isTimePassed($rv->getLastShownAt(), $this->commercialMinShow)) {
return $rv;
} else {
return null;
}
}
return null;
}
private function getFillUpScene(): ?Scene
{
if (!$this->canOverrideCurrentScene(P_FILL_UP)) {
return null;
}
$scenes = $this->getFillUpSceneList();
if ($scenes) {
reset($scenes);
return current($scenes);
}
return null;
}
private function getPlayScene(): Scene
{
($scene = $this->getOnDemandScene())
|| ($scene = $this->getEventScene())
|| ($scene = $this->getImportantSponsoredScene())
|| ($scene = $this->getFunScene())
|| ($scene = $this->getSponsoredScene())
|| ($scene = $this->getFillUpScene())
|| ($scene = $this->currentScene);
return $scene;
}
public function getActiveScene(): array
{
/* TODO Some screens should be counted as shown only in case they are shown for certain amount of time (i.e. Sponsored) */
/* TODO However it should be possible to stop longer advertisement to play some user or event scene */
/* TODO Enable sequence of scenes for certain events (i.e. Show players who will play before the match starts) */
$this->fetchCurrentScene();
$scene = $this->getPlayScene();
$this->saveScene($scene);
return [$scene->getName()];
}
}