/**
 * Multiple transitions
 * Use different transition for description and image
 * Use whatever type of content to slide. Not only images
 * Support for embeded content sliding
 * 
 */
(function($){
	$.fn.featuredbox = function(custom) {
		var defaults = {
		  	width: 629,
			height: 231,
			slidesAnimation: "slide-top",
			slidesSpeed: "fast",
			slidesReverseAnimation: false,
			slidesPattern: "normal",
			hParts: 1,
			vParts: 1,
			descriptionAnimation: "slide-bottom",
			descriptionSpeed: "slow",
			navigationHide: false,
			navigationAnimation: "slide",
			rotateInterval: 6000,
			next: "",
			previous: "",
			startSlide: 1,
			blocksWaitInterval: 100,
			pauseOnMouseHover: false,
			startPositionOffsetX: 0,
			startPositionOffsetY: 0,
			useFadeIn: false,
			onSlideAnimationStart: function(){},
			onSlideAnimationStop: function(){},
			onDescriptionAnimationStart: function(){},
			onDescriptionAnimationStop: function(){},
			onNavigateToSlide: function(){},
			onPause: function(){},
			onPlay: function(){},
			onMouseHover: function(){},
			onMouseOut: function(){}
			
		};
		var settings 			= $.extend({}, defaults, custom);
		var box 				= this;
		var start_zindex		= 10;
		var cur_slide_nr	= 1;
		var cur_slide		= "slide" + cur_slide_nr;
		var lock_slide = lock_description = reloaded_calculation = pause = false;
		var slide_count			= box.find("ul li").length;
		var description_width = description_height = description_top = description_left	= 0;
		var description_load_interval = rotator = "";
		
		// Start slide setting
		if(settings.startSlide != 1 && settings.startSlide > 0 && settings.startSlide <= slide_count) {
			cur_slide_nr	= settings.startSlide;
			cur_slide		= "slide" + cur_slide_nr;
		}
		
		// Set begin slide with hash in url
		var start_slide = parseInt(self.document.location.hash.substring(1).replace('slide', ''));
		if(start_slide > 0 && start_slide <= slide_count) {
			cur_slide_nr	= start_slide;
			cur_slide		= "slide" + start_slide;
		}
		
		// Add featured box wrapper
		div = box.wrapInner('<div class="featuredbox"></div>');
		var box_innner 	= $(div.children()[0]);
		
		// Add extra divs
		box_innner.append('<div class="description" style="z-index:102"></div>');
		box.append('<div class="navigation" style="z-index:101"></div>');
		box_innner.prepend('<div class="box-slide1" style="z-index:50"></div>');
		box_innner.prepend('<div class="box-slide2" style="z-index:51;display:none"></div>');

		// Show the box
		box.show();
		
		// Set auto rotate interval
		startRotate();
		
		// Add extra vars
		var description_box = box.find(".description");
		
		// Set z-index
		box.find("ul").addClass("slides");
		box.find("ul li").each(function (i) {
			$(this).hide().addClass("slide" + (i+1));
			start_zindex--;
		});
		
		// Add transparancy for flash
		box.find("ul").find("embed").attr("wmode", "transparent");
		
		// Set current image
		box.find(".box-slide1").html(box.find("." + cur_slide).children().eq(0).clone()).addClass('loading');
		
		// Startup fadein image 
		box.find(".box-slide1 img").hide().fadeIn(2000, function(){ $(this).parent().removeClass('loading') });

		add_navigate_click_handlers();

		// Create navigation
		var navigation = "<ul>";
		for(var i=0 ; i < slide_count ; i++){
			active = ((i+1) == cur_slide_nr) ? " active" : "";
			navigation += '<li class="nav' + (i+1) + active + '" style="cursor: pointer">' + box.find(".slide" + (i+1)).children().eq(2).html() + "</li>";
		}
		navigation += "</ul>";
		var navigation_box = box.find(".navigation");
		navigation_box.html(navigation);
		navigation_box.find("li").bind("click", function () { 
			if(!lock_slide && !lock_description){
				var current_click = $(this).attr("class").replace("nav", "").replace(" hover", "").replace(" active", "");
				box.go(current_click);
			}
		}).bind("mouseenter",function(){
			$(this).addClass("hover");
		}).bind("mouseleave",function(){
			$(this).removeClass("hover");
		});
		
		// Track when mouse is hover the gallery
		$(this).mouseenter(function()	{
			$(this).addClass('mouse-hover');
			settings.onMouseHover.call();
			if(settings.pauseOnMouseHover) box.pause();
		}).mouseleave(function() {
			$(this).removeClass('mouse-hover');
			settings.onMouseOut.call();
			if(settings.pauseOnMouseHover) box.play();
		});
		
		// Set description
		description_box.html(box.find(".slide1").children().eq(1).html());
		
		// Add menu hider
		if(settings.navigationHide){
			box.find(".navigation").hide();
			box.bind("mouseenter",function(){
				box.find(".navigation:not(:animated)").fadeIn("slow");
			}).bind("mouseleave",function(){
				box.find(".navigation").fadeOut("slow");
			});
		}
		
		// Trigger play
		settings.onPlay.call();
		
		// Slide transition function
		function slidesTransition(from_nr, to_nr, force){
			
			// Don't execute if pause
			if(!force && pause) return;
			
			// Stop interval timer
			stopRotate();
			
			// Create vars
			var from_slide 		= "slide" + from_nr;
			var to_slide		= "slide" + to_nr;
			
			// CB
			settings.onNavigateToSlide.call((parseInt(to_nr)-1));
			
			// Set navigation active
			navigation_box.find("li").removeClass("active");
			navigation_box.find("li.nav" + to_nr).addClass("active");
			
			// No action if click current
			if(from_slide == to_slide) return;	
			
			lock_slide = lock_description = true;
			
			// Set box slide 1 to from slide content
			box.find(".box-slide1").html(box.find("." + from_slide).children().eq(0).clone()).show();
			box.find(".box-slide2").html(box.find("." + to_slide).children().eq(0).clone()).hide();
			
			add_navigate_click_handlers();
			
			// CB
			settings.onSlideAnimationStart.call();
			
			switch(settings.slidesAnimation){
				case "slide-bottom":
					slice(settings.hParts, settings.vParts, {top: settings.height});
					anim_slices({left: 0, top:0  }, settings.slidesReverseAnimation);
					break;
				case "slide-top":
					slice(settings.hParts, settings.vParts, {top: -settings.height});
					anim_slices({ top: 0, left:0 }, settings.slidesReverseAnimation);
					break;
				case "slide-left":
					slice(settings.hParts, settings.vParts, {left: -settings.width});
					anim_slices({ left: 0, top: 0 }, settings.slidesReverseAnimation);
					break;
				case "slide-right":
					slice(settings.hParts, settings.vParts, {left: settings.width});
					anim_slices({ left: 0, top: 0 }, settings.slidesReverseAnimation);
					break;
				case "size":
					slice(settings.hParts, settings.vParts, {width: "0px", height: "0px"});
					anim_slices({ width: "100%", height: "100%", left: 0, top:0 }, settings.slidesReverseAnimation);
					break;
				case "size-horizontal":
					slice(settings.hParts, settings.vParts, {width: "0px"});
					anim_slices({ width: "100%", left: 0, top:0 }, settings.slidesReverseAnimation);
					break;
				case "line":
					lineSlidesAnimation();
					break;
				default:
					slice(settings.hParts, settings.vParts, {opacity: 0});
					anim_slices({ opacity: 1, left: 0, top:0 }, settings.slidesReverseAnimation);
					break;
			}
			
			// CB
			settings.onDescriptionAnimationStart.call();
			
			var new_description_content = box.find("." + to_slide).children().eq(1).html();
			switch(settings.descriptionAnimation){
				case "slide-bottom":
					slideBottomDescriptionAnimation(new_description_content);
					break;
				case "slide-top":
					slideTopDescriptionAnimation(new_description_content);
					break;
				case "slide-left":
					slideLeftDescriptionAnimation(new_description_content);
					break;
				case "slide-right":
					slideRightDescriptionAnimation(new_description_content);
					break;
				default:
					fadeDescriptionAnimation(new_description_content);
					break;
			}
			
			// Set current slide
			cur_slide = "slide" + to_nr;
			cur_slide_nr = to_nr;

		}
		
		// Start rotate interval
		function startRotate(){
			if(settings.rotateInterval > 0 && settings.rotateInterval != "undefined"){	
				rotator = setInterval(rotate, settings.rotateInterval);
			}	
		}
		
		// Stop rotate interval
		function stopRotate(){
			window.clearInterval(rotator);
		}
		
		// Rotate trough slides
		function rotate(force){

			// Don't go to next slide if mouse is hover
			if(!force && ((settings.pauseOnMouseHover && box.hasClass('pause')) || pause)) return;
			
			// Calculate next slide
			var next_slide_nr = (cur_slide_nr+1) > slide_count ? 1 : (cur_slide_nr+1);
			slidesTransition(cur_slide_nr, next_slide_nr);
		}
		
		// Rotate back trough slides
		function rotate_back(){
			// Calculate pervious slide
			var next_slide_nr = (cur_slide_nr-1) < 1 ? slide_count : (cur_slide_nr-1);
			slidesTransition(cur_slide_nr, next_slide_nr);
		}
		
		function lineSlidesAnimation(){
			box.find(".box-slide2").css("left", settings.width).show().animate({ left : "0px" }, settings.slidesSpeed);
			box.find(".box-slide1").animate({ left : -settings.width+"px" }, settings.slidesSpeed, null, function(){	
				$(this).css("left", 0);
				unlock_slide();
			});
		}
		function fadeDescriptionAnimation(new_content){
			var description_box = box.find(".description");
			description_box.fadeOut(settings.descriptionSpeed, function(){
				if(new_content == "" || new_content == "undefined"){ 
					description_box.hide();
					unlock_description();
				}else{
					description_box.html(new_content);
					description_box.fadeIn(settings.descriptionSpeed, unlock_description);	
				}
			});
		}
		function slideBottomDescriptionAnimation(new_content){
			description_box.animate({ top : settings.height + description_height + "px" }, settings.descriptionSpeed, null,
			function(){
				if(new_content == "" || new_content == "undefined"){ 
					description_box.hide();
				}else{
					description_box.show();
				}
				description_box.html(new_content);
				description_box.animate({ top : description_top + "px" }, settings.descriptionSpeed, null, unlock_description);												
			});
		}
		function slideTopDescriptionAnimation(new_content){
			description_box.animate({ top : "-" + description_height + "px" }, settings.descriptionSpeed, null, function(){
				if(new_content == "" || new_content == "undefined"){ 
					description_box.hide();
				}else{
					description_box.show();
				}
				description_box.html(new_content);
				description_box.animate({ top : description_top + "px" }, settings.descriptionSpeed, null, unlock_description);												
			});
		}
		function slideLeftDescriptionAnimation(new_content){
			description_box.animate({ left : "-" + description_width + "px" }, settings.descriptionSpeed, null, function(){
				if(new_content == "" || new_content == "undefined"){ 
					description_box.hide();
				}else{
					description_box.show();
				}
				description_box.html(new_content);
				description_box.animate({ left : description_left + "px" }, settings.descriptionSpeed, null, unlock_description);												
			});
		}
		function slideRightDescriptionAnimation(new_content){
			description_box.animate({ left : settings.width + description_width + "px" }, settings.descriptionSpeed, null, function(){
				if(new_content == "" || new_content == "undefined"){ 
					description_box.hide();
				}else{
					description_box.show();
				}
				description_box.html(new_content);
				description_box.animate({ left : description_left + "px" }, settings.descriptionSpeed, null, unlock_description);												
			});
		}
		
		function unlock_description(){
			lock_description = false;
			is_unlocked();
			settings.onDescriptionAnimationStop.call();
		}
		
		function unlock_slide(){
			lock_slide = false;	
			is_unlocked();
			settings.onSlideAnimationStop.call();
		}
		
		function is_unlocked(){
			if(!lock_description && !lock_slide){
				startRotate();	
				box.find(".box-slide1 embed").remove();
			}
		}
		
		function add_navigate_click_handlers(){
			// next
			if(settings.next != ""){
				box.find(settings.next).bind("click", function(){ 
					box.next(true);
				});
			}	
			
			// previous
			if(settings.previous != ""){
				box.find(settings.previous).bind("click", function(){ 
					if(!lock_description && !lock_slide){
						rotate_back();	
					}
				});
			}
		}
		
		function calc_description_box_position(){
			window.clearInterval(description_load_interval);

			// Description size
			calc_description_box_size();

			// Calculate description top
			description_top =  parseInt(description_box.css("top").replace("px", ""));
			
			// Calculate description left
			description_left =  parseInt(description_box.css("left").replace("px", ""));
			
			if(isNaN(description_left)){
				description_box.hide();	
				description_load_interval = setInterval(calc_description_box_position, 200);	
			}else{
				description_box.fadeIn("fast");
				if(!reloaded_calculation){
					reloaded_calculation = true;
					calc_description_box_position();
				}
			}
		}
		
		function calc_description_box_size(){
			// Calculate description box height
			description_height = parseInt(description_box.css("padding-top").replace("px", "")) + 
								parseInt(description_box.css("padding-bottom").replace("px", "")) + 
								parseInt(description_box.css("height").replace("px", ""));
			
			description_width = parseInt(description_box.css("padding-left").replace("px", "")) + 
								parseInt(description_box.css("padding-right").replace("px", "")) + 
								parseInt(description_box.css("width").replace("px", ""));	
		}
		
		// Slices the image in blocks and returns an array with block names
		function slice(hblocks, vblocks, css){
		
			var block_width = (hblocks > 0) ? settings.width / settings.hParts : settings.width;
			var block_height = (vblocks > 0) ? settings.height / settings.vParts : settings.height;
			var global_block_num = 1;
			
			// Get next image src
			var image = box.find(".box-slide2 img").attr('src');

			// If add fadeIn then set opacity to 0
			if(settings.useFadeIn) css.opacity = 0;
			
			// If it is a flash object then don't slice
			if(box.find(".box-slide2 > img").length == 0){
				var slide = box.find(".box-slide2").children(0);
				var height_padding = parseInt(slide.css('padding-top').replace('px', '')) + parseInt(slide.css('padding-bottom').replace('px', ''));
				var width_padding = parseInt(slide.css('padding-left').replace('px', '')) + parseInt(slide.css('padding-right').replace('px', ''));
				var block_css = $.extend({}, {top: settings.startPositionOffsetY, 
																	left: settings.startPositionOffsetX, 
																	width: (settings.width - width_padding), 
																	height: (settings.height - height_padding),
																	position: "absolute"}, css);
				
				slide.addClass('block').css(block_css);
				return;
			}
			
			box.find(".box-slide2").css("top", 0).html('').show();
			
			// Horizontal blocks
			for(var i=0; i < hblocks ; i++) {
				var block_css = $.extend({}, {top: -settings.height, 
																	left: (i * block_width), 
																	width: block_width, 
																	height: block_height, 
																	backgroundPosition: "-" + (i * block_width) + "px 0", 
																	position: "absolute",
																	"background-image": "url(" + image + ")"}, css);

				if(vblocks < 1){
					var div = $('<div>').addClass('block' + (i+1)).css(block_css);
					box.find(".box-slide2").append(div);
				}
				
				// Vertical blocks
				for(var j=0; j < vblocks ; j++) {
					var block_css = $.extend({}, {top: ((j * block_height) + settings.startPositionOffsetY) + "px", 
																	left: ((i * block_width) + settings.startPositionOffsetX), 
																	width: block_width, 
																	height: block_height, 
																	backgroundPosition: "-" + (i * block_width) + "px -" + (j * block_height) + "px", 
																	position: "absolute",
																	"background-image": "url(" + image + ")"}, css);
					var div = $('<div>').addClass('block' + global_block_num).css(block_css);
					box.find(".box-slide2").append(div);
					global_block_num++;
				}
				
			}
			
		}
		
		// Animates the slices to a specific css
		function anim_slices(css, reverse){
		
			// Convert height and width to the correct values if it's 100% and there are more slices
			if(css.width == "100%"){
				css.width = settings.width / settings.hParts;
			}
			if(css.height == "100%"){
				css.height = settings.height / settings.vParts;
			}
			
			// If add fadeIn then set opacity to 1
			if(settings.useFadeIn) css.opacity = 1;
		
			// Create slides patterns
			var block_pattern = new Array();
			for(var i=0; i < (settings.hParts * settings.vParts) ; i++) {
				block_pattern.push(i);
			}
			switch(settings.slidesPattern) {
				case "random":
					block_pattern = shuffle(block_pattern);
					break;
				case "frontback":
					var new_pattern = new Array();
					var length = block_pattern.length;
					for(var i=0; i < length ; i++){
						if(i%2){
							new_pattern.push(block_pattern.pop());
						}else{
							new_pattern.push(block_pattern.shift());
						}
					}
					block_pattern = new_pattern;
					break;
			}
			if(settings.slidesReverseAnimation) block_pattern = block_pattern.reverse();
		
			// If not image show directly
			if(box.find(".box-slide2 .block").length > 0){
				box.find(".box-slide2").show();
				var slide = box.find(".box-slide2").children(0);
				var height_padding = parseInt(slide.css('padding-top').replace('px', '')) + parseInt(slide.css('padding-bottom').replace('px', ''));
				var width_padding = parseInt(slide.css('padding-left').replace('px', '')) + parseInt(slide.css('padding-right').replace('px', ''));
				css.width = (settings.width-width_padding);
				css.height = (settings.height-height_padding);
				box.find(".box-slide2 .block").animate(css, settings.slidesSpeed, null, unlock_slide);
				return;
			}
		
			for(var i in block_pattern){
				unlock = (block_pattern[i] == block_pattern[block_pattern.length-1]) ? true : false;
				anim_slice(block_pattern[i], css, (settings.blocksWaitInterval * i), unlock);
			}
		}
		
		// Animate one slice
		function anim_slice(i, css, wait, unlock){
		
			// Modify left and top parameter
			if(css.left == "0" || css.left == "0px"){
				var left = ((settings.width / settings.hParts) * Math.floor(i/settings.vParts)) + "px";
			}
			if(css.top == "0" || css.top == "0px"){
				var top = ((settings.height / settings.vParts) * (i%settings.vParts)) + "px";
			}
			
			var cb_executed = false;
			var handle_block = (function(num, left, top, unlock) { return function(){
				css.left = left;
				css.top = top;
				box.find(".box-slide2 .block" + num).animate(css, settings.slidesSpeed, null, function() {
					if(unlock && !cb_executed){
						cb_executed = true;
						unlock_slide();
					}
				});
			} })((i+1), left, top, unlock);
			
			setTimeout(handle_block, wait);
		}
		
		calc_description_box_position();
		
		this.next = function() {
			/*if(!lock_description && !lock_slide){
				rotate(true);	
			}*/
			if(!lock_description && !lock_slide){
				var next_slide_nr = (cur_slide_nr+1) > slide_count ? 1 : (cur_slide_nr+1);
				box.go(next_slide_nr);
			}
		}
		
		this.prev = function() {
			/*if(!lock_description && !lock_slide){
				rotate_back();	
			}*/
			if(!lock_description && !lock_slide){
				var next_slide_nr = (cur_slide_nr-1) < 1 ? slide_count : (cur_slide_nr-1);
				box.go(next_slide_nr);
			}
		}
		
		this.pause = function() {
			pause = true;
			box.removeClass('play').addClass('pause');
			settings.onPause.call();
		}
		
		this.play = function() {
			pause = false;
			box.removeClass('pause').addClass('play');
			settings.onPlay.call();
		}
		
		this.go = function(i) {
			if(i > 0 && i <= slide_count) {
				slidesTransition(cur_slide_nr, i, true);
				cur_slide_nr	= parseInt(i);
			}
		}
		
		this.setting = function(){
			if(arguments.length == 2){
				settings[arguments[0]] = arguments[1];
			}else if(typeof arguments[0] == 'string'){
				return settings[arguments[0]];
			}else if(typeof arguments[0] == 'object'){
				settings = $.extend({}, settings, arguments[0]);
			}
		}
		
		return this;
	}
	
})(jQuery);

shuffle = function(o){
	for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
	return o;
};

