/**
 * Sets up and displays the controlbar.
 * 
 * @author Joey Line <joey.line@skiclubz.com>
 */

(function($) {
	zPlayer.prototype.controlbar = function() {
		var margin = parseInt(this.skin.controlbar.settings.margin, 10);
		var controlbar = {
			elements: {},
			element: undefined,
			margin: margin,
			leftmargin: margin,
			rightmargin: margin,
			topmargin: margin + this.skin.controlbar.elements.timeSliderRail.height
		};
		this.display.controlbar = controlbar;
		
		// the scrubber
		var scrubber = $('<div class="scrubber"></div>')
			.css('height', this.skin.controlbar.elements.timeSliderRail.height)
			.css('width', '100%');
		
		// and the button bar
		var buttonbar = $('<div class="controls"></div>')
			.css('background', 'url(' + this.skin.controlbar.elements.background.src + ') repeat-x center left')
			.css('height', this.skin.controlbar.elements.background.height)
			.css('width', '100%');

		// draw the controlbar
		this.display.controlbar.height = this.skin.controlbar.elements.background.height + this.skin.controlbar.elements.timeSliderRail.height;
		this.display.controlbar.element = $('<div id="' + this.id + '_controlbar" class="controlbar"></div>')
			.css('position', 'relative')
			.css('top', '-6px')
			.css('height', this.display.controlbar.height)
			.css('width', '100%')
			.css('display', 'none')
			.append(scrubber)
			.append(buttonbar)
			.appendTo(this.container);

		// start building elements!
		// time scrubber first...
		this.controlbar.buildElement(this, 'timeSliderRail', 'top', false);
		this.display.controlbar.elements.timeSliderRail.css('width', '100%');
		this.controlbar.buildElement(this, 'timeSliderBuffer', 'top', false);
		this.controlbar.buildElement(this, 'timeSliderProgress', 'top', false);
		this.controlbar.buildElement(this, 'timeSliderThumb', 'top', false);

		// then the controls
		// west side
		this.controlbar.buildElement(this, 'capLeft', 'left', true);
		this.controlbar.buildElement(this, 'playButton', 'left', false);
		this.controlbar.buildElement(this, 'pauseButton', 'left', true);
		this.controlbar.buildElement(this, 'stopButton', 'left', true);
		// this.controlbar.buildElement(this, 'divider1', 'left', true);
		
		// east side
		this.controlbar.buildElement(this, 'capRight', 'right', true);
		// no volume/mute on iPad!
		if(!zPlayer.utils.isiPad()) {
			this.controlbar.buildElement(this, 'volumeSliderRail', 'right', false);
			this.controlbar.buildElement(this, 'volumeSliderBuffer', 'right', false);
			this.controlbar.buildElement(this, 'volumeSliderProgress', 'right', true);
			this.controlbar.buildElement(this, 'muteButton', 'right', false);
			this.controlbar.buildElement(this, 'unmuteButton', 'right', true);
			this.controlbar.buildElement(this, 'divider3', 'right', true);
		}
		
		if(this.config.enableFullscreen) {
			this.controlbar.buildElement(this, 'fullscreenButton', 'right', false)
			this.controlbar.buildElement(this, 'normalscreenButton', 'right', true);
		}
		
		this.controlbar.buildElement(this, 'divider2', 'right', true);
		this.controlbar.buildElement(this, 'durationText', 'right', true);
		this.controlbar.buildElement(this, 'timeTextDivider', 'right', true);
		this.controlbar.buildElement(this, 'elapsedText', 'right', true);
		
		var player = this;
		// set css cursor & build event handlers for buttons
		this.display.controlbar.elements.playButton.mouseup(function(e) {
			zPlayer.utils.log('playButton clicked', player, player.domelement.readyState);
			e.preventDefault();
			player.domelement.play();
		});
		this.display.controlbar.elements.pauseButton.mouseup(function(e) {
			zPlayer.utils.log('pauseButton clicked', player, player.domelement.readyState);
			e.preventDefault();
			player.domelement.pause();
		});
		this.display.controlbar.elements.stopButton.mouseup(function(e) {
			e.preventDefault();
			player.domelement.pause();
			player.domelement.currentTime = 0;
		});
		if(!zPlayer.utils.isiPad()) {
			this.display.controlbar.elements.muteButton.mouseup(function(e) {
				e.preventDefault();
				player.domelement.muted = true;
			});
			
			this.display.controlbar.elements.unmuteButton.mouseup(function(e) {
				e.preventDefault();
				player.domelement.muted = false;
			});
			
			var volumeScrubber = this.display.controlbar.elements.volumeSliderRail
				.add(this.display.controlbar.elements.volumeSliderBuffer)
				.add(this.display.controlbar.elements.volumeSliderProgress);
			
			volumeScrubber.click(function(evt) {
				var pos = (evt.pageX - player.display.controlbar.elements.volumeSliderRail.offset().left) /
					player.display.controlbar.elements.volumeSliderRail.width();
				player.domelement.volume = pos;
			});
		}
		
		if(this.config.enableFullscreen) {
			this.display.controlbar.elements.fullscreenButton.mouseup(function(e) {
				e.preventDefault();
				
				$(document).trigger('fullscreen.zplayer', [true]);
			});
			this.display.controlbar.elements.normalscreenButton.mouseup(function(e) {
				e.preventDefault();
				
				$(document).trigger('fullscreen.zplayer', [false]);
			});
		}
		
		// make the scrubber clickable
		scrubber.mousedown(function(evt) {
			evt.preventDefault();
			zPlayer.utils.log('scrubber mousedown', evt.pageX);
			
			// FIXME: This makes it so that users cannot skip to unbuffered parts of the video.
			//	If and when browsers decide to properly implement the buffered attribute, this
			//	should be removed.
			if((evt.pageX - player.display.controlbar.elements.timeSliderRail.offset().left) /
				player.display.controlbar.elements.timeSliderRail.width() * player.domelement.duration < player.endBuffer) {
				player.display.controlbar.mousedown = true;
			}
		});
		
		scrubber.mousemove(function(evt) {
			evt.preventDefault();
			if(player.display.controlbar.mousedown) {
				zPlayer.utils.log('scrubber mousemove', evt.pageX);
				
				if(!player.domelement.paused) {
					player.domelement.pause();
					player.display.controlbar.playOnMouseup = true;
				}
				
				// to just move the timeSliderThumb with the mouse movements and not the video 
				// itself, uncomment the following two lines and comment the ones below that.
				// var left = evt.pageX - player.display.controlbar.elements.timeSliderRail.offset().left;
				// player.display.controlbar.elements.timeSliderThumb.css('left', left);
				var pos = (evt.pageX - player.display.controlbar.elements.timeSliderRail.offset().left) /
					player.display.controlbar.elements.timeSliderRail.width() * player.domelement.duration;
				
				player.domelement.currentTime = pos;
			}
		});
		
		scrubber.mouseup(function(evt) {
			evt.preventDefault();
			zPlayer.utils.log('scrubber mouseup', evt.pageX);
			
			if(player.display.controlbar.mousedown) {
				player.display.controlbar.mousedown = false;
				var pos = (evt.pageX - player.display.controlbar.elements.timeSliderRail.offset().left) /
					player.display.controlbar.elements.timeSliderRail.width() * player.domelement.duration;
				
				player.domelement.currentTime = pos;
				
				if(player.display.controlbar.playOnMouseup) {
					player.domelement.play();
					player.display.controlbar.playOnMouseup = false;
				}
			}
		});
		
		
		// add event listeners for HTML5 media events
		this.domelement.addEventListener('play', this.controlbar.stateHandler(this), false);
		this.domelement.addEventListener('pause', this.controlbar.stateHandler(this), false);
		this.domelement.addEventListener('progress', this.controlbar.bufferHandler(this), false);
		this.domelement.addEventListener('timeupdate', this.controlbar.timeHandler(this), false);
		this.domelement.addEventListener('ended', this.controlbar.endedHandler(this), false);
		this.domelement.addEventListener('volumechange', this.controlbar.volumeHandler(this), false);
		
		// trigger event handlers so the controlbar looks pretty at load time
		// FIXME: This is a TERRIBLE syntax for calling these functions!
		(this.controlbar.stateHandler(this))({type: this.domelement.autoplay ? 'play' : 'pause'});
		(this.controlbar.bufferHandler(this))({});
		(this.controlbar.timeHandler(this))({});
		(this.controlbar.volumeHandler(this))({});
	};
	
	zPlayer.prototype.controlbar.stateHandler = function(player) {
		return function(e) {
			zPlayer.utils.log('stateHandler', e.type);
			if(e.type=='play') {
				player.display.controlbar.elements.playButton.css('display', 'none');
				player.display.controlbar.elements.pauseButton.css('display', 'block');
			} else {
				player.display.controlbar.elements.pauseButton.css('display', 'none');
				player.display.controlbar.elements.playButton.css('display', 'block');
			}
		};
	};
	
	zPlayer.prototype.controlbar.bufferHandler = function(player) {
		return function(e) {
			if(player.bufferTimeout)
				window.clearTimeout(player.bufferTimeout);
			
			// zPlayer.utils.log('bufferHandler ', player.domelement.buffered, "time ranges; duration is: ", player.domelement.duration);
			// TODO: this needs to be fired by the time handler until the video is fully buffered
			
			var left = 0,
				width = 0;
			if(!zPlayer.utils.isNull(player.domelement.duration) && player.domelement.duration > 0) {
				var startBuffer = 0,
					endBuffer = 0,
					buffered = player.domelement.buffered;
				// NOTE: Firefox 3.6.x doesn't support the buffered attribute
				if(buffered) {
					// FIXME: This smooths over the fact that Chrome and Safari currently don't
					//	report non-contiguous buffered regions and instead just reports that 
					//	they have buffered from the beginning of the video to the last buffered
					//	byte, which may include some unbuffered area between
					for(var i=0;i<buffered.length;i++) {
						var start = buffered.start(i),
							end = buffered.end(i);
						if(startBuffer == 0 || startBuffer > start) {
							startBuffer = start;
						}
						
						if(endBuffer = 0 || endBuffer < end) {
							endBuffer = end;
						}
					}
					var playerWidth = $(player.domelement).width();
					// zPlayer.utils.log('video buffered from ', startBuffer, 'seconds to ', endBuffer, 'seconds of ', player.domelement.duration, 'seconds');
					left = playerWidth * (startBuffer / player.domelement.duration) + 'px';
					width = playerWidth * (endBuffer / player.domelement.duration) + 'px';
					
					player.endBuffer = endBuffer;
					
					if(!player.endBuffer || player.endBuffer < player.domelement.duration) {
						player.bufferTimeout = window.setTimeout(function() {
							(player.controlbar.bufferHandler(player))({});
						}, 1000);
					}
				}
				
				player.display.controlbar.elements.timeSliderBuffer.css('left', left);
				player.display.controlbar.elements.timeSliderBuffer.css('width', width);
			}
		};
	};
	
	zPlayer.prototype.controlbar.timeHandler = function(player) {
		return function(e) {
			// zPlayer.utils.log('timeHandler', player.domelement.currentTime, player.domelement.duration);
			if (!zPlayer.utils.isNull(player.domelement.duration) && player.domelement.duration > 0) {
				var percentage = 100 * player.domelement.currentTime / player.domelement.duration;
			
				// update the scrubber
				player.display.controlbar.elements.timeSliderProgress.css('width', percentage + '%');
				
				// only update the thumb when the user is not currently seeking [dragging the mouse on
				// the scrubber]
				if (zPlayer.utils.isNull(player.display.controlbar.mousedown) || !player.display.controlbar.mousedown) {
					player.display.controlbar.elements.timeSliderThumb.css('left', 
						((percentage * $(player.display.controlbar.element).width() / 100) - 
						(player.skin.controlbar.elements.timeSliderThumb.width / 2)) + 'px');
				}
				
				player.display.controlbar.elements.elapsedText.html(zPlayer.utils.formatTime(player.domelement.currentTime, 2));
				player.display.controlbar.elements.durationText.html(zPlayer.utils.formatTime(player.domelement.duration, 2));
				
				if(player.endBuffer < player.domelement.duration)
					(player.controlbar.bufferHandler(player))({});
			}
		};
	};
	
	zPlayer.prototype.controlbar.volumeHandler = function(player) {
		if(zPlayer.utils.isiPhone() || zPlayer.utils.isiPad())
			return function() {};
		
		return function(e) {
			if(this.muted) {
				// hide mute button
				player.display.controlbar.elements.muteButton.css('display', 'none');
				player.display.controlbar.elements.unmuteButton.css('display', 'block');
				
				player.muted = true;
				
				// hide volumeSliderProgress so it looks like the volume's down to 0
				player.display.controlbar.elements.volumeSliderProgress.css('display', 'none');
			} else {
				if(player.muted || zPlayer.utils.isNull(player.muted)) {
					player.display.controlbar.elements.unmuteButton.css('display', 'none');
					player.display.controlbar.elements.muteButton.css('display', 'block');
					player.muted = false;
					
					// show volume slider again
					player.display.controlbar.elements.volumeSliderProgress.css('display', 'block');
				} else {
					// volume itself was changed, update volume slider
					var width = Math.round(player.display.controlbar.elements.volumeSliderRail.width() *
						player.domelement.volume);
					player.display.controlbar.elements.volumeSliderProgress.css('width', width + 'px');
					player.display.controlbar.elements.volumeSliderProgress.css('right',
						parseInt(player.display.controlbar.elements.volumeSliderRail.css('right').replace('px', ''), 10) +
						player.display.controlbar.elements.volumeSliderRail.width() - width + 'px');
				}
			}
		};
	};
	
	zPlayer.prototype.controlbar.endedHandler = function(player) {
		return function(e) {
			player.domelement.currentTime = 0;
			player.domelement.pause();
		};
	};
	
	zPlayer.prototype.controlbar.resizeHandler = function(player, fullscreen) {
		if(fullscreen) {
			// show normalscreenButton, hide fullscreenButton
			player.display.controlbar.elements.fullscreenButton.css('display', 'none');
			player.display.controlbar.elements.normalscreenButton.css('display', 'block');
			
			// TODO: make it disappear when the video is playing and the mouse is not moving
			player.display.controlbar.element.css('position', 'absolute')
				.css('left', $(window).width() / 2 - player.display.controlbar.element.width() / 2 + 'px')
				.css('top', $(player.domelement).height() - player.display.controlbar.element.height() + 'px');
		} else {
			if(player.config.enableFullscreen) {
				// show fullscreenButton, hide normalscreenButton
				player.display.controlbar.elements.normalscreenButton.css('display', 'none');
				player.display.controlbar.elements.fullscreenButton.css('display', 'block');
			}
			
			player.display.controlbar.element.css('position', 'relative')
				.css('left', '')
				.css('top', '-6px');
		}
		
		(player.controlbar.bufferHandler(player))({});
		(player.controlbar.timeHandler(player))({});
	};
	
	// position: left, right, or top
	zPlayer.prototype.controlbar.buildElement = function(player, name, position, offset) {
		zPlayer.utils.log('buildElement', name, position, player.display.controlbar[position + "margin"], offset, player.id);
		
		var id = player.id + '_' + name,
			element = $('<div id="' + id + '"></div>');
		if(position=='top') {
			element.css('z-index', 99)
				.css('top', '0')
				.css('height', player.skin.controlbar.elements[name].height)
				.appendTo('#' + player.id + '_controlbar .scrubber');
		} else {
			element.css('top', player.display.controlbar.topmargin + 'px')
				.css('z-index', 89)
				.css('height', player.skin.controlbar.elements.background.height)
				.appendTo('#' + player.id + '_controlbar .controls');
		}
		element.css('position', 'absolute');
		
		if (name.indexOf('Text') > 0) {
			element.html('0:00.00')
				.css('font', player.config.fontSize + 'px/' + (player.skin.controlbar.elements.background.height + 1) + 'px Arial,sans-serif')
				.css('text-align', 'center')
				.css('cursor', 'default')
				.css('color', player.skin.settings.frontcolor);
				// .css('font-weight', 'bold');
			
			if(typeof $.textMetrics == 'function') {
				// if jQuery.textMetrics is around, use that to get the dimensions
				var metrics = $.textMetrics(element),
					width = metrics.width + 5,
					height = metrics.height + 5;
			} else {
				// estimate the dimensions
				// FIXME: Where did this number come from!? Is this a good way to estimate size in
				//	the absense of jQuery.textMetrics?
				var width = 14 + 3 * player.config.fontSize,
					height = player.config.fontSize + 2;				
			}
		} else if (name.indexOf('divider') === 0) {
			element.css('background', 'url(' + player.skin.controlbar.elements.divider.src + ') repeat-x center left');
			var width = player.skin.controlbar.elements.divider.width,
				height = player.skin.controlbar.elements.divider.height;
		} else {
			element.css('background', 'url(' + player.skin.controlbar.elements[name].src + ') repeat-x center left');
			var width = player.skin.controlbar.elements[name].width,
				height = player.skin.controlbar.elements[name].height;
			
			if(name.indexOf('cap')!==0) {
				element.css('cursor', 'pointer');
			}
		}
		
		if (name.indexOf('timeTextDivider') === 0) {
			element.html('/');
			width = player.config.fontSize;
		}
		
		if (position == 'left') {
			element.css(position, player.display.controlbar.leftmargin);
			if (offset) {
				player.display.controlbar.leftmargin += width;
			}
		} else if (position == 'right') {
			element.css(position, player.display.controlbar.rightmargin);
			if (offset) {
				player.display.controlbar.rightmargin += width;
			}
		} else if (position == 'top') {
			
		}
		
		element.css('width', width);
		player.display.controlbar.elements[name] = element;
		zPlayer.utils.log(name + ' built!', player, player.id);
		
		return element;
	};
	
	zPlayer.prototype.controlbar.display = function(player) {
		player.display.controlbar.element.css('display', '');
		$(document).trigger('fullscreen.zplayer', [false]);
	}
})(jQuery);

