if (typeof util === "undefined") {
    var util = {};
}

if (!util.ajax) {
    util.ajax = (function() {
        // public interface
        return {
            async: function(ajaxOptions) {
                return ajaxCall(true, ajaxOptions);
            },

            blocked: function(ajaxOptions, leaveBusyAnimation_, removeOldMessages) {
                return ajaxCall(false, ajaxOptions, leaveBusyAnimation_, removeOldMessages);
            },

            blocked2: function(ajaxOptions) {
                ajaxOptions.async = false;
                return ajaxCall2(ajaxOptions);
            },

            isRequestDone: function() {
                return requestDone || false;
            }
        };

        // private variables
        var requestDone;

        // private methods
        function ajaxCall2(ajaxOptions) {
            requestDone = false;

            // default options
            var options = {
                type: "PUT",
                contentType: "application/json",
                dataType: "json",
                global: false, // ignores global ajax event handlers
                removeOldMessages: true,
                async: false,
                dest: false,

                // defines ajax handlers
                beforeSend: function(jqXHR, settings) {
                    // stores the request begin in own settings parameter
                    $.extend(this, {"requestBegin": new Date()});
                    util.log.debug((settings.async ? "async" : "blocked") + " ajax call: " + JSON.stringify(settings).substring(0, 500));
                    // clear displayed messages and show busy animation on blocked call
                    if (!settings.async) {
                        if (this.removeOldMessages) util.message.clearDisplayedMessages();
                        util.style.showBusyAnimation();
                    }
                    extendSession();
                },

                complete: function(jqXHR, status) {
                    util.log.duration(this.requestBegin, "ajax call " + this.url);
                    util.style.hideBusyAnimation();
                    // reset is done
                    requestDone = true;
                },

                success: function(data, status, jqXHR) {
                    if (data) {
                        util.log.debug("Server data after ajax calling " + this.url + ": " + JSON.stringify(data).substring(0, 500));
                        util.message.displayMessages(data);
                    }
                },

                error: function(jqXHR, status, error) {
                    var errorText = "Unexpected error occurred: ";
                    if (jqXHR.status === 0) {
                        errorText += "not connected, verify network options";
                    } else if (jqXHR.status === 404) {
                        errorText += "requested page not found [404]";
                    } else if (jqXHR.status === 500) {
                        errorText += "internal server error [500]";
                    } else if (error instanceof SyntaxError) {
                        errorText += "invalid server response";
                        if (!!jqXHR.responseText) {
                            util.log.error("invalid server response: " + jqXHR.responseText.substring(0, 500));
                        }
                    } else if (!!jqXHR.statusText) {
                        errorText += jqXHR.statusText;
                    } else {
                        errorText += jqXHR.status;
                    }
                    util.log.error(errorText + " on " +  this.url);

                    // show error dialog on blocked call
                    if (!this.async) {
                        util.style.showElement("unexpectedErrorDialog");
                    }
                }
            };

            // extends default options
            $.extend(options, ajaxOptions);
            return $.ajax(options);
        }

        function ajaxCall(asyncReq, ajaxOptions, leaveBusyAnimation_, removeOldMessages) {
            requestDone = false;
            // default options
            var options = {
                type: "PUT",
                contentType: "application/json",
                dataType: "json",
                async: asyncReq,
                global: false, // ignores global ajax event handlers
                leaveBusyAnimation: leaveBusyAnimation_ || false, // additional flag

                // defines ajax handlers
                beforeSend: function(jqXHR, settings) {
                    // stores the request begin in own settings parameter
                    $.extend(this, {"requestBegin": new Date()});
                    util.log.debug((settings.async ? "async" : "blocked") + " ajax call: " + JSON.stringify(settings).substring(0, 500));
                    // clear displayed messages and show busy animation on blocked call
                    if (!settings.async) {
                        if (removeOldMessages) util.message.clearDisplayedMessages();
                        util.style.showBusyAnimation();
                    }
                    extendSession();
                },

                complete: function(jqXHR, status) {
                    util.log.duration(this.requestBegin, "ajax call " + this.url);
                    // hide busy animation on blocked call
                    if (!this.async && !this.leaveBusyAnimation) {
                        util.style.hideBusyAnimation();
                    }
                    // reset is done
                    requestDone = true;
                },

                success: function(data, status, jqXHR) {
                    if (data) {
                        util.log.debug("Server data after ajax calling " + this.url + ": " + JSON.stringify(data).substring(0, 500));
                        util.message.displayMessages(data);

                        var jsonParameter_ = util.message.getParameter(data);
                        if (jsonParameter_) {
                            var jsonParameter = JSON.parse(jsonParameter_);
                            transactionId = jsonParameter.transactionId;
                            if (transactionId) {
                                util.message.startTransactionLogObserver(transactionId);
                            }
                        }
                    }
                },

                error: function(jqXHR, status, error) {
                    var errorText = "Unexpected error occurred: ";
                    if (jqXHR.status === 0) {
                        errorText += "not connected, verify network options";
                    } else if (jqXHR.status === 404) {
                        errorText += "requested page not found [404]";
                    } else if (jqXHR.status === 500) {
                        errorText += "internal server error [500]";
                    } else if (error instanceof SyntaxError) {
                        errorText += "invalid server response";
                        if (!!jqXHR.responseText) {
                            util.log.error("invalid server response: " + jqXHR.responseText.substring(0, 500));
                        }
                    } else if (!!jqXHR.statusText) {
                        errorText += jqXHR.statusText;
                    } else {
                        errorText += jqXHR.status;
                    }
                    util.log.error(errorText + " on " +  this.url);
                    // show error dialog on blocked call
                    if (!this.async) {
                        util.style.showElement("unexpectedErrorDialog");
                    }
                }
            };

            // extends default options
            $.extend(options, ajaxOptions);
            return $.ajax(options);
        }
    })();
}
