<?php declare(strict_types=1);
namespace Newland\NeosFiltering\Traits;

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

use Neos\FluidAdaptor\View\StandaloneView;
use Newland\Contracts\Neos\Filter\FilterRoot;
use Newland\Contracts\Neos\Filter\QueryBoundFilterItem;
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\NodeInterface;

/**
 * Common behaviour that helps implement the `FilterItem` interface.
 */
trait FilterItemCommon
{
    /** @var string */
    protected $id;

    /** @var mixed */
    protected $state;

    /** @var NodeInterface */
    protected $node;

    /** @var string */
    protected $renderableName;

    /** @var array */
    protected $viewAssignments = [];

    /** @var FilterRoot */
    protected $root;

    /** @var array */
    protected $configuration = [];

    /** @var string[][] */
    protected $templateRootPaths = [
        'templateRootPaths' => [],
        'layoutRootPaths' => [],
        'partialRootPaths' => [],
    ];

    public function addTemplateRootPaths(
        array $templateRootPaths = [],
        array $layoutRootPaths = [],
        array $partialRootPaths = []
    ): void {
        $this->templateRootPaths['templateRootPaths'] = array_merge(
            $this->templateRootPaths['templateRootPaths'],
            $templateRootPaths
        );
        $this->templateRootPaths['layoutRootPaths'] = array_merge(
            $this->templateRootPaths['layoutRootPaths'],
            $layoutRootPaths
        );
        $this->templateRootPaths['partialRootPaths'] = array_merge(
            $this->templateRootPaths['partialRootPaths'],
            $partialRootPaths
        );
    }

    public function setConfiguration(array $configuration): void
    {
        $this->configuration = $configuration;
    }

    public function getConfiguration(): array
    {
        return $this->configuration;
    }

    public function getId(): string
    {
        if ($this->id === null) {
            if ($this instanceof QueryBoundFilterItem) {
                $this->id = 'filter-' . $this->getQueryString();
            } else {
                $this->id = 'filter-' . md5((string) random_int(0, 99999));
            }
        }
        return $this->id;
    }

    public function setId(string $id): void
    {
        $this->id = $id;
    }


    public function setState($state): void
    {
        $this->state = $state;
    }

    public function getState()
    {
        return $this->state;
    }

    /**
     * Sets the parsed RootNode which must be handled by this Renderable. In the
     * default implementation these nodes are evaluated by render() and extracted
     * by the NodeConverter
     *
     * @param NodeInterface $node
     * @return void
     */
    public function setNode(NodeInterface $node): void
    {
        $this->node = $node;
    }

    public function getNode(): NodeInterface
    {
        return $this->node;
    }

    /**
     * Returns the name of this Renderable - name must also be passed in constructor.
     * Implementations must always return a non-empty string even if setName() is not
     * called to set the specific name.
     *
     * @return string
     */
    public function getName(): string
    {
        return $this->renderableName;
    }

    /**
     * Setter for the name of this Renderable.
     *
     * @param string $name
     * @return void
     */
    public function setName($name): void
    {
        $this->renderableName = $name;
    }

    protected function initializeView(
        array $additionalTemplateRootPaths = [],
        array $additionalLayoutRootPaths = [],
        array $additionalPartialRootPaths = []
    ): StandaloneView {
        $view = new StandaloneView();
        $view->setTemplateRootPaths(
            array_merge(
                $this->templateRootPaths['templateRootPaths'],
                $additionalTemplateRootPaths,
                [ 'resource://Newland.NeosFiltering/Private/Templates' ]
            )
        );
        $view->setLayoutRootPaths(
            array_merge(
                $this->templateRootPaths['layoutRootPaths'],
                $additionalLayoutRootPaths,
                [ 'resource://Newland.NeosFiltering/Private/Layouts' ]
            )
        );
        $view->setPartialRootPaths(
            array_merge(
                $this->templateRootPaths['partialRootPaths'],
                $additionalPartialRootPaths,
                [ 'resource://Newland.NeosFiltering/Private/Partials' ]
            )
        );
        $view->assignMultiple($this->viewAssignments);

        $view->assignMultiple(
            [
                'id' => $this->getId(),
                'state' => $this->state,
                'node' => $this->node,
                'configuration' => $this->configuration,
            ]
        );
        return $view;
    }

    public function getRoot(): FilterRoot
    {
        return $this->root;
    }

    public function setRoot(FilterRoot $root): void
    {
        $this->root = $root;
    }


    public function __toString(): string
    {
        return static::class;
    }
}
