/*!
 * Feature Carousel, Version 1.0
 * http://www.bkosolutions.com
 *
 * Copyright 2010 Brian Osborne
 * Licensed under GPL version 3
 *
 * http://www.gnu.org/licenses/gpl.txt
 */
/*!
 * Modified by Norman Rzepka | schech.net
 * <code@normanrzepka.de>
 * 2010-07-07:
 *  - Elements move on an ellipsis
 *  - Implemented tooltips
 */
 

 
 
 
 
(function($) {

    $.fn.featureCarousel = function (options) {

        // override the default options with user defined options
        options = $.extend({}, $.fn.featureCarousel.defaults, options || {});

        return $(this).each(function () {

            /* These are univeral values that are used throughout the plugin. Do not modify them
             * unless you know what you're doing. Most of them feed off the options
             * so most customization can be achieved by modifying the options values */
            var pluginData = {
							currentCenterNum:       1,
							containerWidth:         0,
							containerHeight:        0,
							containerTopMultiplier: options.containerTopMultiplier,
							minSizeMultiplier:      options.minSizeMultiplier,
							ellipsisMeasures:       {},
							totalFeatureCount:      $(this).children("div").length,
							currentlyMoving:        false,
							featuresContainer:      $(this),
							featuresArray:          [],
							timeoutVar:             null
            };

            preload(function () {
							setupCarousel();
							move(true);
            });

            /**
             * Function to preload the images in the carousel if desired.
             * This is not recommended if there are a lot of images in the carousel because
             * it may take a while. Functionality does not depend on preloading the images
             */
            function preload(callback) {
							// user may not want to preload images
							if (options.preload == true) {
								var $imageElements = pluginData.featuresContainer.find("img");
								var loadedImages = 0;
								var totalImages = $imageElements.length;

								$imageElements.each(function () {
									// Attempt to load the images
									$(this).load(function () {
										// Add to number of images loaded and see if they are all done yet
										loadedImages++;
										if (loadedImages == totalImages) {
											// All done, perform callback
											callback();
										}
									});
									// The images may already be cached in the browser, in which case they
									// would have a 'true' complete value and the load callback would never be
									// fired. This will fire it manually.
									if (this.complete) {
										$(this).trigger('load');
									}
								});
							} else {
								// if user doesn't want preloader, then just go right to callback
								callback();
							}
            }

            // get previous feature number
            function getPreviousNum(num) {
							if (num == 0)
								return pluginData.totalFeatureCount - 1;
							else
								return num - 1;
            }

            // get next feature number
            function getNextNum(num) {
							if (num + 1 == pluginData.totalFeatureCount)
								return 0;
							else
								return num + 1;
            }
						
						function getDimension(feature, position)
						{
							var size_multiplier = getSizeMultiplier(position);
							size_multiplier = size_multiplier * feature.data('multiplier');
							
							var original_size = feature.data('size');
							var offset_multiplier = getOffsetMultiplier(position);
							
							var width = size_multiplier * original_size.width;
							var height = size_multiplier * original_size.height;
							
							var em = pluginData.ellipsisMeasures;
							
							return {
								width: width,
								height: height,
								left: (em.width / 2) * (offset_multiplier.x + 1) - width / 2 + em.left,
								top: (em.height / 2) * (offset_multiplier.y + 1) - height / 2 + em.top,
								step: getStep(position)};
						}
						
						function getOffsetMultiplier(position)
						{
							var arg = 0.5 * Math.PI - (2 * Math.PI / pluginData.totalFeatureCount) * position;
							
							return {
								x: Math.cos(arg),
								y: Math.sin(arg)};
						}
						
						function getStep(position)
						{
							var steps = pluginData.totalFeatureCount / 2;
							return steps - Math.abs(position - steps);
						}
						
						function getSizeMultiplier(position)
						{
							var steps = Math.ceil(pluginData.totalFeatureCount / 2);
							return (1 - pluginData.minSizeMultiplier) * 0.5 * (Math.cos((Math.PI / steps) * getStep(position)) + 1) + pluginData.minSizeMultiplier;
						}
						
            /**
             * Function to take care of setting up various aspects of the carousel,
             * most importantly the default positions for the features
             */
            function setupCarousel() {
							pluginData.containerWidth = pluginData.featuresContainer.width();
							pluginData.containerHeight = pluginData.featuresContainer.height();
							
						
							// fill in the features array
							// set feature metadata
							pluginData.featuresContainer.children("div")
								.each(function (index) {
									var feature = $(this);
									pluginData.featuresArray[index] = feature;
									
									feature.data('position', index);
									
									// May be used to scale images to the same size
									feature.data('multiplier', 1);
									// Capture initial size of image
									feature.data('size', { width: feature.width(), height: feature.height() });
								});
							
							(function() {
								// size and position of the ellipsis on which the elements will move
								var em = pluginData.ellipsisMeasures;
								original_size = pluginData.featuresArray[0].data('size');
								//ISD BS Radius größer
								//em.width = pluginData.containerWidth - 1.1 * (0.5 * (1 + pluginData.minSizeMultiplier) * original_size.width);
								em.width = 160;
								em.height = pluginData.containerHeight - (0.5 * (1 + pluginData.minSizeMultiplier) * original_size.height);
								em.height = 20;
								//alert(em.height);
								
								em.left = (pluginData.containerWidth - em.width) * 0.5;

								//ISD BS pos Rand oben
								//	em.top = (pluginData.containerHeight - em.height) * pluginData.containerTopMultiplier;
								em.top = (pluginData.containerHeight - em.height) * 0.65;
								})();
							
							// Place all the features in a center hidden position to start off
							pluginData.featuresContainer
								// Have to make the container relative positioning
								.children("div").each(function () {
									// Center all the features in the middle and hide them
									$(this).css({
										'left': pluginData.containerWidth / 2,
										'width': 0,
										'height': 0,
										'top': pluginData.containerHeight / 2
									});
								})
								.find("img:first").css({
									'width': 0,
									'height': 0
								});
            }

            /**
             * This function will set the autoplay for the carousel to
             * automatically rotate it given the time in the options
             */
            function autoPlay() {
							// clear the timeout var if it exists
							if (pluginData.timeoutVar != null) {
									pluginData.timeoutVar = clearTimeout(pluginData.timeoutVar);
							}

							// set interval for moving if autoplay is set
							if (options.autoPlay != 0) {
								var autoTime = (Math.abs(options.autoPlay) < options.carouselSpeed) ? options.carouselSpeed : Math.abs(options.autoPlay);
								pluginData.timeoutVar = setTimeout(function () {
									if (options.autoPlay > 0)
										move(true);
									else if (options.autoPlay < 0)
										move(false);
								}, autoTime);
							}
            }

            /**
             * This function is used to animate the given feature to the given
             * location. Valid locations are "left", "right", "center", "hidden"
             */
            function animateFeature($feature, direction)
            {
							// Determine the old and new positions of the feature
							var oldPosition = $feature.data('position');
							var newPosition;
							if (direction == true)
								newPosition = getPreviousNum(oldPosition);
							else
								newPosition = getNextNum(oldPosition);
							
							$feature.data('position', newPosition);
		
							var animTarget = getDimension($feature, newPosition);
							var new_zindex = 100 - (animTarget.step * 2) + (newPosition % 2);
							
							// have to change the z-index after the animation is done
							$feature.css("z-index", new_zindex);

							// Animate the feature div to its new location
							$feature
								.animate(
									animTarget,
									options.carouselSpeed,
									options.animationEasing,
									function () {
										pluginData.currentlyMoving = false;

										// call autoplay again
										autoPlay();
									}
								)
								.find("img:first")
									// animate its size down
									.animate({
										width: animTarget.width,
										height: animTarget.height
									},
									options.carouselSpeed,
									options.animationEasing)
								.end();
            }

            /**
             * move the carousel to the left or to the right. The features that
             * will move into the four positions are calculated and then animated
             * rotate to the RIGHT when direction is TRUE and
             * rotate to the LEFT when direction is FALSE
             */
            function move(direction)
            {
                // Set the carousel to currently moving
                pluginData.currentlyMoving = true;
								
								$.each(pluginData.featuresArray, function(index, feature) {
									animateFeature(feature, direction);
								}); 

            }

						pluginData.tooltip = $('<div id="featureCarousel-tooltip"></div>');
						$('body').append(pluginData.tooltip);
						
						// Stop auto-animation when mouseover container
						pluginData.featuresContainer
							.mouseover(function () { pluginData.timeoutVar = clearTimeout(pluginData.timeoutVar); })
							.mouseout(function () { autoPlay(); });

            // Show Tooltip on hover
            pluginData.featuresContainer.children("div")
								.mouseover(function (event) {
									pluginData.tooltip
										.html($(this).children('div').html() + '<div class="tip"></div>');
									
									pluginData.tooltip.css({
										top: (event.pageY - pluginData.tooltip.height() - 40) + 'px',
										left: (event.pageX - 25) + 'px' }).show();
								})
								.mousemove(function (event) {
									pluginData.tooltip.css({
										top: (event.pageY - pluginData.tooltip.height() - 40) + 'px',
										left: (event.pageX - 25) + 'px' });
								})
								.mouseout(function () {
									pluginData.tooltip.hide();	
								});
        });
    };

    $.fn.featureCarousel.defaults = {
        // 
				containerTopMultiplier: 0.4,
				// minimum percentage to which an element will be scaled
				minSizeMultiplier:      0.3,
				// time in milliseconds how long an animation takes place
				carouselSpeed:          1000,
        // time in milliseconds to set interval to autorotate the carousel
        // set to zero to disable it, negative to go left
        autoPlay:               0,
        // true to preload all images in the carousel before displaying anything
        preload:                true,
        // an easing can be specified for the animation of the carousel
        animationEasing:        'swing'
    };

})(jQuery);
