<?php

namespace Helpers\Outil;

use DOMDocument;
use Helpers\Log\LogSysteme;
use SimpleXMLElement;

class XmlHelper
{

    /**
     * @return array<SimpleXMLElement>
     */
    public static function toArray(?SimpleXMLElement $xml, string $itemNodeName) :array
    {
        if ($xml === null) {
            return [];
        }
        $res = $xml->xpath($itemNodeName);// TODO : escape node name
        if (!is_array($res)) {
            LogSysteme::prefixErrorLog('toArray failed');
            return [];
        }
        return $res;
    }

    /**
     * Dumps the internal XML tree back into a string
     * Creates an XML document from the DOM representation. This function is usually called after building a new dom document from scratch as in the example below.
     *
     * @param \DOMNode|null $node Use this parameter to output only a specific node without XML declaration rather than the entire document.
     * @param int $options Additional Options. The LIBXML_NOEMPTYTAG and LIBXML_NOXMLDECL options are supported. Prior to PHP 8.3.0, only the LIBXML_NOEMPTYTAG option is supported.
     */
    public static function saveXML(\DOMDocument $doc, ?\DOMNode $node = null, int $options = 0) :string
    {
        $res = $doc->saveXML($node, $options);
        if ($res === false) {
            throw new \Exception('saveXML fail');
        }
        return $res;
    }

    /**
     * attr
     * Turn a map into a lsit of html attribute (string)
     *
     * @param  array<mixed> $attr
     * @return string
     */
    public static function attr($attr):string
    {
        if (empty($attr)) {
            return '';
        }
        return implode(' ', array_map(
            function ($k, $v) {
                if (empty($v)) {
                    return $k;
                }
                return $k .'="'. htmlspecialchars($v) .'"';
            },
            array_keys($attr),
            $attr
        ));
    }

    /**
     * @param mixed $xml
     * @return mixed
     */
    public static function normalize($xml, ?bool $associative = null)
    {
        $json = json_encode($xml);
        if ($json === false) {
            return [];
        }
        return json_decode($json, $associative);
    }

    // /**
    //  * TODO move into an extention class of \DOMXpath
    //  * @param array<string,string> $mapNamespace namespace indexed by prefix
    //  * @return \DOMNodeList<\DOMNode>
    //  */
    // public static function xpath(
    //     DOMDocument $doc,
    //     string $path,
    //     ?\DOMNode $node = null,
    //     array $mapNamespace = []
    // ) :\DOMNodeList {
    //     $xpath = new \DOMXpath($doc);
    //     foreach ($mapNamespace as $alias => $namesp) {
    //         $xpath->registerNamespace($alias, $namesp);
    //     }
    //     /** @var \DOMNodeList<\DOMNode>|false */
    //     $res = $xpath->query($path, $node);
    //     if ($res === false) {
    //         throw new \Exception('xpath failed "'.$path.'"');
    //     }
    //     return $res;
    // }

    // /**
    //  * TODO move into an extention class of \DOMXpath
    //  */
    // public static function xpathFirstValue(
    //     DOMDocument $doc,
    //     string $path,
    //     ?\DOMNode $node = null,
    //     array $mapNamespace = []
    // ) :?string {
    //     $res = self::xpath($doc, $path, $node, $mapNamespace)->item(0) ?? null;
    //     return $res != null ? $res->textContent : null;
    // }
}
