/*
	Javascript for carousel with scaling sides.
*/
$(document).ready(function(){
	var loadingDots = setInterval("showLoadingDots()", 200);

});

var loadingCount = 0;

function showLoadingDots(){
	if (loadingCount == 3)
	{
		loadingCount = 0;
	}
	loadingCount++;
	content = "";
	for (i = 0; i < loadingCount; i++)
	{
		content += ".";
	}
	$("#loading #dots").html(content);
}

$(window).load(function() {
	$("#loading").css("display", "none");
	$("#carousel .view").css("display", "block");

	var carousel= {};
	
	carouselInit(carousel, {
		$me: $('#carousel'),
		speed: 6000,
		radius: 300,
		itemWidth: 412,
		itemHeight: 538
	});
});


//! Initialize a carousel.
/*!	
	@param crs	Carousel object to initialize.
	@param opts	Carousel options:
		- $me			jquery object for carousel;
		- speed			Time for full 360 revolution [ms];
		- radius		carousel radius;
		- itemWidth		Carousel item width;
		- itemHeight	Carousem item height;
	@todo	Generalize more components.
*/
function carouselInit(crs, opts)
{
	crs.$me= opts.$me;
	crs.$view= crs.$me.find('.view');
	crs.$list= crs.$view.find('.carousel-item');
	crs.$pager= crs.$me.find('.pager li');
	crs.$note= crs.$me.find('.note');

	crs.speed= opts.speed;

	crs.count= crs.$list.length;
	crs.width= crs.$view.width();
	crs.height= crs.$view.height();
	crs.itemWidth= opts.itemWidth;
	crs.itemHeight= opts.itemHeight;
	
	crs.x0= crs.width/2;
	crs.y0= crs.itemHeight*0.4;
	crs.radius= opts.radius;			// Radius of carousel
	crs.dphi= 2*Math.PI/20;				// angular distance between items.
	crs.focus= 0.3;						// mid/front scaling ratio.
	
	crs.$me.find('.nav-left').click(function(e) {
		carouselSelect(crs, (crs.sel-1+crs.count)%crs.count, crs.speed);
	});
	
	crs.$me.find('.nav-right').click(function(e) {
		carouselSelect(crs, (crs.sel+1+crs.count)%crs.count, crs.speed);
	});
	
	crs.$pager.click(function(e) {
		carouselSelect(crs, $(this).index(), crs.speed);
	});
	
	if(crs.$me.find('.imap').length > 0)
	{
		crs.$imap= crs.$me.find('.imap');
		crs.imapCoords= $.parseJSON(crs.$imap.find('._opts').text()).map;
		
		crs.$imap.find('area').click(function(e) {
			carouselSelect(crs, $(this).attr('alt'), crs.speed);
			e.preventDefault();
		});
	}

	carouselSelect(crs, Math.max(crs.count/2-1, 0));
}

//! Select an item in a carousel.
/*!
	@param crs	Carousel object.
	@param i	New selection index.
	@param dt	if >0: animation duration [ms].
*/
function carouselSelect(crs, i, dt)
{
	i= parseInt(i);

	// --- Highlight button ---
	$me= crs.$pager.eq(i);
	$sel= $('li.active', $me.parent());
	$sel.removeClass('active');
	$me.addClass('active');

	// --- Turn the carousel ---
	crs.sel= i;
	crs.$note.text($('img', crs.$list.eq(i)).attr("alt"));

	if(dt>0)
	{
		//$(crs).stop();
		var dphi= wrapAngle(i*crs.dphi - crs.phi);
		
		$(crs).animate( {phi: crs.phi + dphi}, { 
			duration: dt*Math.abs(dphi)/(2*Math.PI), 
			step: function(val, opts) {
				carouselPlaceAngle(this, val);
			}
		});
	}
	else
		carouselPlaceIndex(crs);
}

//! Place a carousel by angle.
function carouselPlaceAngle(crs, phi0)
{
	var items= [];
	
	for(i=0; i<crs.count; i++)
	{
		// --- Circlish distribution ---
		/* NOTE: we've chosen for a fixed distance between items, not 
			equidistant distribution. The latter would be awkward for small 
			numbers.
		  NOTE: the scalings have been tweeked slightly for the non-front 
		  items to match the design.
		*/
		var pi= Math.PI;
		var phi= wrapAngle(i*crs.dphi - phi0);
		
		var xf= Math.sin(phi), zf= 1-Math.cos(phi);
		var scale= 1/(1+zf*(1/crs.focus-1));
		
		// Scale fudging to lens front item.
		var LENS_WIDTH= crs.dphi, LENS_SCALE= 0.1;
		
		if(Math.abs(phi) < LENS_WIDTH/2)
			scale *= 1.0 - LENS_SCALE*(1-Math.cos(2*pi*phi/LENS_WIDTH));
		else
			scale *= 1.0 - 2*LENS_SCALE;

		items[i]= {
			i:		i, 
			$me:	crs.$list.eq(i),
			x:		crs.x0 + crs.radius*xf - scale*crs.itemWidth/2, 
			y: 		crs.y0 - scale*crs.itemHeight*0.4 ,
			z: 		zf, 
			scale:	scale
		};

		var css={
			'left' : 	items[i].x, 
			'top' : 	items[i].y, 
			'width':	scale*crs.itemWidth,
		};
		// IE + alpha-png + opacity == hard-fail : don't do opacity in IE.
		if(!$.browser.msie)
			css.opacity= scale;

		items[i].$me.css(css);
	}
	
	// --- Z-sort ---
	items.sort(function(a, b) { return (a.z>b.z ? -1 : (a.z<b.z ? 1 : 0));  });
	
	for(i=0; i<crs.count; i++)
		items[i].$me.css('z-index', i+2);
		
	// --- Image map ---
	if(crs.$imap)
	{
		var $areas= crs.$imap.find('area');
		var shape= crs.imapCoords;

		for(i=0; i<crs.count; i++)
		{
			var coords= [];
			var item= items[i];
			for(j=0; j<shape.length/2; j++)
			{
				coords[2*j+0]= item.scale*shape[2*j+0] + item.x;
				coords[2*j+1]= item.scale*shape[2*j+1] + item.y;
			}
			coords= coords.join();
			
			var $area= $areas.eq(crs.count-i-1);
			$area.attr('coords', coords);
			$area.attr('alt', item.i);
			$area.attr('href', "#" + item.$me.attr('id'));
		}
	}

	crs.phi= phi0;
}

//! Place carousel by index.
function carouselPlaceIndex(crs)
{
	carouselPlaceAngle(crs, crs.sel*crs.dphi);
}

//! Wrap angle to range (-pi, pi].
function wrapAngle(alpha)
{
	var pi= Math.PI;
	return (alpha > pi ? alpha-2*pi : (alpha <= -pi ? alpha+2*pi : alpha));
}

// NOTE: the way console.log works is apparently very browser specific. 
// Firefox: console.log.apply(this, args), but only if Firebug's open.
// IE: console.log is object, not function, so apply doesn't work.
// Safari: ???
// Opera: ???
// Because of the various potential problems, wrapping it in an exception block.
function log(format, args)
{
	try
	{
		console.log.apply(this, arguments);
	}
	catch(err) {}
}

// EOF

