<?php
/**
 * phpDocumentor
 *
 * PHP Version 5.3
 *
 * @copyright 2010-2014 Mike van Riel / Naenius (http://www.naenius.com)
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Plugin\Core\Descriptor\Validator\Constraints\Functions;

use phpDocumentor\Descriptor\Collection;
use phpDocumentor\Descriptor\Interfaces\TypeInterface;
use phpDocumentor\Descriptor\MethodDescriptor;
use phpDocumentor\Descriptor\FunctionDescriptor;
use phpDocumentor\Descriptor\Tag\ParamDescriptor;
use phpDocumentor\Descriptor\Type\UnknownTypeDescriptor;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;

/**
 * Validates whether the type for a param tag with a Method or Function is not a known default.
 *
 * Whenever this validator triggers then it means that someone forgot to replace the pseudo type generated by the IDE
 * with the real type for the given parameter.
 */
class IsParamTypeNotAnIdeDefaultValidator extends ConstraintValidator
{
    /**
     * @see \Symfony\Component\Validator\ConstraintValidatorInterface::validate()
     */
    public function validate($value, Constraint $constraint)
    {
        if (! $value instanceof MethodDescriptor && ! $value instanceof FunctionDescriptor) {
            throw new ConstraintDefinitionException(
                'The Functions\IsParamTypeNotAnIdeDefault validator may only be used on function or method objects'
            );
        }

        $params = $value->getParam();

        foreach ($params as $param) {
            if (! $param instanceof ParamDescriptor) {
                continue;
            }

            /** @var UnknownTypeDescriptor[]|Collection $types */
            $types = $param->getTypes();
            foreach ($types as $type) {
                if (! $this->isTypeAnIdeDefault($type)) {
                    continue;
                }

                $this->context->addViolationAt(
                    'params',
                    $constraint->message,
                    array($param->getVariableName(), $value->getFullyQualifiedStructuralElementName()),
                    null,
                    null,
                    $constraint->code
                );
            }
        }
    }

    /**
     * Verifies if this type is a possible IDE default.
     *
     * @param UnknownTypeDescriptor|TypeInterface $type
     *
     * @return bool
     */
    private function isTypeAnIdeDefault(TypeInterface $type)
    {
        return $type->getName() === '\\type' || $type->getName() === '\\unknown';
    }
}
