<?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  2017 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace Sso\WebserviceBundle\FeatureToggle;

use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RequestContext;

/**
 * Class FeatureToggle
 *
 * @copyright  2017 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 * @package Sso\WebserviceBundle\FeatureToggle
 */
class FeatureToggle
{
    /**
     * @var array
     */
    private $enabledFeatures;

    /**
     * @var RequestContext
     */
    private $context;

    /**
     * @var RequestStack
     */
    private $requestStack;

    /**
     * @var ExpressionLanguage
     */
    private $expressionLanguage;

    /**
     * @var ExpressionFunctionProviderInterface[]
     */
    private $expressionLanguageProviders = array();

    /**
     * FeatureToggle constructor.
     * @param array $enabledFeatures
     * @param RequestContext $context
     * @param RequestStack $requestStack
     */
    public function __construct(array $enabledFeatures, RequestContext $context, RequestStack $requestStack)
    {
        $this->enabledFeatures = $enabledFeatures;
        $this->context = $context;
        $this->requestStack = $requestStack;
    }

    /**
     * @param string $feature
     * @return bool
     */
    public function isActive($feature)
    {
        return isset($this->enabledFeatures[$feature]) && $this->isEnabled($feature, $this->enabledFeatures[$feature]);
    }

    /**
     * @return array
     */
    public function toArray()
    {
        $features = [];
        foreach ($this->enabledFeatures as $feature => $condition) {
            if ($this->isEnabled($feature, $condition)) {
                $features[] = $feature;
            }
        }
        return $features;
    }

    /**
     * @param string $feature
     * @param string|bool $condition
     * @return bool
     */
    private function isEnabled($feature, $condition)
    {
        return
            true === $condition ||
            $this->getExpressionLanguage()->evaluate($condition, [
                'context' => $this->context,
                'request' => $this->requestStack->getCurrentRequest(),
            ]);
    }

    /**
     * @param ExpressionFunctionProviderInterface $provider
     */
    public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
    {
        $this->expressionLanguageProviders[] = $provider;
    }

    /**
     * @return ExpressionLanguage
     */
    private function getExpressionLanguage()
    {
        if (null === $this->expressionLanguage) {
            if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
                throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
            }
            $this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders);
        }

        return $this->expressionLanguage;
    }
}
