/**
* 	Creogallery v1.0 
* 
*	@author: 	Angel Kostadinov
* 	@copyright: 2011, Creozon Ltd
*/
(function($)
{	
	var Block = function(coords)
	{
		this.disabled = false;
		
		/* Coordinates */
		this.coords  = coords;
		
		/* Element */
		this.element = $('<div/>').addClass('g-block').css(
		{
			position:	'absolute',
			overflow:	'hidden',
			top: 		coords.top,
			left: 		coords.left,
			width:  	coords.width,
			height: 	coords.height,
			opacity: 	coords.opacity,
			zIndex: 	9999
		}).hide();
		
		this.wrapper = $('<div/>').addClass('wrapper').css(
		{
			position: 	'absolute',
			overflow:	'hidden',
			top:  		this.coords.backgroundPosition.top,
			left: 		this.coords.backgroundPosition.left,
			width: 		1026,
			height: 	292,
			zIndex: 	9999
		});
		
		this.get = function()
		{
			return this.element;
		};
		
		this.background = function(image) /* (deprecated) */
		{
			this.element.css(
			{
				backgroundImage: 	"url(" + image.attr('src') + ")",
				backgroundPosition: this.coords.backgroundPosition.left + 'px ' + this.coords.backgroundPosition.top + 'px'
			});
		};
	};
	
	var Creomath = 
	{
		random:function(min,max) /*  Returns pseudo-random number within range */
		{
			return Math.round(min + Math.random()*(max-min)); 
		},
		round: function(number) /* Round floating number */
		{
			return Math.ceil(number);
		},
		shuffle: function(target) /* Shuffles array */
		{
			for(var j, x, i = target.length; i; j = parseInt(Math.random() * i), x = target[--i], target[i] = target[j], target[j] = x);
			
			return target;
		}
	};

	/* Creoevo class */
	var Creogallery  = 
	{
		blocks:[],
		queue:[],
		timeline:[],
		progress: false,
		slide: 
		{
			prev: null,
			next: null,
			current: null
		},
		options: 
		{
			width:1026,
			height:292,
			blocks: 
			{
				x:10,
				y:7
			},
			onStart: function(event, ui)
			{
				return true;
			},
			onComplete: 		function(event, ui)
			{
				
			},
			onCompleteFrame: 	function(event, ui){},
			speed: 				1800,
			defaultSpeed: 		0,
			frame: 				30,
			effect: 			"drop",
			animation:			"diagonalBlocks",
			easing: 			"easeInOutQuint",
			easings:			["linear","easeInBack","easeInOutCirc","easeInExpo","easeInOutQuint"],
			auto: 				3600,
			randomEasing: 		5000,
			autoReverse: 		false
		},
		destroy: function() 
		{
			$.Widget.prototype.destroy.apply(this, arguments);
		},
		slide: function(activeSlide, nextSlide)
		{
			this.progress = true;
			
			this.options.onStart.apply(this,[null,
			{
				slide: nextSlide.index()
			}]);
			
			/* Get next slide image */
			var image = nextSlide.find('img');

			/* Update background image */
			for (i = 0, l = this.blocks.length; i < l; i++)
			{
				/* Get slide children */
				this.blocks[i].background(image);
			}
			
			/* Transition */
			this.animate(this.delegate(this,this.swap,[activeSlide, nextSlide]));
		},
		autoplay: function()
		{
			this.next();
		},
		next: function() /* Show next slide */
		{
			if (!this.progress)
			{
				this.slide.current = this.element.find('>li:visible:first'), this.slide.next = this.slide.current.length && this.slide.current.next('li').length > 0 ? this.slide.current.next('li') : this.element.find('>li:first');
				
				this.slide(this.slide.current, this.slide.next);
			}
			
			return false;
		},
		prev: function() /* Show prev slide */
		{
			if (!this.progress)
			{
				this.slide.current = this.element.find('>li:visible');
				
				this.slide.prev = this.slide.current.length && this.slide.current.prev('li').length > 0 ? this.slide.current.prev('li') : this.element.find('>li:last');
				
				this.effects(this.options.animation).slide(this.slide.current, this.slide.prev);
			}
		},
		complete: function()
		{
			this.progress = false;
		},
		swap: function(activeSlide, nextSlide) /* Swap slides */
		{
			/* Hide active slide */
			activeSlide.hide();
			
			/* Show next slide */
			nextSlide.show();
			
			for (i = 0, l = this.blocks.length; i < l; i++)
			{
				this.blocks[i].get().hide();
			}
			
			this.progress = false; 
			
			/* Restore speed */
			this.options.speed = this.options.defaultSpeed;
			
			this.options.onComplete.apply(this,[null,
			{
				slide: nextSlide.index()
			}]);
			
			
			setTimeout(this.delegate(this,this.effects,[this.options.animation]),this.options.auto);
			
			return this;
		}, 
		stop: function()
		{
			return this;
		},
		animate: function(callback)
		{
			this.queue = [];
			
			for (frame = 0; frame < this.timeline.length; frame++)
			{
				var time = setTimeout(this.delegate(this,this.play,[frame, (frame == this.timeline.length - 1) ? callback : this.delegate(this, this.options.onCompleteFrame,[
				{
					frame: frame
				}])]),this.timeline[frame]);
				
				this.queue.push(time);
			}
		},
		play: function(item, callback)
		{
			this.playCustom(item,callback);
		},
		playCore: function(item, callback)
		{
			this.blocks[item].get().stop(true,true).show(
			{ 
				effect: 	this.options.effect, 
				easing: 	this.options.easing,
				duration:	this.options.speed 
			}, callback);
		},
		playCustom: function(item, callback)
		{
			this.blocks[item].get().stop(true,true).animate(
			{ 
				opacity: "show"
			}, this.options.speed, this.options.easing, callback);
		},
		delegate: function(target, method, args)
		{
			return (typeof method == "function") ? function() 
			{ 
				return method.apply(target, !args ? arguments : args); 
			} : function()
			{
				return false;
			};
		},
		appendBlocks: function(grid)
		{
			this.blocks   = [];
			this.timeline = [];
			
			/* Remove previously attached blocks */
			this.element.find('.g-block').remove();

			/* Build blocks */
			for (y = 0; y < grid.height; y += grid.step.y)
			{
				for (x = 0; x < grid.width; x += grid.step.x)
				{
					this.blocks.push(new Block(
					{
						top: 	y,
						left: 	x,
						width: 	grid.step.x,
						height: grid.step.y,
						backgroundPosition: 
						{
							top: -y,
							left: -x
						},
						opacity: 1
					}));
				}
			}
				
			/* Attach blocks */	
			for (i = 0; i < this.blocks.length; i++)
			{
				this.blocks[i].get().appendTo(this.element);
				
				this.timeline.push(i * this.options.frame);
			}
			
			return this;
		},
		effect: function(effect)
		{
			this.options.effect = effect;
			
			return this;
		},
		effects: function(effect, options)
		{
			var grid = /* Default block grid */
			{
				width: 	this.options.width,
				height: this.options.height,
				step:  	
				{
					x: this.options.width/this.options.blocks.x,
					y: this.options.height/this.options.blocks.y
				}
			};

			var Fx = /* Creogallery effects */
			{
				slide:function(options)
				{
					return this.effect("blind").appendBlocks($.extend(true, {}, grid, options));
				},
				explode: function(options)
				{
					return this.effect("puff").appendBlocks($.extend(true, {}, grid, 
					{
						step:  	
						{
							x: Creomath.round(this.options.width/this.options.blocks.x),
							y: Creomath.round(this.options.height/this.options.blocks.y)
						}
					}));
				},
				diagonalBlocks: function(options)
				{
					return this.effect("show").appendBlocks($.extend(true, {}, grid, 
					{
						step:  	
						{
							x: Creomath.round(this.options.width/this.options.blocks.x),
							y: Creomath.round(this.options.height/this.options.blocks.y)
						}
					}));
				},
				windBlocks: function(options)
				{
					return this.effect("slide").appendBlocks($.extend(true, {}, grid, 
					{
						step:  	
						{
							x: Creomath.round(this.options.width/this.options.blocks.x),
							y: Creomath.round(this.options.height/this.options.blocks.y)
						}
					}));
				},
				droppingCurtain: function(options)
				{
					return this.effect("show").appendBlocks($.extend(true, {}, grid, 
					{
						step:  	
						{
							x: Creomath.round(this.options.width/this.options.blocks.x),
							y: Creomath.round(this.options.height/this.options.blocks.y)
						}
					}));
				}
			};
			
			this.delegate(this,Fx[effect],[options]).apply(this,[]).autoplay();
			
			return this;
		},
		init: function(images)
		{
			var create = function(index, image)
			{
				var i = $('<img/>').attr(
				{
					src: image.source
				}).css(
				{
					visibility: "visible"
				}).appendTo(image.parent);
			}
			
			$.each(images, this.delegate(this, create));
			
			/* Start autoplay */
			setTimeout(this.delegate(this,this.effects,[this.options.animation]),3000);
		},
		_create: function()
		{
			var images = [];
			
			this.options.defaultSpeed = this.options.speed;
			
			this.element.find('>li:not(:first)').hide().end().children().each(function(index)
			{
				$(this).css(
				{
					zIndex: 100 - index
				});
				
				images.push(
				{
					source: $(this).attr('data-image'),
					parent: $(this)
				});
			});
			
			Core.preloader.queue(images).preload(this.delegate(this,this.init,[images]));
		} /* Widget Constructor */
	};
	
	/* Widget Namespace */
	$.creo = $.creo || {};
	
	/* Widget */
	$.widget("creo.creogallery", Creogallery);
})(jQuery);
