<?php

namespace Internetgalerie\IgDatapoolFe\ViewHelpers;

use Exception;
use Internetgalerie\IgDatapoolFe\Utility\NeedfulThings;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;


/**
 * FormViewHelper
 */
class FormViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper
{
    /**
     * Current aggregate we're filling up
     *
     * @var AggregateInterface
     */
    public static $curAggregate = null;

    /**
     * Saves an reference to the current form being rendered
     *
     * @var FormViewHelper
     */
    public static $curForm = null;
    /**
     * Stores references to child elements
     *
     * @var array
     */
    protected $children = [];

    /**
     * TabsAsSteps: currentStep
     */
    protected $currentStep = 0;


    /**
     * Base Class for the wrapper div
     * Override this to add searchform
     */
    protected $divBaseClass = ['dp-form']; // ,'ym-grid'

    protected function getRequest(): ?ServerRequestInterface
    {
        $request = null;
        if ($this->renderingContext->hasAttribute(ServerRequestInterface::class)) {
            $request = $this->renderingContext->getAttribute(ServerRequestInterface::class);
        }
        return $request;
    }

    /**
     * Initialize arguments.
     *
     * @return void
     */
    public function initializeArguments(): void
    {
        parent::initializeArguments();
        $this->registerArgument('labelPosition', 'string', 'The position of the Field-Labels', false, 'left');
        $this->registerArgument('labelExtensionName', 'string', 'extension name for labels of fieldWrapper', false);
        $this->registerArgument('labelTableName', 'string', 'table name for labels of fieldWrapper', false);

        $this->registerArgument('formAction', 'string', 'If Tabs as steps: call this action, if were rendering a step.');
        $this->registerArgument('dbAction', 'string', 'If Tabs as steps: call this action, if we want to insert/update the data.');
        $this->registerArgument('clone', 'bool', 'If set the Hidden Identity Field is not set, can be used to clone simple objects (relations are not copied)', false, false);
    }

