﻿(function ($) {
    //	---------------------------------------------------------
    //	             [jQuery.ajaxDotNet, ver 3.1]
    //	Copyright (c) 2008 Richard Kimber, http://www.dogma.co.uk
    //	Licensed under the terms of the MIT Licence (LICENSE.txt)
    //	---------------------------------------------------------
    //	On a personal note, I would love to hear about any
    //	implementations of this plugin. richard [at] dogma.co.uk
    //	---------------------------------------------------------

    //	Defaults
    var _defaults = {
        verb: "POST",
        useGet: false,
        data: new Object(),
        async: true,
        username: null,
        password: null,
        beforeSend: null,
        processData: null,
        success: null,
        error: null,
        complete: null,
        context: new Object(),
        usePrefix: true
    };

    //	Globals
    var _globals = {
        beforeSend: null,
        processData: null,
        success: null,
        error: null,
        complete: null,
        queue: 0,
        urlPrefix: null
    };

    //	Return new XMLHttpRequest Object
    function getXhr() {
        if (typeof XMLHttpRequest != "undefined") {
            return new XMLHttpRequest();
        }
        else if (typeof ActiveXObject != "undefined") {
            try {
                return new ActiveXObject("Msxml2.XMLHTTP");
            }
            catch (err) {
                try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { }
            }
        }
    };

    //	Test parameters of type String for dates and return either
    //	the orignal String or a newly created Date object.
    function cTD(v) {
        var rx = /\/Date\((-?[0-9]+)([+-][0-9]+)?\)\//g;
        if (rx.test(v)) {
            var milli = Number(v.replace(rx, "$1"));
            if (!isNaN(milli))
                v = new Date(Number(v.replace(rx, "$1")));
            else
                throw new Error("Date format not recognised.");
        }
        return v;
    };

    //	Recursively parse the JSON returned from the server.
    function tO(v) {
        if (v != null) {
            if (v.constructor == String) {
                v = cTD(v);
            }
            else if (v.constructor == Object || $.isArray(v)) {
                $.each(v, function (i, x) {
                    v[i] = i != "__type" ? tO(x) : x;
                });
            }
        }
        return v;
    };

    //	Main Function
    $.ajaxDotNet = function (url, options) {
        options = $.extend({}, _defaults, options);

        if (options.usePrefix && _globals.urlPrefix && _globals.urlPrefix != "") {
            url = _globals.urlPrefix + url;
        }

        var xhr = getXhr();

        //	Convert data option into a format readable by the server.
        var data = "";
        if (options.verb == "GET" || options.useGet) {
            options.verb = "GET";

            for (var i in options.data) {
                if (data != "") {
                    data += "&";
                }
                data += i + "=" + JSON.stringify(options.data[i]).replace(/#/, "%23");
            }
            url += "?" + data;
        }
        else {
            data = JSON.stringify(options.data);
        }

        //	Before Send Event Handler, remeber to return the XMLHttpRequest object.
        if ($.isFunction(_globals.beforeSend)) {
            xhr = _globals.beforeSend(xhr, url, options) || false;
        }

        if (xhr && $.isFunction(options.beforeSend)) {
            xhr = options.beforeSend(xhr, url, options) || false;
        }

        //	Make call to server
        if (xhr) {
            xhr.open(options.verb, url, options.async, options.username, options.password);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4) {
                    var r = xhr.responseText;
                    var e = null;

                    //	Parse response from server.
                    if (r.constructor == String) {
                        if (r != "") {
                            try {
                                r = JSON.parse(xhr.responseText);
                                if (typeof r == "object"
									&& r.Message !== undefined
									&& r.StackTrace !== undefined
									&& r.ExceptionType !== undefined) {
                                    e = r;
                                }
                                else {
                                    r = tO(r);
                                }
                            }
                            catch (err) {
                                e = err;
                            }
                        }
                        else {
                            r = {};
                        }
                    }

                    //	Process Data Event Handler
                    if ($.isFunction(_globals.processData)) {
                        r = _globals.processData(r, url, options) || false;
                    }

                    if (r && $.isFunction(options.processData)) {
                        r = options.processData(r, url, options) || false;
                    }

                    if (e == null && xhr.status == 200) {
                        if ($.isFunction(_globals.success)) {
                            _globals.success(r, xhr.status, xhr.statusText, options.context);
                        }

                        if ($.isFunction(options.success)) {
                            options.success(r || e, xhr.status, xhr.statusText, options.context);
                        }
                    }
                    else {
                        if ($.isFunction(_globals.error)) {
                            _globals.error(xhr, xhr.statusText, e, options.context);
                        }

                        if ($.isFunction(options.error)) {
                            options.error(xhr, xhr.statusText, e, options.context);
                        }
                    }

                    if ($.isFunction(_globals.complete)) {
                        _globals.complete(r, e, xhr, options.context);
                    }

                    if ($.isFunction(options.complete)) {
                        options.complete(r, e, xhr, options.context);
                    }
                }
            };
            xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            xhr.send(options.verb == "POST" ? data : null);
        }
        return xhr;
    };

    $.ajaxDotNet.defaults = function (options) {
        _defaults = $.extend(_defaults, options);
    };

    $.ajaxDotNet.globals = function (options) {
        _globals = $.extend(_globals, options);
    };
})(jQuery);
