<?php

namespace Dalten\RuianToUir\Converter;

/**
 * Obaluje converter tak, aby z něj mohl dostat informace o vnitřní struktuře prvku.
 */
class ExplorerWrapper
{
    /** @var ConverterInterface */
    private $innerConverter;

    public function __construct(ConverterInterface $innerConvert)
    {
        $this->innerConverter = $innerConvert;
    }

    /**
     * Zjišťuje, zda tato třída dokáže obsloužit daný element.
     *
     * @param \XMLReader $document Instance readeru s kurzorem na testovaném prvku.
     *
     * @return bool Obsluhuje tato třída daný prvek?
     */
    public function accepts(\XMLReader $document)
    {
        return $this->innerConverter->accepts($document);
    }

    /**
     * Převádí informace z prvku pod do zjednodušeného formátu.
     *
     * @param \XMLReader $document Instance readeru s kurzorem na testovaném prvku.
     *
     * @return array Data (scalar | array) ve zjednodušeném formátu..
     */
    public function convert(\XMLReader $document)
    {
        $name = $document->name;
        $element = $this->_getNextElement($document, $name);

        if ($element instanceof \XMLReader && $element->name === $name) {
            $this->_getNextElement($document, $name);
        }

        return (array) $this->_getValue($document, $name);
    }

    /**
     * @param \XMLReader $document
     * @param string     $tagName
     *
     * @return string|array
     */
    private function _getValue(\XMLReader $document, $tagName)
    {
        $output = [];

        $simpleValue = $document->readString();

        while ($this->_getNextElement($document, $tagName)) {
            if (\XMLReader::ELEMENT === $document->nodeType) {
                $name = $baseName = $document->name;
                $i = 0;
                while (array_key_exists($name, $output)) {
                    $name = $baseName.'#'.++$i;
                }
                if ($document->isEmptyElement) {
                    $output[$name] = null;
                } else {
                    $output[$name] = $this->_getValue($document, $document->name);
                }
            }
        }

        return $output ?: $simpleValue;
    }

    /**
     * Slouží k nalzení dalšího prvku. Hledá prvek a ignoruje všechny ostatní typy XML uzlů.
     *
     * @param \XMLReader $document     Instance readeru s kurzorem na testovaném prvku.
     * @param string     $outerTagName Název obalového tagu.
     *
     * @return bool|\XMLReader XMLreader s nastaveným kurzorem a nebo false, pokud bychom opustili obsluhovaný prvek.
     */
    protected function _getNextElement(\XMLReader $document, $outerTagName)
    {
        $document->read();
        while (\XMLReader::ELEMENT !== $document->nodeType) {
            if ($document->name === $outerTagName && \XMLReader::END_ELEMENT === $document->nodeType) {
                return false;
            }
            $document->read();
        }

        return $document;
    }

    /**
     * Vrátí název converteru.
     *
     * @return string Název converteru.
     */
    public function getName()
    {
        return $this->innerConverter->getName();
    }
}
