<?php

namespace Internetgalerie\IgDatapoolFe\ViewHelpers\Form;

use Internetgalerie\IgDatapoolFe\Services\IconService;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper;

class InlinerecordViewHelper extends AbstractFormFieldViewHelper
{
    /**
     * @var HashService
     */
    protected $hashService;

    protected $hasLanguageUid = false;

    /**
     * @param HashService $hashService
     */
    public function injectHashService(HashService $hashService): void
    {
        $this->hashService = $hashService;
    }

    public function initializeArguments(): void
    {
        parent::initializeArguments();
        $this->registerArgument('sortingForeign', 'boolean', 'Show sorting foreign', false, 0);
        $this->registerArgument('sorting', 'boolean', 'Show sorting', false, 0);
        $this->registerArgument('languages', 'string', 'foreign languages', false);
        $this->registerArgument('showLanguagesLines', 'boolean', 'Objekt hat Funktion get_languageUid und direkt Übersetzungszeilen werden dargestellt', false, false);
        //$this->registerArgument('groupBy', 'string', 'group by property', FALSE);
        $this->registerArgument('as', 'string', 'as for item object', false, '');
        $this->registerArgument('prefixName', 'string', 'prefixName', false, 'prefix');
        $this->registerArgument('maxitems', 'int', 'maxitems', false);
        $this->registerArgument('addLabel', 'string', 'text for add button', false, null);
        $this->registerArgument('confirmText', 'string', 'text  for confirm message', false, null);
        $this->registerArgument('objectName', 'string', 'name of the object that is bound to this Inlinefield', false, 'prototypeObject');
        $this->registerArgument('header', 'string', 'property for header', false, null);
    }

    protected function getPrototypeObjectName()
    {
        return $this->arguments['objectName'];
    }


    private function getInputSortingForeign($name_count, $value)
    {
        return '<input class="dp-file-upload-sort" type="hidden" name="' . $this->getName() . '[' . $name_count . '][sortingForeign]" value="' . $value . '">';
        //return '[Sorting:<input class="dp-file-upload-sort" type="text" name="'.$this->getName().'['.$name_count.'][sortingForeign]" value="'.$value.'" style="width: 30px;">]';
    }
    private function getInputSorting($name_count, $value)
    {
        return '<input class="dp-file-upload-sort" type="hidden" name="' . $this->getName() . '[' . $name_count . '][sorting]" value="' . $value . '">';
        //return '[Sorting:<input class="dp-file-upload-sort" type="text" name="'.$this->getName().'['.$name_count.'][sortingForeign]" value="'.$value.'" style="width: 30px;">]';
    }

    private function renderLang(&$free_count, $defaultLangUidLocal, $langShow, $templateVariableContainer, $sortingForeign, $sorting)
    {
        $output = '';
        foreach ($this->arguments['languages'] as $langUid => $langText) {
            if (in_array($langUid, $langShow)) {
                continue;
            }
            $templateVariableContainer->add('defaultLangUidLocal', $defaultLangUidLocal);

            $templateVariableContainer->add('iterator', $free_count);
            $prefix = $this->arguments['property'] . '.' . $free_count;
            $templateVariableContainer->add($this->arguments['prefixName'], $prefix);

            $templateVariableContainer->add('langUid', $langUid);
            $templateVariableContainer->add('langText', $langText);

            if ($this->arguments['sortingForeign']) {
                $output .= $this->getInputSortingForeign($free_count, $sortingForeign);
            } elseif ($this->arguments['sorting']) {
                $output .= $this->getInputSorting($free_count, $sorting);
            }
            $output .= $this->renderChildren();

            $templateVariableContainer->remove('defaultLangUidLocal');
            $templateVariableContainer->remove('langUid');
            $templateVariableContainer->remove('langText');
            $templateVariableContainer->remove($this->arguments['prefixName']);
            $templateVariableContainer->remove('iterator');
            $free_count++;
        }
        return $output;
    }

