/**
* @overview This library contains the VideoFactory class and the Video base class to be implemented for each platform
* @uses lib/Prototype/Prototype.js
* @uses lib/Sureflix/UI/Element.js
* @uses lib/Sureflix/Plugins/Plugins.js
* @uses lib/Sureflix/Plugins/Detector.js
* @uses lib/Sureflix/Plugins/DetectorPlugins.js
* @uses lib/Sureflix/Error/ErrorHandler.js
* @uses lib/Sureflix/Localization/Localization.js
*/

/**
 * @class This class creates video objects.
 */
Sureflix.Plugins.VideoFactory = {

	/**
	 * Selects and returns a platform that is installed in the current browser.
	 * @param {Sureflix.Plugins.Detector.platforms[]} platformArray Array of platforms supported by the movie to be played, in order of preference
	 */
	selectPlatform: function(platformArray) {
		var platform = false;
		platformArray.each(function(item) {
  			if (!platform) {
				if (Sureflix.Plugins.Detector.isRequiredPlatformInstalled(item)) {
					platform = item;
				}
			}
		});
		
		return platform;
	},
	
	
	/**
	 * Creates and returns a Video object for the specified platform.
	 * @param {Sureflix.Plugins.Detector.platforms} platform
	 * @param {Integer} interval (optional) 
	 * @param {Array[Integer]} speeds (optional) Array of fast forward speeds
	 * @return {Sureflix.Plugins.Video}
	 */
	createVideo: function(platform, interval, speeds) {
		switch (platform) {
			case Sureflix.Plugins.Detector.platforms["WindowsMedia"]:
				return new Sureflix.Plugins.WindowsMediaVideo(interval, speeds);
				break;
			case Sureflix.Plugins.Detector.platforms["Silverlight"]:
				return new Sureflix.Plugins.SilverlightVideo(interval, speeds);
				break;
			case Sureflix.Plugins.Detector.platforms["Flash"]:
				return new Sureflix.Plugins.FlashVideo(interval, speeds);
				break;
			default:
				return undefined;
		}
	}
}




/**
 *	@class This class measures the user's bandwidth.
 *	@author Erik 10/12/2008
 */
