// Animates the dimensional changes resulting from altering element contents
// Usage examples:
// $("#myElement").showHtml("new HTML contents");
// $("div").showHtml("new HTML contents", 400);
// $(".className").showHtml("new HTML contents", 400,
// function() {/* on completion */});
(function ( $ )
{
	$.fn.animateContentSwitch = function (toHide, $toShow, speed, hideProcessingCallback, callback )
	{
		return this.each( function ()
		{
			var $this = $( this ),
			unfinishedPreviousAnimation = $this.data('animateContentSwich.previous'),
			originalHeight = null,
			targetHeight = null;

			var $toHide = $.type(toHide)=='string' ? $this.find(toHide) : toHide;
			if ($toHide.length>1) {
				throw "jQuery.animateContentSwitch accepts only single elements";
			}
			//stop any currently running animations 
			$this.dequeue().stop();
			originalHeight = $this.height();
			$toHide.dequeue().stop();
			$toShow.dequeue().stop();
			
			// check if there was a previous animation by animateContent
			// if the current toHide element is the same as the visible element
			// from the previous animation then continue, otherwise 
			// jump to the end of the previous animation
			if ($.type(unfinishedPreviousAnimation) != 'undefined') {
				var prevToHide = unfinishedPreviousAnimation.start.el;
				if ($.type(prevToHide)=='string') {
					prevToHide = $this.find(prevToHide);
				}
				var visibleStep = prevToHide.is(':visible') ? unfinishedPreviousAnimation.start : unfinishedPreviousAnimation.target;
				var prevVisibleEl = $.type(visibleStep.el)=='string' ? $this.find(visibleStep.el) : visibleStep.el;
				prevVisibleEl.dequeue().stop();
				// check if the visible element from previous animation is not the element that
				// has to be hidden from this current animation
				if (
					!(
						($.type(toHide)=='string' && prevVisibleEl.is(toHide)) ||
						($.type(toHide)!='string' && prevVisibleEl.get(0) == toHide.get(0))
					)
				) {
					$this.css('height',unfinishedPreviousAnimation.target.height);
					unfinishedPreviousAnimation.start.el.dequeue().stop().hide();
					unfinishedPreviousAnimation.target.el.dequeue().stop().show();
				} else {
					originalHeight = visibleStep.height;
				}
			}
//			console.log(originalHeight);
			targetHeight = originalHeight - ($toHide.outerHeight(true) - $toShow.outerHeight(true));
			//save current animation data
			var data = {
				start: {
					height: originalHeight,
					el: toHide
				},
				target: {
					height: targetHeight,
					el: $toShow
				}
			};
			$this.data('animateContentSwich.animating', data);
			var hide = function() {
				$toHide.animate({opacity: 0}, speed, function(){
					$toHide.hide();
					if ( $.isFunction( hideProcessingCallback ) ) {
						hideProcessingCallback(show);						
					} else {
						show();
					}
				});
			}

			var show = function () {
				
				// Using Deferred objects for a `group` callback
				
				var toShowDfd = $.Deferred();
				$toShow.css('opacity',0);
				$toShow.show();
				$toShow.animate({opacity: 1}, speed, toShowDfd.resolve);
				
				var heightDfd = $.Deferred();
				$this.animate( {height: targetHeight}, speed, heightDfd.resolve );
				
				$.when(toShowDfd, heightDfd).then(function () // animate to final dimensions
				{
					$this.removeData('animateContentSwich.previous');
					if ( $.isFunction( callback ) ) {
						callback();						
					}
				});
			}
			hide();
//			preCallback(animation);
		} );
	};


})( jQuery );
