/**
 * Created: Monday 22 February 2010 12:41 PM EST
 *
 * Dependencies:
 * jQuery 1.4.1
 * Scrollbar Class (BR Internal)
 */

/**
 * Controller for all timeline items and the associated scrollbar
 */
function TimelineController() {
	
	TimelineController.instance = this;

	// If this is IE we need to force the horizontal scrollbar from appearing
	if($.browser.msie) {
		$('html').css('overflow-x', 'hidden');
		$('#timeline>p').remove();
	}

	// Abort if there is no content on which to operate (i.e. we're not on
	// the content page)
	if($('#timeline').size() <= 0) {
		this.failed = true;
		return;
	}
	
	// Initialy, hide the timeline while it loads
	hide();	

	var self = this;
	var scrollbar = new Scrollbar();
	var $items = $('#timeline #items');
	var $container = $('#timeline')//.css({position: 'absolute', top: '-3000px', left: '-3000px', opacity: 0.5});
	var itemControllers = [];
	var videos = false;
	var loadingInterval;
	var ie = $.browser.msie;
	var videoSafetyMode = true;


	// SCROLLBAR STUFF

	scrollbar.eventDispatcher.addListener('drag', function() {
		setPosition(scrollbar.position);
	});

	$(window).resize(function() {
		setScrollbarSize();
	});


	// PUBLIC METHODS

	this.addPhoto = function(year, image, description, caption) {
		var i = addItem(year, image, description);
		i.photoize(caption);
	};

	this.addAlbum = function(year, image, description, albumTitle, albumDescription, url) {
		var i = addItem(year, image, description);
		i.albumize(albumTitle, albumDescription, url);
	};

	this.addVideo = function(year, image, description, clipId) {
		var i = addItem(year, image, description);
		i.videoize(clipId);
		videos = true;
	};

	/**
	 * Called after a video item has been loaded. Once it has, contract
	 * the timeline item holding the video that just loaded. This routine
	 * is needed for Flash to appropriately fade in and out when the
	 * timeline expands and contracts.
	 */
	this.contractWhenLoaded = function(swfId) {

		var readyCount = 0;

		for(var i in itemControllers) {
			if((itemControllers[i].ready && !itemControllers[i].expanded) || itemControllers[i].videoId == swfId) itemControllers[i].contract();
			if(itemControllers[i].ready) readyCount++;
		}

		if(readyCount == itemControllers.length) {
			// everything's been loaded
		}
		
		show();
	};


	// PRIVATE METHODS

	function addItem(year, image, description) {
		var i = new TimelineItem(year, image, description);
		i.eventDispatcher.addListener('start', closeOpenItems);
		$items.append(i.$content);

		i.$content.click(function(e) {
			slideToPosition(i.centerPosition, i.positionPercent);
		});

		itemControllers.push(i);

		resizeContainer();
		setScrollbarSize();

		return i;
	}

	/**
	 * Calculate the size of the element containing timeline items and resize
	 * it as such.
	 */
	function resizeContainer() {
		var w = 0;

		for(var i = 0; i < itemControllers.length; i++) {
			// Each closed timeline item is 300 pixels wide + 1 pixel for
			// its rightmost rule
			w += 301;
		}

		// In its open state, each timeline item gains another 240 pixels at
		// most. Because only one item can be open at a time, we compensate
		// for that extra width one here.
		w += 240;

		$items.width(w);
	}

	function setPosition(percent) {
		var overflow = $items.width() - $container.width();
		$items.css('left', -(overflow * percent));
	}

	function slideToPosition(centerPosition, percent) {

		scrollbar.scrollTo(percent, 500);

		$items.animate({
			left: -(centerPosition)
		}, {
			queue: false,
			duration: 500
		});
	}

	function setScrollbarSize() {
		scrollbar.setWidth($container.width() / $items.width());
	}

	function closeOpenItems() {
		for(var i in itemControllers) {
			itemControllers[i].contract();
		}
	}
	
	function hide() {
		if($.browser.msie) {
			return;
		}
		
		$('.scrollbar').css('opacity', 0);
		$('#timeline #items').css({
			position: 'absolute',
			left: -3000,
			top: -3000,
			opacity: 0
		});
	}
	
	function show() {
		if($.browser.msie) {
			return;
		}

		setTimeout(function() {
			
			$('#timeline>p').remove();
			
			$('#timeline #items, .scrollbar').css({
				position: 'relative',
				left: 0,
				top: 0
			}).animate({ opacity: 1 }, { queue: false, duration: 500 });
			
		}, 600);
	}

	this.init = function() {
		if(!videos || videoSafetyMode) this.contractWhenLoaded();
	};
}


/**
 * Single timeline element
 */
