/*
 * Asura Parallax Image Rotator jQuery Plugin
 * 
 * Author: fairfox
 * 
 * Version: 1.1.0
 */

(function($) {
	$.fn.AsuraRotator = function( options ) {
		// override defaults with specified option
		options = $.extend( {}, $.fn.AsuraRotator.options, options );

		var global = {
		    isIPad : false,
		    clickEvent: 'click',
		    asyncSetting: false
		};
		if( navigator.platform.indexOf("iPad") != -1 || document.location.toString().indexOf('ipad') > -1) {
		    global.isIPad = true;
		    global.clickEvent = 'touchstart';
		    global.asyncSetting = true;

		    swfobject = {
		        embedSWF: function() {}
		    };

		    Modernizr = {
		        touch: true
		    };
		}
		
		return this.each(function(){
			
			var elem = $(this),
			number = 0,
			total = elem.children().size(),
			start = options.start - 1;
			
			reset();
			
			if(total == 0)
				return;
			
			elem.data('options', options);
			
			elem.wrap("<div class='asura-3d-rotator-wrapper' />");
			
			var wrapper = elem.parent();
			
			var vars = {
				lastSlide:null,
				currentSlide:null,
				hover:false
			};
			var panel = {
				timer:null
			};
			
			elem.children().each(function(k,v)
			{
				$(v).append($("<div href='#'></div>").addClass("disabler"));
				if(options.dropShadow) {
					$(v).append($("<div href='#'></div>").addClass("side-shadow"));
				}
			});
			
			var winWidth=$(window).width();
			var winHeight=$(window).height();
			
			/* Move the start page to the center of window.*/
			if(start < total) {
				var startPage = elem.children().eq(start);
				vars.currentSlide = startPage;
				
				startPage.children(".disabler").remove();
				
				// adjust page container's position
				var startPos = (winWidth-startPage.width())/2-startPage.position().left;
				elem.css({left:parseInt(startPos)+'px'});
				
				// add current class to start page
				startPage.addClass(options.currentClass);
				startPage.siblings().removeClass(options.currentClass).each(function(k,v){
					if($(v).children(".disabler").length == 0)
						$(v).append($("<div href='#'></div>").addClass("disabler"));
					
				});
			}
			
			// generate next/prev buttons
			if (options.keyboardNavigation) {
				$("body").keydown(function(e){
					// left arrow
				    if(e.which == 37) {
				    	gotoPage("prev");
				    }
				    else if(e.which == 39) { //right arrow
				    	gotoPage("next");
				    }
				});
			}
			
			// generate next/prev buttons
			if (options.generateNextPrev) {
				elem.after('<a href="#" class="'+ options.prev +'">Prev</a>');
				$('.' + options.prev, wrapper).after('<a href="#" class="'+ options.next +'">Next</a>');
			}
			
			// next button
			$('.' + options.next ,wrapper).bind('click',function(e){
				e.preventDefault();
				gotoPage("next");
			});
			
			// previous button
			$('.' + options.prev, wrapper).bind('click',function(e){
				e.preventDefault();
				gotoPage("prev");
			});
			
			// generate pagination
			if (options.generatePagination) {
				// create unordered list
				if (options.prependPagination) {
					elem.before('<ul class='+ options.paginationClass +'></ul>');
				} else {
					elem.after('<ul class='+ options.paginationClass +'></ul>');
				}
				// for each slide create a list item and link
				elem.children().each(function(){
					$('.' + options.paginationClass, wrapper).append('<li><a href="#'+ number +'">'+ (number+1) +'</a></li>');
					number++;
				});
			} else {
				// if pagination exists, add href w/ value of item number to links
				$('.' + options.paginationClass + ' li a', wrapper).each(function(){
					$(this).attr('href', '#' + number);
					number++;
				});
			}
			
			// add current class to start slide pagination
			$('.' + options.paginationClass + ' li:eq('+ start +')', wrapper).addClass(options.currentClass);
			
			// click handling 
			$('.' + options.paginationClass + ' li a', wrapper ).click(function(){
				
				// get clicked, pass to animate function					
				clicked = $(this).attr('href').match('[^#/]+$');
				
				var pageSelected = elem.children().eq(parseInt(clicked,10));
				
				gotoPage("pagination",pageSelected);
				return false;
			});
			
			$("."+options.pageClass+":not(."+options.currentClass+")").live(global.clickEvent, function(e) {
				gotoPage("pagination",$(this));
			});
			
			function gotoPage(direction,page) {
				
				var selectedPage = null;
				
				switch(direction) {
				case "next":
					selectedPage = vars.currentSlide.next();
	            	
	            	if(selectedPage.length == 0)
	            		selectedPage = elem.children().eq(0);
					break;
				case "prev":
					selectedPage = vars.currentSlide.prev();
	            	
	            	if(selectedPage.length == 0)
	            		selectedPage = elem.children(":last");
					break;
				case "pagination":
					if(vars.currentSlide == page)
						return;
					selectedPage = page;
					break;
				}
				
				if(selectedPage == null)
					return;
				
				// pause slideshow
				if (options.autoplay) {
					panel.timer.stopTimer();
				}
				
            	transitTo(selectedPage);
            	
            	if(options.autoplay) {
					if(panel.timer.timerStarted() == false && vars.hover == false){
						// if timer not started and mouse not hover on pages, we just start the timer.
						panel.timer.startTimer();
					}
					else if(panel.timer.timerStarted() == false && vars.hover == true){
						// if timer not started and mouse hover on pages, we set the residue time to 
						// the duration of each page, and wait for the mouse leave event to resume 
						// the timer.
						panel.timer.resetResidue();
					}
				}
			}
			
			function transitTo(page) {
				if(page.length > 0) {
					vars.lastSlide = vars.currentSlide;
	            	vars.currentSlide = page;
	            	var pageIndex = elem.children().index(vars.currentSlide);
	            	
	            	// invoke animationStart callback function
	            	options.animationStart(pageIndex);
	            	
	            	if(options.pagination) {
		            	// update pagination's status
		            	$('.' + options.paginationClass + ' li', wrapper).removeClass(options.currentClass);
	    				$('.' + options.paginationClass + ' li:eq(' + pageIndex + ')', wrapper).addClass(options.currentClass);
	            	}
    				
	            	// get position when current page in center of window
					var startPos = (winWidth-page.width())/2-page.position().left;
					
					elem.animate({left:parseInt(startPos)+'px'},parseInt(options.transSpeed),options.easing,function(){
						// invoke animationComplete callback function
						options.animationComplete(pageIndex);
					});
					// find the mask and remove it
					page.find(".disabler").remove();
					// set current page to current class
					page.addClass(options.currentClass);
					page.siblings().removeClass(options.currentClass).each(function(k,v){
						if($(v).children(".disabler").length == 0)
							$(v).append($("<div href='#'></div>").addClass("disabler"));
						
					});
				}
			}
			
			// reset all elements to initial state
			function reset() {
				if (!elem.data('options')) {
	                return;
	            } else {
	                var oldOptions = elem.data('options');
	                var oldWrapper = elem.parent();
	                
	                if(oldOptions.autoplay)
	                	if(elem.data('timer'))
	                		elem.data('timer').stopTimer();
	                
	                $('body').unbind('keydown');
	                $('.' + oldOptions.prev ,oldWrapper).unbind();
	                $('.' + oldOptions.next ,oldWrapper).unbind();
	                if(oldOptions.generateNextPrev) {
	                	$("."+oldOptions.prev,oldWrapper).remove();
	                	$("."+oldOptions.next,oldWrapper).remove();
	                }
	                if(oldOptions.pagination) {
	                	$('.' + oldOptions.paginationClass + ' li', oldWrapper).removeClass(oldOptions.currentClass);
	                }
	                
	                $('.'+oldOptions.currentClass+'.'+oldOptions.pageClass).die();
	                $('.' + oldOptions.paginationClass + ' li a', oldWrapper ).die();
	                $("."+oldOptions.pageClass+":not(."+oldOptions.currentClass+")").die();
	                
	                if(oldOptions.generatePagination) {
	                	if(oldWrapper) {
	                		$('ul.'+ oldOptions.paginationClass,oldWrapper).remove();
	                	}
	                }
	                elem.children().each(function(k,v) {
	                	$(".disabler",v).remove();
	    				if(oldOptions.dropShadow) {
	    					$(".side-shadow",v).remove();
	    				}
	                });
	                elem.die();
	                elem.unbind();
	                $(window).unbind("resize");
	                elem.unwrap();
	            }
			}
			
			if(options.autoplay && options.pauseOnHover) {
				elem.hover(
				function(){
					// after clicking and animating to another page,
					// the mouse in event will be refired and pauseTimer()
					// will be invoked again. We should avoid the situation
					// because we have reset the residue time and 
					// expect a resumeTimer() invoking, so we set a
					// flag(vars.hover) to avoid invoking pauseTimer()
					// twice.
					if(vars.hover == false){
						panel.timer.pauseTimer();
						vars.hover = true;
					}
				},
				function(){
					if(panel.timer.timerStarted() == false){
						panel.timer.resumeTimer();
					}
					vars.hover = false;
				});
			}
			
			$('.'+options.currentClass+'.'+options.pageClass).live('mousemove', function (e) {
			    if (global.isIPad) {
			        return;
			    }

			    var page = $(this);
			        
			    if (page.hasClass(options.pageClass)) {

			        var width = page.width(),
			            height = page.height(),
			            top = page.offset().top,
			            left = page.offset().left,
			            center = left + (width / 2),
			            multiplier = (e.pageX - center) / (width / 2);

			        page.find('.'+options.movingItemClass).each(function () {
			            
			            var item = $(this),
			                moveX = item.attr('moveX') || 0,
			                pos, defaultPosition;

			            if (!item.data('defaultPosition')) {
			                pos = item.position();
			                defaultPosition = {left: pos.left};
			                item.data('defaultPosition', defaultPosition);
			            } else {
			                defaultPosition = item.data('defaultPosition');    
			            }

			            item.css({
			                left: Math.round(moveX * -multiplier) + defaultPosition.left
			            });

			        });        

			    }

			});
			
			$(window).bind("resize",$.proxy(function(){
				winWidth=$(window).width();
				winHeight=$(window).height();
				
				// adjust the page container's position
				if(vars.currentSlide && vars.currentSlide.length > 0) {
					// make the current page in the center of the window
					var startPos = (winWidth-vars.currentSlide.width())/2-vars.currentSlide.position().left;
					elem.css({left:parseInt(startPos)+'px'});
				}
    		},this));
			
			panel.timer = new AsuraRotateTimer(elem,{
				duration: parseInt(options.duration),
				oncomplete:$.proxy(function() {
				    try{
				    	var nextPage = vars.currentSlide.next();
	                	if(nextPage.length == 0)
	                		nextPage = elem.children().eq(0);
	                	transitTo(nextPage);
	                }catch(e){}
				    
				},this)
			});
			elem.data('timer', panel.timer);
			
			options.slidesLoaded();
			
			if(options.autoplay)
				panel.timer.startTimer();
			
		});
	}
	$.fn.AsuraRotator.options = {
		autoplay: true,					// boolean, autoplay slideshow
		pauseOnHover: true,				// boolean, Set to true and hovering over slideshow will pause it
		duration: 7000,					// number, Set the duration of each page in milliseconds
		transSpeed: 600,       			// number, Set the speed of the animation in milliseconds
		easing: "",						// string, must load jQuery's easing plugin before http://gsgd.co.uk/sandbox/jquery/easing/
		start: 1,						// number, start page of the slider, start from 1
		generateNextPrev: true, 		// boolean, Auto generate next/prev buttons
		next: 'next', 					// string, Class name for next button
		prev: 'prev', 					// string, Class name for previous button
		pagination: false, 				// boolean, If you're not using pagination you can set to false, but don't have to
		generatePagination: false, 		// boolean, Auto generate pagination
		prependPagination: false, 		// boolean, prepend pagination
		paginationClass: 'pagination', 	// string, Class name for pagination
		currentClass: 'current', 		// string, Class name for current page
		pageClass:'parallax',			// string, Class name for each slideshow page
		movingItemClass : 'parallaxItem',// string, Class name for moving item
		dropShadow: true,				// boolean, Set to true and the right side of each page will drop a shadow
		keyboardNavigation: true,		// boolean, Set to true if you want to navigate each page by arrow keys.
		animationStart: function(){}, 	// Function called at the start of animation
		animationComplete: function(){},// Function called at the completion of animation
		slidesLoaded: function() {} 	// Function is called when slides is fully loaded
	};
})(jQuery);

