/*
* jQuery Widdio - A HTML5 video player
*
* Version: 1.0.0
*
* Copyright (c) 2010 Ron Valstar
*
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*
* description
*   - A HTML5 video player
*
* features
*	- video
*
* Usage:
*	mVideo = $("video");
*	oWiddio = mVideo.widdio({
*		 fullscreen:	true
*		,controls:				[$.widdio.SCRUB,$.widdio.MUTE,$.widdio.CENTER]
*		,controlsPosition:		$.widdio.CONTROLS_OVER
*		,controlsHeight:		mPage.css('bottom').replace('px','')
*		,size:					$.widdio.SIZE_FULLSCREENNOBARS
*		,controlsCenterPlay:	$('<div></div>').css({background:'url(css/centerPlay.png)'})
*		,controlsCenterPause:	$('<div></div>').css({background:'url(css/centerPause.png)'})
*		,controlsMuteOn:		$('<div>sound on</div>')
*		,controlsMuteOff:		$('<div>no sound</div>')
*		,overlay:				$("#overlay")
*		,playEnd:				playEnd
*	});
*
* Change default like so:
*   $.widdio.defaults.order = "desc";
*
* in this update:
*
* in last update:
*
* Todos
*   - add lots of stuff
*
*/
;(function($) {
	// private variables
	var oSettings = {};
	var ss = oSettings;
	var iW;
	var iH;
	var iVW;
	var iVH;
	//
	var bPlaying = false;
	//
	var sVideoReadyState = "";
	var iVideoReadyState = -1;
	//
	var mVideoHolder;
	var mVideo;
	var oVideo;
	var aSources;
	var oMimes = {
		ogg:	"ogv"
	};
	var iRun;
	//
	var $Window = $(window);
	var $Document = $(document);
	var $Body;
	//
	var mControls;
	var mCnScrub;
	var mControlsBar;
	var mControlsBuffer;
	//
	var mCenter;
	var iCenterFadeID = 0;
	var iCenterFadeTime = 1500;
	var mCenterPlay;
	var mCenterPause;
	//
	var mMute;
	var mMuteOn;
	var mMuteOff;
	var oToggleSound = -1;
	//
	var bFlash = false;
	//
	// default settings
	$.widdio = ww = {
		 id: "Widdio"
		,version: "1.0.0"
		,copyright: "Copyright (c) 2010 Ron Valstar"
		// constants
		,PLAYPAUSE:		"playpause"
		,SCRUB:			"scrub"
		,STOP:			"stop"
		,MUTE:			"mute"
		,VOLUME:		"volume"
		,FULLSCREEN:	"fullscreen"
		,CENTER:		"center"

		,CONTROLS_OVER:		"controlsOver"
		,CONTROLS_UNDER:	"controlsUnder"

		,SIZE_ORIGINAL:			"sizeOriginal"
		,SIZE_FIXED:			"sizeFixed"
		,SIZE_FULLSCREEN:		"sizeFullscreen"
		,SIZE_FULLSCREENNOBARS:	"sizeFullscreennobars"
	};
	// defaults
	$.extend(ww,{
		 defaults: {
			 debug:	false
			,fullscreen: false
			,width: 320
			,height: 180
			,fadeOutBeforeLoad: 0
			// controls
			,controls: [ww.SCRUB,ww.MUTE]
			,controlsPosition: ww.CONTROLS_OVER
			,controlsHeight: 10
			,size: ww.SIZE_ORIGINAL
			// controls custom elements
			,controlsCenterPlay: null
			,controlsCenterPause: null
			,controlsMuteOn: null
			,controlsMuteOff: null
			,overlay: null
			// event functions
			,playEnd: null
		}
	});
	// init
	//$(function() {
	//	//$.fn.widdio();
	//});
	// call
	$.fn.extend({
		 widdio: function(_settings) {
			trace(ww.id+" "+ww.version,true);
			//$.each($.browser, function(i, val) { trace("\t"+i+": "+val); });
			$.extend(oSettings, ww.defaults, _settings);
			//
			$Body = $('body');
			//
			// public functions
			$.extend(this,{
				 play: function(file) {
					if (file===null) {
						togglePlay(true);
					} else {
						playVideo(file);
					}
				}
				,stop: function() {
					togglePlay(false);
				}
				,toggle: function() {
					togglePlay();
				}
				,pause: function() {
					togglePlay(false);
				}
				,sound: function(o) {
					toggleSound(o);
				}
				,fullscreen: function(full) {
				}
			});
			//
			init(this); // TODO: what if this.length>1 ? (== more video players)
			//
			return this;
		}
	});
	//
	// init
	function init(m) {
		//
		bFlash = ($.browser.msie&&($.browser.version.split(".")[0]<9))===true;
		trace("Flash video: "+bFlash);
		if (!bFlash) { // proceed as planned
			mVideo = m;
//			mVideo.removeAttr("controls");
			oVideo = m.get(0);
			aSources = mVideo.find("source");
			oVideo.onError = videoError;
			oVideo.controls = false;
//			trace(oVideo);
			/* possibly handy properties functions for oVideo:

			controls		Boolean

			volume			float (0,1)
			muted			Boolean

			canPlayType()	String :: "probably" "maybe"
			load()
			play()
			pause()

			networkState	ìnt :: NETWORK_EMPTY NETWORK_IDLE NETWORK_LOADING NETWORK_NO_SOURCE

			loop			Boolean
			autoplay		Boolean
			paused			Boolean
			ended			Boolean
			preload			int

			readyState		int :: HAVE_NOTHING HAVE_METADATA HAVE_CURRENT_DATA HAVE_FUTURE_DATA HAVE_ENOUGH_DATA
			
			startTime		int
			duration		int || NaN
			currentTime		int

			seekable		[object TimeRanges]
			buffered		[object TimeRanges]
			played			[object TimeRanges]
			*/	


		} else { // or fallback to Flash
			trace("IE fallback to Flash");
			mVideo = $("#mediaPlayer");
			oVideo = mVideo.get(0);
			//// the following doesn't work for Flash's External callback 
			//var sTst = "";
			//sTst = '<object';
			//sTst += ' classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
			//sTst += ' id="MediaPlayer">';
			//sTst += '<param name="movie" value="css/MediaPlayer.swf">';
			//sTst += '<param name="wmode" value="transparent">';
			//sTst += '<param name="allowscriptaccess" value="true">';
			//sTst += '<param name="quality" value="low">';
			//sTst += '<param name="allowfullscreen" value="false">';
			//sTst += '</object>';
			//mVideo = $(sTst).insertAfter(mVideo);
			//oVideo = mVideo.get(0);
			//trace("object appended");
			//mVideo.width(200);
			//mVideo.height(200);
			//mVideo.remove(); // doet IE: unspecified error
			//$("video").remove(); // doet IE: unspecified error
		}
		mVideo.css({
			 zIndex:	"10"
		});
		mVideo.click(togglePlay);
		iRun = setInterval(run, 40);
		//
		// controls
		mControls = $("<div class=\"widdioControl\"></div>").insertAfter(mVideo);
		mControls.css({
			 top:		"-5px"
			,width:		mVideo.width()+"px"
			,height:	ss.controlsHeight+"px"
			,zIndex:	"100"
			,overflow:	"hidden"
		});
		$.each(ss.controls,function(i,el){
			switch (el) {
				case ww.PLAYPAUSE: break; // TODO: add
				case ww.SCRUB: 
					mCnScrub = $("<div class=\"scrub\"></div>").appendTo(mControls);
					mCnScrub.click(scrub);
					mCnScrub.css({
						 position:	"relative"
						,width:		"100%"
						,height:	ss.controlsHeight+"px"
					});
					mControlsBar = $("<div class=\"bar\"></div>").appendTo(mCnScrub);
					mControlsBuffer = $("<div class=\"buffer\"></div>").appendTo(mCnScrub);
					mControlsBar.css({
						 width:		"1px"
						,height:	"100%"
					});
				break;
				case ww.STOP: break; // TODO: add
				case ww.MUTE:
					mMute = $("<div class=\"mute\"></div>").appendTo(mControls).css({overflow:"hidden"}).click(toggleSound);
					if (ss.controlsMuteOn) mMuteOn = $(ss.controlsMuteOn).appendTo(mMute).addClass("on").hide();
					if (ss.controlsMuteOff) mMuteOff = $(ss.controlsMuteOff).appendTo(mMute).addClass("off");
					// TODO: else default
				 break;
				case ww.VOLUME: break; // TODO: add
				case ww.CENTER:
					mCenter = $("<div class=\"widdioCenter\"></div>").insertAfter(mVideo).css({overflow:"hidden"}).click(togglePlay);
					if (ss.controlsCenterPlay) mCenterPlay = $(ss.controlsCenterPlay).appendTo(mCenter).css({width:"100%",height:"100%"});
					if (ss.controlsCenterPause) mCenterPause = $(ss.controlsCenterPause).appendTo(mCenter).css({width:"100%",height:"100%"});
					// TODO: else default
					mCenter.css({
						 position:	"fixed"
					});
					mVideo.mouseover(function(e){
						//clearTimeout(iCenterFade);
						//mCenter.stop();
						//mCenter.fadeTo("slow", 1);
						//iCenterFade = setTimeout(function(){
						//	trace("poepjes");
						//	mCenter.fadeTo("slow", 0);
						//},5000);
					}).mouseout(function(e){
						clearTimeout(iCenterFadeID);
						mCenter.stop();
						mCenter.fadeTo("slow", 0);
					}).mousemove(function(e){
						clearTimeout(iCenterFadeID);
						mCenter.stop();
						mCenter.fadeTo("slow", 1);
						iCenterFadeID = setTimeout(function(){
							trace("poepjes");
							mCenter.fadeTo("slow", 0);
						},iCenterFadeTime);
					});
				break;
				case ww.FULLSCREEN: break; // TODO: add
			}
			mControls.find(">*").css("float","left");
		});
		//
		if (ss.overlay!==null) {
			if (bFlash) {
				ss.overlay.click(togglePlay);
				if (mCenter) {
					ss.overlay.mouseover(function(e){
						mCenter.stop();
						mCenter.fadeTo("slow", 1);
						i
					}).mouseout(function(e){
						mCenter.stop();
						mCenter.fadeTo("slow", 0);
					});
				}
			} else {
				ss.overlay.click(function(e){
					mVideo.click();
				}).mouseover(function(e){
					mVideo.mouseover();
				}).mouseout(function(e){
					mVideo.mouseout();
				}).mousemove(function(e){
					mVideo.mousemove();
				});
			}
		}
		//
//		videoResize();
		//
		// events
		$(window).resize(windowResize);
		windowResize();
	}

//	// videoResize
//	function videoResize() {
//		switch (ss.size) {
//			case ww.SIZE_ORIGINAL:
//				if (iVW&&iVH) {
//					mVideo.width(iVW);
//					mVideo.height(iVH);
//					mControls.width(iVW);
//				}
//			break;
//			case ww.SIZE_FIXED:
//				mVideo.width(ss.width); // TODO: maybe put NaN as default
//				mVideo.height(ss.height);
//				mControls.width(ss.width);
//			break;
//			case ww.SIZE_FULLSCREEN:
//				mVideo.css({
//					 position:	"fixed"
//					,width:		"100%"
//					,height:	"100%"
//				});
//				mControls.css({
//					 position:	"fixed"
//					,bottom:	"0px"
//					,width:		"100%"
//				});
//			break;
//			case ww.SIZE_FULLSCREENNOBARS:
//				mVideo.css({
//					 position:	"fixed"
//					,width:		"100%"
//					,height:	"100%"
//				});
//				mControls.css({
//					 position:	"fixed"
//					,top:		"auto"
//					,bottom:	"0px"
//					,width:		"100%"
//				});
//			break;
//		}
//	}

	// windowResize
	function windowResize(e) {
		try{
			iW = $Window.width();
			iH = $Window.height();
		}catch(err){}
		trace('e:',iW,iH); // TRACE ### e
		layVideo();
		layScrub();
		layCenter();
	}
	windowResize();

	// layVideo
	function layVideo() {
		if (ss.size===ww.SIZE_FIXED) {
			mVideo.width(ss.width); // TODO: maybe put NaN as default
			mVideo.height(ss.height);
			mControls.width(ss.width);
		} else if (iVideoReadyState>0) {
			trace('ss.size:',ss.size); // TRACE ### ss.size
			switch (ss.size) {
				case ww.SIZE_ORIGINAL:
					if (iVW&&iVH) {
						mVideo.width(iVW);
						mVideo.height(iVH);
						mControls.width(iVW);
					}
				break;
				case ww.SIZE_FULLSCREEN:
					mVideo.css({
						 position:	"fixed"
						,width:		"100%"
						,height:	"100%"
					});
					mControls.css({
						 position:	"fixed"
						,bottom:	"0px"
						,width:		"100%"
					});
				break;
				case ww.SIZE_FULLSCREENNOBARS:
//				trace('ww.SIZE_FULLSCREENNOBARS:',ww.SIZE_FULLSCREENNOBARS); // TRACE ### ww.SIZE_FULLSCREENNOBARS	
					var fAspR = iW/iH;
					var fVAspR = iVW/iVH;
					var sT = "0px";
					var sL = "0px";
					var sH = "100%";
					var sW = "100%";
					if (fAspR>fVAspR) {
						var iTH = Math.floor(iW/fVAspR);
						sT = Math.floor((iH-iTH)/2)+"px";
						sH = iTH+"px";
					} else {
						var iTW = Math.floor(iH*fVAspR);
						sL = Math.round((iW-iTW)/2)+"px";
						sW = iTW+"px";
					}
					trace('vid sL:',sW,sL); // TRACE ### sL
					mVideo.css({
//						 left:		sL
//						,top:		sT
						 marginLeft:sL
						,marginTop:	sT
						,width:		sW
						,height:	sH
					});
				break;
			}
		}
//		if (iVideoReadyState>0) {
//			if (ss.size===ww.SIZE_FULLSCREENNOBARS) {
//				var fAspR = iW/iH;
//				var fVAspR = iVW/iVH;
//				var sT = "0px";
//				var sL = "0px";
//				var sH = "100%";
//				var sW = "100%";
//				if (fAspR>fVAspR) {
//					var iTH = Math.floor(iW/fVAspR);
//					sT = Math.floor((iH-iTH)/2)+"px";
//					sH = iTH+"px";
//				} else {
//					var iTW = Math.floor(iH*fVAspR);
//					sL = Math.round((iW-iTW)/2)+"px";
//					sW = iTW+"px";
//				}
//				mVideo.css({
//					 left:		sL
//					,top:		sT
//					,width:		sW
//					,height:	sH
//				});
//			}
//		}
	}
	// layCenter
	function layCenter() {
		if (mCenter&&ss.size!=ww.SIZE_ORIGINAL) {
			var l = mVideo.position().left + parseInt(mVideo.css('marginLeft').replace('px',''));
			var t = mVideo.position().top  + parseInt(mVideo.css('marginTop').replace('px',''));
			var iLeft = Math.round(l+(mVideo.width()-mCenter.width())/2);
			var iTop =  Math.round(t+(mVideo.height()-mCenter.height())/2);
			mCenter.css({
				 left:	iLeft+"px"
				,top:	iTop+"px"
			});
		}
	}
	// layScrub
	function layScrub() {
		if (mCnScrub) {
			var iWMinus = 0;
			$.each(ss.controls,function(i,el){
				switch (el) {
					case ww.PLAYPAUSE: break; // TODO: add
					case ww.STOP: break; // TODO: add
					case ww.MUTE: if (mMute) iWMinus += mMute.width(); break;
					case ww.VOLUME: break; // TODO: add
					case ww.FULLSCREEN: break; // TODO: add
				}
			});
			mCnScrub.css({width:(iW-iWMinus)+"px"});
		}
	}

	// setSize
	function setSize() { // TODO: test
		switch (ss.size) {
			case ww.SIZE_ORIGINAL:
				mControls.width(iVW);
			break;
			case ww.SIZE_FIXED:
				mControls.width(ss.width);
			break;
			case ww.SIZE_FULLSCREEN:
				mControls.width(iW);
			break;
			case ww.SIZE_FULLSCREENNOBARS:
				mControls.width(iW);
			break;
		}
	}

	// scrub
	function scrub(e) {
		setPartPlayed((e.pageX-mCnScrub.position().left)/mCnScrub.width());
	}

	// setPartPlayed
	function setPartPlayed(f) {
		if (bFlash) {			
			oVideo.setPercentPlayed(f);
		} else if (oVideo.currentTime) {
			oVideo.currentTime = f*oVideo.duration;
		}
	}

	// getPartPlayed
	function getPartPlayed() {
		var fPartPlayed = 0;
		if (bFlash) {
			if (oVideo&&oVideo.getPercentPlayed) fPartPlayed = oVideo.getPercentPlayed();
		} else {
			if (oVideo.currentTime&&oVideo.duration) fPartPlayed = oVideo.currentTime/oVideo.duration;
		}
		return fPartPlayed;
	}

	// playVideo
	function playVideo(file) {
		if (!bFlash&&bPlaying&&ss.fadeOutBeforeLoad>0) {
			fadeOutBeforeLoad(file);
			return false; // TODO: <-- is lelijk
		}
		var sFile;
		trace("Widdio.playVideo: "+file);
		if (!bFlash) { // proceed
			iVideoReadyState = -1;
			switch (typeof(file)) {
				/*case "string": // insert string and sets same src for all source types
					iVideoReadyState = -1;
					sFile = file.replace(/\.\w+$/gi,"");
					trace("sFile: "+sFile);
					aSources.each(function(i,el){
						var mSource = $(el);
						var sExt = mSource.attr("type").split(";")[0].split("/").pop();
						if (oMimes[sExt]) sExt = oMimes[sExt];
						mSource.attr("src",sFile+"."+sExt);
					});
				break;*/
				case "string":
					oVideo.src = file;
				break;
				case "object": // removes all sources and inserts the new ones from the object
					//aSources.remove();
					var bFound = false;
					$.each(file,function(type,src) {
						if (!bFound) {
							//mVideo.append('<source type="video/'+type+'" src="'+src+'" />');
							var sCanPlay = oVideo.canPlayType("video/"+type);
							if (sCanPlay=="maybe"||sCanPlay=="probably") {
								trace("		oVideo.canPlayType(type): "+type+" "+sCanPlay);
								oVideo.src = src;
								bFound = true;
							}
						}
					});
					aSources = mVideo.find("source");
				break;
			}
			oVideo.load();
			oVideo.play();
			if (oVideo.muted) { // hack for oVideo not remembering the sound state correctly after load
				toggleSound(true);
				toggleSound(false);
			}
			bPlaying = true;
		} else {
			sFile = typeof(file)=="string"?(file+".mp4"):file.mp4;
			//trace("sFile: "+sFile);
			//trace("oVideo: "+oVideo.nodeName);
			//trace("oVideo.load: "+oVideo.load);
			oVideo.load&&oVideo.load("../"+sFile);
			bPlaying = true;
		}
	}

	// togglePlay
	function togglePlay(e) {
		var bT = e===true;
		var bF = e===false;
		var bE = bT||bF;
		if (!bFlash) {
			trace("togglePlay: oVideo.paused: "+oVideo.paused);
			if (oVideo.paused||(bE&&bT)) {
				trace("	play "+getPartPlayed());
				//if (getPartPlayed()===1) setPartPlayed(.5); // does not reset for some video types
				oVideo.play();
				bPlaying = true;
				mCenterPlay&&mCenterPlay.hide();
			} else if (!oVideo.paused||(bE&&bF)) {
				trace("	pause");
				oVideo.pause();
				bPlaying = false;
				mCenterPlay&&mCenterPlay.show();
			}
		} else {
			if (oVideo.pause()) { // maybe add e||null
				bPlaying = true;
				mCenterPlay&&mCenterPlay.hide();
			} else {
				bPlaying = false;
				mCenterPlay&&mCenterPlay.show();
			}
		}
	}

	// toggleSound
	function toggleSound(e) { // volume :: float (0-1), muted :: Boolean, null :: toggle mute
		// TODO: save states in cookie
		if (bFlash) {
			if (oVideo.mute())	mMuteOn.show();
			else				mMuteOn.hide();
		} else {
			if (iVideoReadyState===-1) {
				oToggleSound = e;
			} else {
				if (typeof(e)==='object'||e===null||e===undefined) e = oVideo.muted;
				var bT = e===true;
				var bF = e===false;
				if (bT||bF) { // mute
					oVideo.muted = !e;
					if (e)	mMuteOn.hide();
					else	mMuteOn.show();
				} else { // volume
					toggleSound(true);
					oVideo.volume = e;
				}
				oToggleSound = -1;
			}
		}
	}


	// run
	function run() {
		if (!bFlash) {
			checkVideo();
			var oBff = oVideo.buffered;
//			trace("oBff: "+oBff.length);
//			trace(oBff);
		}
		// scrub bar
		var fPartPlayed = getPartPlayed();
		mControlsBar.css("width",(100*fPartPlayed)+"%");// if (!oVideo.paused) 
//		buffered
		//
		if (bPlaying&&(fPartPlayed===1||(bFlash&&fPartPlayed>.99))) { // <--because flash sets to 0 on end
			trace("ss.playEnd: "+ss.playEnd);
			togglePlay(false);
			ss.playEnd&&ss.playEnd();
		}
	}

	// checkVideo
	function checkVideo(){
		if (oVideo.readyState!=iVideoReadyState) {
			iVideoReadyState = oVideo.readyState;
			switch (iVideoReadyState) {
				case oVideo.HAVE_NOTHING:		sVideoReadyState = "HAVE_NOTHING"; break;
				case oVideo.HAVE_METADATA:		sVideoReadyState = "HAVE_METADATA:"; break;
				case oVideo.HAVE_CURRENT_DATA:	sVideoReadyState = "HAVE_CURRENT_DATA:"; break;
				case oVideo.HAVE_FUTURE_DATA:	sVideoReadyState = "HAVE_FUTURE_DATA:"; break;
				case oVideo.HAVE_ENOUGH_DATA:	sVideoReadyState = "HAVE_ENOUGH_DATA:"; break;
			}
			trace("videoReadyState: "+iVideoReadyState+": "+sVideoReadyState+": "+iVW+"/"+iVH+" : "+oVideo.networkState);
			//
			if (iVideoReadyState>0) {
				iVW = oVideo.videoWidth;
				iVH = oVideo.videoHeight;
				windowResize();
				mCenterPlay&&mCenterPlay.hide();
			}
			if (iVideoReadyState>0&&oToggleSound!==-1) {
				toggleSound(oToggleSound);
			}
		}
	}

	// videoError
	function videoError(err) {
	   switch (err.target.error.code) {
		 case err.target.error.MEDIA_ERR_ABORTED: trace('You aborted the video playback.'); break;
		 case err.target.error.MEDIA_ERR_NETWORK: trace('A network error caused the video download to fail part-way.'); break;
		 case err.target.error.MEDIA_ERR_DECODE: trace('The video playback was aborted due to a corruption problem or because the video used features your browser did not support.'); break;
		 case err.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED: trace('The video could not be loaded, either because the server or network failed or because the format is not supported.'); break;
		 default: trace('An unknown error occurred.'); break;
	   }
	}

	// fadeOutBeforeLoad
	function fadeOutBeforeLoad(file) {
		trace("fadeOutBeforeLoad: "+file);
		mVideo.animate(
			 {opacity:0}
			,{
				 duration: ss.fadeOutBeforeLoad
				,step: function(i,o){
					oVideo.volume = 1-o.pos;
				}
				,complete: function(){
					togglePlay(false);
					playVideo(file);
					mVideo.fadeTo(1,1);
					oVideo.volume = 1;
				}
			}
		);
	}

	// trace
	function trace(s){
		if (!ss.debug) return;
		try {
			window.console.log.apply(console, arguments);				
		} catch (err) {}
	}
})(jQuery);
