<?php
namespace Newland\Toubiz\Poi\Neos\ViewHelpers\Collection\Attributes;

/*
 * This file is part of the "toubiz-poi-neos" package.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 */


use Newland\Toubiz\Sync\Neos\EmptyCheck;
use Newland\Toubiz\Sync\Neos\Service\AttributeCollection;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;

/**
 * Class NotAllEmptyViewHelper
 *
 * @package Newland\Toubiz\Poi\Neos\ViewHelpers\Collection\Attributes
 *
 * This view helper simplifies the decision if a number of attribute collections has any content to render.
 * Since attribute collections can contain different attribute types they need different logic to decide if they
 * should be considered empty.
 *
 * Use <f:then> / <f:else> children just like with <f:if> view helpers.
 *
 * Example:
 *
 * (note that real strings can also be passed inside the `string` array parameter)
 *
 * <poi:collection.attributes.notAllEmpty
 *     arrays="{
 *         0: article.flatAttributes.properties,
 *         1: article.flatAttributes.crossCountryTechnique
 *     }"
 *     strings="{
 *         0: article.flatAttributes.equipment,
 *         1: article.description
 *     }"
 *     integers="{
 *         0: article.flatAttributes.conditionRating,
 *         1: article.flatAttributes.techniqueRating,
 *         2: article.flatAttributes.experienceRating,
 *         3: article.flatAttributes.landscapeRating
 *     }">
 *         <div>my content that will be rendered if at least 1 attribute collection is not empty</div>
 * </poi:collection.attributes.notAllEmpty>
 */
class NotAllEmptyViewHelper extends AbstractConditionViewHelper
{
    public function initializeArguments(): void
    {
        $this->registerArgument(
            'arrays',
            'array',
            'Attribute collections that need at least 1 item to not be considered empty.',
            false,
            []
        );
        $this->registerArgument(
            'strings',
            'array',
            'Attribute collections that need at least 1 string that is not empty to not be considered empty.',
            false,
            []
        );
        $this->registerArgument(
            'integers',
            'array',
            'Attribute collections that need at least 1 value to be larger than 0 to not be considered empty.',
            false,
            []
        );
        $this->registerArgument(
            'objects',
            'array',
            'Attribute collections that need at least 1 object that is not null to not be considered empty.',
            false,
            []
        );
        $this->registerArgument(
            'booleans',
            'array',
            'Attribute collections that need at least 1 true value to not be considered empty.',
            false,
            []
        );
    }

    protected static function evaluateCondition($arguments = null): bool
    {

        /** @var AttributeCollection $array */
        foreach ($arguments['arrays'] as $array) {
            if ($array !== null && !empty($array->getData())) {
                return true;
            }
        }

        /** @var AttributeCollection|string $string */
        foreach ($arguments['strings'] as $string) {
            if ($string instanceof AttributeCollection && $string->__toString() !== '') {
                return true;
            }

            if (is_string($string) && $string !== '') {
                return true;
            }
        }

        /** @var AttributeCollection $integer */
        foreach ($arguments['integers'] as $integer) {
            if ($integer !== null && $integer->getIntValue() > 0) {
                return true;
            }
        }

        /** @var AttributeCollection $bool */
        foreach ($arguments['booleans'] as $bool) {
            if ($bool !== null && $bool->getBoolValue()) {
                return true;
            }
        }

        /** @var EmptyCheck $object */
        foreach ($arguments['objects'] as $object) {
            if (!($object instanceof EmptyCheck)) {
                throw new \InvalidArgumentException(
                    'All objects passed as objects argument must implement ' . EmptyCheck::class
                );
            }
            if (!$object->isEmpty()) {
                return true;
            }
        }

        return false;
    }

    public function render(): string
    {
        if (self::evaluateCondition($this->arguments)) {
            return $this->renderThenChild();
        }

        return $this->renderElseChild();
    }
}
