<?php

namespace Internetgalerie\IgDatapoolFe\ViewHelpers;

use TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormViewHelper;
use TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\TagBuilder;
use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
use Internetgalerie\IgDatapoolFe\Utility\ReflectionUtility;
use TYPO3\CMS\Core\Page\AssetCollector;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
 * Wraps a form fields
 *
 * @api
 * @author     Markus Baumgartner, Daniel Abplanalp, Internetgalerie AG
 * @package    IgDatapoolFE
 * @subpackage ViewHelpers
 */
class FieldWrapperViewHelper extends AbstractFormViewHelper
{
    public static $fieldWrapperCount = 0;
    public $fieldWrapperFields=[];
    public $propertyNames=[];
    public $formConfig=[];
    public $extensionName = '';
    public $tableName = '';

    /**
     * ReflectionUtility
     *
     * @var ReflectionUtility
     */
    protected $reflectionUtility = null;

    /**
     * @param ReflectionUtility $reflectionUtility
     */
    public function injectReflectionUtility(ReflectionUtility $reflectionUtility): void
    {
        $this->reflectionUtility = $reflectionUtility;
    }


    /**
     * Initialize the arguments.
     *
     * @return void
     * @api
     */
    public function initializeArguments(): void
    {
        parent::initializeArguments();
        $this->registerArgument('class', 'string', 'Additional CSS Classes', false, '');
        $this->registerArgument('label', 'string', 'Force a custom label.', false, '');
        $this->registerArgument('labelByProperty', 'string', 'Label of this property from TCA', false, '');
        $this->registerArgument('labelTableName', 'string', 'table name', false, '');
        $this->registerArgument('extensionName', 'string', 'extension name', false, '');
        $this->registerArgument('required', 'bool', 'Is the field required', false, null);
        $this->registerArgument('showErrorMessage', 'bool', 'show messages of errors', false, false);
        $this->registerArgument('infoText', 'string', 'Display an Info-Text', false, '');
        $this->registerArgument('infoBubble', 'string', 'Display an Infobubble', false, '');

        $this->registerArgument('condition', 'string', 'Class of another fieldwrapper.');
        $this->registerArgument('conditionValues', 'string', 'Commaseparated list of values when to display it.');
        $this->registerArgument('conditionInvert', 'boolean', 'Inverts the condition, i.e. the field is shown if the value is NOT specified in conditionValue.', false, false);
        $this->registerArgument('conditionDisable', 'boolean', 'Only disable, don\'t hide.', false, false);
    }

    /**
     * Renders a field warpper with label, errormsg, info text etc.
     *
     * @throws Exception
     * @return string
     * @api
     */
    public function render()
    {
        self::$fieldWrapperCount++;
        //        parent::render();
        //self::$curFieldWrapper = $this;
        //the fieldobject is set as a variable,w hich we can use here

        $this->viewHelperVariableContainer->add(FormViewHelper::class, 'fieldWrapperFields', []);

        if ($this->viewHelperVariableContainer->exists(FormViewHelper::class, 'formConfig')) {
            $this->formConfig = $this->viewHelperVariableContainer->get(FormViewHelper::class, 'formConfig');
        } else {
            $this->formConfig = [];
        }

        $this->extensionName = $this->arguments['extensionName'];
        if (!$this->extensionName) {
            $this->extensionName = $this->formConfig['labelExtensionName'] ?? '';
        }
        $this->tableName = $this->arguments['labelTableName'];
        if (!$this->tableName) {
            $this->tableName = $this->formConfig['labelTableName'] ?? '';
        }


        $formFieldNames = $this->viewHelperVariableContainer->get(FormViewHelper::class, 'formFieldNames');
        $formFieldNamesCount  = count($formFieldNames);
        //$this->oldFormFieldNames=$formFieldNames;

        $renderedField = $this->renderChildren();
        $formFieldNames = $this->viewHelperVariableContainer->get(FormViewHelper::class, 'formFieldNames');

        $this->fieldWrapperFields = $this->viewHelperVariableContainer->get(FormViewHelper::class, 'fieldWrapperFields');
        $this->viewHelperVariableContainer->remove(FormViewHelper::class, 'fieldWrapperFields');


        $this->propertyNames = [];
        for (;$formFieldNamesCount < count($formFieldNames); $formFieldNamesCount++) {
            $fieldName = $formFieldNames[$formFieldNamesCount];
            $fieldNameSegments = explode('[', (string) $fieldName, 4);
            // only tx_myext[object][property] and not tx_myext[name]
            if (isset($fieldNameSegments[2])) {
                $propertyName = rtrim($fieldNameSegments[2], ']');
                $this->propertyNames[]=$propertyName;
            }
        };

        $labelClass = '';
        $classes = [];
        $classes[] = 'dp-fieldWrapper';
        $classes[] = $this->getFieldWrapperClass();
        if ($this->hasError()) {
            $classes[] = 'dp-fieldWrapper-error';
            $labelClass = 'dp-label-error';
        }

        $classes[] = 'ig-inline';
        $classes[] = 'ig-child-top';
        if ($this->hasArgument('class')) {
            $classes[] = $this->arguments['class'];
        }

        /**
         * The conditions
         */
        $conditionData = '';
        if ($this->arguments['condition'] != '') {
            $classes[] = 'dp-condition';

            $arr = [];
            $arr['condition'] = $this->arguments['condition'];
            $arr['values'] = GeneralUtility::trimExplode(',', $this->arguments['conditionValues'], true);
            $arr['invert'] = $this->arguments['conditionInvert'];
            $arr['disable'] = $this->arguments['conditionDisable'];
            $conditionData = (json_encode($arr));
        }

        $infoText = '';
        if ($this->hasArgument('infoText')) {
            $infoText = '<div class="dp-infoText">' . htmlspecialchars((string) $this->arguments['infoText']) . '</div>';
        }


        $required = (bool) $this->arguments['required'];

        //Render the Wrapper
        //add label
        $label = $this->getFieldLabel();
        $innerContent = '
<label class="dp-label ' . $labelClass . ' ig-inline">
	<a name="' . htmlspecialchars($this->getFieldWrapperClass()) . '"></a>' . htmlspecialchars($label) . ($required ? ' *' : '') . '
</label>';
        // for="' . ($this->field ? $this->field->getId() : '') . '"

        /*
        //Set the required flag, this is done via class for styling through css
        // working code for requiered - + tabs
        if (strtolower($this->arguments['required']) == 'true' || ($this->arguments['required'] == 'auto' && $this->field && \Internetgalerie\IgDatapoolFe\Utility\NeedfulThings::isRequiredByAnnotation($this->field->getProperty()))) {
            $isRequiredClass = 'dp-required-label-active';
            TabViewHelper::$hasRequiredFields = TRUE;
        }
            $innerContent .= '<label class="dp-required-label ' . $isRequiredClass . ' ig-inline" for="' . ($this->field ? $this->field->getId() : '') . '"></label>';
        */



        //infobubble
        $infoBubbleClass = $infoBubbleText = '';
        if ($this->arguments['infoBubble']) {
            $assetCollector = GeneralUtility::makeInstance(AssetCollector::class);
            $assetCollector->addStyleSheet('ig_datapool_fe_tooltipster', 'EXT:ig_datapool_fe/Resources/Public/Css/tooltipster.css');
            $assetCollector->addJavaScript('ig_datapool_fe_tooltipster', 'EXT:ig_datapool_fe/Resources/Public/JavaScript/jquery.tooltipster.js');
            $infoBubbleText = 'data-infobubble="' . htmlspecialchars((string) $this->arguments['infoBubble']) . '"';
            $infoBubbleClass = 'dp-fieldInfoWrapper-infobubble';
        }

        $innerContent .= '
<div class="dp-fieldInfoWrapper ig-inline ' . $infoBubbleClass . '" ' . $infoBubbleText . '>
' . $renderedField . '
' . $infoText . '
</div>
';
        if ($this->arguments['showErrorMessage'] && $this->hasError()) {
            $err = $this->getFlattenedErrors();
            $innerContent .= '<div class="ig-inline dp-errormsg">' . $err . '</div>';
        }


        /**
         * @var \TYPO3Fluid\Fluid\Core\ViewHelper\TagBuilder;
         */
        $tag = GeneralUtility::makeInstance(TagBuilder::class);
        $tag->setTagName('div');
        $tag->addAttribute('class', implode(' ', $classes));

        //data-condition
        if ($this->arguments['condition'] != '') {
            $tag->addAttribute('data-condition', $conditionData);
        }

        if ($this->hasArgument('additionalAttributes') && is_array($this->arguments['additionalAttributes'])) {
            $tag->addAttributes($this->arguments['additionalAttributes']);
        }
        $tag->setContent($innerContent);
        return $tag->render();
    }

