<?php

namespace Dalten\RuianToUir\Converter;

use Dalten\RuianToUir\Converter\Field\GeometryFieldInterface;
use Dalten\RuianToUir\Converter\Field\Point;
use Dalten\RuianToUir\Converter\Field\PointCoordinatesConverter;

/**
 * Abstraktní převaděč - obsahuje základní společnou funkcionalitu převaděčů.
 */
abstract class AbstractConverter
{
    /**
     * Název tagu, který třída obsluhuje.
     *
     * @var string
     */
    protected $_handledTag = '';

    /** @var PointCoordinatesConverter */
    protected $_coordinateConverter;

    /**
     * AbstractConverter constructor.
     *
     * @param PointCoordinatesConverter $coordinateConverter
     */
    public function __construct(PointCoordinatesConverter $coordinateConverter)
    {
        $this->_coordinateConverter = $coordinateConverter;
    }

    /**
     * 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 \XMLReader::ELEMENT === $document->nodeType && $document->name === $this->_handledTag;
    }

    public function getName()
    {
        $namespaceParts = explode('\\', get_class($this));

        return end($namespaceParts);
    }

    /**
     * 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.
     *
     * @return bool|\XMLReader XMLreader s nastaveným kurzorem a nebo false, pokud bychom opustili obsluhovaný prvek.
     */
    protected function _getNextElement(\XMLReader $document)
    {
        $document->read();
        while (\XMLReader::ELEMENT !== $document->nodeType) {
            if ($document->name === $this->_handledTag && \XMLReader::END_ELEMENT === $document->nodeType) {
                return false;
            }
            $document->read();
        }

        return $document;
    }

    /**
     * Slouží přesunu kurzoru na konec aktuálního prvku.
     *
     * @param \XMLReader $document
     *
     * @return bool|\XMLReader
     */
    protected function _skipToElementEnd(\XMLReader $document)
    {
        $elementName = $document->name;
        $depth = 1;
        while ($depth > 0) {
            $document->read();
            if ($document->name === $this->_handledTag && \XMLReader::END_ELEMENT === $document->nodeType) {
                return false;
            }
            if ($document->name === $elementName && \XMLReader::END_ELEMENT === $document->nodeType) {
                --$depth;
            } elseif ($document->name === $elementName && \XMLReader::ELEMENT === $document->nodeType) {
                ++$depth;
            }
        }

        return $document;
    }

    /**
     * Vytvoří instani třídy podle daného Geometrického prvku (Point, Polygon, ...).
     *
     * @param \XMLReader $document
     *
     * @return Point|null
     */
    protected function _getGeometryData(\XMLReader $document)
    {
        $data = null;
        do {
            switch ($document->name) {
                case 'gml:Point':
                    $this->_getNextElement($document);
                    if ('gml:pos' === $document->name && $document->readString()) {
                        $data = new Point($this->_coordinateConverter->convertCoords($document->readString()));
                    }

                    break;
            }
            if ($data instanceof GeometryFieldInterface) {
                break;
            }
        } while ($this->_getNextElement($document));

        return $data;
    }
}
