/**
 * @author alexander.farkas
 */

(function($){
		
	var posExclude = {
		absolute: /absolute/,
		relative: /absolute|fixed|relative/
	};
	
	function addStyles(jElm, styles){
		var elem 		= jElm[0];
		if(!elem){return jElm;}
		var elemStyle 	= elem.style;
		if(styles.position && posExclude[styles.position].test($.curCSS(elem, 'position'))){
			styles = $.extend({}, styles);
			delete styles.position;
		}
		for(var style in styles){
			elemStyle[style] = styles[style];
		}
		return jElm;
	}
	
	$.fn.fadeOver = function(opts){
		if(!this[0]){return this;}
		opts = $.extend({}, $.fn.fadeOver.defaults, opts);
		if((this.length > 1 || opts.hideElement.length > 1)){
			console.log('fadeOver: wir können immer nur ein hideElement bzw. ein showElement behandeln');
		}
		
		var jElm 				= $(this[0]),
			parentElement 		= (opts.parentSel) ? jElm.closest(opts.parentSel) : jElm.parent(),
			animInCSS 			= {
									start: {
										position: 'absolute',
										top: (parseInt(parentElement.css('paddingTop'), 10) || 0),
										left: (parseInt(parentElement.css('paddingLeft'), 10) || 0),
										display: 'block'
									},
									end: {},
									after: {
										position: '', top: '', left: ''
									}
								},
			animOutCSS 			= $.extend(true, {}, animInCSS, {after: {}}),
			parentStartStyles 	= {
									position: 'relative',
									zoom: '1',
									overflow: 'hidden',
									height: parentElement.height() +'px'
								},
			parentEndStyles 	= {height: ''}
		;
		if(opts.stopAll){
			opts.hideElement.stop(true, true);
			jElm.stop(true, true);
		}
		if(opts.hideStyle === 'visibility'){
			animInCSS.start.visibility = '';
			animOutCSS.after.visibility = 'hidden';
		} else {
			animInCSS.start.display = 'block';
			animOutCSS.after.display = 'none';
		}
		
		opts.showElement = jElm;
		
		if (opts.inAnim) {
			$.each(opts.inAnim.split(','), function(i, anim){
				$.fn.fadeOver.presets[anim](jElm, animInCSS, opts);
			});
		}
		
		if(opts.outAnim){
			$.each(opts.outAnim.split(','), function(i, anim){
				$.fn.fadeOver.presets[anim](opts.hideElement, animOutCSS, opts);
			});
		}
		
				
		function animateParentHeight(){
			parentElement
				.animate(
					{height: jElm.outerHeight({margin: true})},
					$.extend({}, opts.animOpts, {
						complete: function(){
							parentElement.css(parentEndStyles);
							if(opts.animateHeight === 'linear'){
								opts.complete.apply(jElm[0]);
							}
						}
					})
				);
		}
		
		addStyles(parentElement, parentStartStyles);
		addStyles(opts.hideElement, animOutCSS.start);
		
		if(opts.outAnim){
			opts.hideElement.animate(animOutCSS.end, $.extend({}, opts.animOpts));
		}
		addStyles(jElm, animInCSS.start);
		if (opts.inAnim) {
			jElm.animate(animInCSS.end, $.extend({}, opts.animOpts, {
				complete: function(){
					if (opts.hideStyle === 'visibility') {
						opts.hideElement.parent().css({
							overflow: 'hidden',
							height: 0
						});
					}
					opts.hideElement.css(animOutCSS.after);
					jElm.css(animInCSS.after);
					if (!opts.animateHeight) {
						parentElement.css(parentEndStyles);
					}
					
					if (opts.animateHeight !== 'linear') {
						opts.complete.apply(this, arguments);
					}
					else {
						animateParentHeight();
					}
				}
			}));
		}
		if(opts.hideStyle === 'visibility'){
			jElm.parent().css('height', '');
		}
		
		if(opts.animateHeight === 'sync'){
			animateParentHeight();
		}
		return this;
	};
	
	$.fn.fadeOver.defaults = {
		animateHeight: false, // false | sync || linear
		inAnim: 'fadeIn',
		outAnim: 'fadeOut',
		hideStyle: 'display',
		parentSel: false,
		hideElement: $([]),
		stopAll: true,
		complete: $.noop,
		animOpts: {
			duration: 400
		}
	};
	
	$.fn.fadeOver.presets = {
		fadeIn: function(jElm, css, opts){
			if(!jElm[0]){return css;}
			if( jElm[0].offsetHeight < 3 || jElm[0].offsetWidth < 3 || jElm.css('visibility') === 'hidden' ){
				css.start.opacity = 0;
			}
			css.end.opacity = 1;
			css.after.opacity = '';
			return css;
		},
		fadeOut: function(jElm, css, opts){
			css.end.opacity = 0;
			return css;
		}
	};
	
	$.fn.crossFade = $.fn.fadeOver;
	
	
})(jQuery);