/* 
 * jQuery XQSlider v0.7
 * http://www.xquarters.com
 *
 * Copyright 2012, Martin Veith
 * Free to use and abuse under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Date: Thu December 8 13:00:00 2011 +0100
*/
(function($) {
	$.fn.XQSlider = function(options) {
		// init XQ 
		$.XQ = $.XQ || {};
		
		$.XQ.Slider = $.XQ.Slider || {};
		
		// default settings
		var defaultSettings = {
				autoplay : 1,
				carousel : 1,
				interval : 3000,
				clickable : 1,
				startIndex : 1,
				captions : 1,
				onPlay : "",
				onPause : "",
				onStop : "",
				onPrevious : "",
				onNext : "",
				onRotateBefore : "",
				onRotateAfter : "",
				onImagesLoaded : "",
				onInit : "",
				containerSelector : ".container",
				progressSelector : ".progress",
				pauseOnHover : 1, 
				transition : "default",
				keyboardNav : -1,
				player : 0,
				buttonNav : 0,
				bulletNav : 0,
				preload : 2,
				preloadFadeInSpeed : 250
			},
			userAgent = navigator.userAgent,
			iOS = (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i) || userAgent.match(/iPod/i) || userAgent.match(/iPod/i)),
			Android = (userAgent.match(/Android/i));
		
		/* options for docu 
		 * jquery.swipe.js support
		 * multiple sliders in one
		 * browser
		 */
		
		$.XQ.IsDefined = function(v)
		{
			return !(v === undefined | v === null);	
		}
		
		$.XQ.IsFunction = function(v)
		{
			return typeof v == "function";	
		}
		
		$.XQ.Browser = {
			userAgent : navigator.userAgent,
			iOS : (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i) || userAgent.match(/iPod/i) || userAgent.match(/iPod/i)),
			Android : (userAgent.match(/Android/i)),
			
			/* Google Chrome 15.0.874.121 m flickering problems */
			force3DHWA : ($.browser.safari & userAgent.indexOf("Chrome") == -1) || iOS || Android,
			
			init : function() {
				var style = document.body.style;
				this.transitions = {
					WEBKIT : {support : $.XQ.IsDefined(style.webkitTransition), c : "webkit", s : "Webkit"},
					MOZILLA : {support : $.XQ.IsDefined(style.MozTransition), c : "moz", s : "Moz"},
					OPERA : {support : $.XQ.IsDefined(style.OTransition), c : "o", s : "O"},
					IE : {support : $.XQ.IsDefined(style.MsTransition), c : "ms", s : "Ms"}
				};
				
				this.transitions.support = 
					this.transitions.WEBKIT.support & userAgent.indexOf("Chrome") == -1 |
					this.transitions.MOZILLA.support |
					// Opera seems to be buggy in <= 11.60+ this.transitions.OPERA.support |
					// IE ... this.transitions.IE.support
					0;	
			},
			
			transitions : {},
			getPrefix : function(css, lines) {	 
				for(browser in $.XQ.Browser.transitions) {	
					browser = $.XQ.Browser.transitions[browser];  
					if(typeof browser == "object" && browser.support)
						return css ? (lines ? "-" : "") + browser.c + (lines ? "-" : "") : browser.s;
				}
				return "";
			}
		};

		$.XQ.Slider.Transitions = {
			timeout : "",
			transitions : {
				"default" : function(transition) {
					this.getCurrentItem().hide();       
					this.getActiveItem().show();
					this.finish();	
				},			
				
				"fade" : function(transition) { 
					var tOptions = $.extend({fadeInSpeed : 400, fadeOutSpeed : 400, easing : "swing", CSS3Easing : "ease-in"}, transition),						
						t = this,
						
						$currentItem = t.getCurrentItem(),
						$activeItem = t.getActiveItem(),
						CSS3Support = $.XQ.Browser.transitions.support,
						DOMPrefix = $.XQ.Browser.getPrefix();
						
					tOptions.fadeOutSpeed = Math.min(tOptions.fadeInSpeed, tOptions.fadeOutSpeed);

					if(CSS3Support)
					{
						if($.XQ.force3DHWA) {
							//prevents flickering on several devices
							$currentItem[0].style[DOMPrefix + "Perspective"] = 1000;
							$activeItem[0].style[DOMPrefix + "Perspective"] = 1000;
						}
						
						//fade out  
						$currentItem.show()[0].style[DOMPrefix + "Transition"] = "opacity " + (tOptions.fadeOutSpeed / 1000) + "s " + tOptions.CSS3Easing;  
						
						//fade in (https://bugs.webkit.org/show_bug.cgi?id=27159)
						$activeItem.css({opacity : 0}).show();
						$.XQ.Slider.Transitions.timerID = window.setTimeout(function() {
							$currentItem.css({opacity : 0});
							$activeItem[0].style[DOMPrefix + "Transition"] = "opacity " + (tOptions.fadeInSpeed / 1000) + "s " + tOptions.CSS3Easing;
							$activeItem.css({opacity : 1});
							$.XQ.Slider.Transitions.timerID = window.setTimeout(function() {	
								$activeItem[0].style[DOMPrefix + "Transition"] = "";
								$currentItem[0].style[DOMPrefix + "Transition"] = "";
								
								$currentItem.hide().css({opacity : 1});

								t.finish();			
							}, tOptions.fadeInSpeed);
						}, 0);
					}
					else
					{
						//fade out 
						$currentItem.stop(1).animate({opacity : 0}, tOptions.fadeOutSpeed, tOptions.easing);  
						
						//fade in
						if(!$activeItem.is(":animated"))
							$activeItem.css({opacity : 0}).show();
							
						$activeItem.stop(1).animate({opacity : 1}, tOptions.fadeInSpeed, tOptions.easing, t.finish);
					}
				},
				
				"slide" : function(transition) { 
					var tOptions = $.extend({speed : 400, direction : this.getSettings().random ? "random" : "horizontal", carousel : 1, easing : "swing", CSS3Easing : "ease-in"}, transition),
						t = this,
					
						$items = t.getItems(),
						$itemsAll = [],
						$container = t.getContainer(),
						$clone = [],						
						$animationWrapper = t.getAnimationWrapper(),
						animationWrapper = $animationWrapper[0], 
						
						ActiveIndex = t.getActiveIndex(), activeIndexAll,
						CurrentIndex = t.getCurrentIndex(), currentIndexAll,
						
						horizontal = (tOptions.direction == "horizontal" || (tOptions.direction == "random" & Math.round(Math.random()))) || (tOptions.direction != "vertical" & tOptions.direction != "random"),
						
						containerSize = horizontal ? $container.innerWidth() : $container.innerHeight(),
						toSlide = {}, 
						
						action = t.stack[t.stack.length - 1],
						
						CSS3Support = $.XQ.Browser.transitions.support,
						DOMPrefix = $.XQ.Browser.getPrefix(),
						force3DHWA = $.XQ.Browser.force3DHWA,
						transform = force3DHWA ? "translate3d" : "translate",
						translate3d = transform == "translate3d"; 
					
					tOptions.carousel = tOptions.carousel & t.getSettings().carousel & !t.getSettings().random & $items.length > 2;
											
					if($animationWrapper.hasClass("carousel"))
						tOptions.carousel = 1;
					else if(tOptions.carousel) {
						$animationWrapper.addClass("carousel");
						
						t.addItem($items[0], $items.length, 1);
						t.addItem($items[$items.length - 1], 0, 1);
						
						$items = t.getItems(); 
					}
					
					$itemsAll = t.getItems(1).css({position : "relative", "float" : "left"}).show();
					currentIndexAll = $itemsAll.index($items.filter("[data-initial-index=" + CurrentIndex + "]"));
					
					$animationWrapper = $items.parent().css({position : "relative"});
		
					activeIndexAll = $itemsAll.index($items.filter("[data-initial-index=" + ActiveIndex + "]"));
		
					var dataDirection = $animationWrapper.attr("data-direction"),
						index = activeIndexAll,
						animated = $animationWrapper.is(":animated") || animationWrapper.style[DOMPrefix + "AnimationPlayState"] == "running";
					
					$animationWrapper.stop();
					
					if(tOptions.carousel & action != "show" & !animated)
					{
						if(CurrentIndex == $items.length - 1 & ActiveIndex == 0)
							index = $itemsAll.length - 1;	
						else if(CurrentIndex == 0 & ActiveIndex == $items.length - 1)
							index = 0;	
					}
					
					if(action == "stop" & $.XQ.IsDefined(dataDirection)) {
						horizontal = dataDirection == "horizontal";
						containerSize = horizontal ? $container.innerWidth() : $container.innerHeight();
					}

					var animationStyle = horizontal ? "left" : "top";
					toSlide[animationStyle] = index * containerSize * -1;
					
					if(CSS3Support & force3DHWA) 
						toSlide.transform = transform + "(" + (horizontal ? toSlide.left + "px,0" : "0," + toSlide.top + "px") + "" + (translate3d ? ",0" : "") + ")";
				
					animationWrapper.style[(horizontal ? "width" : "height")] = $itemsAll.length * 100 + "%";
					animationWrapper.style[(horizontal ? "height" : "width")] = 0;
					animationWrapper.style[(horizontal ? "top" : "left")] = 0;
						
					toSlide.init = {};
					toSlide.init[animationStyle] = currentIndexAll * containerSize * -1;	
					
					if(force3DHWA)
					{ 
						var $currentItem = $($itemsAll[currentIndexAll]),
							$activeItem = $($itemsAll[activeIndexAll]);
					
						//prevents flickering on several devices
						$currentItem[0].style[DOMPrefix + "Perspective"] = 1000;
						$activeItem[0].style[DOMPrefix + "Perspective"] = 1000;
					}							
				
					if(action != "stop") {
						if(force3DHWA)
						{
							animationWrapper.style[DOMPrefix + "Transition"] = "";
							animationWrapper.style[DOMPrefix + "Transform"] = transform + "(" + (horizontal ? toSlide.init.left + "px,0" : "0," + toSlide.init.top + "px") + "" + (translate3d ? ",0" : "") + ")";
						}
						else
							animationWrapper.style[animationStyle] = toSlide.init[animationStyle] + "px";
					}
					else {
						if(!animated)
						{
							if(force3DHWA)
							{
								animationWrapper.style[DOMPrefix + "Transition"] = "";
								animationWrapper.style[DOMPrefix + "Transform"] = transform + "(" + (horizontal ? toSlide.init.left + "px,0" : "0," + toSlide.init.top + "px") + "" + (translate3d ? ",0" : "") + ")";
							}
							else
								animationWrapper.style[animationStyle] = toSlide.init[animationStyle] + "px";
						}
					}
		
					$animationWrapper.attr("data-direction", horizontal ? "horizontal" : "vertical");
			
					if(CSS3Support) {  
						$.XQ.Slider.Transitions.timerID = window.setTimeout(function() { 
							$animationWrapper.one($.XQ.Browser.getPrefix(1) + "TransitionEnd", function() {		
								animationWrapper.style[DOMPrefix + "Transition"] = "";
								if(force3DHWA) {
									animationWrapper.style[DOMPrefix + "Transform"] = transform + "(0,0" + (translate3d ? ",0" : "") + ")";
									$animationWrapper.css({width : "100%", height: "100%"});
								}
								else {
									$animationWrapper.css({width : "100%", height: "100%", top : 0, left : 0});	
								}
								
								animationWrapper.style[DOMPrefix + "AnimationPlayState"] = "paused";
								
								t.setItemStyles(ActiveIndex);
		
								t.finish();		
							});
							
							animationWrapper.style[DOMPrefix + "Transition"] = (force3DHWA ? $.XQ.Browser.getPrefix(1, 1) + "transform" : "all") + " " + (tOptions.speed / 1000) + "s" + " " + tOptions.CSS3Easing;
							if(force3DHWA)
								animationWrapper.style[DOMPrefix + "Transform"] = toSlide.transform;
							else
								animationWrapper.style[animationStyle] = toSlide[animationStyle] + "px";
					 
							animationWrapper.style[DOMPrefix + "AnimationPlayState"] = "running";
						}, 0);
					}
					else { 
						$animationWrapper.stop(1).animate(toSlide, tOptions.speed, tOptions.easing, function() {  
							$animationWrapper.css({width : "100%", height: "100%", top : 0, left : 0});
							t.setItemStyles(ActiveIndex);
	
							t.finish();
						});
					}
				}
			},
			
			addTransition : function(name, fn)
			{
				$.XQ.Slider.Transitions.transitions[name] = fn;
			},
			
			doTransition : function(obj, transitions)
			{ 
				var transition = $.XQ.Slider.Transitions.validateTransition(obj, transitions, obj.getActiveIndex());	
		
				//to achieve consistency across different transitions
				if(obj.stack[obj.stack.length - 1] == "stop" && obj.lastTransition)
					transition = obj.lastTransition;
					
				obj.lastTransition = transition;	

				obj.getAnimationWrapper().unbind($.XQ.Browser.getPrefix(1) + "TransitionEnd");
				window.clearTimeout($.XQ.Slider.Transitions.timerID);
				$.XQ.Slider.Transitions.transitions[transition.name].call(obj, transition);
			},
			
			validateTransition : function(obj, transitions, index)
			{
				var transition = transitions;
				
				if(typeof transition == "object")
				{
					if($.XQ.IsDefined(transitions[index]))
						transition = transitions[index];
					else 
						transition = transitions;
				}

				if(!$.XQ.IsDefined(transition.name))
					if(typeof transition == "string")
						transition = {
							name : transition
						};
					else
						transition.name = "default";

				if(transition.name == "random")
				{
					var transitionsLength = 0;
					for(var randomTransition in $.XQ.Slider.Transitions.transitions)
					{
						transitionsLength++;	
					}
					
					var randomTransitionIndex = Math.floor(Math.random() * transitionsLength),
						i = 0;
					
					for(randomTransition in $.XQ.Slider.Transitions.transitions)
					{
						if(i == randomTransitionIndex)
						{
							transition = {
								name : randomTransition
							};
							break;
						}
						i++;
					} 			
				}

				if(!$.XQ.IsDefined($.XQ.Slider.Transitions.transitions[transition.name]))
					transition.name = "default";
					
				return transition;
			}
		};
		
		var Slider = function($slider, options)
		{
			var settings, $container, $items, $bulletNav, $animationWrapper, $progress,
		   
				Timeout = "",
			
				ActiveIndex, CurrentIndex = 0,
		   
				randoms = [],
				images = [],
				progress = "",

				init = 0,
				obj = this,
				
				States = {
					Autoplay : 0,
					Started : 0,
					Stopped : 0,
					Paused : 0,
					Rotation : 0
				};
		 
			$.extend(this, {
				stack : [],
				lastTransition : "",
				hovered : 0,
				
				getSlider : function()
				{
					return $slider;
				},
				
				getContainer : function()
				{
					return $container;
				},

				getAnimationWrapper : function()
				{
					return $animationWrapper;
				},
				
				getActiveIndex : function()
				{
					return ActiveIndex;
				},
			   
				getCurrentIndex : function()
				{
					return CurrentIndex;
				},
				
				getStates : function()
				{
					return States;
				},
				
				getTabs : function(index)
				{   
					if(typeof index == "number")
						return $($bulletNavItems[index]);
						
					return $bulletNavItems;
				},
			   
				getItems : function(all, index)
				{	
					var $itemsCustom = (all ? $($items[0]).parent().children() : $items);
					return $.XQ.IsDefined(index) ? $($itemsCustom[index]) : $itemsCustom;
				},
			   
				getActiveItem : function()
				{
					return $($items[ActiveIndex]);
				},
		
				getCurrentItem : function()
				{
					return $($items[CurrentIndex]);
				},
				
				setSettings : function(options, init)
				{
					settings = $.extend(defaultSettings, options);	
					
					if(init)
					{
						$container = $($slider.find(settings.containerSelector)[0]); 
						
						$container.wrapInner('<div class="animation-wrapper"></div>');
						$animationWrapper = $container.children();	
						
						$items = $animationWrapper.children();
						$progress = $($slider.find(settings.progressSelector)[0]);
			
						if(typeof settings.startIndex != "number")
							settings.startIndex = Math.floor(Math.random() * $items.length);
						else
							settings.startIndex = getRotationIndex(settings.startIndex - 1);
					}
					
					//clickable
					if(settings.clickable)
					{
						$items.bind("click", function(e) {
							e.preventDefault();
							obj.next(1);	
						});
					}
					
					//setStates({Started : settings.autoplay, Paused : !settings.autoplay, Stopped : !settings.autoplay});
				
					//pause slider on hover
					if(settings.pauseOnHover)
					{
						$container.hover(this.pause, function() { if(!States.Rotation & !States.Stopped) { if(init) obj.play(); } });
					}
				},
				
				getSettings : function()
				{
					return settings;
				},
				
				getInterval : function() 
				{
					if(typeof settings.interval == "object")
						return settings.interval[ActiveIndex];
					
					return settings.interval;
				},
		   
				play : function()
				{	  
					continueProgress();

					//clearRotationTimeout();
					setStates({Started : 0, Autoplay : 1, Stopped : 0, Paused : 0});
					if($.XQ.IsFunction(settings.onPlay)) settings.onPlay.call(this);
					obj.stack.push("play");
					
					rotate();
				},
			
				stop : function()
				{
					//clearRotationTimeout();
					pauseProgress(1);
					
					if(States.Stopped)
						return;
						
					setStates({Paused : 0, Autoplay : 0});
					
					if($.XQ.IsFunction(settings.onStop)) settings.onStop.call(this);
					obj.stack.push("stop");
					
					randoms = []; 
					rotate({index : settings.startIndex, random : 0, States : {Started : 0, Stopped : 1}}); 
					setStates({Started : 0, Stopped : 1});
				},
			   
				pause : function()
				{
					if(States.Stopped)
						return;
						
					pauseProgress();
						
					clearRotationTimeout();
					setStates({Paused : 1, Autoplay : 0});
					if($.XQ.IsFunction(settings.onPause)) settings.onPause.call(this);
				},
			   
				show : function(index, stop)
				{
					if(index == ActiveIndex | States.Rotation) 
						return; 
					//clearRotationTimeout();
					setStates({Started : 1, Stopped : 0, Paused : 0, Autoplay : !stop}); 
					obj.stack.push("show");
					if($.XQ.IsFunction(settings.onShow)) settings.onShow.call(this); 
					rotate({index : index, random : 0});   
				},
			   
				previous : function(stop)
				{
					//clearRotationTimeout();
					if(States.Rotation) return; 
					setStates({Started : 1, Stopped : 0, Paused : 0, Autoplay : !stop});
					obj.stack.push("previous");
					if($.XQ.IsFunction(settings.onPrevious)) settings.onPrevious.call(this);
					rotate({index : ActiveIndex - 1});
				},  
			   
				next : function(stop)
				{  
					//clearRotationTimeout();   
					if(States.Rotation | (!settings.carousel & ActiveIndex == obj.getItems().length - 1)) return;  
					setStates({Started : 1, Stopped : 0, Paused : 0, Autoplay : !stop});
					obj.stack.push("next");
					if($.XQ.IsFunction(settings.onNext)) settings.onNext.call(this);
					rotate({index : ActiveIndex + 1});
				},
			
				setItemStyles : function(index)
				{
					var count = $items.length,
						$item = $($items[index]),
						$itemsAll = obj.getItems(1);
					
					//style items
					$itemsAll.not($item).hide();
					
					$itemsAll.stop(1, 1).each(function(index) {
						if(!$(this).find("object").length)
							$(this).css({position : "absolute"});
						$(this).css({zIndex : count - index, top : 0, left : 0});																	  
					});
				},
				
				addItem : function(element, pos, clone) {
					var element = clone ? $(element).clone().addClass("clone") : element;
					
					if(pos <= 0)
						$($items[0]).before(element);
					else
						$($items[pos - 1]).after(element);
						 
					var $item = obj.getItems(1, pos),
						index = pos <= 0 ? parseInt($item.next().attr("data-index")) - 1 : parseInt($item.prev().attr("data-index")) + 1;
		
					$item.attr("data-index", index);
					$item.attr("data-ref-index", obj.getInitialIndex($item));
					$item.removeAttr("data-initial-index");
			
					prepareImageLoad([index], 0, $item, 0);
				},
				
				finish : function() { 
					if($.XQ.IsFunction(settings.onRotateAfter))
						settings.onRotateAfter.call(obj);				
				
					setStates({Rotation : 0}); 	

					if(States.Autoplay & !States.Stopped & !States.Paused & obj.getInterval() > 0)
					{	
						continueProgress();
						Timeout = window.setTimeout(function() {  
							if(!States.Stopped & !States.Paused)
							{
								pauseProgress(1);
								obj.next();	
							}
						}, obj.getInterval());
					}
					else
						pauseProgress(1);
				},
				
				getInitialIndex : function($item) {
					var originalIndex = $item.attr("data-initial-index");
					
					if($.XQ.IsDefined(originalIndex))
						return originalIndex;
					else
						return $item.attr("data-ref-index");
				}
			});
			
			var clearRotationTimeout = function() {
				window.clearTimeout(Timeout);
			};
			
			var continueProgress = function() { 
				$progress.stop().animate({width : "100%"}, obj.getInterval());
			};
			
			var pauseProgress = function(reset) { 
				$progress.stop();
				if(reset)
					$progress.width(0);
			};
							   
			var rotate = function(rotation) { 
				clearRotationTimeout();
				
				if(obj.stack[obj.stack.length - 1] != "play")
					pauseProgress(1);
				
				if(States.Paused | States.Stopped)
					return;
				
				setStates({Rotation : 1});
			
				if(States.Started)
				{	
					rotation = $.extend({
						index : ActiveIndex,
						random : settings.random
					}, rotation);
					setActiveIndex(rotation.index, rotation.random); 
					setStates();

					if($.XQ.IsFunction(settings.onRotateBefore))
						settings.onRotateBefore.call(obj);
						
					if(!(States.Paused | States.Stopped | ActiveIndex == CurrentIndex))
					{
						if(!settings.preload)
							$.XQ.Slider.Transitions.doTransition(obj, settings.transition); 	
						else 
						{
							$.XQ.Slider.Transitions.doTransition(obj, settings.transition); 
							if(States.Autoplay)
							{
								clearRotationTimeout();
				
								$slider.one(ActiveIndex + "onImagesLoaded", function() {  
									var playIntervalID = window.setInterval(function() { 
										if(!States.Rotation)
										{ 
											if(States.Autoplay)
												obj.play();
											window.clearInterval(playIntervalID);
										}
									}, 0);
								});
							}
							loadImages(ActiveIndex, 0);	
						}
					}
					else
					{
						obj.finish();
					}
				}
				else
				{
					obj.finish();
					setStates({Started : 1});
				} 
				
				//setUI();
			};

			var setActiveIndex = function(index, random)
			{
				var finalIndex, randomIndex = 0;
		
				if(random)
				{  
					if(randoms.length == $items.length)
					{ 
						randoms = []; 
						if(!settings.carousel)
						{
							obj.stop();
							finalIndex = settings.startIndex;
						}
					}
		
					while(!$.XQ.IsDefined(finalIndex))
					{
						randomIndex = Math.floor(Math.random() * $items.length);
						if(settings.carousel)
							randomIndex = getRotationIndex(randomIndex);
							
						if(randomIndex == ActiveIndex & randoms.length + 1 < $items.length) {
							continue;
						}
		
						for(var i = 0; i < randoms.length; i++)
						{
							if(randomIndex == randoms[i])
							{
								break; 
							}
						}
						
						if(randomIndex == randoms[i]) {
							continue;
						}
						
						finalIndex = randomIndex;
					} 
				}
				else
				{
					finalIndex = getRotationIndex(index);    
				}

				if(!(States.Paused | States.Stopped))
				{
					randoms.push(finalIndex);
					
					CurrentIndex = ActiveIndex;
					ActiveIndex = finalIndex;  
				}
			};	

			var setStates = function(states)
			{		
				$.extend(States, states);
				setUI();
			};
			
			var getRotationIndex = function(index)
			{
				if(settings.carousel)
				{
					if(index > $items.length - 1)
					{
						index = 0;
					}
					else if(index < 0) 
					{
						index = $items.length - 1;
					}
				}
				else
				{
					if(obj.stack[obj.stack.length - 1] == "next" & index == settings.startIndex)
					{
						//index = settings.startIndex;
						obj.stop();
					}
					else if(index > $items.length - 1)
					{
						index = 0;
					}
					else if(index < 0) 
					{
						index = 0;
					}
				}
				
				return index;
			};
			
			var setRotationSettings = function(rotation)
			{
				var defaultRotation = {
						index : ActiveIndex,
						random : settings.random
					},
					iRandom = 0;
				
				if($.XQ.IsDefined(rotation) & $.XQ.IsDefined(rotation.random))
				{
					iRandom = rotation.random;
					rotation.random = iRandom;
				}
		
				$.extend(defaultRotation, rotation);
				rotation = defaultRotation;
			   
				rotation.index = getRotationIndex(rotation.index);
					
				setActiveIndex(rotation.index, rotation.random);
			
				return rotation;
			};
			
			var setItems = function(init)
			{ 
				obj.getItems(1).each(function(index) { 
					var $item = $(this),
						caption = "";
						
					if(init)
					{
						if(!$item.hasClass("item"))
						{
							$item.wrap('<div class="item"></div>');
							$item = $item.parent();
						}
						
						if(settings.preload && $item.find("img").length && index != settings.startIndex)
							$item.addClass("item-loading");							
							
						if(!$item.find(".item-content").length)
						{
							$item.wrapInner('<div class="item-content"></div>');
						}
						
						if(settings.preload && !$item.find(".item-loading").length)
						{
							$item.append('<div class="item-loading"></div>');
						}
						
						if(settings.captions)
						{
							if($.XQ.IsDefined($item.attr("data-caption")))
								caption = $item.attr("data-caption");
							else if($item.find("[data-caption]").length)
								caption = $($item.find("[data-caption]")[0]).attr("data-caption");
							
							if(caption.length)
								$item.find(".item-content").append('<span class="caption">' + caption + '</span>');
						}
					}
					
					$item.attr("data-index", index);
					if(init)
						$item.attr("data-initial-index", index);
				});
			
				if(init)
				{
					$items = $animationWrapper.children();
					
					setActiveIndex(settings.startIndex);
					CurrentIndex = settings.startIndex;
		
					obj.setItemStyles(settings.startIndex);
				}
				else
					obj.setItemStyles(); 
			};
			
			var setButtonNav = function()
			{
				if(!(settings.buttonNav | settings.player)) return;
				var $previous = $slider.find(".previous"),
					$next = $slider.find(".next");
									
				if(!init & settings.buttonNav)
				{ 
					if(!$previous.length)
					{
						$slider.append('<a class="previous" href="#">Previous</a>');
						$previous = $($slider.find(".previous")[0]);
					}
						
					if(!$next.length)
					{
						$slider.append('<a class="next" href="#">Next</a>');
						$next = $($slider.find(".next")[0]);
					}
						
					$previous.bind("click", function(e) { e.preventDefault(); obj.previous(1); });
					$next.bind("click", function(e) { e.preventDefault(); obj.next(1); });
				}
				
				if(!settings.carousel & !settings.random)
				{
					if(ActiveIndex == 0)
					{
						$previous.addClass("disabled").find("a").addClass("disabled");
					}
					else
					{
						$previous.removeClass("disabled").find("a").removeClass("disabled");
					}
					
					if(ActiveIndex == $items.length - 1)
					{
						$next.addClass("disabled").find("a").addClass("disabled");
					}
					else
					{
						$next.removeClass("disabled").find("a").removeClass("disabled");
					}
				}
			};
			
			var setBulletNav = function()
			{
				if(!settings.bulletNav) return;
				var $bulletNav = $slider.find(".bullets").eq(0),
					$bulletNavItems = $bulletNav.find("a");
								
				if(!init) { 
					if(!$bulletNav.length) {
						$slider.append('<ul class="bullets"></ul>');
						$bulletNav = $($slider.find(".bullets")[0]);
						for(var i = 1; i <= $items.length; i++)
							$bulletNav.append('<li><a href="#">Item ' + i + '</a></li>');
						
						$bulletNavItems = $bulletNav.find("a");
					}
					
					$bulletNavItems.each(function(index) {
						$(this).click(function(e) { 
							e.preventDefault(); 
							
							if(!$(this).parent(".active").length)
								obj.show(index, 1);
						});
					});
				}
			
				$bulletNavItems.removeClass("active").parent().removeClass("active");
				$($bulletNavItems[ActiveIndex]).addClass("active").parent().addClass("active");
			};
			
			var setUI = function(index)
			{
				var actions = ["play", "pause", "stop", "previous", "next"],
					selector = ".player",
					playerExists = 0;

				initKeyboardNav();
				setButtonNav();
				setBulletNav();

				// player
				if(settings.player)
				{
					playerExists = $slider.children(selector).length;
					if(!playerExists)
					{
						$slider.append('<ul class="player"></ul>');
						$player = $($slider.children(selector));
						
						for(var i = 0; i < actions.length; i++)
							$player.append('<li class="' + actions[i] + '"><a href="#">' + actions[i] + '</a></li>');
					}
	
					var $play = $player.find(".play"),
						$pause = $player.find(".pause"),
						$stop = $player.find(".stop"),
						$previous = $player.find(".previous"),
						$next = $player.find(".next");
						
					if(!init) { 
						$play.bind("click", function(e) { e.preventDefault(); obj.play(); });
						$pause.bind("click", function(e) { e.preventDefault(); obj.pause(); });
						$stop.bind("click", function(e) { e.preventDefault(); obj.stop(); });	
				
						$previous.bind("click", function(e) { e.preventDefault(); obj.previous(1); });
						$next.bind("click", function(e) { e.preventDefault(); obj.next(1); });
					}
		
					if(!States.Autoplay & (!settings.autoplay | !init | States.Stopped | States.Paused))
					{
						$pause.hide();
						$play.show();
					}
					else
					{
						$pause.show();
						$play.hide();
						
						$stop.removeClass("disabled").find("a").removeClass("disabled");
					}
			
					if(States.Stopped & ActiveIndex != settings.startIndex)
						$stop.addClass("disabled").find("a").addClass("disabled");
				}
			};
		   
			var initKeyboardNav = function() 
			{
				var keyboardNav = obj.getSettings().keyboardNav;
				if(!keyboardNav | init)
					return;
				
				if(keyboardNav != -1)
				{
					$(document).bind("mousemove", function(e) {
						var offset = $slider.offset();
			
						obj.hovered = e.pageX >= offset.left - keyboardNav & e.pageX <= offset.left + $slider.width() + keyboardNav
							& e.pageY >= offset.top - keyboardNav & e.pageY <= offset.top + $slider.height() + keyboardNav;
					});
				}
				
				$(document).bind("keydown", function(e) { 
					if(!obj.hovered & keyboardNav != -1)
						return;
						
					if (e.which == 37 | e.which == 38) {
						e.preventDefault();
						obj.previous(1);
					} else if (e.which == 39 | e.which == 40) {
						e.preventDefault();
						obj.next(1);
					}
				});
			};
								
			var onScrollVisibleArea = function() { 
				if(($slider.outerHeight(1) + $slider.offset().top) < $(document).scrollTop())
					obj.pause();	
				else if(!States.Stopped & States.Paused & !States.Rotation) {
					obj.play();
				}
			};
			
			var processImageLoadQueue = function(indexes, index) { 
				var $item = images[indexes[index]].$item,
					loadingClass = !images[indexes[index]].$images.filter(".error").length ? "item-loading" : "";
	
				if(loadingClass != "") {
					clearTimeout(images[indexes[index]].loaderTimeout);
				}
				else
					images[indexes[index]].$images.filter(".error").css({visibility : "hidden"});

				if(ActiveIndex == indexes[index] || ActiveIndex == images[indexes[index]].$item.attr("data-ref-index")) { 			
					if(images[indexes[index]].loading)
					{ 	
						if($item.hasClass("item-loading"))
							$item.find(".item-content").fadeIn(settings.preloadFadeInSpeed, function() { $item.removeClass(loadingClass); });
						else
							$item.removeClass(loadingClass).find(".item-content").show();
					}
					
					$slider.trigger(indexes[index] + "onImagesLoaded");
				}
				else 
				{
					$item.removeClass(loadingClass).find(".item-content").show();
				} 
				
				if($.XQ.IsFunction(settings.onImagesLoaded)) settings.onImagesLoaded.call(obj);
				
				images[indexes[index]].loading = 0;	
				if(indexes.length && index < indexes.length - 1)
					prepareImageLoad(indexes, index + 1, 0, 50);								
			};
			
			var checkImagesToLoad = function(indexes, index) {
				images[indexes[index]].$images.each(function(imageIndex) { 
					var $img = $(images[indexes[index]].$images[imageIndex]),
						img = "";
		
					if(!$.XQ.IsDefined($img.data("img"))) {
						img = new Image();
						
						$img.addClass("loading");
						$(img).one("load error", function(e) { 
							if(e.type == "load")
								$img.removeClass("loading").addClass("loaded");
							else

								$img.addClass("error");
					
							$img.attr("src", img.src);
							images[indexes[index]].toLoad--;

							if(images[indexes[index]].toLoad <= 0)
							{  
								processImageLoadQueue(indexes, index);
							}
						});	
						
						img.src = $.XQ.IsDefined($img.attr("data-src")) ? $img.attr("data-src") : $img.attr("src");
												
						$img.data("img", img);	
						images[indexes[index]].$images[imageIndex].$img = $img;
						
						if($.browser.msie) {
							images[indexes[index]].$images[imageIndex].interval = window.setInterval(function() { 
								if(!images[indexes[index]].$images[imageIndex].$img.hasClass("loaded") && !images[indexes[index]].$images[imageIndex].$img.hasClass("error")/* && images[indexes[index]].$images[imageIndex].$img.data("img").complete && images[indexes[index]].$images[imageIndex].$img.data("img").readyState == "complete"*/)
								{
									window.clearInterval(images[indexes[index]].$images[imageIndex].interval);
									$(images[indexes[index]].$images[imageIndex].$img.data("img")).trigger("load");
								}
							}, 100);
						}
					}
				});
				
				return images[indexes[index]];
			};
			
			var prepareImageLoad = function(indexes, index, $item, loaderTimeout)
			{   
				if(!$.XQ.IsDefined(images[indexes[index]])) { 
					var $item = $item ? $item : obj.getItems(0, indexes[index]),
						$images = $item.filter("img").add($item.find("img"));

					images[indexes[index]] = {
						$item : $item,
						$images : $images,
						loading : 1,
						toLoad : $images.length,
						interval : "",
						loaderTimeout : ""
					};
				}

				if(images[indexes[index]].toLoad)
				{			
					checkImagesToLoad(indexes, index);
					
					var isActive = ActiveIndex == indexes[index] || ActiveIndex == images[indexes[index]].$item.attr("data-ref-index");
					if(isActive)
						images[indexes[index]].loaderTimeout = window.setTimeout(function() { 
							if(isActive && images[indexes[index]].toLoad > 0) 
							{ 
								images[indexes[index]].$item.addClass("item-loading").find(".item-content").hide(); 
							}
						}, loaderTimeout);							
				}
				else
					processImageLoadQueue(indexes, index);
			}
			
			var loadImages = function(index, init) { 
				if(settings.preload == 0)
				{
					$slider.trigger(index + "onImagesLoaded");
					return;	
				}

				var indexes = [index],
					maxPreload = settings.preload == -1 ? $items.length - 1 : Math.min($items.length - 1, settings.preload),
					newIndex = index;
					
				for(var i = 0; i < maxPreload; i++)
				{
					newIndex++;
					
					if(newIndex > $items.length - 1)
					{					
						newIndex = 0;
					}
					
					indexes.push(newIndex);
				}

				prepareImageLoad(indexes, 0, 0, 50);
									 
				return images[index];
			};
					   
			(function() {
				obj.setSettings(options, 1);
				
				$.XQ.Browser.init();

				setItems(1);
				setUI();
		
				init = 1;
				if($.XQ.IsFunction(settings.onInit)) settings.onInit.call(obj);
			
				if($items.length > 1)
				{ 
					if(settings.autoplay)
						obj.play();
					else
						setStates({Started : 1});
				}	
				loadImages(settings.startIndex, 1);
				
				onScrollVisibleArea();
				$(window).bind("scroll", onScrollVisibleArea);
			})();
		};
		
		return this.each(function()
       	{
        	var $this = $(this);

			if($this.data('Slider')) 
				return;

			$this.data('Slider', new Slider($(this), options));		
       });	
	};
})(jQuery);
