<?php


namespace App\Model\Facades\Writers;


use App\Model\Exceptions\User\AnonymousUserException;
use App\Model\Entities\Security\User as UserEntity;
use App\Model\Facades\Readers\UserReader;
use App\Model\User;
use Kdyby\Doctrine\EntityManager;
use Nette\DI\Container;
use Nette\Security\IAuthorizator;

abstract class BaseWriter
{
    /** @var Container */
    private $container;
    /**
     * @var EntityManager
     */
    private $entityManager;

    /** @var User */
    private $user;

    /** @var  UserEntity */
    private $loggedInUser;

    /** @var UserReader */
    protected $userReader;

    public function __construct(Container $container, EntityManager $entityManager, UserReader $userReader)
    {
        $this->container = $container;
        $this->entityManager = $entityManager;
        $this->userReader = $userReader;
    }

    protected function beginTransaction()
    {
        $this->entityManager->beginTransaction();
    }

    protected function commit()
    {
        $this->entityManager->flush();
        $this->entityManager->commit();
    }

    protected function rollback()
    {
        $this->entityManager->rollback();
    }

    /**
     * DO NOT USE THIS METHOD AT CONSTRUCTORS AND INJECT METHODS
     * It will result to circular references
     * @return UserEntity
     * @throws AnonymousUserException
     */
    protected function getLoggedInUser() : UserEntity
    {
        if ($this->loggedInUser !== null) {
            return $this->loggedInUser;
        }

        if (!$this->getUser()->isLoggedIn()) {
            throw new AnonymousUserException();
        }

        return $this->userReader->findUserById($this->getUser()->getId());
    }

    /**
     * DO NOT USE THIS METHOD AT CONSTRUCTORS AND INJECT METHODS
     * It will result to circular references
     * @param null $resource
     * @param null $privilege
     * @return bool
     */
    protected function isAllowed($resource = IAuthorizator::ALL, $privilege = IAuthorizator::ALL) : bool
    {
        return $this->getUser()->isAllowed($resource, $privilege);
    }

    private function getUser() : User
    {
        if (!$this->user) {
            $this->user = $this->container->getService('user');
        }

        return $this->user;
    }
}