/* ./_js/index.js
	script for index page
*/


$(document).ready(function() {
	
	// -- internet explorer < 7 warning
	if($.browser.msie && parseInt($.browser.version) < 7) {
		$('div#old_ie').show();
		return;
	}

	
	// -- initialize art
	Art.init();
});










// - art
var Art = {
	
	options : {
		image_dir : '_img/art/', // directory for artwork images (both sizes)
		transition_speed : 750,	// (miliseconds) to transition between pieces of art
		transition_speed_arrows: 1500 // (miliseconds) to animate arrows when intially displaying the artwork area
	},
	
	
	vars : {
		data : {}, // collection of data received from xml
		current_index : -1, // currently selected index
		total_items : 0, // number of items, as per xml
		loading_interval : null // interval for the loader
	},
	
	
	j : {
		wall : null, // wall (its width will be needed in calculating animations) 
		div : null,  // container
		ul : null, // canvas
		prev : null, // "previous" arrow (large)
		next : null, // "next" arrow (large)
		loading : null // loading indicator
	},
	
	
	
	
	
	// -- initialization
	init : function() {
		Art.j.wall = $('div#wall');
		Art.j.div = $('div#art');
		Art.j.ul = $('> ul', Art.j.div);
		Art.j.prev = $('a.nav.prev', Art.j.div);
		Art.j.next = $('a.nav.next', Art.j.div);
		Art.j.loading = $('div.loading', Art.j.div);
		
		
		
		// --- fetch the xml	(relative to the web page)
		$.get('_data/art.xml', null, function(data, textStatus) {
			// ---- store the contents of the root xml element
			Art.vars.data = $('art', data);
			
			
			
			// ---- continue the workflow...
			Art.build();
			Art.NavBar.init();
	 	}, 'xml');
	},
	
	
	
	
	
	// -- called when xml is loaded
	build : function() {
		
		// --- assign # of items
		Art.vars.total_items = $('> item', Art.vars.data).length;
				
				
		// --- add artwork to canvas, with info, bind click listener, and append image which will apply itself once loaded	
		
		var t_data, t_li, info_div, info, k;
		var info_div_template = '<div class="info">$title<a class="inquiry">Piece inquiry</a><div class="clear"></div>$description</div>';
		var replacements = ['title', 'description'];
		
		$('> item', Art.vars.data).each(function(i) {
			
			t_data = $(this);
			
			// --- create the info area
			info_div = info_div_template;
			info = {};
			
			
			if((info.title = $('title', t_data).text())) {
				info.piece = info.title;
				info.title = '<h2>'+info.title+'</h2>';
			} else {
				info.piece = 'Item #'+(i+1);
			}
			
			info.description = $('description', t_data).text();
			if(t_data.attr('is_sold') == 'true') {
				info.description += '<span>Sold</span>';
			}
			if(info.description) {
				info.description = '<h3>'+info.description+'</h3>';
			}
			
			for(k in replacements) {
				info_div = info_div.replace('$'+replacements[k], info[replacements[k]]);
			}
			
			
			t_li = $('<li>')
				//.css('background-image', 'url('+Art.options.image_dir+t_data.attr('name')+'.jpg)')
				.css({
					opacity:0,
					left:-9999
				})
				.append(info_div)
				.append(
					$('<img>')
						.attr('src', Art.options.image_dir+t_data.attr('name')+'.jpg')
						.load(function() {
							var t = $(this);
							var img_height = t.height();
							t.parent()
								.css({
									top:(Math.ceil((Art.j.wall.innerHeight(true) - img_height) / 2)),
									width: t.width(),
									height: img_height,
									'background-image':'url('+t.attr('src')+')'
								})
								.addClass('ready');
							$(t).remove();
						})
						.error(function() {
							// just remove the image and leave the li alone, with the "missing" graphic as the background image.
							// otherwise we'd need to: remove from this ul#canvas, remove from carouse, decrease total items - and still our indexes would all be off
							var t = $(this);
							t.parent().addClass('ready');
							t.remove();
						})
				)
				.appendTo(Art.j.ul)
				.click(function(e) {
					if(e.target.nodeName == 'LI') {
						// ---- only if clicked directly on li!
						Art.change(Art.indexByDirection('next'), 'next');
					}
				})				
				.find('a.inquiry')
					.attr('title', info.piece)
					.click(function() {
						ContactForm.j.f_piece.val($(this).attr('title'));
						Modal.show('contact');
					})
					.css('cursor', 'pointer');
		});
		
		
		
		// --- map, position and animate large arrows
		var return_pos; // position to return to
		var width; // width of arrow
		
		
		// ---- previous
		return_pos = Art.j.prev.css('left');
		width = Art.j.prev.outerWidth(true);
		Art.j.prev
			.click(function() {
				Art.change(Art.indexByDirection('prev'), 'prev');
			})
			.css('left', (0 - width))
			.show()
			.animate({
				left : return_pos
			}, Art.options.transition_speed_arrows, 'easeOutBounce');
		
		
		// ---- next	
		return_pos = Art.j.next.css('right');
		width = Art.j.next.outerWidth(true);
		Art.j.next
			.click(function() {
				Art.change(Art.indexByDirection('next'), 'next');
			})
			.css('right', (0 - width))
			.show()
			.animate({
				right : return_pos
			}, Art.options.transition_speed_arrows, 'easeOutBounce');
		
		
		
		// --- call the change handler, to show the 1st item.
		Art.change(0, 'next');
	},
	
	
	
	
	
	// -- pre-handler for change_ready... presents loading graphic until item is confirmed ready
	change : function(index_to, direction) {
		Modal.hide();		
		clearInterval(Art.vars.loading_interval);
		Art.j.loading.show();
		j = $('> li:eq('+index_to+')', Art.j.ul);
		
		var check = function() {
			if(j.hasClass('ready')) {
				clearInterval(Art.vars.loading_interval);
				Art.j.loading.hide();
				Art.change_ready(index_to, direction);
			}
		}
		Art.vars.loading_interval = setInterval(check, 500); // checks twice every second
		check(); // also check immediately
	},
	
	
	
	
	
	// -- changes art to item at index_to (and transitions out from current_index)
	change_ready : function(index_to, direction) {
		
		
		if(index_to == Art.vars.current_index) return;
		
		if(!direction) {
			// --- we need to calculate what direction we're going in
			
			/* this goes by indexes - but we should really go by distance!
			if((Art.vars.current_index == 0 && index_to == Art.vars.total_items-1) || index_to < Art.vars.current_index) {	
				direction = 'prev';
			} else {
				direction = 'next';
			}*/
			
			
			direction = (findShortestLoopRoute(Art.vars.current_index, index_to, Art.vars.total_items, true) == -1) ? 'prev' : 'next';
		}
		
		
		
		if(Art.vars.current_index > -1) {
			// --- remove current item
			Art.slideOut(direction);
		}
		
		
		// --- update current_index	
		Art.vars.current_index = index_to; 
		
		
		// --- slide in next item
		Art.slideIn(direction);
	},
	
	
	
	
	
	// -- animation to slide item in
	slideIn: function(direction) {
		var j = $('> li:eq('+Art.vars.current_index+')', Art.j.ul);
		var wall_width = Art.j.wall.innerWidth(true);
		var item_width = j.innerWidth();
		var center = Math.ceil((wall_width - item_width) / 2);
		j
			.stop()
			.css({
				opacity:0,
				left:((direction == 'prev') ? 0 - item_width : wall_width)
			})
			.show()
			.animate({
				opacity:1,
				left:center
			}, Art.options.transition_speed);
	},
	
	
	
	
	
	// -- animation to slide item out
	slideOut: function(direction) {
		var j = $('> li:eq('+Art.vars.current_index+')', Art.j.ul);
		var wall_width = Art.j.wall.innerWidth(true);
		var item_width = j.innerWidth();
		j
			.stop()
			.animate({
				opacity:0,
				left:((direction == 'prev') ? wall_width : 0 - item_width)
			}, Art.options.transition_speed, function() {
				$(this).hide();	
			});
	},
	
	
	
	
	
	// -- determines previous or next index based on current_index
	indexByDirection : function(direction) {
		switch(direction) {
			default:
			case 'next':
				return (Art.vars.total_items > Art.vars.current_index+1) ? Art.vars.current_index+1 : 0;
			break;
			case 'prev':
				return (Art.vars.current_index-1 >= 0) ? Art.vars.current_index-1 : Art.vars.total_items-1;
			break;				
		}
	},
	
	
	
	
	
	// -- subcomponent: nav_bar (shows thumbnail navigation)
	NavBar : {
		
		options : {
			transition_speed : 750,	// (miliseconds) to transition positions in the carousel. looks best when it matches Art.transition_speed
			transition_speed_arrows: 1500 // (miliseconds) to animate arrows when intially displaying the artwork area
		},
	
		
		vars : {
			visible_items : 7, // number of visible items in the thumbnail bar
			has_carousel : false // indicates whether or not the carousel is available. can be used to determine whether to make changes to carousel when cycling art
		},
		
		
		j : {
			div : null, // thumbnail area 
			ul : null // container for the thumbnails
		},
		
		
		
		
		
		// --- initialize
		init : function() {
			Art.NavBar.j.div = $('div#thumbnail_bar');
			Art.NavBar.j.ul = $('<ul/>').appendTo($('<div/>').addClass('thumbnails').appendTo(Art.NavBar.j.div));
			
			$('> item', Art.vars.data).each(function(i) {
				Art.NavBar.j.ul
					.append(
						$('<li/>')
							.css('background-image', 'url('+Art.options.image_dir+$(this).attr('name')+'-thumb.jpg)')
							.click(function() {
								Art.change(i);
							})
					)
			});
			
			
			if(Art.vars.total_items > Art.NavBar.vars.visible_items) {
				Art.NavBar.j.ul.jcarousel({
					scroll:1,
					wrap:'circular',
					animation:Art.NavBar.options.transition_speed,
					buttonNextHTML:null,
					buttonPrevHTML:null,
					initCallback:function(carousel) {
						Art.NavBar.vars.has_carousel = true;
						
						// ---- prep the nav
						$('a.art_nav_small', Art.NavBar.j.div)
							.css('opacity', 0)
							.show()
							.fadeTo(Art.NavBar.options.transition_speed_arrows, 1)
							.click(function() {
								if($(this).hasClass('prev')) {
									carousel.prev();
									Art.change(Art.indexByDirection('prev'), 'prev');
								} else {
									carousel.next();
									Art.change(Art.indexByDirection('next'), 'next');
								}
							});
							
						// ---- also bind the functionality to the main nav, so they're synced	
						Art.j.prev
							.bind('click.navbar', function() {
								carousel.prev();
							});
						Art.j.next
							.bind('click.navbar', function() {
								carousel.next();
							});	
					}
				});
			}
		}
	}
}


function findShortestLoopRoute(point_from, point_to, total_items, zero_index) {

    var distance_next; // (int) calculated distance, if we move forward 
    var distance_prev; // (int) calculated distance, if we move backward 
    if(zero_index) {
        point_to++; 
        point_from++;
    } 
	 
    if(point_to > point_from) {
        distance_next = point_to - point_from; 
        distance_prev = total_items - point_to + point_from; 
    } else {
        distance_next = total_items - point_from + point_to; 
        distance_prev = point_from - point_to;
    } 
	 
    return (distance_prev < distance_next) ? -1 : 1; // previous : next. assumes "next" if equidistant 
} 
