﻿/*****************************************************************************\

 Javascript "SOAP Client" library

 @version: 2.1 - 2006.09.08
 @author: Matteo Casati - http://www.guru4.net/

\*****************************************************************************/

function SOAPClientParameters()
{
 var _pl = new Array();
 this.add = function(name, value)
 {
 _pl[name] = value;
 return this;
 }
 this.toXml = function()
 {
 var xml = "";
 for(var p in _pl)
 xml += "<" + p + ">" + SOAPClientParameters._serialize(_pl[p]) + "</" + p + ">";
 return xml;
 }
}



SOAPClientParameters._serialize = function(o)
{
 var s = "";
 switch(typeof(o))
 {
 case "string":
 s += o.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); break;
 case "number":
 case "boolean":
 s += o.toString(); break;
 case "object":
 // Date
 if(o.constructor.toString().indexOf("function Date()") > -1)
 {

 var year = o.getFullYear().toString();
 var month = (o.getMonth() + 1).toString(); month = (month.length == 1) ? "0" + month : month;
 var date = o.getDate().toString(); date = (date.length == 1) ? "0" + date : date;
 var hours = o.getHours().toString(); hours = (hours.length == 1) ? "0" + hours : hours;
 var minutes = o.getMinutes().toString(); minutes = (minutes.length == 1) ? "0" + minutes : minutes;
 var seconds = o.getSeconds().toString(); seconds = (seconds.length == 1) ? "0" + seconds : seconds;
 var milliseconds = o.getMilliseconds().toString();
 var tzminutes = Math.abs(o.getTimezoneOffset());
 var tzhours = 0;
 while(tzminutes >= 60)
 {
 tzhours++;
 tzminutes -= 60;
 }
 tzminutes = (tzminutes.toString().length == 1) ? "0" + tzminutes.toString() : tzminutes.toString();
 tzhours = (tzhours.toString().length == 1) ? "0" + tzhours.toString() : tzhours.toString();
 var timezone = ((o.getTimezoneOffset() < 0) ? "+" : "-") + tzhours + ":" + tzminutes;
 s += year + "-" + month + "-" + date + "T" + hours + ":" + minutes + ":" + seconds + "." + milliseconds + timezone;
 }
 // Array
 else if(o.constructor.toString().indexOf("function Array()") > -1)
 {
 for(var p in o)
 {
 if(!isNaN(p)) // linear array
 {
 (/function\s+(\w*)\s*\(/ig).exec(o[p].constructor.toString());
 var type = RegExp.$1;
 switch(type)
 {
 case "":
 type = typeof(o[p]);
 case "String":
 type = "string"; break;
 case "Number":
 type = "int"; break;
 case "Boolean":
 type = "bool"; break;
 case "Date":
 type = "DateTime"; break;
 }
 s += "<" + type + ">" + SOAPClientParameters._serialize(o[p]) + "</" + type + ">"
 }
 else // associative array
 s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "</" + p + ">"
 }
 }
 // Object or custom function
 else
 for(var p in o)
 s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "</" + p + ">";
 break;
 default:
 throw new Error(500, "SOAPClientParameters: type '" + typeof(o) + "' is not supported");
 }
 return s;
}




function SOAPClient() {}

SOAPClient.invoke = function(url, method, parameters, async, callback)
{
 if(async)
 SOAPClient._loadWsdl(url, method, parameters, async, callback);
 else
 return SOAPClient._loadWsdl(url, method, parameters, async, callback);
}

// private: wsdl cache
SOAPClient_cacheWsdl = new Array();

// private: invoke async
SOAPClient._loadWsdl = function(url, method, parameters, async, callback)
{
 // load from cache?
 var wsdl = SOAPClient_cacheWsdl[url];
 if(wsdl + "" != "" && wsdl + "" != "undefined")
 return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl);
 // get wsdl
 var xmlHttp = SOAPClient._getXmlHttp();
 xmlHttp.open("GET", url + "?wsdl", async);
 if(async)
 {
 xmlHttp.onreadystatechange = function()
 {
 if(xmlHttp.readyState == 4)
 SOAPClient._onLoadWsdl(url, method, parameters, async, callback, xmlHttp);
 }
 }
 xmlHttp.send(null);
 if (!async)
 return SOAPClient._onLoadWsdl(url, method, parameters, async, callback, xmlHttp);
}



