/*****************************************************************************\

 Javascript "SOAP Client" library

 @version: 1.6 - 2007.05.03
 @author: Maximus
 @description: (1) SOAPClientParameters() constructor modifed.

 @version: 1.5 - 2006.12.16
 @author: Maximus
 @description: (1) SOAPClientParameters().add method modifed.
               (2) "_sendSoapRequest" method worked with structs.

 @version: 1.4 - 2005.12.10
 @author: Matteo Casati, Ihar Voitka - http://www.guru4.net/
 @description: (1) SOAPClientParameters.add() method returns 'this' pointer.
               (2) "_getElementsByTagName" method added for xpath queries.
               (3) "_getXmlHttpPrefix" refactored to "_getXmlHttpProgID" (full 
                   ActiveX ProgID).
               
 @version: 1.3 - 2005.12.06
 @author: Matteo Casati - http://www.guru4.net/
 @description: callback function now receives (as second - optional - parameter) 
               the SOAP response too. Thanks to Ihar Voitka.
               
 @version: 1.2 - 2005.12.02
 @author: Matteo Casati - http://www.guru4.net/
 @description: (1) fixed update in v. 1.1 for no string params.
               (2) the "_loadWsdl" method has been updated to fix a bug when 
               the wsdl is cached and the call is sync. Thanks to Linh Hoang.
               
 @version: 1.1 - 2005.11.11
 @author: Matteo Casati - http://www.guru4.net/
 @description: the SOAPClientParameters.toXML method has been updated to allow
               special characters ("<", ">" and "&"). Thanks to Linh Hoang.

 @version: 1.0 - 2005.09.08
 @author: Matteo Casati - http://www.guru4.net/
 @notes: first release.

\*****************************************************************************/

function SOAPClientParameters(arr)
{
	var _pl = (arr==undefined || arr==null) ? new Array() : arr;
	this.arr = function() { return _pl; }
	this.add = function(name, value) 
	{
		if((value + "" == "undefined") || (value + "" == "null"))
			value = "";
		_pl[name] = value; 
		return this; 
	}
	this.toXml = function()
	{
		var xml = "";
		for(var p in _pl)
		{
			if(typeof(_pl[p]) != "function")
				xml += "<" + p + ">" + _pl[p].toString().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;") + "</" + p + ">";
		}
		return xml;	
	}
}

function SOAPClient() {}


SOAPClient.invoke = function(url, method, parameters, async, callback, xmlhttp_method)
{
        GDebugPort.debug("SOAPClient.invoke: " + method);

	if(async)
		SOAPClient._loadWsdl(url, method, parameters, async, callback, xmlhttp_method);
	else
		return SOAPClient._loadWsdl(url, method, parameters, async, callback, xmlhttp_method);
}

// private: wsdl cache
SOAPClient_cacheWsdl = new Array();

// private: invoke async
SOAPClient._loadWsdl = function(url, method, parameters, async, callback, xmlhttp_method)
{
        GDebugPort.debug("SOAPClient._loadWsdl: " + method);
        
        if(System.localRun == true) {
               try {
                   netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
               } catch (e) {
                   alert("Permission UniversalBrowserRead denied.");
               }
        }

	// load from cache?
	var wsdl = SOAPClient_cacheWsdl[url];
	if(wsdl + "" != "" && wsdl + "" != "undefined")
		return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl, xmlhttp_method);
		
        GDebugPort.debug("SOAPClient._getWsdl: " + method);
  
	// get wsdl
	var xmlHttp = SOAPClient._getXmlHttp();
	var wsdl_url = wsdlData + url + ".wsdl";
	GDebugPort.debug("WSDL url: " + wsdl_url);
	xmlHttp.open("GET", wsdl_url, async);

	if(async)
	{
		xmlHttp.onreadystatechange = function() 
		{
			//alert(xmlHttp.readyState);
			if(xmlHttp.readyState == 4)
				SOAPClient._onLoadWsdl(url, method, parameters, async, callback, xmlHttp, xmlhttp_method);
		}
	}
	xmlHttp.send(null);
	if (!async)
		return SOAPClient._onLoadWsdl(url, method, parameters, async, callback, xmlHttp, xmlhttp_method);
}
SOAPClient._onLoadWsdl = function(url, method, parameters, async, callback, req, xmlhttp_method)
{
       GDebugPort.debug("SOAPClient._saveWsdl: " + method);
       GDebugPort.debug(req.responseText);
	var wsdl = req.responseXML;
	SOAPClient_cacheWsdl[url] = wsdl;	// save a copy in cache

	return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl, xmlhttp_method);
}

