(function($){
	var options={
		displayElements : {
			title : {
				id        : "hover-image-title",
				attribute : "innerHTML"
			}
		},
		defaultThumbnailSuffix      : "",
		activeThumbnailSuffix       : "_aktiv",
		displayImageID              : "hover-image-big",
		displayImageSuffix          : "_big",
		displayImageSourceAttribute : "href",
		fadeInDuration              : 200,
		fadeOutDuration             : 200,
		fadeOutColor                : "#FFF",
		showDisplayImage            : true,
		showDisplayElements         : true,
		showHoverImage              : true,
		useChildImageCache          : true,
		hideOnExit                  : false,
		progressIndicatorImageURL   : "/media/image/system_3/indicator.gif"
	};
	
	var progress          = null;
	var progressIndicator = null;
	var progressCreated   = false;
	var displayImage      = null;
	var childImages       = [];
	var activeProcess     = [];
	
	$.fn.hoverimage = function(_options) {
		options = $.extend(true, options, _options);
		
		return this.each(function () {
			if(!activeProcess[this]) {
				$(this).hover(
					function () {
						activeProcess[this] = true;
					
						if(options.showDisplayElements) {
							displayAttributes(this);
						}
					
						if(options.showDisplayImage) {
							loadDisplayImage(this);
						}
					
						if(options.showHoverImage) {
							var img = getHoverImage(this);
							setImageState(img, "active");
						}
					
						activeProcess[this] = false;
					},
					function () {
						activeProcess[this] = true;

						if(options.showDisplayImage && options.hideOnExit) {
							hideDisplayImage();
						}

						if(options.showDisplayElements && options.hideOnExit) {
							hideAttributes(this);
						}

						if(options.showHoverImage) {
							var img = getHoverImage(this);
							setImageState(img, "inactive");
						}
					
						activeProcess[this] = false;
					}
				);
			}
		})
	};
	
	function displayAttributes(obj) {
		var config = options.displayElements;
		
		if(obj && config) {
			var attribute = null;
			
			for(attribute in config) {
				if(obj.getAttribute(attribute)) {
					var value  = obj.getAttribute(attribute);
					var target = document.getElementById(config[attribute].id);
					
					if(target) {
						target[config[attribute].attribute] = value;
					}
				}
			}
		}
	}

	function hideAttributes(obj) {
		var config = options.displayElements;

		if(obj && config) {
			var attribute = null;

			for(attribute in config) {
				if(obj.getAttribute(attribute)) {
					var target = document.getElementById(config[attribute].id);

					if(target) {
						target[config[attribute].attribute] = "";
					}
				}
			}
		}
	}
	
	function getHoverImage(source){
		var child = null;
		var i = null;
		
		if(
			!options.useChildImageCache || (
				childImages[source.href] === undefined ||
				typeof childImages[source.href] !== "object"
			)
		) {
			for(i in source.childNodes) {
				if(
					typeof source.childNodes[i] === "object" &&
					source.childNodes[i].nodeName
				) {
					if(source.childNodes[i].nodeName === "IMG") {
						if(options.useChildImageCache) {
							childImages[source] = source.childNodes[i];
							return childImages[source];
						} else {
							return source.childNodes[i];
						}
						break;
					}
				}
			}
		} else {
			child = childImages[source];
		}
		
		return child;
	}
	
	function setImageState(image, state) {
		var imgSrc     = image.src;
		var isInactive = true;
		var isActive   = false;
		
		if(options.activeThumbnailSuffix !== "") {
			isActive = hasSuffix(imgSrc, options.activeThumbnailSuffix);
		}
		
		if(options.defaultThumbnailSuffix!=="") {
			isInactive = hasSuffix(imgSrc, options.defaultThumbnailSuffix);
		} else {
			if(isActive) {
				isInactive=false
			}
		}
		
		if(state === "active" && isInactive) {
			imgSrc = changeSuffix(
				imgSrc,
				options.defaultThumbnailSuffix,
				options.activeThumbnailSuffix
			);
		} else {
			if(state === "inactive" && isActive) {
				imgSrc = changeSuffix(
					imgSrc,
					options.activeThumbnailSuffix,
					options.defaultThumbnailSuffix
				);
			}
		}
		
		image.src = imgSrc;
	}
		
	function hasSuffix(url, suffix) {
		var urlExtPosition = url.lastIndexOf(".");
		var urlBeforeExt   = url.substring(0, urlExtPosition);
		var possibleSuffix = urlBeforeExt.substr(
			urlBeforeExt.length - suffix.length
		);
		
		return possibleSuffix === suffix;
	}
	
	function changeSuffix(url, oldSuffix, newSuffix) {
		url = removeSuffix(url, oldSuffix);
		return addSuffix(url, newSuffix);
	}
	
	function addSuffix(url, suffix){
		var urlExtPosition = url.lastIndexOf(".");
		var urlExt         = url.substring(urlExtPosition + 1);
		var urlBeforeExt   = url.substring(0, urlExtPosition);
		
		return urlBeforeExt + suffix + "." + urlExt;
	}
	
	function removeSuffix(url, suffix) {
		if(hasSuffix(url, suffix)) {
			var urlExtPosition = url.lastIndexOf(".");
			var urlExt = url.substring(urlExtPosition + 1);
			var urlBeforeExt = url.substring(0 , urlExtPosition);
			
			url = urlBeforeExt.substr(0, urlBeforeExt.length - suffix.length) +
				"." + urlExt;
		}
		return url;
	}
	
	function loadDisplayImage(sourceObj) {
		if(!progressCreated) {
			createProgressDisplay()
		}
		
		$(progress).fadeIn(options.fadeInDuration, function () {
			$(progressIndicator).show();
			
			var imageURL = null;
			
			if(
				sourceObj.getAttribute &&
				sourceObj.getAttribute(options.displayImageSourceAttribute)
			){
				imageURL = sourceObj.getAttribute(
					options.displayImageSourceAttribute
				);
			} else {
				var attribute = null;
				
				for(attribute in sourceObj){
					if(attribute === options.displayImageSourceAttribute) {
						imageURL = sourceObj[attribute];
						break;
					}
				}
			}
			
			if(imageURL) {
				displayImage.src = imageURL;
				$(displayImage).load(function() {
					$(progressIndicator).hide();
					$(displayImage).show();
					$(progress).fadeOut(options.fadeOutDuration);
				});
			}
		});
	}

	function hideDisplayImage() {
		if(!displayImage) return;
		if(displayImage.style.display == "none") return;

		if(progress && progress.style.display != "none") {
			displayImage.src = null;
			$(displayImage).hide();

			$(progress).fadeOut(options.fadeOutDuration);

			if(progressIndicator && progressIndicator.style.display != "none") {
				$(progressIndicator).hide();
			}
		} else {
			$(displayImage).fadeOut(options.fadeOutDuration, function() {
				displayImage.src = null;
				$(displayImage).hide();
			});
		}
	}
	
	function createProgressDisplay() {
		displayImage = document.getElementById(options.displayImageID);
		
		var imagePos = $(displayImage).position();
		
		$(displayImage).parent("div").append(
			progress = $('<div id="hover-image-progress"></div>').append(
				progressIndicator = $(
					'<img id="hover-image-progress-indicator" src="' +
					options.progressIndicatorImageURL +
					'" width="32" height="32" border="0" />'
				)[0]
			)[0]
		);
		
		$(progress).css({
			position        : "absolute",
			display         : "none",
			backgroundColor : options.fadeOutColor,
			top             : imagePos.top+"px",
			left            : imagePos.left+"px",
			width           : displayImage.offsetWidth+"px",
			height          : displayImage.offsetHeight+"px"
		});
		$(progressIndicator).css({
			display  : "none",
			position : "absolute",
			top      : ((displayImage.offsetWidth - 32) / 2)  + "px",
			left     : ((displayImage.offsetHeight - 32) / 2) + "px"
		});
		progressCreated = true;
	}
})(jQuery);