/* -----------------------------------------------------------------------
	
	MediaPlayer.js
	Kevin Eye
	eye@buffalo.edu
	University at Buffalo Creative Services

----------------------------------------------------------------------- */

var MediaPlayer_Utils = {
	'getCookie' : function(name) {
		var dc = document.cookie;

		// find beginning of cookie value in document.cookie
		var prefix = name + "=";
		var begin = dc.indexOf("; " + prefix);
		if (begin == -1) {
			begin = dc.indexOf(prefix);
			if (begin != 0) return null;
			}
		else begin += 2;
		
		// find end of cookie value
		var end = document.cookie.indexOf(";", begin);
		if (end == -1) end = dc.length;
		
		// return cookie value
		return unescape(dc.substring(begin + prefix.length, end));
		},
	
	'setCookie' : function(name, value, expires, path, domain, secure) {
		var curCookie = name + '=' + escape(value) + ((expires) ? '; expires=' + expires.toGMTString() : '') + ((path) ? '; path=' + path : '') + ((domain) ? '; domain=' + domain : '') + ((secure) ? '; secure' : '');
		document.cookie = curCookie;
		},
	
	'deleteCookie' : function(name, path, domain) {
		var value = ArrowEdit_Utils.getCookie(name);
		if (value != null) document.cookie = name + '=' + ((path) ? '; path=' + path : '') + ((domain) ? '; domain=' + domain : '') + '; expires=Thu, 01-Jan-70 00:00:01 GMT';
		return value;
		},
	
	'updateDefaults' : function(obj, newies) {
		var undef;
		if (!obj) obj = {};
		for(k in newies) {
			if(obj[k] === undef) obj[k] = newies[k];
			}
		return obj;
		},
	
	'connectEvent' : function(eventName, code) {
		if(window.addEventListener) {
			window.addEventListener(eventName, code, false);
			}
		else {
			window.attachEvent('on'+eventName, code);
			}
		},
	
	'formatDuration' : function(seconds) {
		var s = '' + Math.floor(seconds%60);
		if(s.length == 1) s = '0' + s;
		if(seconds < 60) return '0:'+s;
		s = Math.floor(seconds/60)%60 + ':' + s;
		if(seconds < 3600) return s;
		if(s.length == 4) s = '0' + s;
		s = Math.floor(seconds/3600) + ':' + s;
		return s;
		}
	
	};

/* -----------------------------------------------------------------------

	MediaPlayer_Clip
	
	A clip encapsulates multiple versions (formats, bandwidths) of the
	same content

----------------------------------------------------------------------- */

function MediaPlayer_Clip() {
	this.streams = [];
	this.chapters = [];
	}

MediaPlayer_Clip.prototype = {
	'streams' : null,
	'chapters' : null,
	'title' : null,
	'date' : null,
	'description' : null,
	'duration' : null,
	
	'addStream' : function(format, bitrate, url) {
		this.streams.push({ 'format' : format, 'bitrate' : bitrate, 'url' : url });
		return this;
		},
	
	'bestStream' : function(formats, max_bitrate) {
		
		// defaults
		if (!formats) formats = MediaPlayer_Detect.defaultPlayers;
		if (!max_bitrate) max_bitrate = MediaPlayer_Detect.defaultMaxBitrate;
		
		// look for each format in order of preference
		for(var i = 0; i < formats.length; i++) {
			var best = null;
			var f = formats[i];
			
			// look for the best bandwidth option in this format
			for(var j = 0; j < this.streams.length; j++) {
				var s = this.streams[j];
				if (s.format == f && s.bitrate <= max_bitrate && (!best || s.bitrate > best.bitrate))
					best = s;
				}
			if(best) return best;
			}
		return null;
		},
	
	'addChapter' : function(seconds, title, image) {
		var i;
		for(i = 0; i < this.chapters.length; i++) {
			if(seconds < this.chapters[i][0]) break;
			}
		this.chapters.splice(i, 0, [ seconds, title, image ]);
		},
	
	'chapterDuration' : function(n) {
		if(n == this.chapters.length-1) {
			return this.duration - this.chapters[n][0];
			}
		else {
			return this.chapters[n+1][0]-this.chapters[n][0];
			}
		},
	
	'currentChapter' : function(seconds, last) {
		if(last && last > 0 && this.chapters[last][0] < seconds && (last == this.chapters.length-1 || this.chapters[last+1] > seconds)) return last;
		for(var i = 0; i<this.chapters.length; i++) {
			if(this.chapters[i][0] > seconds) return i-1;
			}
		return this.chapters.length-1;
		}
	
	};