    /**
     * Render the form.
     *
     * @return string rendered form
     */
    public function render(): string
    {
        self::$curForm = $this;
        self::$curAggregate = $this;
        $class = $this->tag->getAttribute('class');

        /*
        if (\Internetgalerie\IgDatapoolFe\Controller\ActionController::$currentObjectClass == '') {
            throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception(
                'DataPool Form not properly initialized!
            Please inherit your controller from "\\Internetgalerie\\IgDatapoolFe\\Controller\\ActionController"!
            Or did you overwrite initializeAction and forget to call the parent Method?'
            );
        }
        */
        if ($this->isStepForm()) {
            if (!$this->hasArgument('formAction') || !$this->hasArgument('dbAction')) {
                throw new Exception('Bitte formAction und dbAction angeben! z.B. <... formAction="edit" dbAction="update" ...>');
            }
            // In case of steps...
            $request = $this->getRequest();
            $this->currentStep = ($request instanceof \TYPO3\CMS\Extbase\Mvc\Request && $request->hasArgument('step')) ? (int)$request->getArgument('step') : 0;
            $this->templateVariableContainer->add('tabsAsSteps', true);
        }


        // set class attribute
        // In Fluid v4, unregistered attributes like 'class' go to $this->additionalArguments
        $classArg = $this->additionalArguments['class'] ?? $this->arguments['class'] ?? '';
        if ($classArg) {
            $classes = array_unique(array_merge($this->divBaseClass, GeneralUtility::trimExplode(' ', $classArg, true)));
        } else {
            $classes = $this->divBaseClass;
        }
        if ($this->isStepForm()) {
            $classes[] = 'dp-form-stepsform';
            if (TabViewHelper::$tabCount == 0) {
                throw new Exception('TabsAsSteps benötigt mindestens tabNavigation und mindestens ein tab!');
            }
        }
        if (TabViewHelper::$tabCount > 0) {
            $classes[] = 'dp-form-hasTabs';
        }
        $classes[] = 'dp-form-layout-' . $this->arguments['labelPosition'];
        if ($this->hasError()) {
            $classes[] = 'dp-form-has-errors';
        }
        $class = implode(' ', $classes);
        //$this->arguments['class'] = $class;
        $this->tag->addAttribute('class', $class);
        //$class = $this->tag->getAttribute('class');

        //$this->viewHelperVariableContainer->add(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'currentFormObject',  $this);
        $formConfig = [
            'labelExtensionName' => $this->arguments['labelExtensionName'],
            'labelTableName' => $this->arguments['labelTableName'],
        ];
        $this->viewHelperVariableContainer->add(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formConfig', $formConfig);

        if (!$this->viewHelperVariableContainer->exists(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formClass')) {
            $this->viewHelperVariableContainer->add(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formClass', self::class);
            $out = $this->parentRender(self::class);
            $this->viewHelperVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formClass');
        } else {
            $out = $this->parentRender($this->viewHelperVariableContainer->get(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formClass'));
        }
        $this->viewHelperVariableContainer->remove(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formConfig');

        return $out;
        //return '<div class="' . implode(' ', $classes) . '">' . $out . '</div>';
    }

    /**
     * Inject the hidden fields
     */
    public function parentRender($formClass)
    {
        $this->setFormActionUri();
        if (strtolower((string) $this->arguments['method']) === 'get') {
            $this->tag->addAttribute('method', 'get');
        } else {
            $this->tag->addAttribute('method', 'post');
        }
        $this->addFormObjectNameToViewHelperVariableContainer();
        $this->addFormObjectToViewHelperVariableContainer();
        $this->addFieldNamePrefixToViewHelperVariableContainer();
        $this->addFormFieldNamesToViewHelperVariableContainer();
        $formContent = $this->renderChildren();

        if ($this->arguments['hiddenFieldClassName'] !== null) {
            $content = chr(10) . '<div class="' . htmlspecialchars((string) $this->arguments['hiddenFieldClassName']) . '">';
        } else {
            $content = chr(10) . '<div>';
        }

        if (!$this->arguments['clone']) {
            $content .= $this->renderHiddenIdentityField($this->arguments['object'], $this->getFormObjectName());
        }
        $content .= $this->renderAdditionalIdentityFields();
        if ($formClass!=SearchFormViewHelper::class) {
            $content .= $this->renderHiddenReferrerFields();
        }
        /*
          TODO:DADADADA
        if (&&$this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper') === FALSE ) {
            // Render hmac after everything else has been rendered
            $content .= $this->renderRequestHashField();
        } else {
            // Render the trusted list of all properties after everything else has been rendered
            if(!$this->isSearchForm())
                $content .= $this->renderTrustedPropertiesField();
        }
        */

        // Render the trusted list of all properties after everything else has been rendered
        //if(!$this->isSearchForm())
        if ($formClass!=SearchFormViewHelper::class) {
            $content .= $this->renderTrustedPropertiesField();
        }

        $content .= chr(10) . '</div>' . chr(10);
        $content .= $formContent;

        //edit MB:
        $content .= $this->buildHiddenSearchFields();
        $content .= $this->buildHiddenStepFields();
        //end edit MB

        $this->tag->setContent($content);
        $this->removeFieldNamePrefixFromViewHelperVariableContainer();
        $this->removeFormObjectFromViewHelperVariableContainer();
        $this->removeFormObjectNameFromViewHelperVariableContainer();
        $this->removeFormFieldNamesFromViewHelperVariableContainer();
        $this->removeCheckboxFieldNamesFromViewHelperVariableContainer();
        return $this->tag->render();
    }

    /**
     * Is it a tabAsStep form
     *
     * @return bool
     */
    public function isStepForm()
    {
        return $this->arguments['action'] == 'step';
    }

    /**
     * get the current step. Only works for tabsAsSteps Forms.
     *
     * @return int
     * @throws Exception
     */
    public function getCurrentStep()
    {
        if (!$this->isStepForm()) {
            throw new Exception('Called getCurrentStep on a non Step Form?');
        }
        return $this->currentStep;
    }


    /**
     * Check children for errorous fields
     *
     * @return bool;
     */
    public function hasError()
    {
        $error = false;
        foreach ($this->children as $child) {
            if ($child->hasError()) {
                $error = true;
            }
        }
        return $error;
    }

    public function _getFormName()
    {
        return $this->getFormObjectName();
    }

    protected function buildHiddenStepFields()
    {
        if (!$this->isStepForm()) {
            return '';
        }

        $hidden = '<input type="hidden" name="' . $this->prefixFieldName('formAction') . '" value="' . htmlspecialchars((string) $this->arguments['formAction']) . '" />';
        $hidden .= '<input type="hidden" name="' . $this->prefixFieldName('dbAction') . '" value="' . htmlspecialchars((string) $this->arguments['dbAction']) . '" />';
        return $hidden;
    }

    public function buildHiddenSearchFields()
    {
        $arguments = [];
        $request = $this->getRequest();
        $arguments = NeedfulThings::keepAndOverrideArgs($arguments, $request);
        $out = $this->getHiddenFieldsRec($arguments);
        return $out;
    }

    protected function getHiddenFieldsRec($arguments, $prefix = '')
    {
        $out = '';
        foreach ($arguments as $key => $el) {
            if (!is_array($el)) {
                $out .= '<input type="hidden" name="' . $this->prefixFieldName($prefix . '[' . $key . ']') . '" value="' . htmlspecialchars((string) $el) . '" />';
            } else {
                if (!$prefix) {
                    $newPrefix = $key;
                } else {
                    $newPrefix = $prefix . '[' . $key . ']';
                }
                $out .= $this->getHiddenFieldsRec($el, $newPrefix);
            }
        }
        return $out;
    }

    public function isSearchForm()
    {
        return false;
    }

    public function getVariableProvider()
    {
        return $this->templateVariableContainer;
    }
}