function GetAttribute(node, attribute) {
	//alert(node.tagName);
	if(node.nodeType == 1) {
		if(node.attributes[attribute] + "" == "undefined")	// IE
		{
			if(node.attributes.getNamedItem(attribute) != null) 
				return node.attributes.getNamedItem(attribute).nodeValue;
		}
		else // MOZ
		{
			if(node.attributes[attribute] != null)
				return node.attributes[attribute].value;
		}
	} else
		return "undefined";
}

//SOAPClient.prototype.asyncState = null;

SOAPClient._sendSoapRequest = function(url, method, parameters, async, callback, wsdl, xmlhttp_method)
{

       GDebugPort.debug("SOAPClient._sendSoapRequest: " + method);
       //GDebugPort.debug(wsdl);

	// get namespace
	var ns = (wsdl.documentElement.attributes["targetNamespace"] + "" == "undefined") ? wsdl.documentElement.attributes.getNamedItem("targetNamespace").nodeValue : wsdl.documentElement.attributes["targetNamespace"].value;
	GDebugPort.debug("Namespace: " + ns);

	var st, sn;

	var level1 = wsdl.documentElement;
	var request_message = level1.childNodes;

	var i, j = -1;
	for(i=0; i<request_message.length; i++) {
		if(GetAttribute(request_message[i], "name") == (method+"Request")) {
			j = i;
			break;
		}
	}
	if(j != -1) {
		var part = request_message[j].childNodes;
		sn = GetAttribute(part[0], "name");
		st = GetAttribute(part[0], "type");
		//alert(sn);
		//alert(st);
	}

	//alert(parameters.toXml());

	// build SOAP request
	var sr = 
				"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
				"<SOAP-ENV:Envelope SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' " + 
				"xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' " +
				"xmlns:xsd='http://www.w3.org/2001/XMLSchema' " +
				"xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " +
				"xmlns:SOAP-ENC='http://schemas.xmlsoap.org/soap/encoding/' " +
				"xmlns:tns=\"" + ns + "\">" +
				"<SOAP-ENV:Body>" +
				"<tns:" + method + " xmlns:tns=\"" + ns + "\">" +
				"<" + sn + " xsi:type=\"" + st + "\">" +
				parameters.toXml() +
				"</" + sn + ">" +
				"</tns:" + method + "></SOAP-ENV:Body></SOAP-ENV:Envelope>";
	// send request
	var xmlHttp = (xmlhttp_method + "" == "undefined") ? SOAPClient._getXmlHttp() : xmlhttp_method;

	var ws_url = wsData + url + ".ws";
	GDebugPort.debug("WS url: " + ws_url);
	xmlHttp.open("POST", ws_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");
	
	GDebugPort.debug("Request: " + sr);

	if(async)
	{
		xmlHttp.onreadystatechange = function()
		{
			//alert(method + " : " + xmlHttp.readyState);
			//this.asyncState = xmlHttp.readyState;
			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;

	GDebugPort.debug("SOAPClient._onSendSoapRequest: " + method);
        GDebugPort.debug(req.responseText);
        
	var nd = SOAPClient._getElementsByTagName(req.responseXML, method + "Response");
	if(nd.length == 0)
	{
		if(req.responseXML.getElementsByTagName("faultcode").length > 0)
			throw new Error(500, req.responseXML.getElementsByTagName("faultstring")[0].childNodes[0].nodeValue);
	}
	else {
		o = SOAPClient._soapresult2object(nd[0], wsdl);
	}
	if(callback) {
		DecodeData(o);
		callback(o, req.responseXML);
	}
	if(!async)
		return o;
}

function DecodeData(obj) {
	if(obj instanceof Object) {
		for(var i in obj) {
			if(obj[i] instanceof Object)
				DecodeData(obj[i]);
			else
      				obj[i] = StrDecodeSlave(obj[i] + "");
		}
	}
}

// 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

	var myXML = document.getElementsByTagName(tagName);
	return myXML;
}

SOAPClient._soapresult2object = function(node, wsdl)
{
	return SOAPClient._node2object(node, wsdl);
}
SOAPClient._node2object = function(node, wsdl)
{
	// null node
	if(node == null)
		return null;
	// text node
	if(node.nodeType == 3 || node.nodeType == 4)
		return SOAPClient._extractValue(node, wsdl);
	// leaf node
	if (node.childNodes.length == 1 && (node.childNodes[0].nodeType == 3 || node.childNodes[0].nodeType == 4))
		return SOAPClient._node2object(node.childNodes[0], wsdl);
	var isarray = SOAPClient._getTypeFromWsdl(node.nodeName, wsdl).toLowerCase().indexOf("arrayof") != -1;

	// object node
	if(!isarray)
	{
		var obj = null, text_node = false;
		if(node.hasChildNodes()) {
			obj = new Object();

			if(node.childNodes[0].nodeName == "#text") {
				text_node = true;
				obj[node.childNodes[0].nodeName] = "";
			}
		}

		for(var i = 0; i < node.childNodes.length; i++)
		{
			var p = SOAPClient._node2object(node.childNodes[i], wsdl);
			if(text_node)
				obj[node.childNodes[i].nodeName] += p;
			else
				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], wsdl);
		return l;
	}
	return null;
}
SOAPClient._extractValue = function(node, wsdl)
{
	var value = node.nodeValue;
	switch(SOAPClient._getTypeFromWsdl(node.parentNode.nodeName, wsdl).toLowerCase())
	{
		default:
		case "s:string":			
			return (value + "" != "null") ? value : ""; //? StrDecodeSlave(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("."));
				value = value.replace(/T/gi," ");
				value = value.replace(/-/gi,"/");
				var d = new Date();
				d.setTime(Date.parse(value));										
				return d;				
			}
	}
}
SOAPClient._getTypeFromWsdl = function(elementname, wsdl)
{
	var ell = wsdl.getElementsByTagName("s:element");	// IE
	if(ell.length == 0)
		ell = wsdl.getElementsByTagName("element");	// MOZ
	for(var i = 0; i < ell.length; i++)
	{
		if(ell[i].attributes["name"] + "" == "undefined")	// IE
		{
			if(ell[i].attributes.getNamedItem("name") != null && ell[i].attributes.getNamedItem("name").nodeValue == elementname && ell[i].attributes.getNamedItem("type") != null) 
				return ell[i].attributes.getNamedItem("type").nodeValue;
		}
		else // MOZ
		{
			if(ell[i].attributes["name"] != null && ell[i].attributes["name"].value == elementname && ell[i].attributes["type"] != null)
				return ell[i].attributes["type"].value;
		}
	}
	return "";
}

