<?php declare(strict_types=1);
namespace Newland\NeosViewHelpers\ViewHelpers\Format;

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

use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;

class HumanReadableListViewHelper extends AbstractViewHelper
{
    use CompileWithRenderStatic;

    protected $escapeOutput = false;

    public function initializeArguments(): void
    {
        parent::initializeArguments();
        $this->registerArgument('each', 'array', 'The array or \SplObjectStorage to iterated over', true);
        $this->registerArgument('as', 'string', 'The name of the iteration variable', true);
        $this->registerArgument('key', 'string', 'Variable to assign array key to', false);
        $this->registerArgument('reverse', 'boolean', 'If TRUE, iterates in reverse', false, false);
        $this->registerArgument(
            'iteration',
            'string',
            'The name of the variable to store iteration information (index, cycle, isFirst, isLast, isEven, isOdd)'
        );
        $this->registerArgument('glue', 'string', 'The seperator between list items', false, ', ');
    }

    public static function renderStatic(
        array $arguments,
        \Closure $renderChildrenClosure,
        RenderingContextInterface $renderingContext
    ): string {
        $templateVariableContainer = $renderingContext->getVariableProvider();
        if (!isset($arguments['each'])) {
            return '';
        }
        if (is_object($arguments['each']) && !$arguments['each'] instanceof \Traversable) {
            throw new Exception(
                'ForViewHelper only supports arrays and objects implementing \Traversable interface',
                1248728393
            );
        }
        if ($arguments['reverse']) {
            // array_reverse only supports arrays
            if (is_object($arguments['each'])) {
                /** @var \Traversable $each */
                $each = $arguments['each'];
                $arguments['each'] = iterator_to_array($each);
            }
            $arguments['each'] = array_reverse($arguments['each'], true);
        }
        $cycle = 1;
        $count = count($arguments['each']);
        $iterationData = [
            'index' => 0,
            'cycle' => $cycle,
            'total' => $count,
        ];

        $output = '';
        foreach ($arguments['each'] as $keyValue => $singleElement) {
            $templateVariableContainer->add($arguments['as'], $singleElement);
            if (isset($arguments['key'])) {
                $templateVariableContainer->add($arguments['key'], $keyValue);
            }
            $isLast = $cycle === $count;
            if (isset($arguments['iteration'])) {
                $iterationData['isFirst'] = $iterationData['cycle'] === 1;
                $iterationData['isLast'] = $isLast;
                $iterationData['isEven'] = $iterationData['cycle'] % 2 === 0;
                $iterationData['isOdd'] = !$iterationData['isEven'];
                $templateVariableContainer->add($arguments['iteration'], $iterationData);
                $iterationData['index']++;
                $iterationData['cycle'] = $cycle;
            }
            $cycle++;
            $output .= trim($renderChildrenClosure()) . ($isLast ? '' : $arguments['glue']);
            $templateVariableContainer->remove($arguments['as']);
            if (isset($arguments['key'])) {
                $templateVariableContainer->remove($arguments['key']);
            }
            if (isset($arguments['iteration'])) {
                $templateVariableContainer->remove($arguments['iteration']);
            }
        }

        return $output;
    }
}