/* -----------------------------------------------------------------------
	
	MediaPlayer_Object
	MediaPlayer_Object_Real
	MediaPlayer_Object_WMP
	
	MediaPlayer_Object encapsulates a media player plugin's scriptable
	interface
	
	Do not use "new MediaPlayer_Object()" to create an object; use
	"MediaPlayer_Object.makeVariant(...)" instead. It will use the right
	subclass for the clip's preferred format.
	
----------------------------------------------------------------------- */

MediaPlayer_Object.makeVariant = function(options) {
	if(!options['clip']) return null;
	options['_bestClip'] = options['clip'].bestStream();
	if(!options['_bestClip']) return null;
	var f = options['_bestClip'].format;
	if(f == 'real') {
		return new MediaPlayer_Object_Real(options);
		}
	else if(f == 'wmp') {
		return new MediaPlayer_Object_WMP(options);
		}
	else {
		return null;
		}
	}

function MediaPlayer_Object() {}

MediaPlayer_Object.prototype = {
	'container' : null,
	'controllerHeight' : 67,
	'height' : 240,
	'width' : 320,
	'object' : null,
	'clip' : null,
	'format' : null,
	'bitrate' : null,
	'url' : null,
	'valid' : false,
	
	'_init' : function(options) {
		var container = options['container'];
		if(typeof container == 'string') container = document.getElementById(container);
		this.container = container;
		this.container.mediaPlayerObject = this;
		
		this.clip = options['clip'];
		
		var c = options['_bestClip'];
		if(!c) c = clip.bestStream();
		if(!c) return;
		
		this.format = c.format;
		this.bitrate = c.bitrate;
		this.url = c.url;
		this.makeObject();
		if(!this.object) return;
		
		this.valid = true;
		},
	
	'remove' : function() {
		if(!this.valid) return;
		this.valid = false;
		this.object = null;
		this.container.innerHTML = '';
		}
		
	};

/* -------------------------------------------------------------------- */

// Some documentation here:
// http://docs.real.com/docs/smil/embed.pdf

function MediaPlayer_Object_Real(options) {
	this._init(options);
	}

MediaPlayer_Object_Real.prototype = new MediaPlayer_Object();

MediaPlayer_Utils.updateDefaults(MediaPlayer_Object_Real.prototype, {
	
	'canInteract' : function() {
		return true;
		},
	
	'makeObject' : function() {
		var oid = 'MediaPlayer_'+(new Date()).getTime();
		var html;
		if (MediaPlayer_Detect.isIE && MediaPlayer_Detect.isWindows) {
			html = '<object width="'+this.width+'" height="'+this.height+'" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA"><param name="src" value="'+this.url+'" /><param name="controls" value="ImageWindow" /><param name="autoStart" value="true" /><param name="maintainaspect" value="true" /><param name="console" value="one" /></object><object width="'+this.width+'" height="'+this.controllerHeight+'" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" id="'+oid+'"><param name="src" value="'+this.url+'" /><param name="controls" value="All" /><param name="console" value="one" /></object>';
			}
		else {
			html = '<embed type="audio/x-pn-realaudio-plugin" width="'+this.width+'" height="'+this.height+'" src="'+this.url+'" controls="ImageWindow" maintainaspect="true" console="one" autoStart="true" /><embed type="audio/x-pn-realaudio-plugin" console="one" id="'+oid+'" width="'+this.width+'" height="'+this.controllerHeight+'" src="'+this.url+'" controls="All"  autoStart="true"/>';
			}
		this.container.innerHTML = html;
		this.object = document.getElementById(oid);
		return this.object;
		},
	
	'fullScreen' : function() {
		// this doesn't work on Windows for some reason
		this.object.SetFullScreen();
		},
	
	'seek' : function(seconds) {
		this.object.SetPosition(seconds*1000);
		},
	
	'duration' : function() {
		return this.object.GetLength()/1000;
		},
	
	'position' : function() {
		return this.object.GetPosition()/1000;
		},
	
	'stopped' : function() {
		return this.object.GetPlayState() == 0;
		},
		
	'paused' : function() {
		return this.object.GetPlayState() == 4;
		},
	
	'playing' : function() {
		return this.object.GetPlayState() == 3;
		},
	
	'pause' : function() {
		this.object.DoPause();
		},
	
	'play' : function() {
		// this starts playing, but cannot resume from pause on Windows
		this.object.DoPlay();
		},
	
	'stop' : function() {
		this.object.DoStop();
		}
	
	});