    /**
     * generates the current ID
     *
     * @return string
     */
    protected function getFieldWrapperClass()
    {
        //if (!$this->field)
        return 'dp-fieldWrapper-' . self::$fieldWrapperCount;
        //return 'dp-fieldWrapper-' . $this->field->getNamePath('-');
    }

    /**
     * return the Label
     * this looks wwaaayyy too complicated
     *
     * @return string
     */
    protected function getFieldLabel()
    {
        $label = '';

        if ($this->hasArgument('label') && $this->arguments['label']) {
            $label = $this->arguments['label'];
        } elseif ($this->hasArgument('labelByProperty') && $this->arguments['labelByProperty']) {
            $propertyName = $this->arguments['labelByProperty'];
            $label=$this->reflectionUtility->getFieldLabelByProperty($this->renderingContext, $propertyName, $this->extensionName, $this->tableName);
        } else {
            $label=null;
            foreach ($this->propertyNames as $propertyName) {
                $label=$this->reflectionUtility->getFieldLabelByProperty($this->renderingContext, $propertyName, $this->extensionName, $this->tableName);
                break;
            }

            if ($label===null) {
                return 'ig_datapool_fe ERROR: FieldWrapper missing label or labelByProperty and no f:form or dp:form was found in fieldWrapper';
            }
        }
        return $label;
    }


    /**
     * Check children for erroneous fields
     *
     * @return bool;
     */
    public function hasError()
    {
        foreach ($this->propertyNames as $propertyName) {
            $mappingResultsForProperty=$this->reflectionUtility->getMappingResultsForProperty($this->renderingContext, $propertyName);
            if ($mappingResultsForProperty->hasErrors()) {
                return true;
            }
        }
        return false;

        /*
        foreach( $this->fieldWrapperFields as $field) {
            if (is_object($field)) {
                if($field->hasError()) {
                    return true;
                }
            }
        }
        return false;
        */
    }

    /**
     * Check children for erroneous fields
     *
     * @return bool;
     */
    public function getFlattenedErrors()
    {
        $errors=[];
        foreach ($this->propertyNames as $propertyName) {
            $mappingResultsForProperty=$this->reflectionUtility->getMappingResultsForProperty($this->renderingContext, $propertyName);
            if ($mappingResultsForProperty->hasErrors()) {
                $mappingResults = $mappingResultsForProperty->getFlattenedErrors();
                foreach ($mappingResults as $propertyPath => $mappingResultsForProperty) {
                    foreach ($mappingResultsForProperty as $mappingResult) {
                        $errors[] = htmlspecialchars((string) $mappingResult);
                    }
                }
            }
        }
        return implode('<br />', $errors);
    }
}
