///////////////////////////////////////////////////////////////////////////////
//
//  MediaPlayer.js   			version 1.0
//  2007 Lenny Burdette
//
//  FUNCTIONS:
//			Loc.Player
//			Loc.ControlButton
// 			Loc.ScrubBar
//			Loc.Volume
//			
//	DEPENDENCIES:
//			Utils.js
//
///////////////////////////////////////////////////////////////////////////////

if ( !window.Loc) { window.Loc = {}; }

/**
 * The player object
 * Loads a XAML file for style
 * Has a Loc.Controls object
 */
Loc.Player = function(params) {
	this.type = params.type;
	this.parent = params.parent || Loc.root;
	this.source = params.source;
	this.params = params;
	this.cc = false; // close caption is set to off
	this.saveCC = '', // string from previous marker
	this.stop = false;
	
	this.getPresentation();
}
Loc.Player.prototype = {
	getPresentation : function() {
		this.downloader = new Silverlight.Downloader({
		    resource : "cmn/xaml/" + this.type + "/player.zip",
		    plugin: Loc.plugin,
		    onComplete : function(downloader) {
				this.createXaml(downloader);
				this.initialize();
				this.begin();
			}.bind(this)
		});
	},
	
	createXaml : function(downloader) {
		if (this.stop) { return; }
		this.playerXaml = Loc.plugin.content.createFromXaml(downloader.getResponseText('player.xaml'), true);
		this.controlsXaml = Loc.plugin.content.createFromXaml(downloader.getResponseText('controls.xaml'), true);
		this.playerXaml.findName('controlsHolder').children.add(this.controlsXaml);
		this.playerXaml['Canvas.Top'] = this.params.top || 0;
		this.playerXaml['Canvas.Left'] = this.params.left || 0;
		this.playerXaml['Canvas.ZIndex'] = this.params.zIndex || 1;
		this.parent.children.add(this.playerXaml);
	},
	
	initialize : function() {
		if (this.stop) { return; }
		if (!this.playerXaml) { return; }
		
		// get elements
		this.media = this.playerXaml.findName('media');
		this.media.autoplay = false;
		this.title = this.playerXaml.findName('title');
		this.subtitle = this.playerXaml.findName('title');
		this.signatureImage = this.playerXaml.findName('signature');
		this.transcript = this.playerXaml.findName('transcript');
		// this.transcriptText = this.playerXaml.findName('transcription_text');
		this.ccText = this.playerXaml.findName('ccText');
		this.ccTextBG = this.playerXaml.findName('ccTextBG');
		this.overlayImage = this.playerXaml.findName('overlay');
		this.playHit = this.playerXaml.findName('playHit');
		
		// controls
		this.playButton = new Loc.ControlButton('playButton', this.controlsXaml.findName('playButton'), this.play.bind(this));
		this.rewindButton = new Loc.ControlButton('rewindButton', this.controlsXaml.findName('rewindButton'), this.rewind.bind(this));
		this.scrubBar = new Loc.ScrubBar(this.controlsXaml.findName('scrubBar'), this.setPosition.bind(this));
		this.volume = new Loc.Volume(this.controlsXaml.findName('volume'), 5, this.setVolume.bind(this));
		this.durationText = this.controlsXaml.findName('durationText');
		this.ccButton = new Loc.ControlButton('ccButton', this.controlsXaml.findName('ccButton'), this.toggleCC.bind(this));
		this.transcriptButton = new Loc.ControlButton('transcriptButton', this.controlsXaml.findName('transcriptButton'), this.toggleTranscript.bind(this));
		this.transcriptClose = new Loc.ControlButton('transcriptClose', this.playerXaml.findName('transcriptClose'), this.toggleTranscript.bind(this));
		this.ccBtnImage = this.controlsXaml.findName('ccButton_image');
		
		if (this.transcript && this.params.transcript) {
			this.transcriptText = new Loc.textArea({ parent: this.transcript, left: 15, top: 20, content: this.params.transcript, height: 240 });
		}

		// set up events
		this.media.addEventListener('MediaOpened', this.onMediaOpened.bind(this));
		this.media.addEventListener('MediaEnded', this.onMediaEnded.bind(this));
		this.media.addEventListener('MediaFailed', this.onMediaFailed.bind(this));
		this.media.addEventListener('Loaded', this.onMediaLoaded.bind(this));
		this.media.addEventListener('BufferingProgressChanged', this.onBufferingProgressChanged.bind(this));
		this.media.addEventListener('CurrentStateChanged', this.onCurrentStateChanged.bind(this));
		this.media.addEventListener('DownloadProgressChanged', this.onDownloadProgressChanged.bind(this));
		this.media.addEventListener('MarkerReached', this.onMarkerReached.bind(this));
		
		if (this.playHit) {
			this.playHit.cursor = 'Hand';
			this.playHit.addEventListener('MouseLeftButtonDown', this.otherplay.bind(this));
		}
		
		if (this.params.hidden) {
			this.hide();
		} else {
			this.hidden = false;
		}
		if (this.overlayImage) {
			if (this.params.overlay) {
				this.overlayImage.source = this.params.overlay;
			} else {
				this.overlayImage.visibility = 'collapsed';
			}
		}
		
		if (this.params.onLoad) {
			this.params.onLoad();
		}
	},
	
	begin : function() {
		if (this.source) {
			this.media.source = this.source;
		}
	},
	
	setSource : function(source) {
		this.source = source;
		this.clearTimer();
		this.playButton.deselect();
		this.startTimer();
		this.cc = false;
		this.ccBtnImage.Source = "cmn/img/btn_cc_off.png";
		this.ccText.Text = "";
		this.ccTextBG.Visibility = "Collapsed";
		if (this.params.overlay) {
			this.overlayImage.visibility = 'visible';
		}
		this.begin();
	},
	
	/****************************
	*		Media Events		*
	****************************/
	
	onMarkerReached : function(sender, args) {
		var myMarker = args.marker;
		
		// save the caption for next round
		if (myMarker.type == "caption") {
			this.saveCC = myMarker.Text;
			
			if (this.cc) {
				this.ccText.Text = this.saveCC;
				this.ccTextBG.Visibility = "Visible";
			}
		}
	},
	
	onMediaOpened : function() {
		this.mediaOpened = true;	
		this.playButton.enable();
		this.rewindButton.enable();
		this.scrubBar.enable();
		this.volume.enable();
		try {
			this.ccButton.enable();
		} catch(e) {}
		try {
			this.transcriptButton.enable();
			this.transcriptClose.enable();
		} catch(e) {}
	},
	
	onMediaEnded : function() {
		if (this.overlayImage) {
			this.overlayImage.visibility = 'visible';
		}
		this.clearTimer();
		this.playButton.deselect();
		this.rewind();
	},
	
	onMediaFailed : function() {
		this.clearTimer();
		this.playButton.deselect();
		this.rewind();
	},
	
	onMediaLoaded : function() {
		this.mediaLoaded = true;
	},
	
	onBufferingProgressChanged : function() {
		// this.scrubBar.updateBuffer(this.media.bufferingProgress);
	},
	
	onCurrentStateChanged : function() {
		// console.log('current state: ' + this.media.currentState);
	},
	
	onDownloadProgressChanged : function() {
		this.scrubBar.updateBuffer(this.media.downloadProgress);
	},
	
	startTimer : function() {
		if (this.updateTimerId) {
			clearInterval(this.updateTimerId);
			this.updateTimerId = null;
		}
		this.updateTimerId = setInterval(this.updateTimer.bind(this), 100);
	},
	
	clearTimer : function() {
		if (this.updateTimerId) {
			clearInterval(this.updateTimerId);
		}
		this.updateTimerId = null;
	},
	
	updateTimer : function() {
		var time = Math.ceil(this.media.position.seconds),
			minutes = Math.floor(time / 60),
			seconds = time % 60;
		if (minutes < 10) {
			minutes = '0' + minutes;
		}
		if (seconds < 10) {
			seconds = '0' + seconds;
		}
		this.durationText.text = minutes + ':' + seconds;
		this.scrubBar.updatePosition(this.media.position, this.media.naturalDuration);
		// check for the end since mediaEnded doesnt work
		if (time / this.media.naturalDuration > .98) {
			this.onMediaEnded();
		} 
	},
	
	/****************************
	*		Mouse Events		*
	****************************/
	otherplay : function(){
		
		if (this.media.currentState == 'Playing') {
			this.media.pause();
			this.playButton.deselect();
			this.clearTimer();
		} else {
			if (this.overlayImage) {
				this.overlayImage.visibility = 'collapsed';
			}
			this.media.play();
			this.playButton.select();
			this.startTimer();
		}
	},
	
	play : function() {
		if (this.media.currentState == 'Playing') {
			this.media.pause();
			this.playButton.select();
			this.clearTimer();
		} else {
			if (this.overlayImage) {
				this.overlayImage.visibility = 'collapsed';
			}
			this.media.play();
			this.playButton.deselect();
			this.startTimer();
		}
	},
	
	pause : function() {
		this.media.pause();
		this.playButton.select();
	},	
	
	rewind : function() {
		if (this.media.canSeek) {
			var temp = this.media.position;
			temp.seconds = 0;
			this.media.position = temp;
			this.scrubBar.goToBeginning(0);
		}
	},
	
	toggleCC : function() {
		this.cc = this.cc == false ? true : false;
		
		if (!this.cc) {
			this.ccBtnImage.Source = "cmn/img/btn_cc_off.png";
			this.ccText.Text = "";
			this.ccTextBG.Visibility = "Collapsed";
		} else {
			this.ccBtnImage.Source = "cmn/img/btn_cc_on.png";
			this.ccTextBG.Visibility = "Visible";
			this.ccText.Text = this.saveCC; // showprevious caption
			
		}
	},
	
	toggleTranscript : function() {
		this.transcript.visibility = this.transcript.visibility == 'Collapsed' ? 'visible' : 'collapsed';
	},
	
	setVolume : function(level) {
		if (level == 'undefined') {
			level = .5;
		}
		this.media.volume = level;
	},
	
	setPosition : function(ratio) {
		var temp = this.media.position,
			newTime = this.media.naturalDuration.seconds * ratio;
		temp.seconds = newTime;
		this.media.position = temp;
	},
	
	show : function() {		
		this.playerXaml.visibility = 'visible';
		this.hidden = false;
	},
	
	hide : function() {
		this.pause();
		this.playerXaml.visibility = 'collapsed';
		this.hidden = true;
	},
	
	unload : function() {
		this.clearTimer();
	}
}

