(function($){
	var allowFocus 		= true,
		currentFocus 	= document,
		supActiveElem 	= ('activeElement' in document),
		// Jaws 8/9 needs at least 54ms
		minFocusTimer 	= 70,
		focusTimer
	;
	
	
	function addFocus(e){
		currentFocus = e.target;
		if(!supActiveElem){
			document.activeElement = e.target;
		}
	}
	
	$(document).bind('focusin', addFocus);
	
	
	function addTabindex(jElm){
		var tabindex = jElm.attr('tabindex');
		if(!(tabindex || tabindex === 0)){
			jElm.css({outline: 'none'}).attr({tabindex: '-1'});
			if( !$.support.waiAria && jElm[0] ){
				jElm[0].hideFocus = true;
			}
		}
		return jElm;
	}
	
	$.fn.setFocus = function(opts){
		if(!this[0]){return this;}
		opts = $.extend({}, $.fn.setFocus.defaults, opts);
		var elem 			= this[0],
			jElm 			= $(elem),
			activeElem		= document.activeElement,
			now				= new Date().getTime(),
			focusFn 		= function(){
							try{
								elem.focus();
							} catch(e){}
						},
			fxParent
		;
		
		
		if(opts.addTabindex){
			addTabindex(jElm);
		}
				
		if( !opts.fast ){
			//update jaws 8/9 buffer
			if(activeElem && activeElem.focus && activeElem.blur){
				activeElem.blur();
				activeElem.focus();
			}
			
			clearTimeout(focusTimer);
			
			//falsy focus bounce in ie / no scrollIntoView in ff workaround
			fxParent = jElm.closest(':animated', opts.context);
			if( fxParent[0] ){
				fxParent.queue(function(){
					var time = new Date().getTime() - now - minFocusTimer;
					time = (time > 9) ? time : 9;
					focusTimer = setTimeout( focusFn, time );
					setTimeout(function(){
						fxParent.dequeue();
					}, time + 16);
				});
			} else {
				focusTimer = setTimeout( focusFn, minFocusTimer );//min 54
			}
		} else {
			focusFn();
		}
		return this;
	};
	
	$.fn.setFocus.defaults = {
		addTabindex: true,
		fast: false,
		context: false
	};
		
})(jQuery);