/* -------------------------------------------------------------------- */

// Some documentation is here:
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmp6sdk/htm/windowsmediaplayerversion64forsolaris.asp

function MediaPlayer_Object_WMP(options) {
	this._init(options);
	}

MediaPlayer_Object_WMP.prototype = new MediaPlayer_Object();

MediaPlayer_Utils.updateDefaults(MediaPlayer_Object_WMP.prototype, {
	
	'canInteract' : function() {
		return MediaPlayer_Detect.isWindows && MediaPlayer_Detect.isIE;
		},
	
	'makeObject' : function() {
		var oid = 'MediaPlayer_'+(new Date()).getTime();
		var html;
		if (MediaPlayer_Detect.isIE && MediaPlayer_Detect.isWindows) {
			html = '<div style="position: absolute; top: 195px; left: 250px; z-index:2; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'http://raptor.pub.buffalo.edu/Projects/DalaiLama/Product/playlists/watermark50.png\', sizingMethod=\'scale\'); width: 70px; height: 45px" id="ttl"></div><object style="position: absolute; top: 0; left: 0; z-index:1; width: '+this.width+'px; height: '+(this.height+this.controllerHeight)+'px" classid="clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6" id="'+oid+'" width="'+this.width+'" height="'+(this.height+this.controllerHeight)+'"><param name="URL" value="'+this.url+'" /><param name="autoStart" value="true" /><param name="uiMode" value="full" /><param name="stretchToFit" value="true" /><param name="windowlessVideo" value="true" /></object>';
			}
		else {
			html = '<embed type="application/x-mplayer2" id="'+oid+'" width="'+this.width+'" height="'+(this.height+this.controllerHeight)+'" src="'+this.url+'" showstatusbar="1" showpositioncontrols="0" />';
			}
		this.container.innerHTML = html;
		this.object = document.getElementById(oid);
		return this.object;
		},
	
	'fullScreen' : function() {
		this.object.fullScreen = true;
		},
	
	'seek' : function(seconds) {
		this.object.controls.currentPosition = seconds;
		},
	
	'duration' : function() {
		return this.object.currentMedia.duration;
		},
	
	'position' : function() {
		return this.object.controls.currentPosition;
		},
	
	'stopped' : function() {
		return this.object.playState == 1 || this.object.playState == 8;
		},
	
	'paused' : function() {
		return this.object.playState == 2;
		},
	
	'playing' : function() {
		return this.object.playState == 3;
		},
	
	'pause' : function() {
		this.object.controls.pause();
		},
	
	'play' : function() {
		this.object.controls.play();
		},
	
	'stop' : function() {
		this.object.controls.stop();
		}
	
	});

/* -----------------------------------------------------------------------

	MediaPlayer
	
	MediaPlayer provides the illusion of one media player object across
	several formats which require several different player objects/plugins
	
	MediaPlayer also handles playlists

----------------------------------------------------------------------- */