// private: xmlhttp factory
SOAPClient._getXmlHttp = function()
{
	try
	{
		if(window.ActiveXObject) 
			return new ActiveXObject(SOAPClient._getXmlHttpProgID());

		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;
		}
	}
	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");
}

function StrDecodeSlave(str)
{
	replace = [ " ", "!", "\"", "%", "&", "'", "(", ")", "*", "+", "," ,"-", ".", "/", ":", ";", "<", "=", ">", "?", "@", "[", "]", "^", "_", "`", "{", "}", "#", "\\", "|" ];
	template = [ /#32/g, /#33/g, /#34/g, /#37/g, /#38/g, /#39/g, /#40/g, /#41/g, /#42/g, /#43/g, /#44/g, /#45/g, /#46/g, /#47/g, /#58/g, /#59/g, /#60/g, /#61/g, /#62/g, /#63/g, /#64/g, /#91/g, /#93/g, /#94/g, /#95/g, /#96/g, /#123/g, /#125/g, /#35/g, /#92/g, /#124/g ];

	var res = str;

	for(var i=0;i<template.length; i++)
		res = res.replace(template[i], replace[i]);


	/*str = str_replace("#", "#35", $str);
	str = str_replace("\\", "#92", $str);
	str = str_replace("\$", "#36", $str);
	str = str_replace("|", "#124", $str);*/
	//str = preg_replace($pattern, $replace, $str);

	return res;
}
