<?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\BackendBundle\Controller;

use Sso\WebserviceBundle\Database\Manager as DatabaseManager;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sso\WebserviceBundle\Entity\Webservice\Type;
use Pagerfanta\Pagerfanta;
use Pagerfanta\View\TwitterBootstrap3View;
use Pagerfanta\Adapter\DoctrineORMAdapter;

/**
 * Abstract WebserviceController
 */
abstract class WsAbstractController extends Controller
{

    /**
     *
     * @var DatabaseManager
     */
    private $databaseManager;

    /**
     * Filter list
     * @return array
     */
    protected function filter(
        \Symfony\Component\Form\FormTypeInterface $filterFormType,
        \Doctrine\ORM\EntityRepository $repository
    ) {
        $filterKey = get_class($filterFormType);
        $request = $this->getRequest();
        $session = $request->getSession();
        $filterForm = $this->createForm($filterFormType);
        $queryBuilder = $repository->createQueryBuilder('e');
        // Reset filter
        if ($request->get('filter_action') == 'reset') {
            $session->remove($filterKey);
        }

        // Filter action
        if ($request->get('filter_action') == 'filter') {
            // Bind values from the request
            $filterForm->bind($request);

            if ($filterForm->isValid()) {
                // Build the query from the given form object
                $this->get('lexik_form_filter.query_builder_updater')->addFilterConditions($filterForm, $queryBuilder);
                // Save filter to session
                $filterData = $filterForm->getData();
                $session->set($filterKey, $filterData);
            }
        } else {
            // Get filter from session
            if ($session->has($filterKey)) {
                $filterData = $session->get($filterKey);
                $filterForm = $this->createForm($filterFormType, $filterData);
                $this->get('lexik_form_filter.query_builder_updater')->addFilterConditions($filterForm, $queryBuilder);
            }
        }

        return [$filterForm, $queryBuilder];
    }

    /**
     * @param type $queryBuilder
     * @return array
     */
    protected function paginator($queryBuilder, $routeGenerator)
    {
        // Paginator
        $adapter = new DoctrineORMAdapter($queryBuilder, false, false);
        $pagerfanta = new Pagerfanta($adapter);
        $pagerfanta->setMaxPerPage(25);
        $currentPage = $this->getRequest()->get('page', 1);
        $pagerfanta->setCurrentPage($currentPage);

        $entities = $pagerfanta->getCurrentPageResults();

        // Paginator - view
        $translator = $this->get('translator');
        $view = new TwitterBootstrap3View();
        $pagerHtml = $view->render($pagerfanta, $routeGenerator, array(
            'proximity' => 3,
            'prev_message' => $translator->trans('prev', array(), 'JordiLlonchCrudGeneratorBundle'),
            'next_message' => $translator->trans('next', array(), 'JordiLlonchCrudGeneratorBundle'),
        ));

        return [$entities, $pagerHtml];
    }

    /**
     * Add user to application
     * @param string $applicationId
     * @param string $userId
     * @return bool
     */
    protected function addUserApplication($applicationId, $userId)
    {
        if (!($user = $this->webServiceDb()->user()->getUserById($userId))) {
            $this->addError('User not found');

            return false;
        }
        if (!($application = $this->databaseManager()->webservice()->application()->getApplicationById($applicationId))) {
            $this->addError('Application not found');

            return false;
        }
        if ($this->databaseManager()->webservice()->userApplication()->getUserApplication($user, $application)) {
            $this->addError('User "' . $user->getUsername() . '" already linked to application "' . $application->getName() . '"');

            return false;
        }
        $userApplication = new Type\UserApplication($this->validator());
        $userApplication->setUser($user)->setApplication($application)->setActive(1)->generateId();
        if (!$this->webServiceDb()->userApplication()->saveUserApplication($userApplication)) {
            $this->addErrors($userApplication);

            return false;
        }
        $this->addSuccess(
            'User "' . $userApplication->getUser()->getUsername() . '" successfully linked to application "' . $userApplication->getApplication()->getName() . '"'
        );

        return true;
    }

    /**
     * Delete user from application
     * @param string $applicationId
     * @param string $userId
     * @return bool
     */
    protected function deleteUserApplication($applicationId, $userId)
    {
        if (!($userApplication = $this->getUserApplication($applicationId, $userId))) {
            return false;
        }
        if (!$this->webServiceDb()->userApplication()->deleteUserApplication($userApplication)) {
            $this->addErrors($userApplication);

            return false;
        }
        $this->addSuccess(
            'User "' . $userApplication->getUser()->getUsername() . '" successfully deleted from application "' . $userApplication->getApplication()->getName() . '"'
        );

        return true;
    }