Loc.ControlButton = function(id, xaml, callback) {
	this.id = id;
	if (! xaml) {
		return false;
	}
	this.xaml = xaml;
	this.callback = callback;
	this.initEvents();
	this.disable();
}
Loc.ControlButton.prototype = {
	initEvents : function() {
		// hit area and mouse events
		this.hit = this.xaml.findName(this.id + '_hit');
		this.hit.cursor = 'Hand';
		this.hit.addEventListener('MouseEnter', this.onOver.bind(this));
		this.hit.addEventListener('MouseLeave', this.onOut.bind(this));
		this.hit.addEventListener('MouseLeftButtonDown', this.onClick.bind(this));
		
		// states
		this.overState = this.xaml.findName(this.id + '_over');
 		this.selectedState = this.xaml.findName(this.id + '_selected');
		this.nonselectedState = this.xaml.findName(this.id + '_nonselected');
	},
	
	onOver : function() {
		this.overState.visibility = 'visible';
	},
	
	onOut : function() {
		this.overState.visibility = 'collapsed';
	},
	
	onClick : function() {
		this.callback();
		if (this.selectedState) {
			if (this.selected) {
				this.selected = false;
				this.selectedState.visibility = 'collapsed';
			} else {
				this.selected = true;
				this.selectedState.visibility = 'visible';
			}
		}
	},
	
	enable : function() {
		this.disabled = false;
		this.hit.visibility = 'visible';
	},
	
	disable : function() {
		this.disabled = true;
		this.hit.visibility = 'collapsed';
	},
	
	select : function() {
		this.selected = true;
		if (this.selectedState) {
			this.selectedState.visibility = 'visible';
		}
	},
	
	deselect : function() {
		this.selected = false;
		if (this.selectedState) {
			this.selectedState.visibility = 'collapsed';
		}
	}
}