Sureflix.Plugins.BandwidthTest = {
	/**
	*	Constructor
	*	{Function} onComplete A function to call when the bandwidth test is complete
	*/
	initialize: function() {
	},

	resetTest: function() {
		if (this.executer) {
			this.executer.stop();
			this.executer = null;
		}
		if (this.video) {
			this.video.dispose();
			this.video = null;
		}
		if (this.element) {
			this.element.remove();
			this.element = null;
		}

		this.testFiles = $H();
		this.testFiles.set(Sureflix.Plugins.Detector.platforms["RealPlayer"], "rtsp://sureflix.rmod.llnwd.net/a474/d1/noauth/real.maleflixxx.samples/SC/InsidePorn2002SC.rm");
		this.testFiles.set(Sureflix.Plugins.Detector.platforms["WindowsMedia"], "http://meta.advection.net/metagen/?f=mftv|_promo/_dld/8Mb|wvx|wmv&p=httpd&ext=.wmv");
		//this.testFiles.set(Sureflix.Plugins.Detector.platforms["Silverlight"], "http://meta.advection.net/metagen/?f=mftv|_promo/_dld/8Mb|wvx|wmv&p=httpd&ext=.wmv&KB=8612");
		this.testFiles.set(Sureflix.Plugins.Detector.platforms["Silverlight"], "http://meta.advection.net/metagen/?f=mftv|_promo/_dld/109Mb|wvx|wmv&p=httpd&ext=.wmv&KB=110625");
		//this.testFiles.set(Sureflix.Plugins.Detector.platforms["Silverlight"], "http://stream.sureflix.com/LP/FastSex001/FastSex001LP_1100.wmv?KB=8425&Unique=" + escape(new Date().toUTCString()));
		this.avgBandwidth = 0;
		this.avgBandwidthCount = 0;
		this.maxBandwidthCount = 10;
		this.statusElement = null;
		this.progressElement = null;
		this.progressWidth = null;
	},


	/**
	* Starts the bandwidth test
	*/
	beginTest: function(parent, platformArray, onComplete) {
		this.resetTest();
		this.parent = $(parent);
		this.onComplete = onComplete;

		var dimensions = this.parent.getInnerDimensions();

		var str = this.getTemplateText();

		var myTemplate = new Sureflix.Utilities.Template(str)
		var myValues = { width: dimensions.width,
			height: dimensions.height
		};

		new Insertion.Bottom(this.parent, myTemplate.evaluate(myValues));
		this.element = $("bwtest");
		this.element.cloneInnerPosition(this.parent);
		var bg = this.element.getParentBackground();
		this.element.setStyle({ backgroundColor: bg });
		var progressBar = $("bwprogressbar");
		var margin = Math.floor((this.element.getHeight() - progressBar.getHeight()) / 2);
		progressBar.setStyle({ marginTop: margin + "px" });
		var margin = Math.floor((this.element.getWidth() - progressBar.getWidth()) / 2);
		progressBar.setStyle({ marginLeft: margin + "px" });
		this.updateStatus(Sureflix.Localization.getPhrase("Loading+") + "...");

		var testPlatform = Sureflix.Plugins.VideoFactory.selectPlatform(platformArray);
		this.video = Sureflix.Plugins.VideoFactory.createVideo(testPlatform, 1000, [1]);
		this.video.insertVideo("bwtestvideoparent", "bwtestvideo");
		this.video.setMedia(this.testFiles.get(testPlatform));

		this.executer = new PeriodicalExecuter(function(pe) { Sureflix.Plugins.BandwidthTest.doPeriodicalTest() }, 1);
	},


	getTemplateText: function() {
		var str = '' +
			'<style>' +
			'	#bwtest { cursor: pointer; position: absolute; overflow: hidden; padding: 0px; margin: 0px;}' +
			'	#bwteststatus { cursor: pointer; position: absolute; z-index: 2; text-align: center; width: 100%; color: Black; font-family: Verdana, sans-serif; font-size: 10px; }' +
			'	#bwtestvideoparent { width: 40px; height: 30px; border: solid 1px Blue; }' +
			'	#bwprogressbar { position: absolute; overflow: hidden; width: 90%; text-align: left; height: 15px; border: solid 1px black; background-color: White; }' +
			'	#bwprogress { position: absolute; left: 0px; top: 0px; width: 0px; height: 15px; z-index: 1; background-color: #EFCF42; }' +
			'	#bwtestvideoparent { position: absolute; left: 0px; top: -5000px; }' +
			'</style>' +
			'<div id="bwtest" onclick="Sureflix.Plugins.BandwidthTest.resetTest();">\n' +
			'	<div id="bwprogressbar"><div id="bwprogress"></div><div id="bwteststatus"></div></div>\n' +
			'	<div id="bwtestvideoparent"></div>\n' +
			'</div>\n';
		return str;
	},


	doPeriodicalTest: function() {
		if (this.avgBandwidthCount >= this.maxBandwidthCount) {
			var currentAverage = Math.round(this.avgBandwidth / this.avgBandwidthCount);
			this.video.stop();
			this.resetTest();
			this.onComplete("OK", currentAverage);
			return;
		}

		this.video.setMute(true);
		var bandwidth = Math.round(this.video.getCurrentBandwidth() / 1024);
		if (bandwidth > 1) {
			this.avgBandwidth += bandwidth;
			this.avgBandwidthCount++;
			this.updateProgress();

			var currentAverage = Math.round(this.avgBandwidth / this.avgBandwidthCount);
			this.updateStatus(currentAverage + " Kbps");

		}
	},


	updateStatus: function(text) {
		if (!this.statusElement) {
			this.statusElement = $("bwteststatus");
		}
		this.statusElement.innerHTML = text;
	},


	updateProgress: function() {
		if (!this.progressElement) {
			this.progressElement = $("bwprogress");
		}
		if (!this.progressWidth) {
			this.progressWidth = $("bwprogressbar").getInnerDimensions().width;
		}
		this.progressElement.sizeTo(Math.round(this.avgBandwidthCount / this.maxBandwidthCount * this.progressWidth), null);
	}

}




