<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonCommon\Components;

use Shopware\Plugins\ViisonCommon\Classes\Exceptions\ValidationExceptions;

/**
 * The ParameterValidator provides several assertion methods to validate the parameter values of a request.
 *
 * The idea is to safe you a bunch of if-statements when validating the parameters of a request.
 *
 * Pro tip: Use this in backend controllers together with the trait
 * Shopware\Plugins\ViisonCommon\Classes\ExceptionHandling\BackendExceptionHandling. In this case the exceptions thrown by
 * the assertion methods are caught and shown localized to the user.
 */
class ParameterValidator
{
    /**
     * @param mixed $actualValue The actual value to apply the assertion to.
     * @param string $parameterName The name of the request parameter to be validated.
     * @throws ValidationExceptions\ParameterMissingException If $actualValue === null
     * @throws ValidationExceptions\ParameterHasWrongFormatException If the $actualValue is not an array.
     */
    public static function assertIsArray($actualValue, $parameterName)
    {
        if ($actualValue === null) {
            throw new ValidationExceptions\ParameterMissingException($parameterName);
        }
        if (!is_array($actualValue)) {
            throw new ValidationExceptions\ParameterHasWrongFormatException($parameterName, 'array');
        }
    }

    /**
     * @param array $targetArray The array to assert an element of.
     * @param mixed $key The key of the value in the $targetArray to apply the assertion to.
     * @param string|null $parameterName The name of the request parameter to be validated, if null, $key is used.
     * @throws ValidationExceptions\ParameterMissingException If $targetArray[$key] is not an array.
     */
    public static function assertArrayElementIsArray(array $targetArray, $key, $parameterName = null)
    {
        if (!isset($targetArray[$key])) {
            throw new ValidationExceptions\ParameterMissingException($parameterName ?: $key);
        }
        self::assertIsArray($targetArray[$key], $key);
    }

    /**
     * @param mixed $actualValue The actual value to apply the assertion to.
     * @param string $parameterName The name of the request parameter to be validated.
     * @throws ValidationExceptions\ParameterMissingException If $actualValue === null
     * @throws ValidationExceptions\ParameterHasWrongFormatException If the $actualValue is not an integer.
     */
    public static function assertIsInteger($actualValue, $parameterName)
    {
        if ($actualValue === null) {
            throw new ValidationExceptions\ParameterMissingException($parameterName);
        }
        if (!is_numeric($actualValue) || !is_int($actualValue + 0)) {
            throw new ValidationExceptions\ParameterHasWrongFormatException($parameterName, 'integer');
        }
    }

    /**
     * @param mixed $actualValue The actual value to apply the assertion to.
     * @param string $parameterName The name of the request parameter to be validated.
     * @throws ValidationExceptions\ParameterMissingException If $actualValue === null
     * @throws ValidationExceptions\ParameterHasWrongFormatException If the $actualValue is not a number (float or int).
     */
    public static function assertIsNumber($actualValue, $parameterName)
    {
        if ($actualValue === null) {
            throw new ValidationExceptions\ParameterMissingException($parameterName);
        }
        if (!is_numeric($actualValue)) {
            throw new ValidationExceptions\ParameterHasWrongFormatException($parameterName, 'number');
        }
    }

    /**
     * @param array $targetArray The array to assert an element of.
     * @param mixed $key The key of the value in the $targetArray to apply the assertion to.
     * @param string|null $parameterName The name of the request parameter to be validated, if null, $key is used.
     * @throws ValidationExceptions\ParameterMissingException If $targetArray[$key] === null
     */
    public static function assertArrayElementIsInteger(array $targetArray, $key, $parameterName = null)
    {
        if (!isset($targetArray[$key])) {
            throw new ValidationExceptions\ParameterMissingException($parameterName ?: $key);
        }
        self::assertIsInteger($targetArray[$key], $key);
    }

    /**
     * @param array $targetArray The array to assert an element of.
     * @param mixed $key The key of the value in the $targetArray to apply the assertion to.
     * @param string|null $parameterName The name of the request parameter to be validated, if null, $key is used.
     * @throws ValidationExceptions\ParameterMissingException If $targetArray[$key] === null
     */
    public static function assertArrayElementIsNumber(array $targetArray, $key, $parameterName = null)
    {
        if (!isset($targetArray[$key])) {
            throw new ValidationExceptions\ParameterMissingException($parameterName ?: $key);
        }
        self::assertIsNumber($targetArray[$key], $key);
    }

    /**
     * @param mixed $actualValue The actual value to apply the assertion to.
     * @param string $parameterName The name of the request parameter to be validated.
     * @throws ValidationExceptions\ParameterMissingException If $actualValue === null
     */
    public static function assertIsNotNull($actualValue, $parameterName)
    {
        if ($actualValue === null) {
            throw new ValidationExceptions\ParameterMissingException($parameterName);
        }
    }

    /**
     * Asserts that the given value is a not empty string.
     *
     * Remark: We do not check strictly for the parameter type string, hence an integer value 0 is considered a not
     * empty string.
     *
     * @param mixed $actualValue The actual value to apply the assertion to.
     * @param string $parameterName The name of the request parameter to be validated.
     * @throws ValidationExceptions\ParameterMissingException If $actualValue === null or empty string
     */
    public static function assertIsNotEmptyString($actualValue, $parameterName)
    {
        if ($actualValue === null || $actualValue === '') {
            throw new ValidationExceptions\ParameterMissingException($parameterName);
        }
    }

    /**
     * @param array $targetArray The array to assert an element of.
     * @param mixed $key The key of the value in the $targetArray to apply the assertion to.
     * @param string|null $parameterName The name of the request parameter to be validated, if null, $key is used.
     * @throws ValidationExceptions\ParameterMissingException If $targetArray[$key] === null
     */
    public static function assertArrayElementIsNotNull(array $targetArray, $key, $parameterName = null)
    {
        if (!isset($targetArray[$key])) {
            throw new ValidationExceptions\ParameterMissingException($parameterName ?: $key);
        }
    }

    /**
     * @param mixed $entity The value to check whether it is an entity.
     * @param string $modelClassName Name of the entity's model class
     * @param int $entityId Id of the entity that was requested
     * @param string $parameterName The name of the checked request parameter.
     * @throws ValidationExceptions\EntityNotFoundException If $entity === null or \get_class($entity is n
     */
    public static function assertEntityFound($entity, $modelClassName, $entityId, $parameterName)
    {
        if ($entity === null || !is_object($entity)) {
            throw new ValidationExceptions\EntityNotFoundException($parameterName, $modelClassName, $entityId);
        }
    }

    /**
     * @param mixed $entity The entity to check whether it has an attribute model.
     * @param string $modelClassName Name of the entity's model class
     * @param int $entityId Id of the entity that was requested
     * @param string $parameterName The name of the checked request parameter.
     * @throws ValidationExceptions\AttributeNotFoundException If $entry has no method getAttribute or it returns null.
     */
    public static function assertAttributeExists($entity, $modelClassName, $entityId, $parameterName)
    {
        self::assertEntityFound($entity, $modelClassName, $entityId, $parameterName);
        if (!method_exists($entity, 'getAttribute') || $entity->getAttribute() === null) {
            throw new ValidationExceptions\AttributeNotFoundException($parameterName, $modelClassName, $entityId);
        }
    }
}
