﻿// JQuery Web Services Proxy
// based on Matthias Hertel's js webservice soap implementation
// author: omer / started on 22.04.2008
// nullable parameters support added
// auto date serialization functionality added on 23.09.2008
(function($) {
    $.WebServices = new function() {
        this.author = "MagiClick - Omer DUZYOL";
        this.version = "1.2.1";
        this.methodBase = function(srv, method, args, result) {
            function _call() {
                var args = arguments;
                var p = args.callee;

                // envelope start
                var soap = "<?xml version='1.0' encoding='utf-8'?>"
            + "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>"
            + "<soap:Body>"
            + "<" + p.fname + " xmlns='" + p.service.ns + "'>";

                // parameters
                if (p.params != null) {
                    for (n = 0; (n < p.params.length) && (n < args.length); n++) {
                        var val = args[n];
                        var typ = p.params[n].split(':');

                        if ((typ.length == 1) || (typ[1] == "string")) {
                            val = String(args[n]).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

                        } else if (typ[1] == "int") {
                            val = parseInt(args[n]);
                            if (isNaN(val))
                                val = null;
                        } else if (typ[1] == "decimal") {
                            val = parseFloat(args[n])
                        } else if (typ[1] == "short") {
                            val = parseFloat(args[n])
                        } else if (typ[1] == "long") {
                            val = parseInt(args[n])
                        } else if (typ[1] == "float") {
                            val = parseFloat(args[n]);

                        } else if ((typ[1] == "x") && (typeof (args[n]) == "string")) {
                            val = args[n];

                        } else if ((typ[1] == "x") && (typeof (XMLSerializer) != "undefined")) {
                            val = (new XMLSerializer()).serializeToString(args[n].firstChild);

                        } else if (typ[1] == "x") {
                            if (args[n] != null)
                                val = args[n].xml;

                        } else if ((typ[1] == "bool") && (typeof (args[n]) == "string")) {
                            val = args[n].toLowerCase();

                        } else if (typ[1] == "bool") {
                            val = String(args[n]).toLowerCase();

                        } else if (typ[1] == "date") {
                            // calculate the xml format for datetime objects from a javascript date object
                            if (val != null) {
                                if (typeof val == 'object') {
                                    var s, ret;
                                    ret = _makeDigit(String(val.getFullYear()), 4);
                                    ret += "-";
                                    s = _makeDigit(String(val.getMonth() + 1), 2);
                                    ret += (s.length == 1 ? "0" + s : s);
                                    ret += "-";
                                    s = _makeDigit(String(val.getDate()), 2);
                                    ret += (s.length == 1 ? "0" + s : s);
                                    ret += "T";
                                    s = _makeDigit(String(val.getHours()), 2);
                                    ret += (s.length == 1 ? "0" + s : s);
                                    ret += ":";
                                    s = _makeDigit(String(val.getMinutes()), 2);
                                    ret += (s.length == 1 ? "0" + s : s);
                                    ret += ":";
                                    s = _makeDigit(String(val.getSeconds()), 2);
                                    ret += (s.length == 1 ? "0" + s : s);
                                    val = ret;
                                }
                            } else {
                                val = "0001-01-01T00:00:00";
                            }

                        } else if (typ[1] == "s[]") {
                            if (args[n] != null)
                                val = "<string>" + args[n].join("</string><string>") + "</string>";
                            else val = "";

                        } else if (typ[1] == "int[]") {
                            if (args[n] != null)
                                val = "<int>" + args[n].join("</int><int>") + "</int>";
                            else val = "";
                        } else if (typ[1] == "short[]") {
                            if (args[n] != null)
                                val = "<short>" + args[n].join("</short><short>") + "</short>";
                            else val = "";
                        } else if (typ[1] == "decimal[]") {
                            if (args[n] != null)
                                val = "<decimal>" + args[n].join("</decimal><decimal>") + "</decimal>";
                            else val = "";
                        } else if (typ[1] == "long[]") {
                            if (args[n] != null)
                                val = "<long>" + args[n].join("</long><long>") + "</long>";
                            else val = "";
                        } else if (typ[1] == "float[]") {
                            if (args[n] != null)
                                val = "<float>" + args[n].join("</float><float>") + "</float>";
                            else val = "";

                        } else if (typ[1] == "bool[]") {
                            if (args[n] != null)
                                val = "<boolean>" + args[n].join("</boolean><boolean>") + "</boolean>";
                            else val = "";

                        } // if
                        if (val != null)
                            soap += "<" + typ[0] + ">" + val + "</" + typ[0] + ">"
                    } // for
                } //if

                // envelope end
                soap += "</" + p.fname + ">"
            + "</soap:Body>"
            + "</soap:Envelope>";

                // enable cookieless sessions:
                var u = p.service.url;
                var cs = document.location.href.match(/\/\(.*\)\//);
                if (cs != null) {
                    u = p.service.url.split('/');
                    u[3] += cs[0].substr(0, cs[0].length - 1);
                    u = u.join('/');
                }



                // finally call web services with jquery
                var soapXhr = $.ajax({
                    url: u,
                    type: "POST",
                    timeout: 50000,
                    data: soap,
                    beforeSend: function(xhr) {
                        // raise onCall event
                        if (p.onBeforeCall != null) {
                            p.onBeforeCall(xhr, u, soap);
                        } else {
                            $.WebServices.onBeforeCall(xhr, u, soap);
                        }

                        xhr.setRequestHeader("SOAPAction", p.action);
                        xhr.setRequestHeader("X-Requested-With", "");
                    },
                    contentType: "text/xml; charset=utf-8",
                    dataType: "xml",
                    success: function(responseXML, textStatus) {
                        var ret = null;
                        var cc = p;

                        if (cc == null) return;
                        var rtype = null;

                        if ((cc.rtype.length > 0) && (cc.rtype[0] != null))
                            rtype = cc.rtype[0].split(':');

                        var xNode = null;

                        if (rtype != null)
                            xNode = responseXML.getElementsByTagName(rtype[0])[0];

                        if (xNode == null) {
                            ret = null;

                        } else if (xNode.firstChild == null) { // 27.12.2005: empty string return values
                            ret = ((rtype.length == 1) || (rtype[1] == "string") ? "" : null);

                        } else if ((rtype.length == 1) || (rtype[1] == "string")) {
                            ret = xNode.textContent || xNode.innerText || xNode.text || xNode.childNodes[0].nodeValue;

                        } else if (rtype[1] == "bool") {
                            ret = xNode.textContent || xNode.innerText || xNode.text || xNode.childNodes[0].nodeValue;
                            ret = (ret == "true");

                        } else if (rtype[1] == "int") {
                            ret = xNode.textContent || xNode.innerText || xNode.text || xNode.childNodes[0].nodeValue;
                            ret = parseInt(ret);

                        } else if (rtype[1] == "float") {
                            ret = xNode.textContent || xNode.innerText || xNode.text || xNode.childNodes[0].nodeValue;
                            ret = parseFloat(ret);

                        } else if ((rtype[1] == "x") && (typeof (XMLSerializer) != "undefined")) {
                            ret = (new XMLSerializer()).serializeToString(xNode.firstChild);
                            ret = $.WebServices._getXMLDOM(ret);

                        } else if ((rtype[1] == "ds") && (typeof (XMLSerializer) != "undefined")) {
                            // serialize dataset object to xml and finally to json
                            ret = (new XMLSerializer()).serializeToString(xNode);
                            ret = $.WebServices._getXMLDOM(ret);
                            ret = $.WebServices._xml2json(ret);

                        } else if (rtype[1] == "x") {
                            ret = xNode.firstChild.xml;
                            ret = $.WebServices._getXMLDOM(ret);

                        } else if (rtype[1] == "ds") {
                            // serialize dataset object to xml and finally to json
                            ret = xNode.xml;
                            ret = $.WebServices._getXMLDOM(ret);
                            ret = $.WebServices._xml2json(ret);

                        } else if (rtype[1] == "s[]") {
                            // Array of strings
                            ret = new Array();
                            xNode = xNode.firstChild;
                            while (xNode != null) {
                                ret.push(xNode.textContent || xNode.innerText || xNode.text || xNode.childNodes[0].nodeValue);
                                xNode = xNode.nextSibling;
                            } // while

                        } else if (rtype[1] == "int[]") {
                            // Array of int
                            ret = new Array();
                            xNode = xNode.firstChild;
                            while (xNode != null) {
                                ret.push(parseInt(xNode.textContent || xNode.innerText || xNode.text || xNode.childNodes[0].nodeValue));
                                xNode = xNode.nextSibling;
                            } // while

                        } else if (rtype[1] == "float[]") {
                            // Array of float
                            ret = new Array();
                            xNode = xNode.firstChild;
                            while (xNode != null) {
                                ret.push(parseFloat(xNode.textContent || xNode.innerText || xNode.text || xNode.childNodes[0].nodeValue));
                                xNode = xNode.nextSibling;
                            } // while

                        } else if (rtype[1] == "bool[]") {
                            // Array of bool
                            ret = new Array();
                            xNode = xNode.firstChild;
                            while (xNode != null) {
                                ret.push((xNode.textContent || xNode.innerText || xNode.text || xNode.childNodes[0].nodeValue).toLowerCase() == "true");
                                xNode = xNode.nextSibling;
                            } // while

                        } else {
                            ret = xNode.textContent || xNode.innerText || xNode.text || xNode.childNodes[0].nodeValue;
                        } // if

                        // sycronize call response
                        if (cc.Callback == null) {
                            return ret;
                        } else {
                            // if returning value is json data?
                            var jsonCheck = null;
                            try {
                                // then convert json string to object
                                jsonCheck = $.JSON.parse(ret, function(key, value) {
                                    var a;
                                    if (typeof value === 'string') {
                                        a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                                        if (a)
                                            return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]));
                                    }
                                    return value;
                                });
                                if (jsonCheck != null && jsonCheck.Succeed != null) {
                                    ret = jsonCheck;
                                }
                            } catch (e) { }
                            if (jsonCheck != null && jsonCheck.Exception != null && jsonCheck.Message != null) {
                                // raise an exception
                                ret = new Error();
                                ret.name = 'Handled Webservice Exception';
                                ret.message = jsonCheck.Message;
                                ret.description = jsonCheck.Exception;
                                if (p.onError != null) {
                                    p.onError(ret);
                                } else {
                                    $.WebServices.onError(ret);
                                }
                            } else {
                                cc.Callback(ret);
                            }
                            return;
                        }
                        //}
                    },
                    error: function(xhr, textStatus, errorThrown) {
                        var extraDetails = "";
                        var skipError = false;

                        if (textStatus == "timeout")
                            skipError = true;

                        // raise an exception
                        ret = new Error();
                        try {
                            if (xhr.status == 404) {
                                ret.message = "The webservice could not be found.";

                            } else if (xhr.status == 500) {
                                var ret_name, ret_message, ret_description;
                                ret_name = "SoapException";
                                //ret.name = "SoapException";
                                var n = xhr.responseXML.documentElement.firstChild.firstChild.firstChild;
                                while (n != null) {
                                    if (n.nodeName == "faultcode") ret_message = n.firstChild.nodeValue; //ret.message = n.firstChild.nodeValue;
                                    if (n.nodeName == "faultstring") ret_description = n.firstChild.nodeValue; //ret.description = n.firstChild.nodeValue;
                                    n = n.nextSibling;
                                } // while
                                ret.name = ret_name;
                                ret.message = ret_message;
                                ret.description = ret_description;

                            } else if ((xhr.status == 502) || (xhr.status == 12031)) {
                                ret.message = "The server could not be found.";

                            } else {
                                // no classified response.
                                ret.message = "Result-Status:" + xhr.status + "\n" + xhr.responseText;
                            } // if


                        } catch (err) {
                            if (err.name == "NS_ERROR_NOT_AVAILABLE") {

                                skipError = true;
                            } else {
                                ret.name = "XMLHttpBrokenConnectionException";
                                ret.message = "Connection closed unexpectedly. You may not have access to get request.";
                                ret.description = "";
                                extraDetails = err;
                            }
                        }

                        if (!skipError) {
                            if (p.onError != null) {
                                p.onError(ret, extraDetails);
                            } else {
                                $.WebServices.onError(ret, extraDetails);
                            }
                        }
                    },
                    complete: function(XMLHttpRequest, textStatus) {
                        if (p.onFinally != null) {
                            p.onFinally(XMLHttpRequest, textStatus);
                        } else {
                            $.WebServices.onFinally(XMLHttpRequest, textStatus);
                        }
                    }
                });
                p.xhr = soapXhr;
            }
            
            function _getXMLDOM(xmlText) {
                var obj = null;

                if ((document.implementation != null) && (typeof document.implementation.createDocument == "function")) {
                    // Gecko / Mozilla / Firefox
                    var parser = new DOMParser();
                    obj = parser.parseFromString(xmlText, "text/xml");

                } else {
                    // IE
                    try {
                        obj = new ActiveXObject("MSXML2.DOMDocument");
                    } catch (e) { }

                    if (obj == null) {
                        try {
                            obj = new ActiveXObject("Microsoft.XMLDOM");
                        } catch (e) { }
                    } // if

                    if (obj != null) {
                        obj.async = false;
                        obj.validateOnParse = false;
                    } // if
                    obj.loadXML(xmlText);
                } // if
                return (obj);
            } // _getXMLDOM
            
            function _xml2json(xObj) {
                if (xObj.nodeType == 9)
                    return (this._xml2json(xObj.documentElement));

                var n = xObj.firstChild;
                if (n.nodeType == 3) {
                    // just a text node.
                    ret = n.nodeValue;

                } else {
                    // a complex node.
                    var ret = {};

                    // analyse all subnodes
                    while (n != null) {
                        var nn = n.nodeName;
                        var nv = this._xml2json(n); // recursion !
                        if (ret[nn] == null) {
                            // maybe just a simple nested value
                            ret[nn] = nv;
                        } else if (ret[nn].constructor == Array) {
                            // nn is already an array, now with another value
                            ret[nn].push(nv);
                        } else {
                            // if more than 1 element with the same name is present
                            // an array is used to collect them all.
                            var tmp = new Array();
                            tmp[0] = ret[nn];
                            tmp[1] = nv;
                            ret[nn] = tmp;
                        } // if
                        n = n.nextSibling;
                    } // while
                } // if
                return (ret);
            } // xml2json
            
            function _makeDigit(strData, intDigits) {
                var ret = strData;
                for (var t = 0; t < intDigits; t++)
                    ret = "0" + ret;

                ret = ret.substring(ret.length - intDigits)
                return ret;
            }

            var newMethod = $.extend(_call, this);
            newMethod.fname = method;
            newMethod.service = srv;
            newMethod.action = "\"" + srv.ns + method + "\"";
            newMethod.params = args;
            newMethod.rtype = result;
            return newMethod;
        };
        this.methodBase.prototype.fname = null;
        this.methodBase.prototype.service = null;
        this.methodBase.prototype.action = null;
        this.methodBase.prototype.params = null;
        this.methodBase.prototype.rtype = null;
        this.methodBase.prototype.__typeName = 'methodBase';
        this.methodBase.prototype.__class = true;

        this.onError = function(err, extraDetails) {
            alert("Web Service error\r\n" + err.name + "\r\nMessage: " + err.message + "\r\n" + err.description);
        };
        this.onBeforeCall = function() {
            return;
        };
        this.onFinally = function() {
            return;
        }
    }
})(jQuery);