/**
 * flowplayer.controls 3.0.2. Flowplayer JavaScript plugin.
 * 
 * This file is part of Flowplayer, http://flowplayer.org
 *
 * Author: Tero Piirainen, <info@flowplayer.org>
 * Copyright (c) 2008 Flowplayer Ltd
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * SEE: http://www.opensource.org/licenses
 * 
 * Date: 2008-11-25 11:29:03 -0500 (Tue, 25 Nov 2008)
 * Revision: 1424
 */ 
$f.addPlugin("controls", function(wrap, options) {
	
//{{{ private functions
	
	function fixE(e) {
		if (typeof e == 'undefined') { e = window.event; }
		if (typeof e.layerX == 'undefined') { e.layerX = e.offsetX; }
		if (typeof e.layerY == 'undefined') { e.layerY = e.offsetY; }
		return e;
	}
	
	function w(e) {
		return e.clientWidth;
	}
	
	function offset(e) {
		return e.offsetLeft;
	}
	
	function blockTextSelection(){
		document.body.focus();
		document.onselectstart = function () { return false; };
	}
	
	function unblockTextSelection(){
		document.onselectstart = function () { return true; };
	}
	
	// Return the relative horizonal position of an event as a value from 0-1
	function getRelativePosition(x, relativeElement){
		return Math.max(0, Math.min(1, (x - _V_.findPosX(relativeElement)) / relativeElement.offsetWidth));
	}
	
	function findPosX(obj) {
		var curleft = obj.offsetLeft;
		while(obj = obj.offsetParent) {
			curleft += obj.offsetLeft;
		}
		return curleft;
	}
	
	function getControlsPadding(){
		return findPosX(this.playControl) - findPosX(this.controls);
	}
	
	
	/* a generic dragger utility for hoirzontal dragging */
	function Draggable(o, min, max, offset) {
		
		var dragging = false;
		
		function foo() { }
		
		o.onDragStart = o.onDragStart || foo;
		o.onDragEnd = o.onDragEnd || foo;
		o.onDrag = o.onDrag || foo;
		
		function move(x) {
			// must be withing [min, max]
			if (x > max) { return false; }
			if (x < min) { return false; }
			o.style.left = x + "px";
			return true;
		}
		
		function end() {
			document.onmousemove = null;
			document.onmouseup   = null;
			o.onDragEnd(parseInt(o.style.left, 10));
			dragging = false;
		}
		
		function drag(e) {
			e = fixE(e);
			var x = e.clientX - offset;
			if (move(x)) {
				dragging = true;
				o.onDrag(x);
			}
			return false;
		}
		
		o.onmousedown = function(e)  {
			e = fixE(e);
			o.onDragStart(parseInt(o.style.left, 10));
			document.onmousemove = drag;
			document.onmouseup = end;
			return false;
		};
		
		this.dragTo = function(x) {
			if (move(x)) {
				o.onDragEnd(x);
			}
		};
		
		this.setMax = function(val) {
			max = val;
		};
		
		this.isDragging = function() {
			return dragging;
		};
		
		return this;
	}

	function extend(to, from) {
		if (from) {
			for (var key in from) {
				if (key) {
					to[key] = from[key];
				}
			}
		}
	}
	
	// prefix integer with zero when nessessary
	function pad(val) {
		val = parseInt(val, 10);
		return val >= 10 ? val : "0" + val;
	}
	
	// display seconds in hh:mm:ss format
	function toTime(sec) {
		
		var h = Math.floor(sec / 3600);
		var min = Math.floor(sec / 60);
		sec = sec - (min * 60);
		
		if (h >= 1) {
			min -= h * 60;
			return pad(h) + ":" + pad(min) + ":" + pad(sec);
		}
		
		return pad(min) + ":" + pad(sec);
	}
	
	function getTime(time, duration) {
		return "<span>" + toTime(time) + "</span> <strong>" + toTime(duration) + "</strong>";
	}
	
	function merge(obj1, obj2){
		for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
		return obj1;
	}
	
	function createElement(tagName, attributes){
		return merge(document.createElement(tagName), attributes);
	}
  
//}}}
	
	
	var player = this;
	
	var opts = {
		playClass: 'vjs-play-control vjs-play',
		pauseClass: 'vjs-play-control vjs-pause',
		duration: 0,
		defaultVolume: 0.85
	};
	
	extend(opts, options);
	
	if (typeof wrap == 'string') {
		wrap = document.getElementById(wrap);
	}
	
	if (!wrap) {return;}


	// Show the controller
	function showController(){
		player.controls.style.opacity = 0.75;
		positionController();
	}
	
	// Place controller relative to the video's position
	function positionController(){
		player.controls.style.top = (wrap.offsetHeight - player.controls.offsetHeight) + "px";
		sizeProgressBar();
	}
	
	function hideController(){
		// if (this.options.controlsHiding) {
			player.controls.style.opacity = 0;
		// }
	}
	
	function showStatus(extraClass){
		player.clicktoplay.className = "status button showing";
		if (extraClass) {
			player.clicktoplay.className += " " + extraClass;
		}
		positionStatus();
	}
	
	// Place controller relative to the video's position
	function positionStatus(){
		player.clicktoplay.style.top = (wrap.offsetHeight - player.clicktoplay.offsetHeight)/2 + "px";
		player.clicktoplay.style.left = (wrap.offsetWidth - player.clicktoplay.offsetWidth)/2 + "px";
	}
	
	function hideStatus(){
		player.clicktoplay.className = "status hidden";
	}
	
	function sizeProgressBar(){
		// player.progressControl.style.width =
		// 	player.controls.offsetWidth 
		// 	- player.playControl.offsetWidth
		// 	- player.volumeControl.offsetWidth
		// 	- player.timeControl.offsetWidth
		// 	- (this.getControlsPadding() * 5) 
		// 	// - this.getControlBorderAdjustment() 
		// 	+ "px";
		// 	
		// player.progressHolder.style.width = (player.progressControl.offsetWidth - (player.timeControl.offsetWidth + 20)) + "px";
		// 
		// player.progressControl.style.width = (player.controls.offsetWidth - 125) + "px";
		// player.progressHolder.style.width = (player.progressControl.offsetWidth - 80) + "px";
		
		// updatePlayProgress();
		// updateLoadProgress();
	}
	
	// Set a new volume based on where the user clicked on the volume control
	function setVolume(newVol){
		player.setVolume(parseFloat(newVol * 100));
	}
	
	function setVolumeWithEvent(e){
		if (!e) var e = window.event;
		if (e.pageX || e.pageY) {
				posX = e.pageX;
				posY = e.pageY;
		} else if (e.clientX || e.clientY) {
			posX = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
			posY = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
		}
		
		var newVol = getRelativePosition(posX, player.volumeControl.children[0]);
		setVolume(newVol);
	}

	// Update the volume control display
	// Unique to these default controls. Uses borders to create the look of bars.
	function updateVolumeDisplay(){
		var volNum = Math.ceil(player.getVolume()/100 * 6);
		for(var i=0; i<6; i++) {
			if (i < volNum) {
				$(player.volumeDisplay.children[i]).addClass("vjs-volume-level-on");
			} else { 
				$(player.volumeDisplay.children[i]).removeClass("vjs-volume-level-on");
			}
		}
		player.volumeControl.setAttribute('aria-valuenow', player.getVolume()/100);
		player.volumeControl.setAttribute('aria-valuetext', Math.round(player.getVolume())+"%");
	}






	// inner HTML
    this.clicktoplay = createElement("div", { className: "status button showing", innerHTML: "PLAY"});
	wrap.appendChild(this.clicktoplay);

	// Create a list element to hold the different controls
	this.controls = createElement("ul", { className: "vjs-controls" });
	this.controls.setAttribute("role","toolbar");
	this.controls.setAttribute("aria-label","VIDEO PLAYER CONTROLS");
	this.controls.setAttribute("tabindex","-1");
	// Add the controls to the video's container
	wrap.appendChild(this.controls);

	// Build the play control
	this.playControl = createElement("li", { className: "vjs-play-control vjs-play", innerHTML: "<span></span>" });
	// this.playControl = createElement("li", { className: "vjs-play-control vjs-play", innerHTML: "<canvas width=\"17\" height=\"17\" ></canvas>" });
	this.playControl.setAttribute("role","button");
	this.playControl.setAttribute("aria-label","PLAY");
	this.playControl.setAttribute("tabindex","0");
	this.controls.appendChild(this.playControl);

	// Build the progress control
	this.progressControl = createElement("li", { className: "vjs-progress-control" });
	this.progressControl.setAttribute('role', 'group');
	this.controls.appendChild(this.progressControl);

	// Create a holder for the progress bars
	this.progressHolder = createElement("ul", { className: "vjs-progress-holder" });
	this.progressHolder.setAttribute('role', 'group');
	this.progressControl.appendChild(this.progressHolder);

	// Create the loading progress display
	this.loadProgress = createElement("li", { className: "vjs-load-progress" });
	this.loadProgress.setAttribute('role', 'progressbar');
	this.loadProgress.setAttribute('aria-label', 'LOAD PROGRESS');
	this.loadProgress.setAttribute('aria-valuenow', 0);
	this.loadProgress.setAttribute('aria-valuemin', 0);
	// this.loadProgress.setAttribute('aria-valuemax', this.video.duration);
	this.loadProgress.setAttribute('aria-valuetext', Math.round(this.percentLoaded)+"%");
	this.loadProgress.setAttribute('tabindex','-1');
	this.progressHolder.appendChild(this.loadProgress);

	// Create the playing progress display
	this.playProgress = createElement("li", { className: "vjs-play-progress" });
	this.playProgress.setAttribute('role', 'slider');
	this.playProgress.setAttribute('aria-label', 'SEEK BAR');
	// this.playProgress.setAttribute('aria-valuenow', this.video.currentTime);
	this.playProgress.setAttribute('aria-valuemin', 0);
	// this.playProgress.setAttribute('aria-valuemax', this.video.duration);
	// this.playProgress.setAttribute('aria-valuetext', _V_.formatTime(this.video.currentTime)+ " of " + _V_.formatTime(this.video.duration) + " elapsed" );
	this.playProgress.setAttribute('tabindex','0');
	this.progressHolder.appendChild(this.playProgress);

	// Create the play head
	this.playHead = createElement("li", { className: "vjs-play-head" });
	this.progressHolder.appendChild(this.playHead);

	// Create the progress time display (00:00 / 00:00)
	this.timeControl = createElement("li", { className: "vjs-time-control" });
	this.timeControl.setAttribute('role', 'status');
	this.timeControl.setAttribute('tabindex','-1');
	this.controls.appendChild(this.timeControl);

	// Create the current play time display
	this.currentTimeDisplay = createElement("span", { className: "vjs-current-time-display", innerHTML: "00:00" });
	this.timeControl.appendChild(this.currentTimeDisplay);

	// Add time separator
	this.timeSeparator = createElement("abbr", { innerHTML: " / " });
	this.timeSeparator.setAttribute('title', 'of');
	this.timeControl.appendChild(this.timeSeparator);

	// Create the total duration display
	this.durationDisplay = createElement("span", { className: "vjs-duration-display", innerHTML: "00:00" });
	this.timeControl.appendChild(this.durationDisplay);

	// Create the volumne control
	this.volumeControl = createElement("li", {
	  className: "vjs-volume-control",
      innerHTML: "<ul><li class=\"one\"></li><li class=\"two\"></li><li class=\"three\"></li><li class=\"four\"></li><li class=\"five\"></li><li class=\"six\"></li></ul>"
	});
	this.volumeControl.setAttribute('role', 'slider');
	this.volumeControl.setAttribute('aria-label', 'VOLUME');
	this.volumeControl.setAttribute('aria-valuemin', 0);
	this.volumeControl.setAttribute('aria-valuemax', 1);
	this.volumeControl.setAttribute('aria-valuenow', (opts.defaultVolume));
	this.volumeControl.setAttribute('aria-valuetext', Math.round((opts.defaultVolume)*100)+"%");
	this.volumeControl.setAttribute('tabindex','0');
	this.controls.appendChild(this.volumeControl);
	this.volumeDisplay = this.volumeControl.children[0];

	// // Create the fullscreen control
	this.fullscreenControl = createElement("li", {
	  className: "vjs-fullscreen-control",
	  innerHTML: "<ul><li></li><li></li><li></li><li></li></ul>"
	});
	// this.fullscreenControl.setAttribute('role', 'button');
	// this.fullscreenControl.setAttribute('aria-label', 'GO FULL SCREEN');
	// this.fullscreenControl.setAttribute('tabindex','0');
	// this.controls.appendChild(this.fullscreenControl);

	showController();
	
	// initial time
	this.timeControl.innerHTML = getTime(0, opts.duration);
	
	// get dimensions 
	var trackWidth = w(this.progressControl);
	
	// initialize draggable playhead
	var head = new Draggable(this.playHead, 0, 0, offset(wrap) + offset(this.progressControl));
	
	// track click moves playHead
	this.progressControl.onclick = function(e) {
		e = fixE(e);
		if (e.target == this.playHead) { return false; }
		head.dragTo(e.layerX);
	};
	
	this.playControl.onclick = function() {
		if (player.isLoaded()) {
			player.toggle();
		} else {
			player.play();
		}
	};
	
	// setup timer
	var timer = null;
	
	function getMax(len, total) {
		var x = parseInt(Math.min(len / total * trackWidth, trackWidth), 10);
		return isNaN(x) ? 0 : x;
	}
	
	this.onStart(function(clip) {
		
		var duration = clip.duration || 0;

		// clear previous timer
		clearInterval(timer);
		 
		// begin timer
		timer = setInterval(function()  {
			
			var status = player.getStatus();
			
			// time display
			if (status.time)  {
				player.timeControl.innerHTML = getTime(status.time, clip.duration);
			} 
			
			if (status.time === undefined) {
				clearInterval(timer);
				return;
			}
			
			// buffer width
			var x = getMax(status.bufferEnd, duration);
			player.loadProgress.style.width = x + "px";
			head.setMax(x);
			
			// progress width
			if (!player.isPaused() && !head.isDragging()) {
				x = getMax(status.time, duration);
				player.playProgress.style.width = x + "px";
				player.playHead.style.left = x + "px";
			}
			
		}, 500);
	});
	
	this.onBegin(function() {
		hideStatus();
		this.playControl.className = opts.pauseClass;
		// Set volume to 85%
		setVolume(opts.defaultVolume);
		updateVolumeDisplay();
	});
	
	// pause / resume states
	this.onPause(function() {
		showStatus();
		this.clicktoplay.innerHTML = "PLAY";
		this.playControl.className = opts.playClass;
	});
	
	this.onResume(function() {
		hideStatus();
		this.playControl.className = opts.pauseClass;
	});
	
	// clear timer when clip ends
	this.onFinish(function(clip) {
		if (clip.type == 'image') {
			showStatus();
			this.clicktoplay.innerHTML = "PLAY";
		} else {
			showStatus();
			this.clicktoplay.innerHTML = "WATCH AGAIN";
		}
		this.playControl.className = opts.playClass;
		clearInterval(timer);
	});
	
	this.onUnload(function() {
		this.timeControl.innerHTML = getTime(0, opts.duration);
	});
	
	this.playHead.onDragEnd = function(x) {
		var to = parseInt(x / trackWidth  * 100, 10) + "%";
		player.playProgress.style.width = x + "px";
		if (player.isLoaded()) {
			player.seek(to);
		}
	};
	
	this.playHead.onDrag = function(x) {
		player.playProgress.style.width = x + "px";
	};
	

	this.clicktoplay.onclick = function() {
		if (player.isLoaded()) {
			player.toggle();
		} else {
			player.play();
		}
	};
	

	// Listen for a drag on the volume control
	$(this.volumeControl).bind("mousedown", function(event){
		blockTextSelection();
		document.onmousemove = function(event) {
			setVolumeWithEvent(event);
		};
		document.onmouseup = function() {
			unblockTextSelection();
			document.onmousemove = null;
			document.onmouseup = null;
		};
	});
	
	// Listen for a release on the volume control
	// When the user stops dragging, set a new volume
	// Backup for when the user only clicks and doesn't drag
	$(this.volumeControl).bind("mouseup", function (event){
		setVolumeWithEvent(event);
	});
	
	// Listen for the mouse move the video. Used to reveal the controller.
	$(wrap).bind("mousemove", function (event){
		showController();
		clearInterval(this.mouseMoveTimeout);
		this.mouseMoveTimeout = setTimeout(function(){ hideController(); }, 4000);
	});
	// Listen for the mouse moving out of the video. Used to hide the controller.
	$(wrap).bind("mouseout", function(event){
		// Prevent flicker by making sure mouse hasn't left the video
		var parent = event.relatedTarget;
		while (parent && parent !== player && parent !== player.controls) {
			parent = parent.parentNode;
		}
		if (parent !== player && parent !== player.controls) {
			hideController();
		}
	});
	// Listen for clicks on the fullscreen button
	$(this.fullscreenControl).bind("click", function (event){
		if (!player.isFullscreen()) {
			player.toggleFullscreen();
		} else {
			player.toggleFullscreen();
		}
	});
	
	
	
	this.onVolume(function(event){
		updateVolumeDisplay();
	});
	
	
	// return player instance to enable plugin chaining
	return this;
	
});
