/** Calls a SOAP function
  *
  * @param string $function_name   The name of the SOAP function to call
  * @param array  $arguments       An array of the arguments to pass to the function
  * @param array  $options         An associative array of options to pass to the client
  * @param mixed  $input_headers   An array of headers to be sent along with the SOAP request
  * @param array  &$output_headers If supplied, this array will be filled with the headers from the SOAP response
  *
  * @throws Exception|SoapFault
  *
  * @return mixed SOAP functions may return one, or multiple values
  */
 public function call($function_name, $arguments, $options = null, $input_headers = null, &$output_headers = null)
 {
     $client = $this->client;
     if (!is_array($arguments)) {
         $arguments = array($arguments);
     }
     /* @todo Lors d'un appel d'une méthode RPC le tableau $arguments contient un élement vide array( [0] => )
      * posant problème lors de l'appel d'une méthode du WSDL sans argument */
     if (isset($arguments[0]) && empty($arguments[0])) {
         $arguments = array();
     }
     if ($client->flatten && isset($arguments[0]) && !empty($arguments[0])) {
         $arguments = $arguments[0];
     }
     $output = null;
     $echange_soap = new CEchangeSOAP();
     $echange_soap->date_echange = CMbDT::dateTime();
     $echange_soap->emetteur = CAppUI::conf("mb_id");
     $echange_soap->destinataire = $client->wsdl_url;
     $echange_soap->type = $client->type_echange_soap;
     $url = parse_url($client->wsdl_url);
     $path = explode("/", $url['path']);
     $echange_soap->web_service_name = end($path);
     $echange_soap->function_name = $function_name;
     // Truncate input and output before storing
     $arguments_serialize = array_map_recursive(array('CSOAPClient', "truncate"), $arguments);
     $echange_soap->input = serialize($arguments_serialize);
     if ($client->loggable) {
         $echange_soap->store();
     }
     CApp::$chrono->stop();
     $chrono = new Chronometer();
     $chrono->start();
     try {
         $output = $client->call($function_name, $arguments, $options, $input_headers, $output_headers);
         if (!$client->loggable) {
             CApp::$chrono->start();
             return $output;
         }
     } catch (SoapFault $fault) {
         // trace
         if (CAppUI::conf("webservices trace")) {
             $client->getTrace($echange_soap);
         }
         $chrono->stop();
         $echange_soap->date_echange = CMbDT::dateTime();
         $echange_soap->output = $fault->faultstring;
         $echange_soap->soapfault = 1;
         $echange_soap->response_time = $chrono->total;
         $echange_soap->store();
         CApp::$chrono->start();
         throw $fault;
     }
     $chrono->stop();
     CApp::$chrono->start();
     $echange_soap->date_echange = CMbDT::dateTime();
     // trace
     if (CAppUI::conf("webservices trace")) {
         $client->getTrace($echange_soap);
     }
     // response time
     $echange_soap->response_time = $chrono->total;
     if ($echange_soap->soapfault != 1) {
         $echange_soap->output = serialize(array_map_recursive(array("CSOAPClient", "truncate"), $output));
     }
     $echange_soap->store();
     return $output;
 }