function MediaPlayer(playlist, container) {
	this.playlist = playlist || [];

	var self = this;
	this.interval = window.setInterval(function() { self._intervalCallback() }, 1000);
	this.onfinish = this.next;
	
	if (window.attachEvent) window.attachEvent('onunload', function() { self.cleanup() });
	
	if(!container) container = 'media_player_object';
	if(typeof container == 'string') container = document.getElementById(container);
	this.container = container;
	this.container.mediaPlayer = this;
	this.object = null;
	}

MediaPlayer.prototype = {
	'playlist' : null,
	'currentNum' : 0,
	'intervalLast' : null,
	'onfinish' : null,
	'container' : null,
	'object' : null,
	'onchange' : null,
	'onchangeplaylist' : null,
	'onchangechapter' : null,
	'currentChapter' : null,
	
	'add' : function(clip) {
		this.playlist.push(clip);
		if(this.onchangeplaylist) onchangeplaylist();
		},
	
	'load' : function(clip) {
		this.add(clip);
		this.play(this.playlist.length);
		},
	
	'clear' : function() {
		this.replace();
		this.playlist = [];
		if(this.onchangeplaylist) onchangeplaylist();
		if(this.onchange) this.onchange(null, 0);
		},
	
	'replace' : function(html) {
		this.container.innerHTML = html || '';
		if(this.object) this.object.remove();
		this.object = null;
		},
	
	'current' : function() {
		return this.currentNum;
		},
	
	'clip' : function() {
		return this.currentNum > 0 ? this.playlist[this.currentNum-1] : null;
		},
	
	'length' : function() {
		return this.playlist.length;
		},
	
	// play(clip) will play the clip, skipping to it in the playlist or adding it if necessary
	// play(int) will play that number in the playlist
	// play() will resume when paused or start playing the first clip
	'play' : function(variant) {
		if(this.paused()) return this.object.play();
		
		var n;
		if (variant instanceof MediaPlayer_Clip) {
			for(var i = 0; i < this.playlist.length; i++) {
				if(this.playlist[i] == variant) {
					n = i + 1;
					break;
					}
				}
			if(!n) {
				this.add(clip);
				n = this.playlist.length;
				}
			}
		else {
			n = variant;
			if(this.playlist.length == 0) return this.stop();
			if(!n || n < 1 || n > this.playlist.length) n = 1;
			}
		
		var clip = this.playlist[n-1];
		this.currentNum = n;
		this.object = MediaPlayer_Object.makeVariant({ 'clip' : clip, 'container' : this.container });
		if(this.onchange) this.onchange(clip, n);
		if(this.onchangechapter) {
			this.lastChapter = this.clip().currentChapter(this.clip(), 0);
			this.onchangechapter(this.lastChapter);
			}
		},
	
	'previous' : function() {
		this.play(this.current()-1);
		},
	
	'next' : function() {
		this.play(this.current()+1);
		},

	'stop' : function() {
		if(this.object) this.object.stop();
		},

	'stopped' : function() {
		return !this.object || this.object.stopped();
		},

	'paused' : function() {
		return this.object && this.object.paused();
		},

	'playing' : function() {
		return this.object && this.object.playing();
		},

	'pause' : function() {
		if(this.object) this.object.pause();
		},

	'playPause' : function() {
		if(this.stopped() || this.paused()) {
			this.play();
			}
		else if(this.playing()) {
			this.pause();
			}
		},
	
	'seek' : function(seconds) {
		this.object.seek(seconds);
		},
	
	'seekChapter' : function(n) {
		this.seek(this.clip().chapters[n][0]);
		},
	
	'_intervalCallback' : function() {
		if(this.object && this.object.canInteract()) {
			if(this.onfinish) {
				if(this.playing()) {
					this.intervalLast = this.object.duration() - this.object.position();
					if(this.intervalLast < 0) this.intervalLast = null;
					}
				else if (this.stopped()) {
					if(this.intervalLast && this.intervalLast < 4) this.onfinish();
					this.intervalLast = null;
					}
				}
			if(this.onchangechapter) {
				var c = this.clip().currentChapter(this.object.position(), this.lastChapter);
				if(c !== this.lastChapter) {
					this.lastChapter = c;
					this.onchangechapter(this.clip(), c);
					}
				}
			}
		},
	
	'cleanup' : function() {
		if(this.interval !== null) window.clearInterval(this.interval);
		
		// without this, it seems that the video player plugin object(s)
		// will be burned into IE until it gets restarted
		if(this.object && this.object.valid) this.object.remove();
		}
	
	};

