<?php

/**
 * Lifestyle Webconsulting GmbH
 *
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is private by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * @copyright  2018 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace Sso\WebserviceBundle\Entity\Webservice\Type;

use Symfony\Component\Validator\Validator\ValidatorInterface as Validator;
use Doctrine\Common\Collections\ArrayCollection;
use Sso\WebserviceBundle\Api\Exception\Type\Api as ApiException;

/**
 * Class UserApplication
 *
 * @copyright  2017 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 * @package Sso\WebserviceBundle\Entity\Webservice\Type
 */
class UserApplication extends Base
{
    /**
     * @var string
     */
    private $Id;

    /**
     * @var string
     */
    private $Name;

    /**
     * @var boolean
     */
    private $Active;

    /**
     * @var ArrayCollection|UserApplicationRole[]
     */
    private $Roles;

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

    /**
     * @var Application
     */
    private $Application;

    /**
     * @var ArrayCollection|UserApplicationAttribute[]
     */
    private $Attributes;

    /**
     * @var \DateTime
     */
    private $UpdatedAt;

    /**
     * @var string
     */
    private $updateHash;

    /**
     * Constructor
     *
     * @param Validator $valApi
     */
    public function __construct(Validator $valApi)
    {
        parent::__construct($valApi);
        $this->Attributes = new ArrayCollection();
        $this->Roles = new ArrayCollection();
        $this->UpdatedAt = new \DateTime();
    }

    /**
     * Initialize object with new values
     *
     * @param array|object $values
     * @param array|null $validationGroups Null for full validation, array of group-name(s) for group specific validation
     */
    public function init($values, $validationGroups = null)
    {
        // Generate new application-id
        $this->generateId();

        parent::init($values, $validationGroups);
    }

    /**
     * Generate unique user application id
     *
     * @throws ApiException
     * @return string User-Application-Id
     */
    public function generateId()
    {
        if (null !== $this->Id) {
            throw new ApiException('Changing the user-application-id is not allowed!');
        }
        return $this->Id = hash('sha256', mt_rand() . '#' . microtime());
    }

    /**
     * Get Id
     *
     * @return string
     */
    public function getId()
    {
        return $this->Id;
    }

    /**
     * Set Id
     *
     * @param string $id
     * @throws ApiException
     */
    public function setId($id)
    {
        if (null !== $this->Id && $id !== $this->Id) {
            throw new ApiException('It is not allowed, to change the user-application-id!');
        }
    }

    /**
     * Get Active
     *
     * @return boolean
     */
    public function getActive()
    {
        return $this->Active;
    }

    /**
     * Set Active
     *
     * @param boolean $active
     * @return UserApplication
     */
    public function setActive($active)
    {
        $this->Active = $active;

        return $this;
    }

    /**
     * Add Roles
     *
     * @param UserApplicationRole $role
     * @return UserApplication
     */
    public function addRole(UserApplicationRole $role)
    {
        $this->Roles[] = $role;

        return $this;
    }

    /**
     * Remove Roles
     *
     * @param UserApplicationRole $role
     */
    public function removeRole(UserApplicationRole $role)
    {
        $this->Roles->removeElement($role);
    }

    /**
     * Check for role by userApplicationRole
     *
     * @param UserApplicationRole|Role $role
     * @return boolean
     */
    public function hasRole($role)
    {
        return null !== $this->getRole($role->getName());
    }

    /**
     * Get for role by name
     *
     * @param string $name
     * @return null|UserApplicationRole
     */
    public function getRole($name)
    {
        foreach ($this->getRoles() as $role) {
            if (0 === strcasecmp($name, $role->getName())) {
                return $role;
            }
        }
        return null;
    }

    /**
     * Get Roles
     *
     * @return ArrayCollection|UserApplicationRole[]
     */
    public function getRoles()
    {
        return $this->Roles;
    }

    /**
     * Get Application
     *
     * @return Application
     */
    public function getApplication()
    {
        return $this->Application;
    }

    /**
     * Set Application
     *
     * @param Application $application
     * @return UserApplication
     */
    public function setApplication(Application $application = null)
    {
        $this->Application = $application;
        $this->Name = $application->getName();

        return $this;
    }

    /**
     * Add Attributes
     *
     * @param UserApplicationAttribute $attribute
     * @return UserApplication
     */
    public function addAttribute(UserApplicationAttribute $attribute)
    {
        if (!$this->Attributes->contains($attribute)) {
            $this->Attributes->add($attribute);
        }

        return $this;
    }

    /**
     * Remove Attributes
     *
     * @param UserApplicationAttribute $attribute
     */
    public function removeAttribute(UserApplicationAttribute $attribute)
    {
        $this->Attributes->removeElement($attribute);
    }

    /**
     * Get Attributes
     *
     * @return UserApplicationAttribute[]|ArrayCollection
     */
    public function getAttributes()
    {
        return $this->Attributes;
    }

    /**
     * Get Name
     *
     * @return string
     */
    public function getName()
    {
        return $this->Name;
    }

    /**
     * Set Name
     *
     * @param string $name
     * @return UserApplication
     */
    public function setName($name)
    {
        $this->Name = $name;

        return $this;
    }

    /**
     * Get User
     *
     * @return User
     */
    public function getUser()
    {
        return $this->User;
    }

    /**
     * Set User
     *
     * @param User $user
     * @return UserApplication
     */
    public function setUser(User $user = null)
    {
        $this->User = $user;

        return $this;
    }

    /**
     * lifecycleCallbacks prePersist
     */
    public function onPrePersist()
    {
        $this->checkObjectUpdate();
    }

    /**
     * lifecycleCallbacks preUpdate
     */
    public function onPreUpdate()
    {
        $this->checkObjectUpdate();
    }

    /**
     * lifecycleCallbacks preRemove
     */
    public function onPreRemove()
    {
        $this->getUser()->setUserUpdatedReferences();
    }

    /**
     * lifecycleCallbacks postLoad
     */
    public function onPostLoad()
    {
        $this->updateHash = $this->getObjectHash();
    }

    /**
     * Update application updated-at and
     * user updated-at if any role or
     * attribute has been changed
     */
    public function checkObjectUpdate()
    {
        if ($this->getObjectHash() !== $this->updateHash) {
            $this->UpdatedAt = new \DateTime();
            $this->getUser()->setUserUpdatedReferences();
        }
    }

    /**
     * @return string
     */
    public function getObjectHash()
    {
        $parts = [
            $this->Active ? 1 : 0
        ];
        foreach ($this->Roles as $role) {
            $parts[] = $role->getObjectHash();
        }
        foreach ($this->Attributes as $attribute) {
            $parts[] = $attribute->getObjectHash();
        }
        return hash('adler32', implode('|', $parts));
    }
}
