<?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\Database\ServiceProvider;

use Sso\WebserviceBundle\Entity\ServiceProvider\Type\Token as ServiceProviderToken;
use Doctrine\ORM\NoResultException;
use Doctrine\ORM\NonUniqueResultException;

/**
 * Class Token
 * @package Sso\WebserviceBundle\Database\ServiceProvider
 */
class Token extends Base
{

    /**
     * List of all tokens
     * @return array
     */
    public function getAll()
    {
        return $this->entityManager->getRepository('Sso\WebserviceBundle\Entity\ServiceProvider\Type\Token')
            ->findAll();
    }

    /**
     * @param string $token
     * @return object|ServiceProviderToken|null
     */
    public function getOneById($token)
    {
        return $this->entityManager->getRepository('Sso\WebserviceBundle\Entity\ServiceProvider\Type\Token')
            ->findOneBy(['ServiceToken' => $token]);
    }

    /**
     * @param $serviceNameId
     * @return array
     */
    public function getByServiceNameId($serviceNameId)
    {
        $dql = 'SELECT a FROM Sso\WebserviceBundle\Entity\ServiceProvider\Type\Token a '
            .'JOIN a.ServiceNames sn '
            .'WHERE sn.ServiceNameId=:ServiceNameId ';
        $query = $this->entityManager->createQuery($dql);

        $query->setParameters(array(
            'ServiceNameId' => (string)$serviceNameId
        ));

        return $query->getResult();
    }

    /**
     * @param string $serviceNameId
     * @return array
     */
    public function getNotAssignedByServiceNameId($serviceNameId)
    {
        $allTokens = $this->entityManager->getRepository('Sso\WebserviceBundle\Entity\ServiceProvider\Type\Token')
            ->findAll();

        // filter out all tokens that currently do not have the given ServiceNameId assigned to them
        $tokens = [];
        foreach ($allTokens as $aToken) {
            if ($aToken->getServiceNames()->count() == 0) {
                $tokens[] = $aToken;
            } else {
                $hasServiceNameId = false;
                foreach ($aToken->getServiceNames() as $tokenServiceName) {
                    if ($tokenServiceName->getServiceNameId() == $serviceNameId) {
                        $hasServiceNameId = true;
                    }
                }
                if (!$hasServiceNameId) {
                    $tokens[] = $aToken;
                }
            }
        }

        return $tokens;
    }

    /**
     * @param string $tokenId
     * @param string $serviceNameId
     * @return bool
     */
    public function addToServiceName($tokenId, $serviceNameId)
    {
        if ((null === $tokenId) || (null === $serviceNameId)) {
            return false;
        }

        $serviceName = $this->entityManager->getRepository('Sso\WebserviceBundle\Entity\ServiceProvider\Type\ServiceName')->findOneBy(['ServiceNameId' => $serviceNameId]);
        $token = $this->entityManager->getRepository('Sso\WebserviceBundle\Entity\ServiceProvider\Type\Token')->findOneBy(['ServiceToken' => $tokenId]);
        $token->addServiceName($serviceName);
        $this->entityManager->persist($serviceName);
        $this->entityManager->flush();
        return true;
    }

    /**
     * @param string $serviceToken
     * @param string $serviceNameId
     * @return bool
     */
    public function removeFromServiceName($serviceToken, $serviceNameId)
    {
        $serviceName = $this->entityManager->getRepository('Sso\WebserviceBundle\Entity\ServiceProvider\Type\ServiceName')->findOneBy(['ServiceNameId' => $serviceNameId]);
        $token = $this->entityManager->getRepository('Sso\WebserviceBundle\Entity\ServiceProvider\Type\Token')->findOneBy(['ServiceToken' => $serviceToken]);
        $token->removeServiceName($serviceName);
        $this->entityManager->persist($serviceName);
        $this->entityManager->flush();
        return true;
    }

    /**
     * Save token from data array
     * @param array $data
     */
    public function saveTokenFromArray($data)
    {
        $model = new ServiceProviderToken();
        $model->setServiceToken($data['ServiceToken']);
        $model->setServiceToken2Ip($data['ServiceToken2Ip']);
        $model->setAllowedCallsPerDay((int)$data['AllowedCallsPerDay']);
        $model->setValidUntil(new DateTime($data['ValidUntil']));
        $model->setBlocked((int)$data['Blocked']);

        $this->saveToken($model);
    }

    /**
     * Save token
     * @param \Sso\WebserviceBundle\Entity\ServiceProvider\Type\Token $model
     * @return boolean
     */
    public function saveToken(ServiceProviderToken $model)
    {
        if (!$this->readonly) {
            $this->entityManager->persist($model);
            $this->entityManager->flush($model);
        }
    }

    /**
     * @param ServiceProviderToken $model
     */
    public function deleteToken(ServiceProviderToken $model)
    {
        if (!$this->readonly) {
            $this->entityManager->remove($model);
            $this->entityManager->flush($model);
        }
    }

    /**
     * @param string $ServiceToken
     * @return ServiceProviderToken|null
     * @throws \Exception
     */
    public function credentialsGetActiveToken($ServiceToken)
    {
        $dql = 'SELECT t FROM Sso\WebserviceBundle\Entity\ServiceProvider\Type\Token t '
            .'WHERE t.ServiceToken=:ServiceToken '
            .'AND t.Blocked=:Blocked '
            .'AND t.ValidUntil>CURRENT_DATE()';
        $query = $this->entityManager->createQuery($dql);
        $query->setParameters(array(
            'ServiceToken' => (string)$ServiceToken,
            'Blocked' => 0,
        ));

        try {
            $tokenModel = $query->getSingleResult();
        } catch (\Exception $exc) {
            // Token not found or too many rows
            if ($exc instanceof NoResultException || $exc instanceof NonUniqueResultException) {
                return null;
            }
            // An unexpected error
            throw $exc;
        }

        return $tokenModel;
    }

    /**
     * Find user by token by id
     * @param string $tokenId
     * @return ModelToken|null
     */
    public function getTokenByToken($token)
    {
        return $this->getRepository()->findOneBy(array('ServiceToken' => $token));
    }

    /**
     * @return \Doctrine\ORM\EntityRepository
     */
    public function getRepository()
    {
        return $this->entityManager->getRepository('Sso\WebserviceBundle\Entity\ServiceProvider\Type\Token');
    }
}
