﻿var zajaxm = function() {
    XMLHttpFactories = [
	            function() { return new XMLHttpRequest() },
	            function() { return new ActiveXObject("Msxml2.XMLHTTP") },
	            function() { return new ActiveXObject("Msxml3.XMLHTTP") },
	            function() { return new ActiveXObject("Microsoft.XMLHTTP") }
            ];

    dispose = function() {
        this.XMLHttpFactories = null;
    };
    A = function(o) {
        if (o == undefined) return false;
        if (!o) return false;
        return true;
    };
    AP = function(o) {
        if (!o) return '';
        if (o.length < 0) return '';
        var lout = new Array();
        for (var i = 0; i < o.length; i++) {
            if (o[i].value) {
                lout[lout.length] = o[i].key + "=" + o[i].value.toString();
            }
        }

        return lout.join("&");
    }

    call = function(o, context) {
        if (!A(o)) o = {};
        if (!A(context)) context = null;

        var lxmlHttp = this.createXMLHttp();
        if (!lxmlHttp) return;

        if (!A(o.async)) o.async = false;
        if (!A(o.onOk)) o.onOk = null;
        if (!A(o.onError)) o.onError = null;
        if (!A(o.postType)) o.postType = "GET";
        if (!A(o.file)) o.file = "ajax.ashx";
        if (!A(o.assembly)) o.assembly = '';
        if (!A(o.methodClass)) o.methodClass = '';
        if (!A(o.methodName)) o.methodName = '';
        if (!A(o.args)) o.args = new Array();
        if (!A(o.params)) o.params = null;

        var params = AP([
                    { key: "ahhc", value: o.methodClass },
                    { key: "ahhm", value: o.methodName },
                    { key: "ahass", value: o.assembly },
                    { key: "ahargs", value: this.toJSON(o.args) },
                    { key: "cache", value: (new Date()).getTime() }
                    ]);

        if (o.params) {
            params += "&" + o.params;
        };

        var isPost = (o.postType == 'POST');

        if (o.async) lxmlHttp.onreadystatechange = (function() {
            this.onreadystatechange(o, context, lxmlHttp);
        }).bind(this);

        if (!isPost) {
            if (params.length > -1) {
                var ld = (o.file.indexOf("?") > -1) ? "&" : "?";
                o.file += ld + params;
            }
        }

        lxmlHttp.open(o.postType, o.file, o.async);
        if (isPost) {
            lxmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            lxmlHttp.setRequestHeader("Content-length", params.length);
        }

        lxmlHttp.send((isPost) ? params : null);
        if (!o.async) this.onreadystatechange(o, context, lxmlHttp);

        return lxmlHttp;
    };

    onreadystatechange = function(o, context, xmlHttp) {
        if (!xmlHttp) return;
        if (xmlHttp.readyState != 4) return;
        if (xmlHttp.status == 200) {
            if (o.onOk) o.onOk(xmlHttp.responseText, o, context);
        } else {
            if (o.onError) o.onError(o, context, xmlHttp);
        }
        o = null;
        xmlHttp = null;
    };

    createXMLHttp = function() {
        var o = false;
        for (var i = 0; i < this.XMLHttpFactories.length; i++) {
            try { o = this.XMLHttpFactories[i](); } catch (e) { continue; }
            break;
        }
        return o;
    };

    AddEvent(window, "unload", (this.dispose).bind(this));
    return this;
} ();


(function($) {
    function toIntegersAtLease(n)
    // Format integers to have at least two digits.
    {
        return n < 10 ? '0' + n : n;
    }

    Date.prototype.toJSON = function(date)
    // Yes, it polutes the Date namespace, but we'll allow it here, as
    // it's damned usefull.
    {
        return this.getUTCFullYear() + '-' +
             toIntegersAtLease(this.getUTCMonth()) + '-' +
             toIntegersAtLease(this.getUTCDate());
    };

    var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
    var meta = {    // table of character substitutions
        '\b': '\\b',
        '\t': '\\t',
        '\n': '\\n',
        '\f': '\\f',
        '\r': '\\r',
        '"': '\\"',
        '\\': '\\\\'
    };

    $.quoteString = function(string)
    // Places quotes around a string, inteligently.
    // If the string contains no control characters, no quote characters, and no
    // backslash characters, then we can safely slap some quotes around it.
    // Otherwise we must also replace the offending characters with safe escape
    // sequences.
    {
        if (escapeable.test(string)) {
            return '"' + string.replace(escapeable, function(a) {
                var c = meta[a];
                if (typeof c === 'string') {
                    return c;
                }
                c = a.charCodeAt();
                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
            }) + '"';
        }
        return '"' + string + '"';
    };

    $.toJSON = function(o, compact) {
        var type = typeof (o);

        if (type == "undefined")
            return "undefined";
        else if (type == "number" || type == "boolean")
            return o + "";
        else if (o === null)
            return "null";

        // Is it a string?
        if (type == "string") {
            return $.quoteString(o);
        }

        // Does it have a .toJSON function?
        if (type == "object" && typeof o.toJSON == "function")
            return o.toJSON(compact);

        // Is it an array?
        if (type != "function" && typeof (o.length) == "number") {
            var ret = [];
            for (var i = 0; i < o.length; i++) {
                ret.push($.toJSON(o[i], compact));
            }
            if (compact)
                return "[" + ret.join(",") + "]";
            else
                return "[" + ret.join(", ") + "]";
        }

        // If it's a function, we have to warn somebody!
        if (type == "function") {
            throw new TypeError("Unable to convert object of type 'function' to json.");
        }

        // It's probably an object, then.
        var ret = [];
        for (var k in o) {
            var name;
            type = typeof (k);

            if (type == "number")
                name = '"' + k + '"';
            else if (type == "string")
                name = $.quoteString(k);
            else
                continue;  //skip non-string or number keys

            var val = $.toJSON(o[k], compact);
            if (typeof (val) != "string") {
                // skip non-serializable values
                continue;
            }

            if (compact)
                ret.push(name + ":" + val);
            else
                ret.push(name + ": " + val);
        }
        return "{" + ret.join(", ") + "}";
    };

    $.compactJSON = function(o) {
        return $.toJSON(o, true);
    };

    $.evalJSON = function(src)
    // Evals JSON that we know to be safe.
    {
        return eval("(" + src + ")");
    };

    $.secureEvalJSON = function(src)
    // Evals JSON in a way that is *more* secure.
    {
        var filtered = src;
        filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
        filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
        filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');

        if (/^[\],:{}\s]*$/.test(filtered))
            return eval("(" + src + ")");
        else
            throw new SyntaxError("Error parsing JSON, source is not valid.");
    };
})(zajaxm);