/*****************************************************************************\

 Javascript "SOAP Client" library
 
 @version: 2.4 - 2007.12.21
 @author: Matteo Casati - http://www.guru4.net/
  
Für Glassfish optimierte/lauffähige Version. angepasst von Sven Mandera. 

\*****************************************************************************/

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)
        {

			
            if (p.prototype){
                continue;
            }
            switch(typeof(_pl[p])) 
            {
                case "string":
                case "number":
                case "boolean":
                case "object":
                    if (p.indexOf("____array") == -1){
                        if(_pl[p].constructor.toString().indexOf("function Array()") > -1){
                            if (!_pl[p].prototype){
                                xml += "<Object name='"+p+"' type='array'>" + SOAPClientParameters._serialize(_pl[p],p)+"</Object>";
                            }
                        }
                        else {
                            xml += "<Object name='"+p+"' type='"+typeof(_pl[p])+"'>" + SOAPClientParameters._serialize(_pl[p]) + "</Object>";
                        }
                    }
                    break;
                default:
                    break;
            }
			
        }
		
        return xml;	
    }
}
SOAPClientParameters._serialize = function(o,pa)
{
    var s = "";
    if (o.prototype){
        return;
    }
    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 &&o.constructor.toString().indexOf("function Array()") > -1)
            {
                /*if (pa){
                    s += "<Object name='" + pa + "' type='array'>";
                }
                else {
                    s += "<Object name='" + type + "' type='array'>";
                }*/
                for(var p =0; p< o.length;p++)
                {
                    if (p.prototype){
                        continue;
                    }
                    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;
                        }
                    if (o[p] && o[p].prototype){
                        continue;
                    }
                        if (pa){
                            s += "<Object name='" + pa + "' type='"+typeof(o[p])+"'>" + SOAPClientParameters._serialize(o[p]) + "</Object>";
                        }
                        else if (o[p] && o[p].constructor.toString().indexOf("function Array()") > -1) {
                            s +="<Object name='" + type + "' type='array'>"+ SOAPClientParameters._serialize(o[p],type)+"</Object>";
                        }
                        else {
                            s += "<Object name='" + type + "' type='object'>"+SOAPClientParameters._serialize(o[p])+"</Object>";
                        }
                    }
                    else  {  // associative array
                         if (o[p] && o[p].prototype){
                        continue;
                    }
                        if (p.indexOf("____array") == -1 && o[p]){
                            s += "<Object name='" + p + "' type='array'>" + SOAPClientParameters._serialize(o[p]) + "</Object>"
                        }
                    }
                }
            // s += "</Object>";
            }
            // Object or custom function
            else 
                for(var p in o){
                      if (p.prototype){
                        continue;
                    }
                    if (p.indexOf("____array") == -1 && o[p]){
                          if (o[p] && o[p].prototype){
                        continue;
                    }
                        if (o[p].constructor.toString().indexOf("function Array()") > -1) {
                            s += "<Object name='" + p + "' type='object'>" +SOAPClientParameters._serialize(o[p].toArray(),p)+"</Object>";
                        }
                        else {
                            s += "<Object name='" + p + "' type='object'>" +SOAPClientParameters._serialize(o[p]) +"</Object>";
                        }
                    }
                }
            break;
        default:
            break; // throw new Error(500, "SOAPClientParameters: type '" + typeof(o) + "' is not supported");
    }
   
    return s;
}

function SOAPClient() {}

SOAPClient.username = null;
SOAPClient.password = null;

SOAPClient.invoke = function(url, method, parameters, async, callback,parseEntityAsId)
{
    //Hme hack lädt die Sachen über den Request Provider als XML
    // alert(url);
    return invokeSOAP(url, method, parameters, async, callback,parseEntityAsId);
//Original
/*
    if(async)
        SOAPClient._loadWsdl(url, method, parameters, async, callback,null);
    else
        return SOAPClient._loadWsdl(url, method, parameters, async, callback,null);*/
    
}


// private: wsdl cache
SOAPClient_cacheWsdl = new Array();

