<?php
namespace Helpers\Webservice;
// phpcs:ignoreFile
use Helpers\Session\ParseBase1;
class Soap
{
    
    var string $host = '127.0.0.1';
    var bool $diag = false;
    private bool $useNameSpace  = true;
    private bool $modeASynchrone = false;
    public mixed $port;
    public string $path;
    public mixed $query;
    public mixed $responseData;
    
    public function setUseNameSpace(bool $value) :void
    {
        $this->useNameSpace = $value;
    }
    
    public function & isUseNameSpace() :bool
    {
        return $this->useNameSpace;
    }
    
    public function setModeASynchrone(bool $value) :void
    {
        $this->modeASynchrone = $value;
    }
    
    public function & isModeASynchrone() :bool
    {
        return $this->modeASynchrone;
    }
    
    function __construct(?string $wsdl = null)
    {
        if (is_null($wsdl)) {
            $wsdl = 'null.wsdl'; // Obligation sinon le parsing ne va pas se faire
        }
            
        if ($wsdl != '') {
            $wsdlparts = parse_url($wsdl);

            if (!$wsdlparts) {
                return;
            }
                
            if (!array_key_exists('port', $wsdlparts)) {
                if (!array_key_exists('scheme', $wsdlparts)) {
                    $wsdlparts['port'] = 80;
                } else {
                    switch ($wsdlparts['scheme']) {
                        case 'http':
                            $wsdlparts['port'] = 80;
                            break;
                        case 'https':
                                $wsdlparts['port'] = 443;
                            break;
                    }
                }
            }
                        
                    $this->host = (array_key_exists('host', $wsdlparts) ? $wsdlparts['host'] : $this->host);
                    $this->port = $wsdlparts['port'];
                    $this->path = (array_key_exists('path', $wsdlparts))?$wsdlparts['path']:'';
                        
                    // Construction du systeme de query
                        
            if (array_key_exists('query', $wsdlparts)) {
                foreach (explode('&', $wsdlparts['query']) as $data) {
                    $element = explode('=', $data);
                    $this->query[$element[0]] = $element[1];
                }
            }
        }
    }
    
    function & parseResponse(string &$flux_xml) :mixed
    {
        return Soap::xmlstr_to_array($flux_xml);
    }
    
    /**
     * @param string $method
     * @param mixed $xml_string
     * @param bool $retourIsArray
     * @param mixed $prgName
     * @param mixed $appName
     * @param mixed $NOS
     * @param mixed $vers
     * @return mixed
     */
    function & call(string $method, mixed $xml_string, bool $retourIsArray = true, $prgName = 'APPEL_PHP_CENTRAL', $appName = 'Oxaproc', $NOS = null, $vers = null  ) :mixed
    {
        // Translation du mot relatif � la method par le mot relatif au noeud primaire
        // enveloppe soap + tag de la methode + message xml
        $return = null;
        $wsdlparts = parse_url((new ParseBase1())->getPath()->wsdl);
        
        
        $Ria = new \Helpers\Webservice\SendHttpRIA($appName, $prgName);
        $Ria->setHost($wsdlparts['host'] ?? '');
        $Ria->setProtocol($wsdlparts['scheme'] ?? '');
        $Ria->setIspi($wsdlparts['path'] ?? '');
        $Ria->setPort($this->port);
        $Ria->setDiag($this->diag);
        $retourRIA = $Ria->send($method, $xml_string, null, $this->isModeASynchrone(), $NOS, $vers);
        if ($retourRIA === true) {
            $this->responseData = $Ria->getXmlFromRia()->SaveXml();
            return Soap::xmlstr_to_array($this->responseData, true, $retourIsArray);
        }else if($retourRIA == 'noXML')
        {
            $this->responseData = $Ria->getXmlFromRia();
            return $this->responseData;
        }
        
        return $return;
    }
    
    public static function & xmlstr_to_array(string $xmlstr, mixed $useNameSpace = true, bool $retourIsArray = true) :mixed
    {
        $doc = new \DOMDocument();
        $doc->loadXML($xmlstr);
        
        if ($retourIsArray) {
            return  Soap::domnode_to_array($doc->documentElement, $useNameSpace);
        }
            
        if ($ret =  Soap::domnode_to_arrayStruct($doc->documentElement, $useNameSpace)) {
            foreach ($ret as $index => & $cle) {
                return $ret[$index];
            }
        }
        return $ret;
    }
    
