/**!
 * project-site: http://plugins.jquery.com/project/AjaxManager
 * repository: http://github.com/aFarkas/Ajaxmanager
 * @author Alexander Farkas
 * @version 3.12
 * Copyright 2010, Alexander Farkas
 * Dual licensed under the MIT or GPL Version 2 licenses.
 */

(function($){
    "use strict";
    var managed = {},
        cache   = {}
    ;
    $.manageAjax = (function(){
        function create(name, opts){
            managed[name] = new $.manageAjax._manager(name, opts);
            return managed[name];
        }
        
        function destroy(name){
            if(managed[name]){
                managed[name].clear(true);
                delete managed[name];
            }
        }

        
        var publicFns = {
            create: create,
            destroy: destroy
        };
        
        return publicFns;
    })();
    
    $.manageAjax._manager = function(name, opts){
        this.requests = {};
        this.inProgress = 0;
        this.name = name;
        this.qName = name;
        
        this.opts = $.extend({}, $.manageAjax.defaults, opts);
        if(opts && opts.queue && opts.queue !== true && typeof opts.queue === 'string' && opts.queue !== 'clear'){
            this.qName = opts.queue;
        }
    };
    
    $.manageAjax._manager.prototype = {
        add: function(url, o){
            if(typeof url == 'object'){
                o = url;
            } else if(typeof url == 'string'){
                o = $.extend(o || {}, {url: url});
            }
            o = $.extend({}, this.opts, o);
            
            var origCom        = o.complete || $.noop,
                origSuc        = o.success || $.noop,
                beforeSend    = o.beforeSend || $.noop,
                origError     = o.error || $.noop,
                strData     = (typeof o.data == 'string') ? o.data : $.param(o.data || {}),
                xhrID         = o.type + o.url + strData,
                that         = this,
                ajaxFn         = this._createAjax(xhrID, o, origSuc, origCom)
            ;
            if(o.preventDoubleRequests && o.queueDuplicateRequests){
                if(o.preventDoubleRequests){
                    o.queueDuplicateRequests = false;
                }
                setTimeout(function(){
                    throw("preventDoubleRequests and queueDuplicateRequests can't be both true");
                }, 0);
            }
            if(this.requests[xhrID] && o.preventDoubleRequests){
                return;
            }
            ajaxFn.xhrID = xhrID;
            o.xhrID = xhrID;
            
            o.beforeSend = function(xhr, opts){
                var ret = beforeSend.call(this, xhr, opts);
                if(ret === false){
                    that._removeXHR(xhrID);
                }
                xhr = null;
                return ret;
            };
            o.complete = function(xhr, status){
                that._complete.call(that, this, origCom, xhr, status, xhrID, o);
                xhr = null;
            };
            
            o.success = function(data, status, xhr){
                that._success.call(that, this, origSuc, data, status, xhr, o);
                xhr = null;
            };
                        
            //always add some error callback
            o.error =  function(ahr, status, errorStr){
                var httpStatus     = '',
                    content     = ''
                ;
                if(status !== 'timeout' && ahr){
                    httpStatus = ahr.status;
                    content = ahr.responseXML || ahr.responseText;
                }
                if(origError) {
                    origError.call(this, ahr, status, errorStr, o);
                } else {
                    setTimeout(function(){
                        throw status + '| status: ' + httpStatus + ' | URL: ' + o.url + ' | data: '+ strData + ' | thrown: '+ errorStr + ' | response: '+ content;
                    }, 0);
                }
                ahr = null;
            };
            
            if(o.queue === 'clear'){
                $(document).clearQueue(this.qName);
            }
            
            if(o.queue || (o.queueDuplicateRequests && this.requests[xhrID])){
                $.queue(document, this.qName, ajaxFn);
                if(this.inProgress < o.maxRequests && (!this.requests[xhrID] || !o.queueDuplicateRequests)){
                    $.dequeue(document, this.qName);
                }
                return xhrID;
            }
            return ajaxFn();
        },
        _createAjax: function(id, o, origSuc, origCom){
            var that = this;
            return function(){
                if(o.beforeCreate.call(o.context || that, id, o) === false){return;}
                that.inProgress++;
                if(that.inProgress === 1){
                    $.event.trigger(that.name +'AjaxStart');
                }
                if(o.cacheResponse && cache[id]){
                    if(!cache[id].cacheTTL || cache[id].cacheTTL < 0 || ((new Date().getTime() - cache[id].timestamp) < cache[id].cacheTTL)){
                        that.requests[id] = {};
                        setTimeout(function(){
                            that._success.call(that, o.context || o, origSuc, cache[id]._successData, 'success', cache[id], o);
                            that._complete.call(that, o.context || o, origCom, cache[id], 'success', id, o);
                        }, 0);
                    } else {
                         delete cache[id];
                    }
                } 
                if(!o.cacheResponse || !cache[id]) {
                    if (o.async) {
                        that.requests[id] = $.ajax(o);
                    } else {
                        $.ajax(o);
                    }
                }
                return id;
            };
        },
        _removeXHR: function(xhrID){
            if(this.opts.queue || this.opts.queueDuplicateRequests){
                $.dequeue(document, this.qName);
            }
            this.inProgress--;
            this.requests[xhrID] = null;
            delete this.requests[xhrID];
        },
        clearCache: function () {
            cache = {};
        },
        _isAbort: function(xhr, status, o){
            if(!o.abortIsNoSuccess || (!xhr && !status)){
                return false;
            }
            var ret = !!(  ( !xhr || xhr.readyState === 0 || this.lastAbort === o.xhrID ) );
            xhr = null;
            return ret;
        },
        _complete: function(context, origFn, xhr, status, xhrID, o){
            if(this._isAbort(xhr, status, o)){
                status = 'abort';
                o.abort.call(context, xhr, status, o);
            }
            origFn.call(context, xhr, status, o);
            
            $.event.trigger(this.name +'AjaxComplete', [xhr, status, o]);
            
            if(o.domCompleteTrigger){
                $(o.domCompleteTrigger)
                    .trigger(this.name +'DOMComplete', [xhr, status, o])
                    .trigger('DOMComplete', [xhr, status, o])
                ;
            }
            
            this._removeXHR(xhrID);
            if(!this.inProgress){
                $.event.trigger(this.name +'AjaxStop');
            }
            xhr = null;
        },
        _success: function(context, origFn, data, status, xhr, o){
            var that = this;
            if(this._isAbort(xhr, status, o)){
                xhr = null;
                return;
            }
            if(o.abortOld){
                $.each(this.requests, function(name){
                    if(name === o.xhrID){
                        return false;
                    }
                    that.abort(name);
                });
            }
            if(o.cacheResponse && !cache[o.xhrID]){
                if(!xhr){
                    xhr = {};
                }
                cache[o.xhrID] = {
                    status: xhr.status,
                    statusText: xhr.statusText,
                    responseText: xhr.responseText,
                    responseXML: xhr.responseXML,
                    _successData: data,
                    cacheTTL: o.cacheTTL, 
                    timestamp: new Date().getTime()
                };
                if('getAllResponseHeaders' in xhr){
                    var responseHeaders = xhr.getAllResponseHeaders();
                    var parsedHeaders;
                    var parseHeaders = function(){
                        if(parsedHeaders){return;}
                        parsedHeaders = {};
                        $.each(responseHeaders.split("\n"), function(i, headerLine){
                            var delimiter = headerLine.indexOf(":");
                            parsedHeaders[headerLine.substr(0, delimiter)] = headerLine.substr(delimiter + 2);
                        });
                    };
                    $.extend(cache[o.xhrID], {
                        getAllResponseHeaders: function() {return responseHeaders;},
                        getResponseHeader: function(name) {
                            parseHeaders();
                            return (name in parsedHeaders) ? parsedHeaders[name] : null;
                        }
                    });
                }
            }
            origFn.call(context, data, status, xhr, o);
            $.event.trigger(this.name +'AjaxSuccess', [xhr, o, data]);
            if(o.domSuccessTrigger){
                $(o.domSuccessTrigger)
                    .trigger(this.name +'DOMSuccess', [data, o])
                    .trigger('DOMSuccess', [data, o])
                ;
            }
            xhr = null;
        },
        getData: function(id){
            if( id ){
                var ret = this.requests[id];
                if(!ret && this.opts.queue) {
                    ret = $.grep($(document).queue(this.qName), function(fn, i){
                        return (fn.xhrID === id);
                    })[0];
                }
                return ret;
            }
            return {
                requests: this.requests,
                queue: (this.opts.queue) ? $(document).queue(this.qName) : [],
                inProgress: this.inProgress
            };
        },
        abort: function(id){
            var xhr;
            if(id){
                xhr = this.getData(id);
                
                if(xhr && xhr.abort){
                    this.lastAbort = id;
                    xhr.abort();
                    this.lastAbort = false;
                } else {
                    $(document).queue(
                        this.qName, $.grep($(document).queue(this.qName), function(fn, i){
                            return (fn !== xhr);
                        })
                    );
                }
                xhr = null;
                return;
            }
            
            var that     = this,
                ids     = []
            ;
            $.each(this.requests, function(id){
                ids.push(id);
            });
            $.each(ids, function(i, id){
                that.abort(id);
            });
        },
        clear: function(shouldAbort){
            $(document).clearQueue(this.qName); 
            if(shouldAbort){
                this.abort();
            }
        }
    };
    $.manageAjax._manager.prototype.getXHR = $.manageAjax._manager.prototype.getData;
    $.manageAjax.defaults = {
        beforeCreate: $.noop,
        abort: $.noop,
        abortIsNoSuccess: true,
        maxRequests: 1,
        cacheResponse: false,
        async: true,
        domCompleteTrigger: false,
        domSuccessTrigger: false,
        preventDoubleRequests: true,
        queueDuplicateRequests: false,
        cacheTTL: -1,
        queue: false // true, false, clear
    };
    
    $.each($.manageAjax._manager.prototype, function(n, fn){
        if(n.indexOf('_') === 0 || !$.isFunction(fn)){return;}
        $.manageAjax[n] =  function(name, o){
            if(!managed[name]){
                if(n === 'add'){
                    $.manageAjax.create(name, o);
                } else {
                    return;
                }
            }
            var args = Array.prototype.slice.call(arguments, 1);
            managed[name][n].apply(managed[name], args);
        };
    });
    
})(jQuery);

