//vim: et:ts=4:sw=4:sts=4:ft=js
Ox.Request = function(options) {

    /***
    Ox.Request
        Basic request handler
    Options
        timeout
    Methods
        cancel()        cancel request
        clearCache()    clear cache
        options()       get or set options
        requests()      return number of active requests
        send()          send request
    ***/

    var cache = {},
        //dfd = $.Deferred(),
        pending = {},
        requests = {},
        self = {
            options: $.extend({
                timeout: 60000,
                type: 'POST',
                url: '/api/'
            }, options)
        };

    return {

        cancel: function() {
            if (arguments.length == 0) {
                // cancel all requests
                requests = {};
            } else if (Ox.isFunction(arguments[0])) {
                // cancel with function
                Ox.forEach(requests, function(req, id) {
                    if (arguments[0](req)) {
                        delete requests[id];
                    }
                });
            } else {
                // cancel by id
                delete requests[arguments[0]];
            }
        },

        clearCache: function() {
            cache = {};
        },

        options: function(options) {
            return Ox.getset(self.options, options, $.noop(), this);
        },

        requests: function() {
            return Ox.len(requests);
        },

        send: function(options) {

            var options = $.extend({
                    age: -1,
                    callback: null,
                    id: Ox.uid(),
                    timeout: self.options.timeout,
                    type: self.options.type,
                    url: self.options.url
                }, options),
                req = JSON.stringify({
                    url: options.url,
                    data: options.data
                });

            if (pending[options.id]) {
                setTimeout(function() {
                    Ox.Request.send(options);
                }, 0);
            } else {
                requests[options.id] = {
                    url: options.url,
                    data: options.data
                };
                if (cache[req] && (options.age == -1 || options.age > Ox.getTime() - cache[req].time)) {
                    setTimeout(function() {
                        callback && callback(cache[req].data);
                    }, 0);
                } else {
                    pending[options.id] = true;
                    $.ajax({
                        data: options.data,
                        dataType: 'json',
                        error: error,
                        success: success,
                        timeout: options.timeout,
                        type: options.type,
                        url: options.url
                    });
                }
            }

            function callback(data) {
                delete requests[options.id];
                //Ox.len(requests) == 0 && $body.trigger('requestStop');
                options.callback && options.callback(data);
            }

            function debug(request) {
                var $iframe = $('<iframe>')
                        .css({ // fixme: should go into a class
                            width: 768,
                            height: 384
                        }),
                    $dialog = new Ox.Dialog({
                            title: 'Application Error',
                            buttons: [
                                new Ox.Button({
                                    title: 'Close'
                                })
                                .bindEvent({
                                    click: function() {
                                        $dialog.close();
                                    }
                                })
                            ],
                            content: $iframe,
                            width: 800,
                            height: 400
                        })
                        .open(),
                    iframe = $iframe[0].contentDocument || $iframe[0].contentWindow.document;
                iframe.open();
                iframe.write(request.responseText);
                iframe.close();
            }

            function error(request, status, error) {
                var data;
                if (arguments.length == 1) {
                    data = arguments[0]
                } else {
                    try {
                        data = JSON.parse(request.responseText);
                    } catch (err) {
                        try {
                            data = {
                                status: {
                                    code: request.status,
                                    text: request.statusText
                                }
                            };
                        } catch (err) {
                            data = {
                                status: {
                                    code: '500',
                                    text: 'Unknown Error'
                                }
                            };
                        }
                    }
                }
                if (data.status.code < 500) {
                    callback(data);
                } else {
                    var $dialog = new Ox.Dialog({
                            title: 'Application Error',
                            buttons: [
                                new Ox.Button({
                                        id: 'details',
                                        title: 'Details'
                                    })
                                    .bindEvent({
                                        click: function() {
                                            $dialog.close(function() {
                                                debug(request);
                                            });
                                        }
                                    }),
                                new Ox.Button({
                                        id: 'close',
                                        title: 'Close'
                                    })
                                    .bindEvent({
                                        click: function() {
                                            $dialog.close();
                                        }
                                    })
                            ],
                            content: 'Sorry, we have encountered an application error while handling your request. To help us find out what went wrong, you may want to report this error to an administrator. Otherwise, please try again later.',
                            keys: {enter: 'close', escape: 'close'},
                            width: 400,
                            height: 200
                        })
                        .open();
                        // fixme: change this to Send / Don't Send
                    /*Ox.print({
                        request: request,
                        status: status,
                        error: error
                    });*/
                }
                pending[options.id] = false;
            }

            function success(data) {
                pending[options.id] = false;
                cache[req] = {
                    data: data,
                    time: Ox.getTime()
                };
                callback(data);
            }

            // return dfd.promise();

            return options.id;

        }

    };

}();