// AnnoTube.js - a jQuery plugin to annotate your YouTube video
// Pre-alpha preview edition 0.0.0
// Copyright 2008 Michael Geary
// http://mg.to/
// Free beer and free speech license (MIT+GPL). Enjoy!

function S() {
	return Array.prototype.join.call( arguments, '' );
}

(function( $ ) {
	
	$.annotube = function( anno ) {
		
		$( function() {
			anno = $.extend(
				{ containers: { video:'annotube_video', index:'annotube_index', note:'annotube_note' } },
				window.AnnoTube,
				anno
			);
			var current;
			var $video = $( '#' + anno.containers.video );
			var $index = $( '#' + anno.containers.index );
			var $note = $( '#' + anno.containers.note );
			
			var index = [];
			var note = '';
			var timeline = anno.timeline, n = timeline.length;
			for( var i = 0;  i < n;  ++i ) {
				var at = timeline[i];
				if( typeof at == 'string' ) {
					var parts = at.split('|');
					at = {};
					at.time = parts.shift();
					at.title = parts.shift();
					at.note = parts.join('|');
					if( at.note.match( /^https?:\/\// ) ) at.note = { iframe:at.note };
					timeline[i] = at;
				}
				if( at.note == ''  ||  at.note == null ) at.note = note;
				note = at.note;
				at.seconds = timeFromStr( at.time );
				index.push( S(
					'<a href="javascript:;" onclick="return annotubeIndex(this,\'', at.time, '\')" class="annolink" id="annoindex-', i, '">',
						at.title,
					'</a>'
				) );
			}
			
			$index.html( index.join('') );
			
			loadSwf( $video, anno.video );
			function loadSwf( $container, video ) {
				var params = { allowScriptAccess: 'always' };
				var atts = { id: 'myytplayer' };
				swfobject.embedSWF(
					'http://www.youtube.com/v/' + video +
						'&amp;border=0&amp;enablejsapi=1&amp;playerapiid=ytplayer',
					$container[0].id, $container.width(), $container.height(),
					'8', null, null, params, atts );
			}
			
			//$.each( [ '1:00', '2:00', '2:06', '2:07', '2:08' ], function( i, time ) {
			//	var seconds = timeFromStr( time );
			//	var at = findTime( seconds );
			//	console.log( time, at.time );
			//});
			
			function timeFromStr( str ) {
				var ms = str.split(':');
				return (+ms[0]) * 60 + (+ms[1]);
			}
			
			//function timeToStr( time ) {
			//	return time;
			//}
			
			function findTime( seconds ) {
				for( var i = timeline.length - 1;  i >= 0;  --i )
					if( timeline[i].seconds <= seconds )
						break;
				return { i:i, at:timeline[i] };
				//// TODO: binary search - not quite working right
				//var low = 0, high = timeline.length;
				//while( low < high ) {
				//	var mid = Math.floor( ( low + high ) / 2 );
				//	if( timeline[mid].seconds < seconds )
				//		low = mid + 1; 
				//	else
				//		high = mid; 
				//}
				//return low;
			}
			
			annotubeIndex = function( element, time ) {
				element.blur();
				var seconds = timeFromStr( time );
				seekTo( '' + seconds );
				return false;
			};
			
			onYouTubePlayerReady = function(playerId) {
				ytplayer = document.getElementById("myytplayer");
				setInterval(updateytplayerInfo, 250);
				updateytplayerInfo();
				//ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
				ytplayer.addEventListener("onError", "onPlayerError");
			};
			
			//function onytplayerStateChange( state ) {
			//	console.log( 'state', state );
			//}
			
			function onPlayerError(errorCode) {
				alert("An error occurred: "+ errorCode);
			}
			
			function isPlaying() {
				var state = getPlayerState();
				return state == 1;
			}
			
			function updateytplayerInfo() {
				if( isPlaying() ) {
					var seconds = getCurrentTime();
					//console.log( seconds );
					hiliteTime( seconds );
				}
			}
			
			function hiliteTime( seconds ) {
				var t = findTime( seconds );
				if( ! current  ||  t.i != current.i ) {
					hilite( current, false );
					loadNote( t );
					current = t;
					hilite( current, true );
				}
			}
			
			function hilite( t, yes ) {
				if( ! t ) return;
				var $div = $( '#annoindex-' + t.i );
				$div[ yes ? 'addClass' : 'removeClass' ]( 'annohilite' );
			}
			
			function loadNote( t ) {
				if( current  &&  t.at.note == current.at.note ) return;
				var note = t.at.note;
				if( ! note ) {
					$note.empty();
				}
				else if( note.iframe ) {
					$note.html( S(
						'<iframe frameborder="0" width="100%" height="100%;" src="', note.iframe, '">',
						'</iframe>'
					) );
				}
				else if( typeof note == 'string' ) {
					$note.html( note );
				}
				else if( typeof note == 'function' ) {
					$note.html( note(t) );
				}
			}
			
			// functions for the api calls
			function play() {
				ytplayer && ytplayer.playVideo && ytplayer.playVideo();
			}
			
			function pause() {
				ytplayer && ytplayer.pauseVideo && ytplayer.pauseVideo();
			}
			
			function stop() {
				ytplayer && ytplayer.stopVideo && ytplayer.stopVideo();
			}
			
			function getPlayerState() {
				return ytplayer && ytplayer.getPlayerState && ytplayer.getPlayerState();
			}
			
			function seekTo(seconds) {
				//console.log( 'seekTo', seconds, typeof seconds );
				ytplayer && ytplayer.seekTo && ytplayer.seekTo(seconds, true);
			}
			
			function getBytesLoaded() {
				return ytplayer && ytplayer.getVideoBytesLoaded && ytplayer.getVideoBytesLoaded();
			}
			
			function getBytesTotal() {
				return ytplayer && ytplayer.getVideoBytesTotal && ytplayer.getVideoBytesTotal();
			}
			
			function getCurrentTime() {
				return ytplayer && ytplayer.getCurrentTime && ytplayer.getCurrentTime();
			}
			
			function getDuration() {
				return ytplayer && ytplayer.getDuration && ytplayer.getDuration();
			}
			
			function getStartBytes() {
				return ytplayer && ytplayer.getVideoStartBytes && ytplayer.getVideoStartBytes();
			}
			
			function mute() {
				ytplayer && ytplayer.mute && ytplayer.mute();
			}
			
			function unMute() {
				ytplayer && ytplayer.unMute && ytplayer.unMute();
			}
		});
	}
})( jQuery );