    public static function & domnode_to_arrayStruct(mixed $node, mixed $useNameSpace) :mixed
    {
        $output = null;
        
        /**
         * NE JAMAIS PRENDRE le textContent sur l'element XML_ELEMENT_NODE car sinon il concatene tous les textContent des noeuds fils
         */
        switch ($node->nodeType) {
            case XML_TEXT_NODE: // Uniquement un renvoi de texte
                if (trim($node->textContent)!='') {
                    $output = trim($node->textContent);
                }
                break;
            case XML_ELEMENT_NODE:
                // Affectation des attributes � la donn�e
                if ($node->attributes->length != 0) {
                    foreach ($node->attributes as $attrName => $attrNode) {
                        $output[$node->nodeName]['!'.$attrName] = (string) $attrNode->value;
                    }
                }
                        
                        $tabExist = array();
                        
                for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
                    $child = $node->childNodes->item($i);
                            
                    $ret = Soap::domnode_to_arrayStruct($child, $useNameSpace);
                    if (! is_null($ret)) {
                        if (is_array($ret)) {
                            foreach ($ret as $index => & $suite) {
                                if (array_key_exists($index, $tabExist)) {
                                    if ($tabExist[$index] == 1) {
                                        $t = $output[$node->nodeName][$index];
                                        unset($output[$node->nodeName][$index]);
                                                
                                        $output[$node->nodeName][$index][] = $t;
                                        $tabExist[$index] = 2;
                                    }
                                    $output[$node->nodeName][$index][] = $suite;
                                } else {
                                    $output[$node->nodeName][$index] = $suite;
                                    $tabExist[$index] = 1;
                                }
                            }
                        } else {
                            $output[$node->nodeName]['#text'] = $ret; // Pourquoi #text, c'est les memes valeur utilis� dans les RFC standard
                        }
                    }
                }
                break;
        }
        
        return $output;
    }
    
    /**
     * Summary of domnode_to_array
     * @param mixed $node
     * @param mixed $useNameSpace
     * @return mixed
     */
    public static function & domnode_to_array($node, $useNameSpace)
    {
        /** @var array<mixed> */
        $output = array();
        switch ($node->nodeType) {
            case XML_CDATA_SECTION_NODE:
            case XML_TEXT_NODE:
                $output = trim($node->textContent);
                break;
            case XML_ELEMENT_NODE:
                for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
                    /** @var \stdClass $child */
                    $child = $node->childNodes->item($i);
                    $v = Soap::domnode_to_array($child, $useNameSpace);
                    if ($v || $v === '0') { // https://github.com/gaarf/XML-string-to-PHP-array/blob/master/xmlstr_to_array.php
                        return (string) $v;
                    }
                    if (isset($child->tagName)) {
                        if ($useNameSpace || (is_string($useNameSpace) && strpos($useNameSpace, ':') === false)) {
                            $t = $child->tagName;
                        } else {
                            $t = substr($child->tagName, strpos($child->tagName, ':')+1);
                        }
                                
                        if (!isset($output[$t])) {
                            $output[$t] = array();
                        }
                                
                        $output[$t][] = $v;
                                
                        if ($child->attributes->length != 0) {
                            foreach ($child->attributes as $attrName => $attrNode) {
                                $output['!'.$attrName] = (string) $attrNode->value;
                            }
                        }
                    }
                }
                if (is_array($output)) {
                    foreach ($output as $t => $v) {
                        if (is_array($v) && count($v) == 1 && $t != '@attributes') {
                            if ($useNameSpace || strpos($t, ':') === false) {
                                // On ne touche � rien
                            } else {
                                $t = substr($t, strpos($t, ':')+1);
                            }
                                
                            if (count($v[0]) == 0) {
                                $output[$t] = '';
                            } else {
                                $output[$t] = $v[0];
                            }
                        }
                    }
                    
                    if ($node->attributes->length) {
                        foreach ($node->attributes as $attrName => $attrNode) {
                            $output['!'.$attrName] = (string) $attrNode->value;
                        }
                    }
                }
                break;
        }
        return $output;
    }
}
