$.widget("ui.carousel", {
	items: [],
    current: -1,
	total: 0,
	dimensions: [],
	properties: [
		// Bottom
		{
			left: 400,
			top: 240,
			opacity: 1,
			zIndex: 6,
			scale: 1
		},
		// Bottom right
		{
			left: 712,
			top: 188,
			opacity: 0.8,
			zIndex: 5,
			scale: 0.75
		},
		// Top right
		{
			left: 712,
			top: 70,
			opacity: 0.5,
			zIndex: 4,
			scale: 0.5
		},
		// Top
		{
			left: 400,
			top: 40,
			opacity: 0.25,
			zIndex: 3,
			scale: 0.3
		},
		// Top left
		{
			left: 88,
			top: 70,
			opacity: 0.5,
			zIndex: 4,
			scale: 0.5
		},
		// Bottom left
		{
			left: 88,
			top: 188,
			opacity: 0.8,
			zIndex: 5,
			scale: 0.75
		}
	],
	start: {
		left: 400,
		top: 180,
		opacity: 0
	},
	
	options: {
		speed	: 1,
		data	: [],
		group	: null
	},
	
	/**
	* Initialize the widget.
	**/
    _init: function()
	{
		var klass = this;
		
		this.total = this.options.data.length;
		
		this._build_templates(function(){
			//klass._loaded();
		});
		klass._loaded();
    },
	
	/**
	* All images are loaded, carousel is ready to begin
	**/
	_loaded: function()
	{
		this._listen();
		this.intro();
	},
	
	/**
	* Next: Returns newly selected group id
	**/
	next: function()
	{
		return this.jump((this.current >= (this.total-1)) ? 0 : this.current + 1);
	},
	
	/**
	* Previous: Returns newly selected group id
	**/
	previous: function()
	{
		return this.jump((this.current <= 0) ? this.total - 1 : this.current - 1);
	},
	
	/**
	* Jump to group in carousel
	**/
	jump: function(to)
	{
		var klass = this;
		
		if (this._check_bounds(to))
		{
			this._animate(this.current, to, function(){
				setTimeout(function(){klass.select(to);}, 200);
			});
			this.current = to;
		}
		
		return this.current;
	},
	
	intro: function()
	{
		this.jump(0);
	},
	
	/**
	* Selects group to display products
	**/
	select: function(id)
	{
		if (id == -1)
			return this.options.group.html('');
		
		var products = this.options.data[id]['products'];
		
		if (products)
			this.options.group.html($.tmpl(templates['product'], products));
		else
			this.options.group.html('');
	},
	
	/**
	* Carousel animation
	**/
	_animate: function(from, to, callback, animate)
	{
		var fn = function(){};
		
		if (animate == undefined || animate == null)
			animate = animate || true;
		
		for (i=0; i < this.total; ++i) {
			pos = (i-to);
			
			if (pos < 0)
				pos = this.total - Math.abs(pos);
			
			reference = this.properties[pos];
			
			// Set up properties
			properties = {
				width		: this.dimensions[i]['w'] * reference.scale,
				height		: this.dimensions[i]['h'] * reference.scale,
				left		: reference['left'] - ((this.dimensions[i]['w'] * reference.scale) / 2),
				top			: reference['top'] - ((this.dimensions[i]['h'] * reference.scale) / 2)
			};
			
			if (!($.browser.msie))
				properties['opacity'] = reference['opacity'];
						
			if (i == (this.total-1))
				fn = callback;
			
			if (animate)
			{
				// Animate
				$(this.items[i]).animate(
					properties,
					{
		            	duration: 400 * this.options.speed,
		            	easing: "easeInOutQuad",
						complete: fn
		        	}
				).css('z-index', reference['zIndex']);
			}
			else
			{
				// No animation
				$(this.items[i]).css(properties).css('z-index', reference['zIndex']);
				fn();
			}
		}
	},
	
	/**
	* Builds templates: groups
	**/
	_build_templates: function(callback)
	{
		var klass = this;
		
		this.element.prepend(
			$.tmpl(
				templates['items'], {
				data: this.options.data
			})
		);
		
		this.items = $('img', this.element);
		var loaded = 0;
		
		this.items.each(function(i, el){
			$(el).load(function(){
				loaded++;
				if (loaded == klass.items.length)
					callback();
			});
			
			klass.dimensions.push({ w: $(el).width(), h: $(el).height() });
			
			var properties = {
				left: klass.start.left - ($(el).width() / 2),
				top: klass.start.right -  ($(el).height() / 2)
			};
			
			if (!($.browser.msie))
				properties['opacity'] = klass.start.opacity;
		});
	},
	
	/**
	* Listen for interactivity
	**/
	_listen: function()
	{
		var klass = this;
		
		this.items.click(function(e){
			klass.jump(klass._get_id($(this).attr('id')));
			return false;
		});
		
		$('a#previous').click(function(e){
			klass.previous();
			return false;
		});
		
		$('a#next').click(function(e){
			klass.next();
			return false;
		});
		
		$(document).keyup(function(e){
			switch (e.keyCode) {
				case 37:
					klass.previous();
					break;
				case 39:
					klass.next();
					break;
			}
		});
	},
	
	/**
	* Check wether id is in bounds (0 to this.items.length)
	**/
	_check_bounds: function(to)
	{
		return (to <= this.items.length && to != this.current && to >= 0);
	},
	
	/**
	* Extracts id as integer from a given string. Expects the following pattern: 'item_1' (str_id).
	* Returns -1 if id can't be found or isn't an integer.
	**/
	_get_id: function(value)
	{
		var id = parseInt(value.split('_')[1]);
		
		if (isNaN(id))
			return -1;
		else
			return id;
	}
});