function TimelineItem(year, image, description) {

	this.$content;
	this.type;
	this.eventDispatcher = new EventDispatcher;
	this.expanded = false;
	this.animating = false;
	this.projectedWidth;
	this.videoId;
	this.ready = false;
	this.centerPosition;
	this.positionPercent;

	var self = this;
	var $description;
	var transitionDuration = 500;
	var ie = $.browser.msie;
	var videoSafetyMode = true;

	// Keep a counter of all timeline items. This becomes necessary in the
	// calculation necessary to center a timeline item into view on click
	if(typeof TimelineItem.itemNumber == 'undefined') {
		TimelineItem.itemNumber = 0;
	} else {
		TimelineItem.itemNumber++;
	}

	this.itemNumber = TimelineItem.itemNumber;

	// Build initial content
	self.$content = $('<li><div><span class="overlay"></span><span class="image"></span><h2>' + year + '</h2></div></li>');
	self.$content.find('span.image').css('backgroundImage', 'url(' + image + ')');
	self.$content.find('div').append('<p class="caption">' + description + '</p>');

	$description = self.$content.find('p.caption');

	// Move background image (sprite map) to show the correct year
	self.$content.find('h2').css('background-position', '0 ' + ((year-1980)*-20) + 'px');

	// On click, expand or contract this item and center the item
	self.$content.click(function(e) {

		var itemWidth = (self.type == 'album') ? 495 : 540;
		var parentWidth = $(this).parent().width();
		var windowWidth = $(window).width();

		self.centerPosition = Math.max(0, Math.min(parentWidth - windowWidth, (self.itemNumber * 300 - (windowWidth/2 - itemWidth/2))) );
		self.positionPercent = Math.max(0, Math.min(1, self.centerPosition / (parentWidth - windowWidth)));

		self.eventDispatcher.dispatchEvent('click');
		self.expanded ? self.contract() : expand();

		return false;
	});


	/**
	 * Format this item for photo content
	 */
	this.photoize = function(caption) {
		
		if(typeof caption != 'undefined' && caption != '') {
			var $div = $('<div class="photoInfo internal"><div>' + caption + '</div></div>');
			this.$content.find('div').append($div);
		}
		
		// Make sure hyperlinks work as normal
		this.$content.find('a').click(function(e) {
			e.stopPropagation();
			
			if($(this).attr('target') == '_blank') {
				window.open($(this).attr('href'));
			} else {
				window.location = $(this).attr('href');
			}
			
			return false;
		});

		this.$content.mouseover(function() {
			if(self.expanded) self.$content.find('.photoInfo').animate( {opacity: (ie ? 0.75 : 1)}, {duration: 150, queue: false} );
		});

		this.$content.mouseout(function() {
			if(self.expanded) self.$content.find('.photoInfo').animate( {opacity: 0}, {duration: 150, queue: false} );
		});

		if(!ie && !videoSafetyMode) this.$content.width(540);

		this.type = 'photo';
		this.ready = true;
	};


	/**
	 * Format this item for album content
	 */
	this.albumize = function(title, description, url) {
		url = url || '#';

		this.$content.find('div').append(
			'<div class="internal album">' +
			'<h3>' + title + '</h3>' +
			'<p class="description">' + description + '</p>' +
			'<a class="albumDetails" href="' + url + '">Album Details</a>' +
			'</div>'
		);

		this.$content.find('a.albumDetails').click(function(e) {
			e.stopPropagation();
		});

		if(!ie && !videoSafetyMode) this.$content.width(495);

		this.type = 'album';
		this.ready = true;
	};


	/**
	 * Format this item for video content
	 */
	this.videoize = function(clipId) {

		if(!TimelineItem.videoId) TimelineItem.videoId = 0;
		this.videoId = 'video' + (TimelineItem.videoId++);

		$div = $('<div>');
		
		var flashvars = {
			clip_id: clipId,
			width: 540,
			height: 495,
			color: 'db2334',
			show_portrait: 0,
			show_byline: 0,
			show_title: 0,
			fullscreen: 0,
			js_api: (ie) ? 0 : 1,
			js_swf_id: self.videoId
		}
		
		if(!ie && !videoSafetyMode) {
			flashvars.js_onLoad = 'TimelineController.instance.contractWhenLoaded';
		}

		$div.flash({
			src: 'http://vimeo.com/moogaloop.swf',
			width: 540,
			height: 495,
			allowscriptaccess: 'always',
			bgcolor: '#000000',
			flashvars: flashvars
		});

		$div.find('embed').attr('id', self.videoId);

		// If the video is clicked, don't collapse this item
		$div.click(function(e) {
			e.stopPropagation();
		});

		this.$content.find('div').append($div);
		this.$content.find('div.flash-replaced').css('z-index', '1');
		this.$content.find('h2, .image').css('z-index', '2');
		this.$content.find('.overlay').css('z-index', '3');

		if(!ie && !videoSafetyMode) this.$content.width(540);

		this.type = 'video';
	};


	/**
	 * 'Open' this item.
	 */
	function expand() {

		var width = self.type == 'album' ? 495 : 540;

		self.animating = true;
		self.eventDispatcher.dispatchEvent('start');

		self.$content.animate({ width: width }, { duration: transitionDuration });
		$description.fadeOut(transitionDuration);
		self.$content.find('.internal').fadeIn(transitionDuration);
		
		if(ie) self.$content.find('.overlay').fadeOut(transitionDuration);

		if(self.type == 'photo') {
			self.$content.find('h2, span.overlay').fadeOut(transitionDuration);
		} else if(self.type == 'video') {
			self.$content.find('h2, span.overlay, span.image').fadeOut(transitionDuration);
			if(ie || videoSafetyMode) self.$content.find('embed').show();
		}

		self.projectedWidth = width;
		self.expanded = true;
	}


	/**
	 * 'Close' this item.
	 */
	this.contract = function() {
		var width = 300;

		self.animating = true;

		self.$content.animate({ width: width }, { duration: transitionDuration, queue: false });
		$description.fadeIn(transitionDuration);
		self.$content.find('.internal').fadeOut(transitionDuration);
		
		if(ie) self.$content.find('.overlay').fadeIn(transitionDuration);

		if(self.type == 'photo') {

			self.$content.find('h2, span.overlay').fadeIn(transitionDuration);

		} else if(self.type == 'video') {

			self.$content.find('h2, span.overlay, span.image').fadeIn(transitionDuration);
			if(ie || videoSafetyMode) self.$content.find('embed').hide();

			try {
				// Stop the video from playing
				document.getElementById(self.videoId).api_pause();
			} catch(e) {
				// Oh well. The swf probably hasn't been initialized yet.
			}
		}

		self.projectedWidth = width;
		self.expanded = false;

		if(!this.ready) this.ready = true;
	};
}