/* -----------------------------------------------------------------------

	MediaPlayer_Detect
	
	Runs automatically when loaded to detect features of the environment.

----------------------------------------------------------------------- */

MediaPlayer_Detect = {
	'capable' : false,
	
	'isWindows' : null,
	'isIE' : null,

	'hasReal' : false,
	'hasWMP' : false,
	
	'defaultPlayers' : [],
	'defaultMaxBitrate' : 0,
	
	'findActiveXObject' : function(list) {
		if(!window.ActiveXObject) return null;
		for(var i = 0; i < list.length; i++) {
			try {
				var o = new ActiveXObject(list[i]);
				if(o) return o;
				}
			catch(e) {}
			}
		return null;
		},
	
	'findPlugin' : function(str) {
		if (navigator.plugins && navigator.plugins.length) {
			for (var i = 0; i < navigator.plugins.length; i++) {
				if (navigator.plugins[i].name.indexOf(str) != -1) {
					return navigator.plugins[i];
					}
				}
			}
		return null;
		},
	
	'alert' : function() {
		var a = [];
		var p = ['isWindows', 'hasReal', 'hasWMP', 'defaultPlayers', 'defaultMaxBitrate'];
		for(var i = 0; i<p.length; i++) {
			a.push(p[i]+': '+this[p[i]]);
			}
		alert(a.join("\n"));
		},
	
	'_detect' : function() {
		this.isWindows = navigator.userAgent.indexOf('Win') == -1 ? false : true;
		this.isIE = navigator.userAgent.indexOf('MSIE') == -1 ? false : true;
		
		this.hasWMP = (this.findActiveXObject(['WMPlayer.OCX.7']) || this.findPlugin('Windows Media')) ? true : false;
		this.hasReal = (this.findActiveXObject(['rmocx.RealPlayer G2 Control', 'IERJCtl.IERJCtl.1', 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)']) || this.findPlugin('RealPlayer')) ? true : false;
		
		this.setupDefaultPlayersList();
		this.defaultMaxBitrate = this.getMaxBitrate() || 550000;
		
		this.capable = this.defaultPlayers.length ? true : false;
		},
	
	'setupDefaultPlayersList' : function() {
		this.defaultPlayers = [];
		var pf = this.getPreferredFormat();
		if(pf) this.defaultPlayers.push(pf);
		if(this.isWindows && this.isIE) {
			if(this.hasWMP) this.defaultPlayers.push('wmp');
			if(this.hasReal) this.defaultPlayers.push('real');
			}
		else {
			if(this.hasReal) this.defaultPlayers.push('real');
			if(this.hasWMP) this.defaultPlayers.push('wmp');
			}
		},
	
	'getPreferredFormat' : function() {
		return MediaPlayer_Utils.getCookie('MediaPlayer_format');
		},
	
	'setPreferredFormat' : function(format) {
		var exp = new Date();
		exp.setFullYear(exp.getFullYear()+2);
		MediaPlayer_Utils.setCookie('MediaPlayer_format', format, exp, '/', false);
		this.setupDefaultPlayersList();
		},
	
	'getMaxBitrate' : function() {
		return parseInt(MediaPlayer_Utils.getCookie('MediaPlayer_bitrate'));
		},
	
	'setMaxBitrate' : function(bitrate) {
		var exp = new Date();
		exp.setFullYear(exp.getFullYear()+2);
		MediaPlayer_Utils.setCookie('MediaPlayer_bitrate', bitrate, exp, '/', false);
		this.defaultMaxBitrate = bitrate;
		}

	};

MediaPlayer_Detect._detect();