    /**
     * Set active-flag for users application
     * @param string $applicationId
     * @param string $userId
     * @param bool $active
     * @return bool
     */
    protected function setUserApplicationActive($applicationId, $userId, $active)
    {
        if (!($userApplication = $this->getUserApplication($applicationId, $userId))) {
            return false;
        }
        $userApplication->setActive($active ? 1 : 0);
        if (!$this->databaseManager()->webservice()->userApplication()->saveUserApplication($userApplication)) {
            $this->addErrors($userApplication);

            return false;
        }
        $this->addSuccess(
            'User "' . $userApplication->getUser()->getUsername() . '" successfully set to ' . ($active ? 'active' : 'inactive') . ' for application "' . $userApplication->getApplication()->getName() . '"'
        );

        return true;
    }

    /**
     * Get user application roles
     *
     * @param string $userApplicationId
     * @return boolean|array
     */
    protected function getUserApplicationRoles($userApplicationId)
    {
        if (!($userApplication = $this->databaseManager()->webservice()->userApplication()->getUserApplicationById($userApplicationId))) {
            return false;
        }

        return $userApplication->getRoles();
    }

    /**
     * Add role to users application
     *
     * @param string $userApplicationId
     * @param string $roleId
     */
    protected function addUserApplicationRole($userApplicationId, $roleId)
    {
        if (!($userApplication = $this->databaseManager()->webservice()->userApplication()->getUserApplicationById($userApplicationId))) {
            $this->addError('User application not found');

            return false;
        }
        if (!($role = $this->databaseManager()->webservice()->role()->getRoleById($roleId))) {
            $this->addError('Role not found');

            return false;
        }
        if (!$userApplication->getApplication()->hasRole($role)) {
            $this->addError('Role "' . $role->getName() . '" is not linked to application');

            return false;
        }
        if ($userApplication->hasRole($role)) {
            $this->addError('Role "' . $role->getName() . '" is already linked to users application');

            return false;
        }
        $userApplicationRole = new Type\UserApplicationRole($this->validator());
        $userApplicationRole->setRole($role)->setUserApplication($userApplication)->setActive(1)->generateId();
        if (!$this->webServiceDb()->userApplicationRole()->addUserApplicationRoles(array($userApplicationRole))) {
            $this->addErrors($userApplicationRole);

            return false;
        }
        $this->addSuccess('User "' . $userApplication->getUser()->getUsername() . '" successfully linked to applications role "' . $userApplicationRole->getName() . '"');

        return true;
    }

    /**
     * Get user application link
     *
     * @param string $applicationId
     * @param string $userId
     * @return boolean|Type\UserApplication
     */
    protected function getUserApplication($applicationId, $userId)
    {
        if (!($user = $this->webServiceDb()->user()->getUserById($userId))) {
            $this->addError('User not found');

            return false;
        }
        if (!($application = $this->webServiceDb()->application()->getApplicationById($applicationId))) {
            $this->addError('Application not found');

            return false;
        }
        if (!($userApplication = $this->webServiceDb()->userApplication()->getUserApplication($user, $application))) {
            $this->addError('User "' . $user->getUsername() . '" not linked to application "' . $application->getName() . '"');

            return false;
        }

        return $userApplication;
    }

    /**
     *
     * @return DatabaseManager
     */
    protected function databaseManager()
    {
        return null !== $this->databaseManager ? $this->databaseManager : ($this->databaseManager = $this->get('service_database_manager'));
    }

    /**
     * @return \Sso\WebserviceBundle\Database\Webservice\Manager
     */
    protected function webServiceDb()
    {
        return $this->databaseManager()->webservice();
    }

    /**
     * Validator
     *
     * @return \Symfony\Component\Validator\Validator\LegacyValidator
     */
    protected function validator()
    {
        return $this->container->get('validator');
    }

    /**
     * Set errors from model
     *
     * @param \Sso\WebserviceBundle\Entity\Webservice\Type\Base $model
     */
    protected function addErrors(Type\Base $model)
    {
        foreach ($model->errors()->getErrors() as $error) {
            $this->addError($error->longMessage ? $error->longMessage : $error->shortMessage);
        }
    }

    /**
     * Add error message to frontend
     *
     * @param string $message
     */
    protected function addError($message)
    {
        $this->get('session')->getFlashBag()->add('error', $message);
    }

    /**
     * Add success message to frontend
     *
     * @param string $message
     */
    protected function addSuccess($message)
    {
        $this->get('session')->getFlashBag()->add('success', $message);
    }

    /**
     * Add info message to frontend
     *
     * @param string $message
     */
    protected function addInfo($message)
    {
        $this->get('session')->getFlashBag()->add('info', $message);
    }
}
