/**
 * @author trixta
 */
(function($){
	
	/* Mask */
	
	$.fn.fadeInTo = function(){
		var args = arguments;
		return this.each(function(){
			var jElm = $(this);
			
			if(jElm.css('display') === 'none'){
				jElm.css({opacity: '0', display: 'block'});
			}
			$.fn.fadeTo.apply(jElm, args);
		});
	};
	
	var maskID = new Date().getTime();
	
	$.overlayProto = {
		hideElementsOnShow: function(){
			var o 		= this.options,
				that 	= this
			;
			
			this.hiddenElements = $([]);
			
			if(o.hideWindowedFlash){
				this.hiddenElements = $('object').filter('[classid=clsid:d27cdb6e-ae6d-11cf-96b8-444553540000], [type=application/x-shockwave-flash]');
				this.hiddenElements = this.hiddenElements.filter(function(){
						return (/<param\s+(?:[^>]*(?:name=["'?]\bwmode["'?][\s\/>]|\bvalue=["'?](?:opaque|transparent)["'?][\s\/>])[^>]*){2}/i.test(this.innerHTML));
					});
			}
			
			if(o.hideWhileShown){
				this.hiddenElements = this.hiddenElements.add(o.hideWhileShown);
			}
			
			this.hiddenElements = this.hiddenElements
				.filter(function(){
					var jElm = $(this);
					return (jElm.is(':visible') && jElm.css('visibility') === 'visible' && !$.ui.contains(this, that.element[0]));
				})
				.filter(o.hideFilter)
				.css({visibility: 'hidden'});
		}
	};
	
    $.widget('ui.mask', $.extend({
		_init: function(){
			var o  		= this.options,
				that 	= this,
				css
			;
			maskID++;
			this.id = maskID;
			this.maskedElement = this.element.parent();
			
			if(this.maskedElement.is('body')){
				this.dimensionElement = $(document);
				this.calcMethod = {
					height: 'height',
					width: 'width'
				};
			} else {
				this.dimensionElement = this.maskedElement.css({position: 'relative'});
				this.calcMethod = {
					height: 'innerHeight',
					width: 'innerWidth'
				};
			}
			if(this.maskedElement.is('body') || (parseInt($.browser.version, 10) < 7 && $.browser.msie)){
				css = {
					display: 'none',
					position: 'absolute',
					top: '0',
					left: '0'
				};
				this.calcSize = true;
			} else {
				css = {
					display: 'none',
					position: 'absolute',
					top: 0,
					left: 0,
					right: 0,
					bottom: 0
				};
				
				this.calcSize = false;
			}
			this.element.css(css);
			o.cssWidth = ($.curCSS(this.element[0], 'width') === '100%');
			this.isVisible = false;
			if(o.closeOnClick){
				this.element.click(function(e){
					that.hide.call(that, e, this);
				});
			}
			if(o.extraClass){
				this.element.addClass(o.extraClass);
			}
		},
		ui: function(){
			return {
				instance: this
			};
		},
		hide: function(e, elem){
			
			if(!this.isVisible){return;}
			var result 	= this._trigger('close', e, this.ui()),
				o 		= this.options,
				that 	= this
			;
			if(result === false){return;}
			this.isVisible = false;
			
			if(o.handleDisplay){
				if(o.fadeOutTime){
					this.element.fadeOut(o.fadeOutTime, function(){
						that.unexpose.call(that);
					});
				} else {
					this.element.hide();
					this.unexpose();
				}
			}
			this.element.queue(function(){
				if(that.hiddenElements && that.hiddenElements.css){
					that.hiddenElements.css({visibility: 'visible'});
				}
				that.maskedElement.removeClass('mask-visible');
				that.element.dequeue();
			});
			$(document).unbind('.mask'+ this.id);
			$(window).unbind('.mask'+ this.id);
		},
		resize: function(set){
			var ret = {
				'height': this.dimensionElement[this.calcMethod.height]()
			};
			if(!this.options.cssWidth){
				ret.width = this.dimensionElement[this.calcMethod.width]();
			}
			if(set){
				this.element.css(ret);
			}
			return ret;
		},
		show: function(e, o){
			
			if(this.isVisible){return;}
			o = (o) ? $.extend({}, this.options, o) : this.options;
			var that 	= this,
				resize 	= function(e){
						that.resize.call(that, true);
					}
			;
			if(o.expose){
				this.expose(o.expose);
			}
			
			this._trigger('show', e, $.extend({} , this.ui(), o));
			this.isVisible = true;
			this.maskedElement.addClass('mask-visible');
			this.hideElementsOnShow();
			if(o.handleDisplay){
				if(this.calcSize){
					this.resize(true);
				}
				if(o.fadeInTime){
					this.element.fadeInTo(o.fadeInTime, o.opacity);
				} else {
					this.element.css({opacity: o.opacity, display: 'block'});
				}
			}
			
			if(o.closeOnEsc){
				$(document).bind('keydown.mask'+ this.id, function(e){
					if(e.keyCode === $.ui.keyCode.ESCAPE){
						that.hide.call(that, e, this);
					}
				});
			}
			if (that.calcSize) {
				$(document).bind('resize.mask'+ this.id +' emchange.mask'+ this.id, resize);
				$(window).bind('resize.mask'+ this.id, resize);
			}
		},
		unexpose: function(elem){
			if(!elem && !this.exposed){return;}
			var exposed = elem || this.exposed;
			exposed.each(function(){
				$(this).css({
					position: '',
					zIndex: ''
				});
			});
			if(!elem){
				this.exposed = false;
			}
		},
		expose: function(jElm){
			var zIndex =  parseInt(this.maskedElement.css('z-index'), 10) || 9;
			jElm = this.maskedElement.find(jElm);
			jElm.each(function(){
				var jExpose = $(this);
				if(jExpose.css('position') === 'static'){
					jExpose.css({position: 'relative'});
				}
				zIndex++;
				jExpose.css({
					zIndex: zIndex
				});
			});
			this.exposed = jElm;
		}
	}, $.overlayProto));
	$.ui.mask.defaults = {
		extraClass: false,
		closeOnClick: true,
		closeOnEsc: true,
		handleDisplay: true,
		fadeInTime: 0,
		fadeOutTime: 0,
		opacity: 0.8,
		bgIframe: false,
		cssWidth: true
	};
		
	/* END: Mask */
	
	/* Content-Overlay */
	
	var currentFocus,
		id 		= new Date().getTime()
	;
	var throwError = function(message){
		setTimeout(function(){
			if(/file:|127\.0\.0\.1|localhost/.test(location.href)){
				if(window.console && console.log){
					console.log(message);
				} else {
					throw(message);
				}
			}
		}, 0);
	};
	
	$(document).bind('focusin', function(e){
		if(e.target.nodeType == 1){
			currentFocus = e.target;
		}
	});
	
	if(!$.fn.mask){
		$.fn.mask = function(){return this;};
	}
	
	$.widget('ui.cOverlay', $.extend({
		_init: function(){
			var o 		= this.options,
				that 	= this,
				close 	= function(e){
					var elem = this;
					clearInterval(that.openTimer);
					that.closeTimer = setTimeout(function(){
						that.hide(e, {closer: elem});
					}, 1);
					return false;
				},
				show 	= function(e){
					clearInterval(that.closeTimer);
					var elem = this;
					that.openTimer = setTimeout(function(){
						that.show(e, {opener: elem});
					}, o.openDelay);
					return false;
				},
				isDialog, isSpecial
			;
			
			this.mask = $([]);
			
			if(o.mask){
				this.mask = $('<div class="mask" />')
					.insertBefore(this.element)
					.mask(
						$.extend(o.maskOpts, 
							{
								close: function(e, ui){
									clearInterval(that.openTimer);
									return that.hide(e, ui);
								}
							}
						)
					);
			}
			
			this.element.ariaHide().attr(o.attr).attr({tabindex: '-1'}).getID();
			
			if(o.createA11yWrapper === true || (o.createA11yWrapper && this.element.parent().is('body'))){
				this.element.wrap('<div class="a11y-wrapper" />');
			}
			
			if(o.setInitialContent){
				this.fillContent(this.element, o.setInitialContent);
			}
			
			this.clonedOverlay = this.element.clone().attr({role: 'presentation'}).addClass('cloned-overlay');
			
			if(o.bgIframe && $.fn.bgIframe && parseInt($.browser.version, 10) < 7){
				this.element.bgIframe();
			}
			
			id++;
			this.id = 'overlay-'+ id;
			this.isVisible = false;
			this.hiddenElements = $([]);
			this.openers = $([]);
			
			this.closeBtn = $(o.closeBtnSel, this.element)
				.bind('ariaclick', function(e){
					clearInterval(that.openTimer);
					that.hide(e, {closer: this});
					return false;
				});
			
			if(o.openerSel){
				this.openers = $(o.openerSel, o.openercontext)
					[o.bindStyle](o.openEvent, show);
				
				if(o.closeEvent){
					this.openers[o.bindStyle](o.closeEvent, close);
				}
					
			}
			
			if(o.a11yMode){
				this.element.addClass('a11y-js-overflow');
				isSpecial = (o.a11yMode.indexOf('special') !== -1);
				isDialog = (o.a11yMode.indexOf('dialog') !== -1);
				
				o.modal = (o.modal === 'auto' && o.mask && isDialog) ? true : o.modal;
				
				if(o.labelledbySel){
					this.element.labelWith($(o.labelledbySel, this.element));
				} else if(!isSpecial){
					if(isDialog){
						throwError('Sie müssen die labelledbySel-Eigenschaft');
					} else if(o.a11yMode.indexOf('alert') !== -1){
						throwError('Sie können die labelledbySel-Eigenschaft konfigurieren');
					}
				}
				
				if(o.describedbySel){
					this.element.describeWith($(o.describedbySel, this.element));
				}else if(!isSpecial && isDialog){
					throwError('Sie können die describedbySel-Eigenschaft konfigurieren');
				}
				
				if(!isSpecial){
					this.element.attr('role', o.a11yMode);
				}
				
				if(isDialog){
					o.restoreFocus = true;
					o.focusOnShow = o.focusOnShow || true;
					if(!isSpecial && o.focusOnShow === true){
						throwError('Sie müssen mit focusOnShow ein Nachfahren-Element selektieren, welches beim Öffnen des Dialogs fokusiert werden soll');
					}
				} else {
					o.focusOnShow = false;
					o.restoreFocus = false;
				}
				
				if(o.a11yMode === 'tooltip' || o.a11yMode === 'alert'){
					$('*', this.element).attr({role: 'presentation'});
				}
				
				if((isDialog || o.a11yMode.indexOf('alert') !== -1) && o.openEvent.indexOf('click') === -1){
					this.openers[o.bindStyle]('ariaclick', show);
					
					this.openers
						[o.bindStyle]('domfocusout', close);
					
					this.element
						.bind('mouseenter', function(){
							clearTimeout(that.closeTimer);
						});
				}
				
				if(o.a11yMode === 'tooltip'){
					this.openers
						[o.bindStyle]('focusin', show)
						[o.bindStyle]('focusout', function(e){
							clearInterval(that.openTimer);
							that.hide(e, {closer: this});
						});
					
					this.element
						.bind('mouseenter', function(){
							clearTimeout(that.closeTimer);
						}).bind('mouseleave', close);
				}
				
				this.element.bind('focusin', function(){
					clearTimeout(that.closeTimer);
				});
				if(!isDialog){
					this.element.bind('domfocusout', close);
				}
			}
			this._trigger('init', {
				type: 'init'
			}, this.ui());
		},
		fillContent: function(element, content, isClone){
			var o = this.options;
			element = element || this.element;
			content = content || this.content || {};
			$.each(content, function(name, html){
				if($.isFunction(html)){
					html(name, element, content, isClone);
				} else {
					$('.'+ name, element).html(html);
				}
			});
			if(o.a11yMode === 'tooltip' || o.a11yMode === 'alert'){
				$('*', this.element).attr({role: 'presentation'});
			}
		},
		ui: function(){
			var obj = {
				instance: this,
				isVisible: this.isVisible,
				openers: this.openers,
				id: this.id
			};
			
			for(var i = 0, len = arguments.length; i < len; i++){
				if(arguments[i]){
					$.extend(obj, arguments[i]);
				}
			}
			return obj;
		},
		show: function(e, extras){
			clearTimeout(this.closeTimer);
			this.currentOpener = (extras && extras.opener) ? $(extras.opener) : (e && e.type && (/click|ariaclick|mouseenter|focus/.test(e.type)) && e.currentTarget) ? $(e.currentTarget) : $(currentFocus);
			
			extras.opener = this.currentOpener;
			if(this.isVisible || this._trigger('beforeShow', e, this.ui({extras: extras})) === false || this.stopShow){return;}
			this.isVisible = true;
			var o 				= this.options,
				that 			= this,
				focusElement 	= (o.focusOnShow === true) ? 
									this.element : 
									(o.focusOnShow) ? 
									$(o.focusOnShow, this.element) : 
									$([]),
				posCSS,
				ui
			;
			
			this.hideElementsOnShow();
			
			if(o.a11yMode === 'tooltip' && this.currentOpener){
				this.currentOpener.attr({
					'aria-describedby': this.element.getID()
				});
			}
			
			posCSS = this.setPosition(e, extras);
			
			ui = this.ui({extras: extras, posCSS: posCSS});
			this.mask.mask('show');
			
			o.animShow(this.element.stop(true, true), ui);
			
			this.element.attr({'aria-hidden': 'false'});
			$.ui.SR.update();
			
			
			
			this.restoreFocus = currentFocus;
			
			focusElement.setFocus({
					addTabindex: true,
					parent: this.element,
					time: 180
				});
				
			$('body').addClass(o.bodyShowClass);
			
			if(o.closeOnEsc){
				$(document).bind('keydown.'+ this.id, function(e){
					if(e.keyCode === $.ui.keyCode.ESCAPE){
						that.hide.call(that, e, {closer: this});
					}
				});
			}
			
			if(o.modal === true){
				var shift;
				$(document).bind('keydown.'+ this.id, function(e){
					if($.ui.keyCode.SHIFT === e.keyCode ){
						shift = true;
					}
				}).bind('keyup.'+ this.id, function(e){
					if($.ui.keyCode.SHIFT === e.keyCode ){
						shift = false;
					}
				}).bind('focusin.'+ this.id, function(e){
					if(e.target === document || e.target === window || ( e.target !== that.element[0] && !$.ui.contains(that.element[0], e.target) )){
						that.innerFocusElements = that.innerFocusElements ||
							$('a, input, button, select, textarea, area', that.element).filter(':not(:hidden)');
						that.innerFocusElements.filter((shift) ? ':last' : ':first').setFocus(0);
					}
				});
			}
			
			this.mask.mask('resize', true);
			this.element.queue(function(){
				that._trigger('show', e, ui);
				that.mask.mask('resize', true);
				$.ui.SR.update();
				that.element.dequeue();
			});
		},
		hide: function(e, extras){
			clearTimeout(this.openTimer);
			if(!this.isVisible){return;}
			var o 		= this.options,
				ui 		= this.ui({extras: extras}),
				that 	= this
			;
			if(this._trigger('beforeHide', e, ui) === false){return false;}
			
			this.isVisible = false;
			
			if(o.a11yMode === 'tooltip' && this.currentOpener){
				this.currentOpener.removeAttr('aria-describedby');
			}
			
			
			this.mask.mask('hide');
			o.animHide(this.element, ui);
			this.element.attr({'aria-hidden': 'true'});
			$(document).unbind('.'+ this.id);
			$(window).unbind('.'+ this.id);
			if (o.focusOnShow && this.restoreFocus) {
				$(this.restoreFocus).setFocus(0);
			}
			this.element.queue(function(){
				that.hiddenElements.css({visibility: 'visible'});
				that._trigger('hide', e, ui);
				$('body').removeClass(o.bodyShowClass);
				that.restoreFocus = false;
				that.innerFocusElements = false;
				that.element.css({left: '', top: ''}).dequeue();
			});
		},
		setPosition: function(e, extras, elem){
			elem = elem || this.element;
			var o 	= this.options,
				pos = {};
			e = (e && e.type) ? e : {type: 'unknown'};
			if(extras && !extras.opener){
				extras.opener = this.currentOpener;
			} else if(!extras){
				extras = {opener: this.currentOpener};
			}
			if(typeof o.positionType === 'string' && $.ui.cOverlay.posMethods[o.positionType]){
				pos = $.ui.cOverlay.posMethods[o.positionType](elem, e, extras, this);
			} else if($.isFunction(o.positionType)){
				pos = o.positionType(elem, e, extras, this);
			}
			return pos;
		}
	}, $.overlayProto));
	
	$.ui.cOverlay.posMethods = {};
	
	$.ui.cOverlay.posMethods.around = function(overlay, e, extra, ui){
		var o 	= ui.options,
			pos
		;
		
		if(!$.posAround){
			setTimeout(function(){
				throw('please install the posAround plugin');
			},0);
			return {};
		}
		if(o.followMouse && e.type.indexOf('mouse') != -1){
			pos = $.posAround(overlay, e, o.positionOpts);
			$(document).bind('mousemove.'+ ui.id, function(evt){
				var delta = {
						top: e.pageY - evt.pageY,
						left: e.pageX - evt.pageX
					},
					posDelta = {
						top: pos.top - delta.top,
						left: pos.left - delta.left
					}
				;
				overlay.css({
						top: pos.top - delta.top,
						left: pos.left - delta.left
					});
			});
		} else if(extra.opener){
			pos = $.posAround(overlay, extra.opener, o.positionOpts);
		}
		return pos;
	};
	
	$.ui.cOverlay.posMethods.centerInsideView = function(overlay, e, extra, ui){
		var o 	= ui.options,
			doc = $(document),
			pos
		;
		
		if(!$.objScale){
			setTimeout(function(){
				throw('please install the objScale plugin');
			},0);
			return {};
		}
		
		pos = $.objScale.centerObjTo(overlay, $(window), o.positionOpts);
		pos.top += doc.scrollTop();
		pos.left += doc.scrollLeft();
		return pos;
	};
	
	$.ui.cOverlay.defaults = {
		//
		mask: false, //Soll die Seite zusätzlich maskiert werden
		maskOpts: {}, //Optionen für die Maskierung, siehe mask-Plugin im Overlay-Ordner
		
		bgIframe: false, //IE6 bugfix für select-zIndex-Bug
		hideWindowedFlash: true, // Sollen Flashelemente versteckt werden, die kein wmode haben
		hideWhileShown: false, // Selektor von Elementen, DOM-Objekte die während der Anzeige versteckt werden sollen
		hideFilter: function(){return true;}, // funktion zum herausfiltern von Objekten die versteckt werden sollen
		
		extraClass: false, // Zusatzklasse für Overlay-Element
		attrs: {}, //zusätzliche Attribute, für das Overlay-Element
		bodyShowClass: 'overlay-visible', //body-Klasse die gesetzt ist solange das Overlay angezeigt wird (gut für Print-Stylesheets
		
		positionType: '', // Name der Funktion im Namespace  $.ui.cOverlay.posMethods bzw die Funktion selbst, welche die Position berechnet 
		positionOpts: {}, //optionen der positions-Funktion
		//mögliche weitere Positionierungs-Optionen
		followMouse: false,
		
		//focusmanagement wird durch a11ymode überschrieben
		restoreFocus: false, // Ob der Focus beim Schliessen auf das Element gesetzt werden soll, welches vor dem öffnen fokusiert war
		focusOnShow: false, // Ob das Overlay fokusiert werden soll, wenn es geöffnet  wird. Wird ein Selektor angegeben, dann wird dieses Element fokusiert
		
		closeOnEsc: true,
		closeBtnSel: 'a.close-button',
		
		animShow: function(jElm, ui){ //Show-Animation (ui.posCSS enthält die berechnete Positionierung und muss gesetzt werden) 
			jElm.css(ui.posCSS).css({display: 'block'});
		},
		animHide: function(jElm, ui){//Hide-Animation 
			jElm.css({display: 'none'});
		},
		
		a11yMode: false, // nonfocussyle: tooltip || alert || focusstyle: alertdialog || dialog || specialdialog
		createA11yWrapper: 'auto',
		labelledbySel: false,
		describedbySel: false,
		
		//Opener
		openerSel: false, // Elemente (Selektor:String, jQuery:Object, DOM:Object), welche das Overlay öffnen
		openerContext: document, // Kontext (DOM:Object, jQuery:Object) in dem nach openerSel gesucht wird
		bindStyle: 'bind', // Art des Event-Bindings (bind|live)
		
		//opencloseEvents werden durch a11ymode erweitert
		openEvent: 'ariaclick', // mouseenter || click
		closeEvent: false,
		openDelay: 0, //Zeit die vergehen soll bis das overlay geöffnet wird
		
		setInitialContent: false,
		modal: 'auto' // Macht ein Fenster Modal, so dass der focus nicht mehr entfernt werden kann. Auto bedeutet, dass es bei Verwendung von mask: true und einer dialog-Rolle auf true gesetzt wird
	};
})(jQuery);