// private: invoke async
SOAPClient._loadWsdl = function(url, method, parameters, async, callback,schemaName)
{
    // 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();
    //Crazy WSDL Generation from NetBeans need this, because the types are defined in an imported xsd file.
    xmlHttp.open("GET", url + (schemaName != null ? schemaName:"?xsd=1"), 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
	
    //SMA glassfish need another request type, so i have changed something because the original have dont request the parameters.
	
	
    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/\">" +
    //"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"+
				
    "<soap:Body>" +
    "<ns0:" + method + " xmlns:ns0=\"" + ns + "\">" +
    parameters.toXml() +
    "</ns0:" + method + "></soap:Body></soap:Envelope>";
    // send request
    var xmlHttp = SOAPClient._getXmlHttp();

    var getIn = true;
    if (SOAPClient.userName ){
        xmlHttp.open("POST", url, async, SOAPClient.userName, SOAPClient.password);
        // Some WS implementations (i.e. BEA WebLogic Server 10.0 JAX-WS) don't support Challenge/Response HTTP BASIC, so we send authorization headers in the first request
        xmlHttp.setRequestHeader("Authorization", "Basic " + SOAPClient._toBase64(SOAPClient.userName + ":" + SOAPClient.password));
        getIn = false;
        
    }
    if (getIn) {
        var user = getLoggedInUser();
        var pass = getLoggedInPassword();
    }
    if (user && getIn){
        xmlHttp.open("POST", url, async, user, pass);
        // Some WS implementations (i.e. BEA WebLogic Server 10.0 JAX-WS) don't support Challenge/Response HTTP BASIC, so we send authorization headers in the first request
        xmlHttp.setRequestHeader("Authorization", "Basic " + SOAPClient._toBase64(user + ":" +pass));
        SOAPClient.userName = user;
        SOAPClient.password=pass;
    }
    else if (getIn)
        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");
    var ret = false;
    if(nd.length == 0){
        nd = SOAPClient._getElementsByTagName(req.responseXML, "return");	// PHP web Service?
        ret = true;
    }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);			
        }
    }
	
    var wsdlTypes = SOAPClient._getTypesFromWsdl(wsdl);
    var normal = true;
    if ( nd.length > 1 && ret){
        var methodName = nd[0].parentNode.nodeName;
 		
        if (methodName.indexOf(":")>-1){
            methodName = methodName.substring(methodName.indexOf(":")+1);
        }
 		
        var typeFromWSDL = SOAPClient._getTypeFromWsdl(methodName,wsdlTypes);
		
        if (typeFromWSDL){
            o = new Array();
            for (var i = 0; i< nd.length;i++){				
                o[o.length] = SOAPClient._soapresult2object(nd[i], wsdl,wsdlTypes);
            }
            normal = false;
        }
    }
    if (normal && ret && nd.length == 1){
        //TODO HEADER
        var methodName = nd[0].parentNode.nodeName;
        if (methodName.indexOf(":")>-1){
            methodName = methodName.substring(methodName.indexOf(":")+1);
        }
        var typeFromWSDL = SOAPClient._getTypeFromWsdl("subtype_"+methodName,wsdlTypes);
        if (typeFromWSDL.indexOf('arrayof')>-1){
            o = new Array();
            for (var i = 0; i< nd.length;i++){				
                o[o.length] = SOAPClient._soapresult2object(nd[i], wsdl,wsdlTypes);
            } 
            normal = false;
        }
           
    }
    if (normal)
        o = SOAPClient._soapresult2object(nd[0], wsdl,wsdlTypes);
		
    if(callback)
        callback(o, req.responseXML);
    if(!async)
        return o;
}
SOAPClient._soapresult2object = function(node, wsdl,wsdlTypes)
{
   
    return SOAPClient._node2object(node, wsdlTypes);
}
SOAPClient._node2object = function(node, wsdlTypes)
{
	
    //alert("node2Object "+node.nodeType+" childs = "+node.childNodes.length);
    // 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
    //TODO SMA
    //alert("nodeName "+node.nodeName+" nodeParent = "+node.parentNode.nodeName+" isArray = "+isarray+" type = "+SOAPClient._getTypeFromWsdl(node.nodeName, wsdlTypes)+" nods = "+node.childNodes.length);
	
    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);
            //alert(p);
            //alert("gegentest = "+SOAPClient._getTypeFromWsdl("test_"+node.nodeName, wsdlTypes));
            var subType = SOAPClient._getTypeFromWsdl("subtype_"+node.childNodes[i].nodeName, wsdlTypes);
            if (subType.indexOf('arrayof')>-1){
                var arr;
                if (obj[node.childNodes[i].nodeName]){
                    arr = obj[node.childNodes[i].nodeName];	
                }
                else {
                    arr = new Array();
                    //  alert("array"+node.childNodes[i].nodeName);
                    obj[node.childNodes[i].nodeName] = arr;
                }
                arr[arr.length] = 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], 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();
    //Kleine Anpassung da keine "isarray" im namen vorkommt wenn die daten aus glassfish kommen
    var arrayTypes = new Array();
    // IE
    var ell = wsdl.getElementsByTagName("xs:element");	
    var useNamedItem = true;

    // MOZ
    if(ell.length == 0)
    {
        ell = wsdl.getElementsByTagName("element");	     
        useNamedItem = false;
	
    }
	
    for(var i = 0; i < ell.length; i++)
    {
		
        if (ell[i].parentNode.nodeName.indexOf("sequence")>-1){
            var parentMethod = ell[i].parentNode.parentNode.getAttribute('name');
            var type = ell[i].getAttribute('type');
            if (ell[i].getAttribute('maxOccurs')){
                nodeValue = "arrayof("+type+")";
                wsdlTypes["subtype_"+parentMethod] = nodeValue;
            }
            if (type.indexOf("tns:")>-1){
                wsdlTypes[parentMethod] = type;
            }
        }
		
        //
        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;
                if (ell[i].attributes["maxOccurs"]){
                    nodeValue = "arrayof("+ell[i].attributes.getNamedItem("type").nodeValue+")";
                    wsdlTypes["subtype_"+ell[i].attributes.getNamedItem("name").nodeValue] = nodeValue;
                }
            //alert("named = "+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;
                if (ell[i].attributes["maxOccurs"]){
                    nodeValue = "arrayof("+ell[i].attributes["type"].value+")";
                    wsdlTypes["subtype_"+ell[i].attributes["name"].value] = nodeValue;
                }
            //alert("notnamed = "+ell[i].attributes["name"].value+" type = "+ell[i].attributes["type"].value);
            }
        }
		
    }
    return wsdlTypes;
}
SOAPClient._getTypeFromWsdl = function(elementname, wsdlTypes)
{
	
    var type = wsdlTypes[elementname] + "";
    //alert("getTypeFromWSDL = "+elementname+" type = "+type);
    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 = ["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");
}

SOAPClient._toBase64 = function(input)
{
    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    do {
        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }

        output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
        keyStr.charAt(enc3) + keyStr.charAt(enc4);
    } while (i < input.length);

    return output;
}