Loc.ScrubBar = function(xaml, callback) {
	this.xaml = xaml;
	this.callback = callback;
	this.getElements();
	this.initEvents();
	this.disable();
}
Loc.ScrubBar.prototype = {
	getElements : function() {
		this.track = this.xaml.findName('track');
		this.downloadBar = this.xaml.findName('downloadBar');
		this.scrubber = this.xaml.findName('scrubber');
		this.hit = this.xaml.findName('scrubberHit');
	},
	
	initEvents : function() {
		this.hit.cursor = 'Hand';
		this.hit.addEventListener('MouseLeftButtonDown', this.onClick.bind(this));
		this.hit.addEventListener('MouseLeftButtonUp', this.onRelease.bind(this));
		this.hit.addEventListener('MouseMove', this.onDrag.bind(this));
	},
	
	updateBuffer : function(amount) {
		this.downloadBar.width = this.track.width * amount;
	},
	
	updatePosition : function(current, total) {
		if (this.captured) {
			return;
		}
		try {
			this.scrubber['Canvas.Left'] = (this.track.width - this.scrubber.width) * (current.seconds / total.seconds);
		} catch(e) {}
	},
	
	goToBeginning : function(position) {
		this.scrubber['Canvas.Left'] = 0;
	},
	
	/************************
	*	Dragging Callbacks	*
	************************/
	onClick : function(sender, e) {
		this.captured = true;
		sender.captureMouse();
		this.beginDragX = e.getPosition(null).x;
		this.hit.width = 70;
		this.hit['Canvas.Left'] = -1 * (70 - this.scrubber.width) / 2;
	},
	
	onRelease : function(sender) {
		this.captured = false;
		sender.releaseMouseCapture();
		this.hit.width = this.scrubber.width;
		this.hit['Canvas.Left'] = 0;
		this.respond();
	},
	
	onDrag : function(a, e) {
		if (this.captured) {
			var currentX = e.getPosition(null).x,
				deltaX = currentX - this.beginDragX,
				newX = this.scrubber['Canvas.Left'] + deltaX;
			newX = newX < 0 ? 0 : newX;
			newX = newX > this.track.width - this.scrubber.width ? this.track.width - this.scrubber.width : newX;
			this.scrubber['Canvas.Left'] = newX;
			this.beginDragX = currentX;
		}
	},
	
	enable : function() {
		this.disabled = false;
		this.hit.visibility = 'visible';
	},
	
	disable : function() {
		this.disabled = true;
		this.hit.visibility = 'collapsed';
	},
	
	respond : function() {
		var position = this.scrubber['Canvas.Left'] / (this.track.width - this.scrubber.width);
		this.callback(position);
	}
}