$(document).ready(function() {
    var managedAjax = $.manageAjax.create('ajaxProfiler', {
        queue: 'clear',
        cacheResponse: true, 
        abortOld: true, 
        preventDoubleRequests: true
    });
    
    var searchRequest = null;
    var t;
    
    $(document).keyup(function(e){
        if (e.keyCode == 40) { 
            // Down                                                              
            if ($('.fastSearchResults a.choice.active').length == 0) {         
                $('.fastSearchResults a.choice').first().addClass('active'); 
            } else if ($('.fastSearchResults a.choice.active').length > 0) {
                current = $('.fastSearchResults a.choice.active');
                var nextIndex = $('.fastSearchResults a.choice').index($('.fastSearchResults a.choice.active'));            
                next = $('.fastSearchResults a.choice:eq(' + (nextIndex+1) + ')');
                                                              
                current.removeClass('active');
                next.addClass('active');                
            }
            
            return false;
        }
        
        if (e.keyCode == 38) { 
            // Up                                                           
            if ($('.fastSearchResults a.choice.active').length == 0) {
                $('.fastSearchResults a.choice').last().addClass('active');    
            } else if ($('.fastSearchResults a.choice.active').length > 0) {
                current = $('.fastSearchResults a.choice.active');
                var nextIndex= $('.fastSearchResults a.choice').index($('.fastSearchResults a.choice.active'));        
                next = $('.fastSearchResults a.choice:eq(' + (nextIndex-1) + ')');
                                        
                current.removeClass('active');
                next.addClass('active');                
            }
            
            return false;    
        }        
        
        if (e.keyCode == 27) {                                                                                      
            $('.searchElements').stop().fadeOut(); 
            $(this).removeClass('active');
            
            return false;
        }
        
        if (e.keyCode == 13 && $('.fastSearchResults a.choice.active').length==1) { 
            window.location = $('.fastSearchResults a.choice.active').attr('href');        
            return false;
        }
    });
    
    $('.modal').click(function(){ 
        $('.searchElements').stop().fadeOut(); 
        $(this).removeClass('active'); 
        $(this).fadeOut();
        
        return false;
    });
    
    $('#keywords').focus(function() {
        if ($(this).attr('rel') == 'makeEmpty') {
            $(this).val('');
            $(this).attr('rel', '');
        }
    });
                  
    $('#keywords').keyup(function(event) {     
        if (event.keyCode == 27 || event.keyCode == 38 || event.keyCode == 40 || event.keyCode == 13) {
            return true;    
        }
        
        var input = $(this);
        input.addClass('active');
        clearTimeout(t);
                            
        if (input.val().length > 1 || $('#fastSearchResults:visible').length == 1) {
            // Pending Request
            $('.submit').addClass('searching');
            
            t = setTimeout(function(){
                searchRequest = $.manageAjax.add('ajaxProfiler', { 
                    url: "/search/quick/results/", 
                    data: {                      
                        'keyword'   :   input.val()
                    },
                    success: function (data) {
                        $('.modal').css('zIndex', 1000).css('position', 'fixed').fadeTo('slow', 0.7, function() {})
                        $('#fastSearchResults').css ( {
                            'position'    : 'absolute',
                            'top'        : input.offset().top+getAbsoluteHeight(input)+2,
                            'left'        : input.offset().left-3
                        });
                        
                         $('#fastSearchResults').html(data);
                         $('.submit').removeClass('searching');
                         $('#fastSearchResults').fadeIn();     
                         $('.fastSearchResults a.choice').hover(function() {
                            $('.fastSearchResults a.choice.active').removeClass('active');
                            $(this).addClass('active');        
                        }, function() {
                            $(this).removeClass('active');    
                        });
                    }                           
                });
            }, 250);
        }
    });
});

function getAbsoluteHeight(element)
{
    paddingTop  = element.css('padding-top').replace('px', '')*1;
    paddingBottom  = element.css('padding-bottom').replace('px', '')*1;
    return (element.height()*1+paddingBottom+paddingTop);
}