    /**
     * @param array $action
     * @param array $arguments
     *
     * @return string
     */
    public function render(array $action = null, array $arguments = [])
    {
        $templateVariableContainer = $this->renderingContext->getVariableProvider();
        $output = '';
        $hiddenFields = '';
        $defaultLangUidLocal = 0;
        $lastUid = 0;
        $lastLangUid = 0;
        $lastSortingForeign = -1;
        $lastSorting = -1;
        // Loop through all  elements
        $origObjs = $this->getValueAttribute();
        $this->hasLanguageUid = $this->arguments['showLanguagesLines'];

        //HEADER
        $headerProperty = $this->arguments['header'];
        $headerMethod = $headerProperty ?  'get' . ucfirst((string) $headerProperty) : null;
        $headerShow = $headerProperty && $headerMethod;
        
        //FIX IT, i.e. standardize it!!!
        //$objects = array();
        //$i = 0;
        /*
          foreach ($origObjs as $key => $obj) {
          echo('key='.$key.'<br />');
          if (is_numeric($key)) {
          $objects[$key] = $obj;
          } else {
          $objects[$i++] = $obj;
          }
          }
          $count = count($objects);
          foreach ($objects as $key => $obj) {
        */
        $count = $origObjs ? count($origObjs) : 0;
        $i = 0;
        $langShow = [];
        $c = 0;
        $free_count = $count;
        $must_close = 0;
        /*
          if( $this->arguments['groupBy'] ) {
          //echo('Group by: '. $this->arguments['groupBy'] );

          $sortObjects = array();
          $last_objects = array();
          $last_fileUid=0;
          $groupByFunc = 'get' . ucfirst($this->arguments['groupBy']);

          // Eintraege umsortieren
          foreach ($origObjs as $key => $obj) {
          if( !method_exists($obj, $groupByFunc)) {
          $output .= 'ERROR: Function ' . get_class($obj) . '.' . $groupByFunc . ' missing';
          break;
          }

          echo('G: '. $obj->{$groupByFunc}(). '<br />');
          if($obj->get_languageUid()<=0) {
          $sortObjects[]=$obj;
          foreach( $lastobjects as $l ) {
          $sortObjects[]=$l;
          }
          $last_fileUid=$obj->getOriginalResource()->getOriginalFile()->getUid();
          $lastobjects = array();
          } else {
          if( $last_fileUid==$obj->getOriginalResource()->getOriginalFile()->getUid()) {
          $sortObjects[]=$obj;
          } else {
          if( count( $lastobjects )>0) {
          // Default Sprache fehlt !!! -> Error?
          foreach( $lastobjects as $l ) {
          $sortObjects[]=$l;
          }
          $lastobjects = array();
          }
          $last_fileUid=$obj->getOriginalResource()->getOriginalFile()->getUid();
          $lastobjects[$obj->get_languageUid()] = $obj;
          }
          }
          }
          // fehlen noch eintraege
          foreach( $lastobjects as $l ) {
          $sortObjects[]=$l;
          }

          $origObjs = $sortObjects;
          }
        */
        $prototypeObjectName = $this->getPrototypeObjectName();
        $this->viewHelperVariableContainer = $this->renderingContext->getViewHelperVariableContainer();
        $this->viewHelperVariableContainer->add(\Internetgalerie\IgDatapoolFe\ViewHelpers\Form\InlinerecordViewHelper::class, 'prototypeObjectName', $prototypeObjectName);
        if (!empty($origObjs)) {
            foreach ($origObjs as $key => $obj) {
                $c++;
                //echo('key('.$count.')='.$key.'<br />');
                //remove fields that actuelly arent
                if (!(is_array($obj) || $obj instanceof AbstractEntity)) {
                    continue;
                }
                $this->viewHelperVariableContainer->add(\Internetgalerie\IgDatapoolFe\ViewHelpers\Form\InlinerecordViewHelper::class, $prototypeObjectName, $obj);
                //add variables to be used in fluid

                //add a disabled hidden fields, which willb e enabled when the record is deleted, so the property mapper will delete the actual model
                //    $hiddenFields .= '<input class="record' . $i . '" type="hidden" name="' . $this->getName() . '[' . $i . ']" disabled="disabled" value="" />';

                //DebuggerUtility::var_dump($obj);
                //DebuggerUtility::var_dump($langShow);
                //$output .= 'obj.uid='. $obj->getUid() .'<br />';
                //$output .= 'obj.SortingForeign='. $obj->getSortingForeign() .'<br />';
                //$output .= 'obj.class='. get_class($obj) .'<br />';
                //$output .= 'obj.uid_local='. $obj->getUidLocal() .'<br />';
                //$output .= 'obj.uid_local='. $obj->getOriginalResource()->getUid() .'<br />';
                // HTML output
                // Nach Sorting sortiert - Ausnahme alle sprachen (sinnvoll?) $obj->get_languageUid()<0 ||
                if ($this->arguments['sortingForeign'] && $lastSortingForeign != $obj->getSortingForeign()) {
                    //echo('if:'. count($langShow) .' , '. $defaultLangUidLocal . ', ' . $lastLangUid .'<br />');
                    if (count($langShow) > 0 && $defaultLangUidLocal && $lastLangUid == 0) {
                        $output .= $this->renderLang($free_count, $defaultLangUidLocal, $langShow, $templateVariableContainer, $lastSortingForeign, $lastSorting);
                    }
                    $langShow = [];
                    $lastUid = $obj->getUid();
                    if ($this->hasLanguageUid) {
                        $lastLangUid = $obj->get_languageUid();
                    }
                    $lastSortingForeign = $obj->getSortingForeign();
                }
                if ($this->arguments['sorting'] && $lastSorting != $obj->getSorting()) {
                    //echo('if:'. count($langShow) .' , '. $defaultLangUidLocal . ', ' . $lastLangUid .'<br />');
                    if (count($langShow) > 0 && $defaultLangUidLocal && $lastLangUid == 0) {
                        $output .= $this->renderLang($free_count, $defaultLangUidLocal, $langShow, $templateVariableContainer, $lastSortingForeign, $lastSorting);
                    }
                    $langShow = [];
                    $lastUid = $obj->getUid();
                    if ($this->hasLanguageUid) {
                        $lastLangUid = $obj->get_languageUid();
                    }
                    $lastSorting = $obj->getSorting();
                }
                if ($c > 1) {
                    $output .= '</div>';
                    $output .= '</div>';
                    if ($headerShow) {
                        $output .= '</div>'; //HEADER
                    }
                }

                $dpRecordContainerClass = 'dp-record-container dp-record-container-persist dp-record-container-show';
                $style = '';
                if ($this->arguments['header']) {
                    $dpRecordContainerClass .= ' ig-accordion default';
                    //$style = 'display: none;';
                }
                
                
                $output .= '
<div class="' . $dpRecordContainerClass . '" data-rel="' . trim(str_replace(['][', '['], '-', $this->getNameWithoutPrefix()), '[]') . '-' . $i . '">';

                $classEntry = 'dp-record-entry';
                if ($headerShow) {
                    $output .= '<div class="' . $classEntry . '">'; //HEADER
                    $classEntry = '';
                    if ($headerMethod) {
                        if (method_exists($obj, $headerMethod)) {
                            $header = $obj->{$headerMethod}();
                        } else {
                            $header = $c;
                        }
                        
                        $output .= '<div class="csc-header csc-header-layout2 csc-header-n"><span>' . htmlspecialchars((string) $header) . '</span></div>';
                    }
                }
                
                //$output .= '<div class="dp-record"' . ( $style ? ' style="' . $style . '"' : '') . '>';
                $output .= '<div class="dp-record ' . $classEntry . '">';
                $subCount = 0;

                if (method_exists($obj, 'getOriginalResource')) {
                    $defaultLangUidLocal = $obj->getOriginalResource()->getOriginalFile()->getUid();
                } //$obj->getUid();
                else {
                    if (is_array($obj)) {
                        //var_dump($obj);
                        $defaultLangUidLocal = $obj['__identity'];
                    } else {
                        $defaultLangUidLocal = $obj->getUid();
                    }
                }
                if ($this->hasLanguageUid) {
                    $langShow[] = $obj->get_languageUid();
                }
                if ($this->arguments['languages'] && 0) {
                } else {
                    $templateVariableContainer->add('iterator', $i);
                    $prefix = $this->arguments['property'] . '.' . $i;
                    $templateVariableContainer->add('prefixName', $this->arguments['prefixName']);
                    $templateVariableContainer->add($this->arguments['prefixName'], $prefix);

                    if ($this->arguments['sortingForeign']) {
                        $output .= $this->getInputSortingForeign($i, $obj->getSortingForeign());
                    } elseif ($this->arguments['sorting']) {
                        $output .= $this->getInputSorting($i, $obj->getSorting());
                    }

                    $templateVariableContainer->add('defaultLangUidLocal', $defaultLangUidLocal);
                    if ($this->hasLanguageUid) {
                        $templateVariableContainer->add('langUid', $obj->get_languageUid());
                    }
                    if ($this->arguments['as']) {
                        $templateVariableContainer->add($this->arguments['as'], $obj);
                    }
                    $output .= $this->renderChildren();
                    
                    $output .= $this->renderLinePanel(is_object($obj));
                    if ($this->arguments['as']) {
                        $templateVariableContainer->remove($this->arguments['as']);
                    }

                    if ($this->hasLanguageUid) {
                        $templateVariableContainer->remove('langUid');
                    }
                    $templateVariableContainer->remove('defaultLangUidLocal');

                    $templateVariableContainer->remove($this->arguments['prefixName']);
                    $templateVariableContainer->remove('prefixName');
                    $templateVariableContainer->remove('iterator');
                    $i++;
                }
                //remove them, to clean up
                $must_close = 1;
                $this->viewHelperVariableContainer->remove(\Internetgalerie\IgDatapoolFe\ViewHelpers\Form\InlinerecordViewHelper::class, $prototypeObjectName);
            }
        }
        if ($must_close) {
            if ($this->hasLanguageUid && $lastLangUid == 0) {
                $output .= $this->renderLang($free_count, $defaultLangUidLocal, $langShow, $templateVariableContainer, $lastSortingForeign, $lastSorting);
            }
            $output .= '</div>';
            $output .= '</div>';
            if ($headerShow) {
                $output .= '</div>'; //HEADER
            }
        }
        //add the dummy element
        $output .= '
<div class="dp-record-container dp-record-container-dummy">
	<div class="dp-record">
		' . $this->renderAddLine($prototypeObjectName) . '
	</div>
</div>';
        $this->viewHelperVariableContainer->remove(\Internetgalerie\IgDatapoolFe\ViewHelpers\Form\InlinerecordViewHelper::class, 'prototypeObjectName');

        $maxitems = (int)($this->arguments['maxitems'] ?? 0);
        $dataAttributeSource = $maxitems > 0 ? ' data-maxitems="' . $maxitems . '"' : '';
        $confirmText = htmlspecialchars($this->arguments['confirmText'] ?? LocalizationUtility::translate('confirm.text', 'ig_datapool_fe'));
        $dataAttributeSource .= ' data-confirm-text="' . $confirmText . '"';

        // add hidden fields
        // register for automapping @see ActionController
        $hiddenFields .= '<input type="hidden" name="' . $this->prefixFieldName('__dpInlineFields[]') . '" value="' . $this->hashService->appendHmac($this->arguments['property']) . '" />';
        //add an empty field, so a value is always submitted. also in the empty case.
        $hiddenFields .= '<input class="isEmpty" type="hidden" ' . ($count > 0 && 0 ? 'disabled="disabled"' : '') . ' name="' . htmlspecialchars($this->getName()) . '" value="" />';

        $containerClass = 'dp-form-inline dp-form-inline-record';
        //return the context
        return '<div class="' . $containerClass . '"' . $dataAttributeSource . '>
<div class="hiddenfields">' . $hiddenFields . '</div>
' . $output . '
</div>';
    }
        
