/**
 * @author trixta 
 */
(function($){
	
	var offsetBaseCSS 	= 'position: absolute; width: 1px; height: 1px; overflow: hidden;maring: 0; padding: 0;',
		offsetDir 		= ($('html').attr('dir') === 'rtl') ? 'right: -9999em;' : 'left: -9999em;',
		offsetCSS 		= offsetBaseCSS+offsetDir
	;
	
	/*
	 * hover = focusblur
	 */
	
$(function(){
	
	var style = document.createElement('style'),
		styleS
	;
	
	style.setAttribute('type', 'text/css');
	style = $(style).prependTo('head');
	
	styleS = document.styleSheets[0];
	
	function add(sel, prop){
		if ((styleS.cssRules && !styleS.cssRules.length) || (styleS.rules && !styleS.rules.length)) {
			if (styleS.insertRule) {
				styleS.insertRule(sel +' {'+ prop +';}', styleS.cssRules.length);
			} else if (styleS.addRule) {
				styleS.addRule(sel, prop);
			}
		}
	}
	
	add('.a11y-js-overflow', 'overflow:visible !important');
	
	$.cssRule = {
		add: add
	};
});
	 
	$.each({
		focus: 'focusin',
		blur: 'focusout'	
	}, function( original, fix ){
		$.event.special[fix] = {
			setup:function() {
				if ( $.browser.msie ) return false;
				this.addEventListener( original, $.event.special[fix].handler, true );
			},
			teardown:function() {
				if ( $.browser.msie ) return false;
				this.removeEventListener( original,
				$.event.special[fix].handler, true );
			},
			handler: function(e) {
				arguments[0] = $.event.fix(e);
				arguments[0].type = fix;
				return $.event.handle.apply(this, arguments);
			}
		};
	});
	
	$.ui = $.ui ||
		{};
	/*
	 * HCM-Detection
	 */
	$.ui.userMode = (function(){
		var userBg, 
			timer, 
			testDiv,
			boundEvents = 0;
		
		function testBg(){
			testDiv = testDiv || $('<div style="'+ offsetCSS +'"></div>').appendTo('body');
			var black = $.curCSS( testDiv.css({backgroundColor: '#000000'})[0], 'backgroundColor', true),
				white = $.curCSS( testDiv.css({backgroundColor: '#ffffff'})[0], 'backgroundColor', true),
				newBgStatus = (black === white || white === 'transparent');
			if(newBgStatus != userBg){
				userBg = newBgStatus;
				$.event.trigger('_internalusermode');
			}
			return userBg;
		}
		
		function init(){
			testBg();
			timer = setInterval(testBg, 3000);
		}
		
		function stop(){
			clearInterval(timer);
			(testDiv && testDiv.remove());
			testDiv = null;
		}
		
		$.event.special.usermode = {
			setup: function(){
				(!boundEvents && init());
				boundEvents++;
				var jElem = $(this)
					.bind('_internalusermode', $.event.special.usermode.handler);
				//always trigger
				setTimeout(function(){
					jElem.triggerHandler('_internalusermode');
				}, 1);
                return true;
            },
			teardown: function(){
                boundEvents--;
				(!boundEvents && stop());
				$(this).unbind('_internalusermode', $.event.special.usermode.handler);
                return true;
            },
            handler: function(e){
                e.type = 'usermode';
				e.disabled = !userBg;
				e.enabled = userBg;
                return $.event.handle.apply(this, arguments);
            }
		};
		
		return {
			get: testBg
		};
		
	})();
	
	$.fn.userMode = function(fn){
		return this[(fn) ? 'bind' : 'trigger']('usermode', fn);
	};
	
	$(function(){
		$('html').userMode(function(e){
			$('html')[e.enabled ? 'addClass' : 'removeClass']('hcm');
		});
	});
	
	(function($){
		var preventclick = false;
		
		function handleAriaClick(e){
			
			if(!preventclick && (!e.keyCode || e.keyCode === $.ui.keyCode.ENTER || e.keyCode === $.ui.keyCode.SPACE)){
				preventclick = true;
				setTimeout(function(){
					preventclick = false;
				}, 1);
				return $.event.special.ariaclick.handler.apply(this, arguments);
			} else if(preventclick && e.type == 'click'){
				e.preventDefault();
				return false;
			}
			
		}
		$.event.special.ariaclick = {
			setup: function(){
				$(this).bind('click keydown', handleAriaClick);
	            return true;
	        },
			teardown: function(){
	            $(this).unbind('click keydown', handleAriaClick);
	            return true;
	        },
	        handler: function(e){
	            e.type = 'ariaclick';
	            return $.event.handle.apply(this, arguments);
	        }
		};
	})(jQuery);
	
	
	/* EM-Change */
	
	$.testEm = (function(){
		var emElem = $('<div style="width: 1em; position: absolute; visibility: hidden;'+ offsetDir +'" />'),
			timer,
			emPx = 0,
			oldVal = 0,
			boundEvents = 0;
		
		function init(){
			timer = setInterval(test, 999);
		}
		
		function test(){
			var width = emElem.width();
			
			if(emPx && emPx !== width){
				emPx = width;
				$.event.trigger('_internalemchange');
			}
			oldVal = width;
			emPx = width;
			
			return {
				type: 'emsize',
				emPx: emPx,
				oldEmPx: oldVal
			};
		}
			
		$.event.special.emchange = {
			setup: function(){
				(!boundEvents && init());
				boundEvents++;
				
				$(this)
					.bind('_internalemchange', $.event.special.emchange.handler);
				
                return true;
            },
			teardown: function(){
                boundEvents--;
				(!boundEvents && clearInterval(timer));
				$(this).unbind('_internalemchange', $.event.special.emchange.handler);
                return true;
            },
            handler: function(e){
                e.type = 'emchange';
				e.emPx = emPx;
				e.oldEmPx = oldVal;
                return jQuery.event.handle.apply(this, arguments);
            }
		};
		$(function(){
			emElem
				.appendTo('body');
			test();
		});
		return test;
	})();
	
	(function($){
		var allowFocus 	= true;
		
		function stopFocus(){
			allowFocus = false;
			setTimeout(function(){
				allowFocus = true;
			}, 1);
		}
		
		function testDomTarget(e){
			var oE 			= e.originalEvent;
			if(e.target === document || e.target === window){
				stopFocus();
				return false;
			}
			if(oE){
				if(
						allowFocus && e.target && e.target.nodeType === 1 &&
						(oE.explicitOriginalTarget && oE.explicitOriginalTarget && oE.explicitOriginalTarget !== window &&  oE.explicitOriginalTarget !== document && !$(oE.explicitOriginalTarget).is('html, body') ||
						oE.toElement || oE.fromElement)
					) {
						return true;
					} else {
						return false;
					}
			}
			return true;
		}
		
		$.each(['focusin', 'focusout'], function(i, eType){
			
			$.event.special['dom'+ eType] = {
				setup: function(){
					$(this)
						.bind(eType, $.event.special['dom'+ eType].handler);
	                return true;
	            },
				teardown: function(){
	                $(this).unbind(eType, $.event.special['dom'+ eType].handler);
	                return true;
	            },
	            handler: function(e){
					if(testDomTarget(e)){
		                e = $.extend({}, e, {type: 'dom'+ eType});
		                return $.event.handle.call(this, e);
					}
	            }
			};
			
		});
		
		
	})(jQuery);
	
	(function($){
		var allowFocus 	= true,
			allowScroll = true,
			focusTimer,
			currentFocus,
			mouseFocus
		;
		
		function stopKeyFocus(e){
			allowFocus = false;
			mouseFocus = e && e.type;
			setTimeout(function(){
				allowFocus = true;
			}, 1);
		}
		
		function removeActive(e){
			if(!e || !e.keyCode || e.keyCode === 13 || e.keyCode === 32){
				$(this).removeClass('a11y-active');
			}
		}
		
		function addActive(e){
			if(!e || !e.keyCode || e.keyCode === 13 || e.keyCode === 32){
				$(this).addClass('a11y-active');
			}
		}
		function addActiveListener(jElm){
			jElm.bind('mouseup mouseleave keyup', removeActive);
			
			jElm.bind('mousedown keydown', addActive);
			
		}
		
		function removeFocusMouse(){
			$(this)
				.removeClass('a11y-focus-mouseblur')
				.unbind('mouseleave', removeFocusMouse)
			;
		}
		
		function addFocus(e){
			var jElm = $(e.target).addClass('a11y-focus a11y-focus-mouseblur');
			currentFocus = e.target;
			
			
			if(allowFocus){
				jElm.addClass('a11y-focus-key').trigger('keyfocus');
			} else if(mouseFocus === 'mousedown'){
				jElm.addClass('a11y-active').bind('mouseleave', removeFocusMouse);
			}
			addActiveListener(jElm);
		}
		
		function preventScroll(){
			allowScroll = false;
			setTimeout(function(){
				allowScroll = true;
			}, 99);
		}
		
		function stopScroll(e){
			if(!allowScroll){
				e.preventDefault();
				return false;
			}
		}
		
		$(document).bind('scroll', stopScroll);
		$(window).bind('scroll', stopScroll);
		$(document)
			.bind('mousedown click', stopKeyFocus)
			.bind('domfocusin', addFocus)
			.bind('focusout', function(e){
				$(e.target)
					.removeClass('a11y-focus-key a11y-focus-widget a11y-focus a11y-active a11y-focus-mouseblur')
					.unbind('mouseleave', removeFocusMouse)
					.unbind('mousedown keydown', addActive)
					.unbind('mouseup mouseleave keyup', removeActive)
				;
			})
		;
		
		
		function addTabindex(jElm){
			if(!jElm.is('a, area, input, button, select, textarea, [tabindex=0]')){
				jElm.css({outline: 'none'}).attr({tabindex: '-1'});
			}
			return jElm;
		}
		
		$.fn.setFocus = function(time, doTabI){
			if(!this[0]){return this;}
			
			var elem 	= this[0],
				jElm 	= $(elem),
				opts 	= {},
				focusFn	= function(){
						stopKeyFocus();
						try{
							if(opts.stopScroll){
								preventScroll();
							}
							elem.focus();
							jElm.addClass(' ui-widgetfocus');
							complete.apply(elem, arguments);
						} catch(e){}
					},
				queueFn = function(){
					opts.parent.queue(function(){
						focusFn();
						opts.parent.dequeue();
					});
				}
			;
			
			if(isFinite(time)){
				opts.time = time;
				if(doTabI !== undefined){
					opts.addTabindex = doTabI;
				}
			} else {
				opts = time;
			}
			opts = $.extend({}, $.fn.setFocus.defaults, opts);
			
			
			if(opts.addTabindex){
				addTabindex(jElm);
			}
			
			clearTimeout(focusTimer);
			focusTimer = setTimeout(opts.parent ? queueFn : focusFn, opts.time);
			return this;
		};
		
		$.fn.setFocus.defaults = {
			time: 0,
			stopScroll: true,
			addTabindex: false,
			parent: false,
			complete: function(){}
		};
			
	})(jQuery);
	
	/* hide/show */
	
	$.fn.ariaHide = function(){
		$.fn.hide.apply(this, arguments);
		return this.attr({'aria-hidden': 'true'});
	};
	
	$.fn.ariaShow = function(){
		$.fn.show.apply(this, arguments);
		return this.attr({'aria-hidden': 'false'});
	};
	
	
	/*
	 * SR-Update
	 */
	$.ui.SR = (function(){
		var input, val = 0, alertBox, boxTimer;
		
		function init(){
			alertBox = $('<div class="aural" role="alert" style="'+ offsetCSS +'" />').ariaHide().appendTo('body');
			input = $('<form role="presentation" action="#" class="aural" style="'+ offsetCSS +'"><input name="sr-update" id="sr-update" type="hidden" value="'+val+'" /></form>')
				.appendTo('body')
				.find('input')
				.ajaxComplete(update);
		}
		
		function update(notice){
			var posStyle, wrapperHeight;
			if(input){
				input[0].setAttribute('value', '' +(++val));
				alert(notice);
				setTimeout(function(){
					input[0].setAttribute('value', '' +(++val));
				}, 1);
			}
		}
		
		function announceText(notice, box){
			if(typeof notice == 'string'){
				clearTimeout(boxTimer);
				box.ariaHide().html(notice).ariaShow();
				
				boxTimer = setTimeout(function(){
					box.ariaHide().empty();
				}, 2999);
			}
		}
		
		function alert(notice){
			announceText(notice, alertBox);
		}
		
		
		return {
			update: update,
			alert: alert,
			init: init
		};
	})();
	$($.ui.SR.init);
	
	/*
	 * getID-Exts
	 */
	
	if(!$.fn.getID){
		var uId = new Date().getTime();
		$.fn.getID = function(){
			var id = '';
			if(this[0]){
				var elem = $(this[0]);
				id = elem.attr('id');
				if(!id){
					id = 'ID-' + (uId++);
					elem.attr({'id': id});
				}
			}
			return id;
		};
	}
	
	$.each({
		labelWith: 'aria-labelledby',
		describeWith: 'aria-describedby',
		ownsThis: 'aria-owns',
		controlsThis: 'aria-controls'
	}, function(name, prop){
		$.fn[name] = function(elem){
			return this.attr(prop, $(elem).getID());
		};
	});
	
	/*
	*  inout
	*  hover = focusblur
	*/
		
	$.fn.inOut = function(enter, out, opts){
		opts = $.extend({}, $.fn.inOut.defaults, opts);
		
		var eventTypes = 'mouseenter mouseleave focusin focusout',
			selector = this.selector,
			context = this.context
		;
		
		if(opts.useEventTypes === 'mouse'){
			eventTypes = 'mouseenter mouseleave';
		} else if(opts.useEventTypes === 'focus'){
			eventTypes = 'focusin focusout';
		}
		
		function handler(e){
			var fn,
				params,
				elem = this,
				evt
			;
			if(/focusin|mouseenter/.test(e.type)){
				fn = enter;
				params =  [1, 'in', true]; 
			} else {
				fn = out;
				params = [-1, 'out', false];
			}
			
			var inOutData = $.data(this, 'inOutData');
			
			clearTimeout(inOutData.inOutTimer);
			inOutData.inEvents = Math.max(inOutData.inEvents + params[0], 0);
			inOutData.inOutTimer = setTimeout(function(){
				if(params[2] != inOutData.inOutState && 
						(params[2] || !opts.bothOut || !inOutData.inEvents)){
					inOutData.inOutState = params[2];
					evt = $.Event(params[1]);
					evt.originalEvent = e;
					fn.call(elem, evt);
				}
			}, /focus/.test(e.type) ? opts.keyDelay : opts.mouseDelay);
		}

		this
			.each(function(){
				$(this).data('inOutData', {inEvents: 0});
			})
			[opts.bindStyle](eventTypes, handler);
		return this;
	};
	
	$.fn.inOut.defaults = {
		mouseDelay: 0,
		bindStyle: 'bind', // bind | live | bubbleLive
		keyDelay: 1,
		bothOut: false,
		useEventTypes: 'both' // both || mouse || focus
	};
	
	$.fn.slideParentDown = function(opts){
		opts = $.extend({}, $.fn.slideParentDown.defaults, opts);
		var fn = opts.complete;
		
		return this.each(function(){
			var jElm 		= $(this),
				parent		= jElm.parent().css({overflow: 'hidden', height: '0px'}),
				outerHeight = jElm.css({display: 'block'}).outerHeight({margin: true})
			;
			parent.animate({
				height: outerHeight
			}, $.extend({}, opts, {complete: function(){
				parent.css({height: '', overflow: ''});
				fn.apply(this, arguments);
			}}));
		});
	};
	$.fn.slideParentDown.defaults = {
		duration: 400,
		complete: function(){}
	};
	$.fn.slideParentUp = function(opts){
		opts = $.extend({}, $.fn.slideParentDown.defaults, opts);
		var fn = opts.complete;
		return this.each(function(){
			var jElm 		= $(this),
				parent		= jElm.parent().css({overflow: 'hidden', height: jElm.outerHeight({margin: true})})
			;
			parent.animate({
				height: '0px'
			}, $.extend({}, opts, {complete: function(){
				jElm.css({display: 'none'});
				parent.css({height: '', overflow: '', display: ''});
				fn.apply(this, arguments);
			}}));
		});
	};
	$.fn.slideParentDown.defaults = {
		duration: 400,
		complete: function(){}
	};
})(jQuery);
