/*
 * JSVideo v0.1 - and experimental Javascript Video Player
 * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
 * This software is free to use for non-commercial purposes. For anything else, please contact the author.
 */


var JSVideo = (function() {

function addEvent(oElement, strEvent, fncAction) {
	if (oElement.addEventListener) { 
		oElement.addEventListener(strEvent, fncAction, false); 
	} else if (oElement.attachEvent) { 
		oElement.attachEvent(strEvent, fncAction); 
	}
}


// run through the page and initiate videos
function processVideos() {
	var aDiv = document.getElementsByTagName("div");
	for (var i=0;i<aDiv.length;i++) {
		if (aDiv[i].getAttribute("videosrc")) {
			var oVP = new JSVideo(aDiv[i]);
			if (aDiv[i].getAttribute("videoautoplay") == "true") {
				oVP.onload = function() {
					this.play();
				}
			}
			oVP.loadFile(aDiv[i].getAttribute("videosrc"));
		}
	}
}
addEvent(window, "load", processVideos);

return function(oContainer) {

	this.onload = null;
	this.onerror = null;

	var oVideoData;

	var oCanvas = oContainer.appendChild(document.createElement("div"));
	oCanvas.style.backgroundColor = "black";
	oCanvas.style.width = "320px";
	oCanvas.style.height = "240px";
	oCanvas.style.position = "relative";

	var oLogoImage = document.createElement("img");
	var oStyle = oLogoImage.style;
	oStyle.display = "none";
	oStyle.position = "absolute";
	oStyle.width = "320px";
	oStyle.height = "240px";
	oStyle.zIndex = 10;
	oStyle.padding = oStyle.borderWidth = 0;
	oCanvas.appendChild(oLogoImage);

	// we embed this awesome logo (and a few other images) using a base64 encoded data:uri
	var strLogo = "data:image/jpeg;base64,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";

	oLogoImage.src = strLogo;
	oLogoImage.style.display = "block";

	var fScale = 1;

	var bFileLoaded = false;
	var bPlaying = false;
	var bPaused = false;

	var iLastTime = -1;
	var iFrameCtr = -1;
	var bFrameSkip = true;

	var oLoading = document.createElement("div");
	oLoading.style.width = "100%";
	oLoading.style.height = "30px";
	oLoading.style.position = "absolute";
	oLoading.style.bottom = "0px";
	oLoading.style.paddingTop = "10px";
	oLoading.style.color = "white";
	oLoading.style.textAlign = "center";
	oLoading.style.display = "none";
	oLoading.style.fontFamily = "verdana";
	oLoading.style.fontSize = "12px";
	oLoading.style.zIndex = 50;
	oLoading.innerHTML = "LOADING VIDEO FILE..."
	oCanvas.appendChild(oLoading);

	// create controls
	var oControls = document.createElement("div");
	oControls.style.width = "100%";
	oControls.style.height = "30px";
	oControls.style.position = "absolute";
	oControls.style.background = "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA9JREFUeNpiYGBgaAUIMAAAigCGNg2QYwAAAABJRU5ErkJggg==)";
	oControls.style.bottom = "0px";
	oControls.style.textAlign = "center";
	oControls.style.paddingTop = "10px";
	oControls.style.zIndex = 100;
	oControls.style.display = "none";
	oCanvas.appendChild(oControls);

	// show/hide controls on mouseover/out
	addEvent(oCanvas, "mouseover", function() {
		if (bFileLoaded) oControls.style.display = "block";
	});
	addEvent(oCanvas, "mouseout", function(e) {
		oControls.style.display = "none";
	});

	// create buttons
	var oBtnStop = oControls.appendChild(document.createElement("img"));
	oBtnStop.style.padding = oBtnStop.style.borderWidth = 0;
	oBtnStop.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAYAAACaq43EAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAS9JREFUeNrslk1qwzAQhf0jYtcQg8+QK2RRss1ZcqqepdvSRa/QMwTS4MSNrekInsyQSI4jLbpoHzwsGzOfnpA9Sokokdp9fqV8ydg5W7EXYmyep4lbppBm9+yB/S3G5jm9rJbjy8pRIAXIAJ/YFbvEvYW7ZKEGeGa37BPuCb4LVoCaKTbsGhMoMCmXTLIOwAN7LyY0XL/sAmdIZ0DN69v7RxKg7eZ5DeAFHq4hvqUukTRUNWrkrn2ReRIrkTpU1dS+8G0UCy8iwMXUZvSB5ScVqnzq88uSX9I/+O+Cyfere0Bjc3gEbH/4XQS4Qw09Fyy7TBsBbkVr1HPAhGU6o8uE6oAag2u5lSexTbtHlwltiza1ngMmLM9JFDxGHAT6uYlJHF00eukx8uhzA/4RYAA+32qUpPWCZAAAAABJRU5ErkJggg==";

	var oBtnPlay = document.createElement("img");
	oBtnPlay.style.padding = oBtnPlay.style.borderWidth = 0;
	oBtnPlay.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAYAAACaq43EAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAllJREFUeNq8lk1v00AQhrv22mkSWpo2/UipEmhKEVLECaQKceulv4ELp575BT31yAVxQxRx4cYf4MKBCwoUKaJQgYBUAgTlQ22axkkTf6wZS6/REryJgwojPXI2XvudmfXOLPN9f0i21WqD0UUjdIITBq4MUwThEC4Q4PcXRdid4siv3zziPoOoSSSJFJGQ5gZiHaINbDgSOhDLVMIcooGLGeIExDWINAkLNCUH3LjRRwlriDaINPPoSfm5fNPgfLdwanaDKNOwRtSJQ6IFB5w46dd6pHqYGO2+6bhu7v2Hj2vPtl6uWa1Wif6aI2aIccxP4bvQFe9XCmvIRBh1pDWs5tLm1qubb6o7V2mYJ2aJSeIkkcbzSnHewyGOdVWaECL1+dv3a3sHB1cWCvm709lsBc/sI3MtTPW7065Khbyl+lq7Yxe331XXK9uvr3dsO4+0p6UPksVJ9V8Z1QN9v15fKVde3Kb0r3Sl+98Jh+Z6XpbSv95vjY9dODBd13elNfX/i3A6mXx66UJpFdXNUVUzflyCjDEnNzV5/3xx/gENv6KiBdXMi4paJezDUy+OqGkYX87Nn7k1NTEebKcf2E6hsBhEWEjNoKeNjY48Li0ubiRM4xMN91BCLal8xo44FLWlAvDnx8HY0Vxu5t7Z04WHUpRhze70axhckWYPHh9GPZQwzR1ayxsTmbG3aBQ1RHnUta7+IN1JSNHWli8vXUTxH8a+9CAQCDVA2JncuH1ZFbGLlw9ByELHYRjb0kGgLZ1IYvXifqm2pWOOJdVcIR173EGilO2nAAMAzaLgW9GvhTsAAAAASUVORK5CYII=";

	var oBtnPause = document.createElement("img");
	oBtnPause.style.padding = oBtnPause.style.borderWidth = 0;
	oBtnPause.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAYAAACaq43EAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWlJREFUeNrsll9OAjEQxlta5Y+I4QxegQfllbN4Ks/iq/rgFTyDERDYpdsyTb4lE5i2a2JiYpzky7LMdH6dZtuODiEobg/vK02PHsmQLOkS7/H/GOxJezwVfBdCTE1ypAbv4fH2+six6tw0oBE4JI0YvE24A1wBOhBiNqQtfgeoCLaAxilOAbeoICZcIqECcCLEfMDvUbUqgXtIFhNNn55f304DFvO7eySPNqKYFyFmBuAearpUbLB8EyXbDSaosCqSxbFrSHet2LKqJRuzCsaJmPbbsGySWTCH9xP+PpKqQowIzYH5lkqNM4Uchm0xsbJfsX/w3wenvsiQOupgjvlcIuZ4OXwH7JGwSvgrdlbnYhy7xYrgFlqz8/jU1syX2usbdjX6LuCAZdrhFpLsk4F9ImaJHI203FpoBAyOu6sfuBZXpC8se1NqBAIGb9lHUmoE6kwj4KSKc0tdszYn1/pUUK71OQMfBBgAX9GM3df/0c4AAAAASUVORK5CYII=";

	oControls.appendChild(oBtnPlay);
	oControls.appendChild(oBtnPause);

	var me = this;

	// and link them to video control functions
	addEvent(oBtnStop, "click", function() { me.stop(); });
	addEvent(oBtnPlay, "click", function() { me.play(); });
	addEvent(oBtnPause, "click", function() { me.pause(); });

	var aFrameImages = [];

	// load a video file from URL.
	this.loadFile = function(strURL) {
		oLoading.style.display = "block";
		var me = this;
		var fncLoad = function(oHTTP) {
			try {
				oVideoData = eval("(" + oHTTP.responseText + ")");
				aFrameImages = [];
				oLoading.style.display = "none";
				bFileLoaded = true;
			} catch(e) {
				if(typeof me.onerror == "function")
					me.onerror("Error parsing video data");
			}
			if (typeof me.onload == "function") me.onload();
		}
		var fncError = function() {
			if(typeof me.onerror == "function")
				me.onerror("Error loading video file");
		}
		XHR(strURL, fncLoad, fncError);
	}

	// scale the video with the factor fScale.
	this.setScale = function(fScale) {
		fScale = parseFloat(fScale);
		this._updateCanvas();
	}

	// start playback
	this.play = function() {
		if (bPlaying) {
			if (bPaused) bPaused = false;
			return;
		}
		oLogoImage.style.display = "none";
		this._updateCanvas();
		bPlaying = true;
		this._nextFrame();
	}

	// update the videocanvas when scaling/dimensions have changed
	this._updateCanvas = function() {
		oCanvas.style.width = Math.round(oVideoData.width*fScale)+"px";
		oCanvas.style.height = Math.round(oVideoData.height*fScale)+"px";
	}

	var aFrameImages;
	var oLastImage = null;

	function renderImage(oImage) {
		oImage.style.width = "320px";
		oImage.style.height = "240px";
		if (oLastImage) {
			oCanvas.replaceChild(oImage, oLastImage);
		} else {
			oCanvas.appendChild(oImage);
		}
		oLastImage = oImage;
	}

	// render next frame
	this._nextFrame = function() {
		if (!bPlaying) return;

		var iFrameRate = Math.round(1000 / oVideoData.rate);
		var iNow = new Date().getTime();
		var iLag = 0;
		var me = this;
		if (!bPaused) {
			iFrameCtr++;
			if (bFrameSkip && iLastTime > -1) {
				var iDeltaTime = iNow - iLastTime;
				iLag = iDeltaTime - iFrameRate;
				while (iLag > iFrameRate) {
					iFrameCtr++;
					iLag -= iFrameRate;
				}
			}
			if (iLag < 0) iLag = 0;
			if (iFrameCtr >= oVideoData.frames) iFrameCtr = 0;

			if (!aFrameImages[iFrameCtr]) {
				var oImage = document.createElement("img");
				var oStyle = oImage.style;
				oStyle.display = "block";
				oStyle.position = "absolute";
				oStyle.padding = 0;
				oStyle.borderWidth = 0;
				oImage.onload = function() {
					renderImage(this);
				}
				aFrameImages[iFrameCtr] = oImage;
				oImage.src = oVideoData.data.video[iFrameCtr];
			} else {
				renderImage(aFrameImages[iFrameCtr]);
			}
		}
		iLastTime = iNow;
		setTimeout(
			function() {
				me._nextFrame();
			}, iFrameRate - iLag
		)
	}

	// stop playback and rewind
	this.stop = function() {
		bPaused = false;
		bPlaying = false;
		iFrameCtr = -1;
		iLastTime = -1;
		oLogoImage.src = strLogo;
		oLogoImage.style.display = "block";
		oLogoImage.zIndex = 20;
	}

	// temporarily pause playback, resume by calling pause() or play() again
	this.pause = function() {
		bPaused = !bPaused;
	}
};



})();