Loc.Volume = function(xaml, steps, callback) {
	this.xaml = xaml;
	this.steps = steps;
	this.callback = callback;
	this.getElements();
	this.initEvents();
	this.level = 3;
	this.update();
	this.disable();
}
Loc.Volume.prototype = {
	getElements : function() {
		this.images = [];
		for (var i = 0; i <= this.steps; i++) {
			this.images.push(this.xaml.findName('volume_' + i));
			if (this.xaml.findName('volume_' + i).visibility != 'collapsed') {
				this.level = i;
			}
		}
		this.hit = this.xaml.findName('volume_hit');
	},
	
	initEvents : function() {
		this.hit.cursor = 'Hand';
		this.hit.addEventListener('MouseLeftButtonDown', this.onClick.bind(this));
		this.hit.addEventListener('MouseLeftButtonUp', this.onRelease.bind(this));
		this.hit.addEventListener('MouseMove', this.onMove.bind(this));
	},
	
	onClick : function(sender, event) {
		this.capture = true;
		this.hit.captureMouse();
		this.translate(event.getPosition(this.hit).x);
		this.update();
	},
	
	onRelease : function() {
		this.capture = false;
		this.hit.releaseMouseCapture();
	},
	
	onMove : function(sender, event) {
		if (this.capture) {
			this.translate(event.getPosition(this.hit).x);
			this.update();
		}
	},
	
	translate : function(pixels) {
		this.level = Math.round(pixels / this.hit.width * this.steps);
		this.level = this.level < 0 ? 0 : this.level;
		this.level = this.level > this.steps ? this.steps : this.level;
	},
	
	update : function() {
		for (var i = 0, image = null; image = this.images[i]; i++) {
			this.images[i].visibility = i == this.level ? 'visible' : 'collapsed';
		}
		this.callback(this.level / this.steps);
	},
	
	enable : function() {
		this.disabled = false;
		this.hit.visibility = 'visible';
	},
	
	disable : function() {
		this.disabled = true;
		this.hit.visibility = 'collapsed';
	}
}