<?php
/**
 * ValidExpression Validator
 *
 * @author Elze Kool <info@visualmedia.nl>
 */

namespace VisualM\TagManagerBundle\Validator\Constraints;

use Exception;
use RuntimeException;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use VisualM\TagManagerBundle\Util\ExtendedDataDictionary;

/**
 * ValidExpression Constraint
 *
 * @Annotation
 * 
 * @author Elze Kool <info@visualmedia.nl>
 */
class ValidExpressionValidator extends ConstraintValidator
{
    /**
     * Valid Field names
     * @var array
     */
    protected $fieldNames = [];

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


    /**
     * Constructor
     * 
     * @param ExtendedDataDictionary $dataDictionary     Data Dictionary
     * @param ExpressionLanguage     $expressionLanguage ExpressionLanguage
     */
    public function __construct(ExtendedDataDictionary $dataDictionary, ExpressionLanguage $expressionLanguage)
    {
        // The ExpressionLanguage needs a list of valid variabele names
        // so extract them from the data dictionary
        $field_names = [];
        foreach($dataDictionary->getAvailableFields() as $field) {
            $field_names[] = strtok($field, '.');
        }
        $this->fieldNames = array_unique($field_names);
        $this->expressionLanguage = $expressionLanguage;
    }

    /**
     * {@inheritdoc}
     */
    public function validate($value, Constraint $constraint)
    {
        if (empty($constraint->valueFunc)) {
            throw new RuntimeException(sprintf("valueFunc is not provided for %s", get_class($this)));
        }

        if (empty($constraint->enabledFunc)) {
            throw new RuntimeException(sprintf("enabledFunc is not provided for %s", get_class($this)));
        }

        if (empty($constraint->target)) {
            throw new RuntimeException(sprintf("target is not provided for %s", get_class($this)));
        }

        if ($value->{$constraint->enabledFunc}() !== true) {
            return;
        }

        try {           
            $this->expressionLanguage->compile($value->{$constraint->valueFunc}(), $this->fieldNames);
        } catch (Exception $ex) {
            $this->context->addViolationAt(
                $constraint->target,
                $constraint->message,
                array('%expr_error%' => $ex->getMessage())
            );
        }
    }
}