SOAPClient._onLoadWsdl = function(url, method, parameters, async, callback, req)
{
 var wsdl = req.responseXML;
 SOAPClient_cacheWsdl[url] = wsdl; // save a copy in cache
 return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl);
}



SOAPClient._sendSoapRequest = function(url, method, parameters, async, callback, wsdl)
{
 // get namespace
 var ns = (wsdl.documentElement.attributes["targetNamespace"] + "" == "undefined") ? wsdl.documentElement.attributes.getNamedItem("targetNamespace").nodeValue : wsdl.documentElement.attributes["targetNamespace"].value;
 // build SOAP request
 var sr =
 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
 "<soap:Envelope " +
 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
 "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
 "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
 "<soap:Body>" +
 "<" + method + " xmlns=\"" + ns + "\">" +
 parameters.toXml() +
 "</" + method + "></soap:Body></soap:Envelope>";
 // send request
 var xmlHttp = SOAPClient._getXmlHttp();
 xmlHttp.open("POST", url, async);
 var soapaction = ((ns.lastIndexOf("/") != ns.length - 1) ? ns + "/" : ns) + method;
 xmlHttp.setRequestHeader("SOAPAction", soapaction);
 xmlHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
 if(async)
 {
 xmlHttp.onreadystatechange = function()
 {
 if(xmlHttp.readyState == 4)
 SOAPClient._onSendSoapRequest(method, async, callback, wsdl, xmlHttp);
 }
 }
 xmlHttp.send(sr);
 if (!async)
 return SOAPClient._onSendSoapRequest(method, async, callback, wsdl, xmlHttp);
}





SOAPClient._onSendSoapRequest = function(method, async, callback, wsdl, req)
{
 var o = null;
 var nd = SOAPClient._getElementsByTagName(req.responseXML, method + "Result");
 if(nd.length == 0)
 {
 if(req.responseXML.getElementsByTagName("faultcode").length > 0)
 {
 if(async || callback)
 o = new Error(500, req.responseXML.getElementsByTagName("faultstring")[0].childNodes[0].nodeValue);
 else
 throw new Error(500, req.responseXML.getElementsByTagName("faultstring")[0].childNodes[0].nodeValue);
 }
 }
 else
 o = SOAPClient._soapresult2object(nd[0], wsdl);
 if(callback)
 callback(o, req.responseXML);
 if(!async)
 return o;
}



SOAPClient._soapresult2object = function(node, wsdl)
{
 var wsdlTypes = SOAPClient._getTypesFromWsdl(wsdl);
 return SOAPClient._node2object(node, wsdlTypes);
}



SOAPClient._node2object = function(node, wsdlTypes)
{
 // null node
 if(node == null)
 return null;
 // text node
 if(node.nodeType == 3 || node.nodeType == 4)
 return SOAPClient._extractValue(node, wsdlTypes);
 // leaf node
 if (node.childNodes.length == 1 && (node.childNodes[0].nodeType == 3 || node.childNodes[0].nodeType == 4))
 return SOAPClient._node2object(node.childNodes[0], wsdlTypes);
 var isarray = SOAPClient._getTypeFromWsdl(node.nodeName, wsdlTypes).toLowerCase().indexOf("arrayof") != -1;
 // object node
 if(!isarray)
 {
 var obj = null;
 if(node.hasChildNodes())
 obj = new Object();
 for(var i = 0; i < node.childNodes.length; i++)
 {
 var p = SOAPClient._node2object(node.childNodes[i], wsdlTypes);
 obj[node.childNodes[i].nodeName] = p;
 }
 return obj;
 }
 // list node
 else
 {
 // create node ref
 var l = new Array();
 for(var i = 0; i < node.childNodes.length; i++)
 l[l.length] = SOAPClient._node2object(node.childNodes[i], wsdlTypes);
 return l;
 }
 return null;
}