    /**
     * @param bool $showSorting
     *
     * @return string
     */
    public function renderLinePanel(bool $showSorting = true)
    {
        $output = '<div class="dp-panel">';
        if ($this->arguments['sortingForeign'] && $showSorting) {
            $output .= '<span class="dp-sorting-up">' . IconService::getIcon('actions-move-up', 'dp-up') . '</span> <span class="dp-sorting-down">' . IconService::getIcon('actions-move-down', 'dp-down') . '</span> ';
        } elseif ($this->arguments['sorting'] && $showSorting) {
            //$output .= '<span class="dp-sorting-up">' . \Internetgalerie\IgDatapoolFe\Services\IconService::getIcon('actions-move-up', 'dp-up') . '</span> <span class="dp-sorting-down">' . \Internetgalerie\IgDatapoolFe\Services\IconService::getIcon('actions-move-down', 'dp-down') . '</span> ';
            $output .= '<span class="dp-sorting-up">' . IconService::getIcon('actions-move-up', 'dp-up') . '</span> <span class="dp-sorting-down">' . IconService::getIcon('actions-move-down', 'dp-down') . '</span> ';
        }
        $output .= IconService::getIcon('actions-edit-delete', 'dp-delete');
        $output .= '</div>';
        return $output;
    }

    /**
     * Renders a dummy line for new values and an add button
     */
    protected function renderAddLine(string $prototypeObjectName)
    {
        $this->viewHelperVariableContainer->add(\Internetgalerie\IgDatapoolFe\ViewHelpers\Form\InlinerecordViewHelper::class, $prototypeObjectName . 'Button', []);
        $templateVariableContainer = $this->renderingContext->getVariableProvider();
        $output = '';
        $property = $this->arguments['property'];
        $prefix = $property . '.' . 'TEMP';
        
        $this->arguments['property'] = $prefix;
        $name = $this->getName();
        $this->arguments['property'] = $property;
        
        $templateVariableContainer->add($this->arguments['prefixName'], $prefix);

        $output .= '<div class="dp-ibnlinerecord-container-entries"></div>';

        $renderedContent = $this->renderChildren();

        $prototypeButtons = $this->viewHelperVariableContainer->get(
            InlinerecordViewHelper::class,
            $prototypeObjectName . 'Button'
        );
        $addLabel = htmlspecialchars($this->arguments['addLabel'] ?? LocalizationUtility::translate('entry.add', 'ig_datapool_fe'));
        if (empty($prototypeButtons)) {
            $output .= '<input type="button" name="add" value="' . $addLabel . '" class="dp-form-inline-record-add" />';
            $output .= '<div class="dp-inlinerecord-container-new">';
            $output .= '<div class="dp-record-container dp-record-container-persist dp-record-container-show">';
            $output .= '<div class="dp-record">';
            $output .= $renderedContent;
            $output .= $this->renderLinePanel(true);
            $output .= '</div>';
            $output .= '  </div></div>';
        } else {
            $output .= '<div class="dp-text-for-button">' . $addLabel .':</div>';
            foreach ($prototypeButtons as $prototypeButton) {
                $output .= '<input type="button" name="add" value="' . $prototypeButton['label']. '" class="dp-form-inline-record-add" />';
                $output .= '<div class="dp-inlinerecord-container-new">';
                $output .= '<div class="dp-record-container dp-record-container-persist dp-record-container-show">';
                $output .= '<div class="dp-record">';
                $output .= '<input type="hidden" name="' . $name . '[__type]" value="' . $prototypeButton['type'] . '" />';

                $output .= $prototypeButton['renderedContent'];
                $output .= $this->renderLinePanel(true);
                $output .= '</div>';
                $output .= '  </div></div>';
            }
        }
        if ($this->arguments['sortingForeign']) {
            $output .= $this->getInputSortingForeign('TEMP', '');
        } elseif ($this->arguments['sorting']) {
            $output .= $this->getInputSorting('TEMP', '');
        }

        $templateVariableContainer->remove($this->arguments['prefixName']);
        $this->viewHelperVariableContainer->remove(\Internetgalerie\IgDatapoolFe\ViewHelpers\Form\InlinerecordViewHelper::class, $prototypeObjectName. 'Button');

        //yep, this is ugly: set the fieldnames to dummies values
        $output = str_replace('name="', 'name="dummy-', $output);

        return $output;
    }
}