(function($) {
    AsuraRotateTimer = function(element,options){
    	return AsuraRotateTimer.fn.create(element,options);
    };
    
	function time() {
        return (new Date).getTime();
    }
	
    var lastTime = time();

    AsuraRotateTimer.fn = AsuraRotateTimer.prototype = {
    	version : "1.1.0.0",
    	create : function(element,options){
    		
    		var defaults = {
    			duration:3000,
    			oncomplete:null
    		};
    		this.options = $.extend(true,defaults,options);
    		this.vars = {
    			startTime:0,
    			lastPauseResidue:0,
    			pause:true
    		};
    		
    		this.timer = null;
			
    		lastTime = this.vars.startTime = time();
		    
    	},
    	
    	timerStarted : function() {
    		return this.timer != null;
    	},
    	
    	stopTimer : function(){
    		if(this.timer){
    			clearInterval(this.timer);
    			this.timer = null;
    		}
    	},
    	
    	pauseTimer: function() {
    		this.vars.lastPauseResidue = this.options.duration - (time() - lastTime);
    		this.stopTimer();	
    	},
    	
    	resumeTimer : function() {
    		this.stopTimer();
    		this.timer = setTimeout($.proxy(this.runResidueTime,this),this.vars.lastPauseResidue);
    	},
    	
    	resetResidue : function() {
    		this.vars.lastPauseResidue = this.options.duration;
    	},
    	
    	startTimer : function(){
    		this.stopTimer();
    		lastTime = time();
    		this.timer = setInterval($.proxy(this.refreshTimer,this), this.options.duration);
    	},
    	
    	refreshTimer : function(){
    		lastTime = time();
        	if(this.options.oncomplete)
        		this.options.oncomplete();
	        
		},
		
		runResidueTime : function() {
			this.refreshTimer();
			this.startTimer();
		}
    };
})(jQuery);