/**
*	@class This is the base class for subclasses which handle low level cross-platform video functionality. Subclasses 
*   exist for Windows Media and RealPlayer support in Internet Explorer, Firefox, and Safari in Windows and Macintosh.
*   In the future Silverlight and Flash support will be added.
*   @using Sureflix.Plugins.Detector
*   @using Sureflix.Error.ErrorHandler
*   @property {Sureflix.Plugins.Video.platformsEnum} platform The video platform
*   @property {HtmlElement} vid The <object> or <embed> page element
*   @property {Integer} interval Frequency of calling interval functions in milliseconds; usually 1000
*   @property {Array[Integer]} speeds Array of fast forward speeds (progressively faster)
*/
Sureflix.Plugins.Video = Class.create({

	initialize: function(interval, speeds) {
		this.platform = null;
		this.vid = null;
		this.parent = null;
		this.mediaUrl = null;
		this.elementID = null;
		
		this.interval = interval || 1000;	// 1000 = 1 second
		this.speeds = speeds || [1, 2, 5, 20];
	},


	dispose: function() {
		if (this.parent) this.parent.innerHTML = "";
	},


	/**
	* Instantiates a video embed and inserts it into the DOM
	* @param {Object} parentID
	* @param {Object} elementID
	*/
	insertVideo: function(parentID, elementID, extraQSParams) {
		var str;

		this.parentID = parentID;
		this.parent = $(parentID);
		this.elementID = elementID;

		//var detector = Sureflix.Plugins.Detector;
		//detector.detectBrowser();

		var dimensions = this.parent.getInnerDimensions();

		str = this.getEmbedHtml(extraQSParams);

		var myTemplate = new Sureflix.Utilities.Template(str)
		var myValues = { width: dimensions.width,
			height: dimensions.height,
			elementID: elementID
		};

		this.parent.innerHTML = myTemplate.evaluate(myValues);
		this.vid = $(elementID);
	},


	/** 
	* Returns the HTML template for an <embed> or <object> element
	*/
	getEmbedHtml: function(extraQSParams) {
		try {
			throw "Sureflix.Plugins.Video is a base class that must not be instantiated. Instantiate a subclass instead."
		} catch (e) {
			Sureflix.Error.ErrorHandler.userError(e);
		}
	},


	/**
	* Sets the video to the given url
	* @param {String} mediaUrl
	*/
	setMedia: function(mediaUrl) {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},


	/**
	* Sets the user interface language (for tips, messages, etc.) (not requred)
	* @param {String} lang 2-character language code
	*/
	setLang: function(lang) {
	},


	/**
	* Sets the movie and scene number to enable such things as filmstrip support (not requred)
	* @param {String} movieCode
	* @param (int) sceneNum
	* @param {int} startMillisecs
	* @param {int} durationMillisecs
	* @param (bool) isWidescreen
	*/
	setScene: function(movieCode, sceneNum, startMillisecs, durationMillisecs, isWidescreen) {
	},


	/**
	* Returns a phrase corresponding to the play state of the video
	* @example	var state = sureVideo.getPlayState();   //<A href=http://alpha.sureflix.com/SampleCode/ClientJSSamples/Sureflix.Plugins.Video.htm target=_blank>sample code</A>
	* @author Erik 12/26/2007
	*/
	getPlayState: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns true if the the video can be paused (pause button should be enabled)
	* @example	if (sureVideo.canPause()) sureVideo.pause();   //<A href=http://alpha.sureflix.com/SampleCode/ClientJSSamples/Sureflix.Plugins.Video.htm target=_blank>sample code</A>
	* @author Erik 12/26/2007
	*/
	canPause: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns true if the the video can be played (play button should be enabled)
	* @example	if (sureVideo.canPlay()) sureVideo.play();   //<A href=http://alpha.sureflix.com/SampleCode/ClientJSSamples/Sureflix.Plugins.Video.htm target=_blank>sample code</A>
	* @author Erik 12/26/2007
	*/
	canPlay: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns true if the the video can be stopped (stop button should be enabled)
	* @example	if (sureVideo.canStop()) sureVideo.stop();   //<A href=http://alpha.sureflix.com/SampleCode/ClientJSSamples/Sureflix.Plugins.Video.htm target=_blank>sample code</A>
	* @author Erik 12/26/2007
	*/
	canStop: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Pauses the video
	* @example	sureVideo.pause();   //<A href=http://alpha.sureflix.com/SampleCode/ClientJSSamples/Sureflix.Plugins.Video.htm target=_blank>sample code</A>
	* @author Erik 12/25/2007
	*/
	pause: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Starts playing the video
	* @example	sureVideo.play();   //<A href=http://alpha.sureflix.com/SampleCode/ClientJSSamples/Sureflix.Plugins.Video.htm target=_blank>sample code</A>
	* @author Erik 12/25/2007
	*/
	play: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Stops playing the video
	* @author Erik 12/25/2007
	*/
	stop: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},


	cycleSpeeds: function() {
		if (this.isPaused()) {
			this.play();
		}

		var speedsIndex = this.getSpeedsIndex();

		if (speedsIndex >= (this.speeds.length - 1)) {
			speedsIndex = 0;
		} else {
			speedsIndex++;
		}

		this.setRate(this.speeds[speedsIndex]);
	},

	/**
	* Returns false if the video is not fast forwarding, or an index in this.speeds[].
	* @author Erik 12/26/2007
	*/
	getSpeedsIndex: function() {
		var rate = this.getRate();

		for (var i = 0; i < this.speeds.length; i++) {
			if (rate <= this.speeds[i]) {
				return i;
			}
		}

		return i;
	},

	/**
	* Returns the playback speed of the video; 1 is normal speed
	* @author Erik 12/26/2007
	*/
	getRate: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Sets the playback speed of the video to the desired rate
	* @param {Number} rate The desired speed; 0.5 is half speed; 2 is double speed; etc
	* @author Erik 12/26/2007
	*/
	setRate: function(rate) {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},


	/**
	* Gets the percentage of video that has downloaded; returns 0 if streaming
	* @author Erik 12/26/2007
	*/
	getDownloadProgress: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns the connection bandwidth of the video or the encoded bitrate
	* @author Erik 12/26/2007
	*/
	getConnectionBandwidth: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns the average bandwidth of the video
	* @author Erik 12/26/2007
	*/
	getAverageBandwidth: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},


	/**
	* Returns the current bandwidth of the video
	* @author Erik 12/26/2007
	*/
	getCurrentBandwidth: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns true if the video is in full screen mode
	* @author Erik 12/26/2007
	*/
	getFullScreen: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Puts the video into full screen mode
	* @author Erik 12/26/2007
	*/
	setFullScreen: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Sets the browser focus on the video
	* @author Erik 12/22/2008
	*/
	setFocus: function() {
	},

	/**
	* Returns true if the video is muted
	* @author Erik 12/26/2007
	*/
	getMute: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Sets the mute state of the video to true or false
	* @param {Boolean} set The desired mute state
	* @author Erik 12/26/2007
	*/
	setMute: function(set) {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns the number of lost packets which reflects the quality of the network connection
	* @author Erik 12/26/2007
	*/
	getPacketsMissing: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},


	/**
	* Returns the buffering progress of the video as a percentage
	* @author Erik 12/26/2007
	*/
	getBuffering: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns a string with the full name of the video this.platform ("Real Media", "Windows Media", etc.)
	* @author Erik 12/26/2007
	*/
	getPlatform: function() {
		return this.platform;
	},

	/**
	* Returns a string with the full name of the video this.platform ("Real Media", "Windows Media", etc.)
	* @author Erik 12/26/2007
	*/
	getPlatformName: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns the installed version of the player this.platform
	* @author Erik 12/26/2007
	*/
	getVersionInfo: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns the length of the video in seconds
	* @author Erik 12/26/2007
	*/
	getLength: function() {
		//wm gets length in seconds, rm gets length in milliseconds
		//this function always returns the length of the clip in seconds

		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns the position of the playback in seconds
	* @author Erik 12/26/2007
	*/
	getPosition: function() {
		//wm gets position in seconds, rm gets position in milliseconds
		//this function always returns the position in seconds (as a floating point number)

		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},


	/**
	* Sets playback to a specific position in the video
	* @param {Integer} seconds The desired position of the vido
	* @author Erik 12/26/2007
	*/
	setPosition: function(seconds) {
		//wm gets position in seconds, rm gets position in milliseconds
		//this function is always passed seconds and it normalizes it for rm

		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns the volume of the video from 1 to 100
	* @author Erik 12/26/2007
	*/
	getVolume: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},


	/**
	* Sets the volume of the video to the desired level
	* @param {Integer} volume The desired volume from 0 to 100
	* @author Erik 12/26/2007
	*/
	setVolume: function(volume) {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns true if the video is paused
	* @author Erik 12/26/2007
	*/
	isPaused: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns true if the video is playing
	* @author Erik 12/26/2007
	*/
	isPlaying: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/**
	* Returns true if the video is stopped
	* @author Erik 12/26/2007
	*/
	isStopped: function() {
		Sureflix.Error.ErrorHandler.consoleError(new Error("Not implemented"));
	},

	/*
	* Private function, used to estimate bandwidth when not available
	*/
	getEstimatedCurrentBandwidth: function() {
		var fileSizeKB = GetQSValue("KB", this.mediaUrl);
		if (IsEmpty(fileSizeKB)) return 0;

		var fileSizeBits = parseInt(fileSizeKB) * 8 * 1024;

		var dlProgress = this.getDownloadProgress();
		if (dlProgress == 0) return 0;

		if (this.lastDownloadTime == null || this.lastDownloadProgress == null) {
			this.lastDownloadTime = new Date();
			this.lastDownloadProgress = dlProgress;
			return 0;
		}

		var currentTime = new Date();
		var elapsedSeconds = (currentTime.valueOf() - this.lastDownloadTime.valueOf()) / 1000;
		var elapsedDownload = (dlProgress - this.lastDownloadProgress);

		var bandwidth = (fileSizeBits * elapsedDownload) / elapsedSeconds;

		this.lastDownloadProgress = dlProgress;
		this.lastDownloadTime = currentTime;

		return bandwidth;
	},

	getEstimatedConnectionBandwidth: function() {
		if (this.mediaUrl == null) return 0;
		var strBitrate = this.mediaUrl.match("(0056|0112|0256|0512|0768|0900|1100)");
		if (strBitrate == null) return 0;
		return strBitrate[0] * 1024;
	}


});