SOAPClient._extractValue = function(node, wsdlTypes)
{
 var value = node.nodeValue;
 switch(SOAPClient._getTypeFromWsdl(node.parentNode.nodeName, wsdlTypes).toLowerCase())
 {
 default:
 case "s:string":
 return (value != null) ? value + "" : "";
 case "s:boolean":
 return value + "" == "true";
 case "s:int":
 case "s:long":
 return (value != null) ? parseInt(value + "", 10) : 0;
 case "s:double":
 return (value != null) ? parseFloat(value + "") : 0;
 case "s:datetime":
 if(value == null)
 return null;
 else
 {
 value = value + "";
 value = value.substring(0, (value.lastIndexOf(".") == -1 ? value.length : value.lastIndexOf(".")));
 value = value.replace(/T/gi," ");
 value = value.replace(/-/gi,"/");
 var d = new Date();
 d.setTime(Date.parse(value));
 return d;
 }
 }
}



SOAPClient._getTypesFromWsdl = function(wsdl)
{
 var wsdlTypes = new Array();
 // IE
 var ell = wsdl.getElementsByTagName("s:element");
 var useNamedItem = true;
 // MOZ
 if(ell.length == 0)
 {
 ell = wsdl.getElementsByTagName("element");
 useNamedItem = false;
 }
 for(var i = 0; i < ell.length; i++)
 {
 if(useNamedItem)
 {
 if(ell[i].attributes.getNamedItem("name") != null && ell[i].attributes.getNamedItem("type") != null)
 wsdlTypes[ell[i].attributes.getNamedItem("name").nodeValue] = ell[i].attributes.getNamedItem("type").nodeValue;
 }
 else
 {
 if(ell[i].attributes["name"] != null && ell[i].attributes["type"] != null)
 wsdlTypes[ell[i].attributes["name"].value] = ell[i].attributes["type"].value;
 }
 }
 return wsdlTypes;
}



SOAPClient._getTypeFromWsdl = function(elementname, wsdlTypes)
{
 var type = wsdlTypes[elementname] + "";
 return (type == "undefined") ? "" : type;
}
// private: utils



SOAPClient._getElementsByTagName = function(document, tagName)
{
 try
 {
 // trying to get node omitting any namespaces (latest versions of MSXML.XMLDocument)
 return document.selectNodes(".//*[local-name()=\""+ tagName +"\"]");
 }
 catch (ex) {}
 // old XML parser support
 return document.getElementsByTagName(tagName);
}
// private: xmlhttp factory



SOAPClient._getXmlHttp = function()
{
 try
 {
 if(window.XMLHttpRequest)
 {
 var req = new XMLHttpRequest();
 // some versions of Moz do not support the readyState property and the onreadystate event so we patch it!
 if(req.readyState == null)
 {
 req.readyState = 1;
 req.addEventListener("load",
 function()
 {
 req.readyState = 4;
 if(typeof req.onreadystatechange == "function")
 req.onreadystatechange();
 },
 false);
 }
 return req;
 }
 if(window.ActiveXObject)
 return new ActiveXObject(SOAPClient._getXmlHttpProgID());
 }
 catch (ex) {}
 throw new Error("Your browser does not support XmlHttp objects");
}



SOAPClient._getXmlHttpProgID = function()
{
 if(SOAPClient._getXmlHttpProgID.progid)
 return SOAPClient._getXmlHttpProgID.progid;
 var progids = ["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
 var o;
 for(var i = 0; i < progids.length; i++)
 {
 try
 {
 o = new ActiveXObject(progids[i]);
 return SOAPClient._getXmlHttpProgID.progid = progids[i];
 }
 catch (ex) {};
 }
 throw new Error("Could not find an installed XML parser");
}
