
/**
 * 
 * @return
 */
function HTML5Video(defaults)
{
	//debugging variables.
	this.debugging = true;
	this.debuggingElementId;
	
	//keys used for detecting the different platforms.
	this.osKeyBlackberry = ['blackberry'];
	this.osKeyAndroid = ['android'];
	this.osKeyiOS = ['webos','iphone','ipod','ipad'];
	
	//in case you hate a particular platform
	this.detectIOS = true;
	this.detectBlackberry = true;
	this.detectAndroid = true;
	
	//this property can be toggled to use flash and HTML5 only as a fallback.
	this.useFlashFirst = false;
	
	//you can set the flash requirements as well if you are using the Adobe flash detection plugin.
	this.flashMajorVersion = 8;
	this.flashMinorVersion = 0;
	this.flashRequiredRevision = 0;
	this.hasFlash = false;
	
	//this is a required field. you must specificy the ID of the DIV or element that you want to inject the video into
	this.outputElementId;
	
	//these are all required properties for the mobile devices
	this.mobileVideoObject;
	this.mobileH264;
	this.mobileAdditionalVideos = {};
	this.mobilePosterImage;
	this.androidPosterImage;
	
	//these are the required properties for serving to a desktop platform
	this.desktopVideoObject;
	this.desktopH264;
	this.desktopAdditionalVideos = {};
	this.desktopFlashObject;
	this.desktopPosterImage;
	
	if(defaults != null)
	{
		this.init(defaults);
	}
	
	/**
	 * initializes the properties passed in and checks for flash.
	 */
	this.init = function(defaults)
	{
		for(var i in defaults)
		{
			this[i] = defaults[i];
		}
		
		try 
		{
			this.hasFlash = DetectFlashVer(this.flashMajorVersion, this.flashMinorVersion, this.flashRequiredRevision);
		}
		catch(e) 
		{
			this.hasFlash = false;
		}
	}
	
	/**
	 * Helper function to find the element by the id specified. Cross-browser compatible.
	 */
	this.getElementById = function(id)
	{
		var object = null;
		if (document.layers) {
			object = document.layers[id];
		} 
		else if (document.all) {
			object = document.all[id];
		}
		else if (document.getElementById) {
			object = document.getElementById(id);
		}
		return object;
	}
	
	/**
	 * Runs the actual detection and injects the proper video. 
	 */
	this.detect = function()
	{
		var result = '';
		var element;
		var isMobile = false;
		
		if(this.detectAndroid)
		{
			if(this.detectOS(this.osKeyAndroid))
			{
				this.debug('HTML5Video::detect() - detectAndroid');
				result = this.onAndroidCallback();
				isMobile = true;
			}
		}
		if(this.detectBlackberry)
		{
			if(this.detectOS(this.osKeyBlackberry))
			{
				this.debug('HTML5Video::detect() - detectBlackberry');
				result = this.onBlackberryCallback();
				isMobile = true;
			}
		}
		if(this.detectIOS)
		{
			if(this.detectOS(this.osKeyiOS))
			{
				this.debug('HTML5Video::detect() - detectIOS');
				result = this.oniOSCallback();
				isMobile = true;
			}
		}
		
		if(!isMobile)
		{
			this.debug('HTML5Video::detect() - default to desktop');
			result += this.onDesktopCallback();
		}
		
		if(this.outputElementId != '')
		{
			element = this.getElementById(this.outputElementId);
			if(element != null)
			{
				this.debug('HTML5Video::detect() - outputElementId found. injecting.');
				element.innerHTML = result;
			}
			else
			{
				this.debug('HTML5Video::detect() - outputElementId not found. injecting into body.');
				document.write(result);
			}
		}
		else
		{
			this.debug('HTML5Video::detect() - outputElementId not provided. injecting into body.');
			document.write(result);
		}
	}
	
	/**
	 * Callback for when android is found.
	 */
	this.onAndroidCallback = function()
	{
		this.debug('HTML5Video::onAndroidCallback()');
		var output = '';
		
		this.mobileVideoObject.params['onclick'] = "this.play();";
		this.mobileVideoObject.params['poster'] = this.androidPosterImage.src;
		this.mobileVideoObject.params['src'] = this.mobileH264.src;
		
		this.onVideoEndCallback = this.outputFallbackImage;
		output = this.outputVideo(this.mobileVideoObject, this.mobileH264, this.mobileAdditionalVideos, this.mobilePosterImage);
		
		var videos = document.getElementsByTagName('video') || [];
		for (var i = 0; i < videos.length; i++) {
			videos[i].addEventListener('click', function(videoNode) {
				return function() {
					videoNode.play();
				};
			}(videos[i]));
		}
		
		return output;
	}
	
	/**
	 * Callback for when blackberry is found.
	 */
	this.onBlackberryCallback = function()
	{
		this.debug('HTML5Video::onBlackberryCallback()');
		var output = '';
		
		this.mobileVideoObject.params['poster'] = this.mobilePosterImage.src;

		this.onVideoEndCallback = this.outputFallbackImage;
		output = this.outputVideo(this.mobileVideoObject, this.mobileH264, this.mobileAdditionalVideos, this.mobilePosterImage);
		
		return output;
	}
	
	/**
	 * Callback for when iphone/ipod/ipad/ios is found.
	 */
	this.oniOSCallback = function()
	{
		this.debug('HTML5Video::oniOSCallback()');
		var output = '';
		
		this.mobileVideoObject.params['poster'] = this.mobilePosterImage.src;

		this.onVideoEndCallback = this.outputFallbackImage;
		output = this.outputVideo(this.mobileVideoObject, this.mobileH264, this.mobileAdditionalVideos, this.mobilePosterImage);
		
		return output;
	}
	
	/**
	 * Default callback when none of the above is found. Serves as a desktop.
	 */
	this.onDesktopCallback = function()
	{
		this.debug('HTML5Video::onDesktopCallback()');
		var output = '';
		this.mobileVideoObject.params['poster'] = this.desktopPosterImage.src;
		
		if(this.hasFlash && this.useFlashFirst)
		{
			this.debug('HTML5Video::onDesktopCallback() - has flash');
			this.onFlashEndCallback = this.outputVideo;
			this.onVideoEndCallback = this.outputFallbackImage;
			output = this.outputFlash(this.desktopVideoObject, this.desktopH264, this.desktopAdditionalVideos, this.desktopPosterImage, this.desktopFlashObject);
		}
		else
		{
			this.debug('HTML5Video::onDesktopCallback() - no flash');
			this.onVideoEndCallback = this.outputFlash;
			this.onFlashEndCallback = this.outputFallbackImage;
			output = this.outputVideo(this.desktopVideoObject, this.desktopH264, this.desktopAdditionalVideos, this.desktopPosterImage, this.desktopFlashObject);
		}
		
		return output;
	}
	
	/**
	 * Debugging method that looks for firebug console, or optionally injects into a container on the page.
	 */
	this.debug = function(message)
	{
		if (typeof console == "undefined" || typeof console.log == "undefined") var console = { log: function() {} }; 
	
		if(this.debugging == true)
		{
			if(typeof console != "undefined")
			{
				console.log(message);
			}
			if(this.debuggingElementId)
			{
				var element = this.getElementById(this.debuggingElementId);
				if(element != null)
				{
					element.innerHTML += message + '<br />\n';
				}
				else
				{
					document.write(message + '<br />\n');
				}
			}
		}
	}
	
	/**
	 * Detects the OS based on the OS key passed in. Uses the userAgent of the browser.
	 */
	this.detectOS = function(device)
	{
		var uagent = navigator.userAgent.toLowerCase();
		this.debug('HTML5Video::detectOS() - ' + uagent);
		for(var i in device)
		{
			this.debug('HTML5Video::detectOS() - ' + device[i]);
			if (uagent.search(device[i]) > -1)
			{
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Outputs the HTML5 video.
	 */
	this.outputVideo = function(srcVideoObject, primaryVideoAsset, additionalVideos, fallbackImage, flashObject)
	{
		this.debug('HTML5Video::outputVideo()');
		var outputText = '';
		
		outputText += '<video width="' + srcVideoObject.width + '" height="' + srcVideoObject.height + '" ';
		
		for(var i in srcVideoObject.params)
		{
			outputText += ' ' + i + '="' + srcVideoObject.params[i] + '"';
		}
		
		outputText += '>';
		
		outputText += '<source src="' + primaryVideoAsset.src + '" type="' + primaryVideoAsset.type + '" />';
		
		for(var n in additionalVideos)
		{
			outputText += '<source src="' + additionalVideos[n].src + '" type="' + additionalVideos[n].type + '" />';
		}
		
		outputText += this.onVideoEndCallback(srcVideoObject, primaryVideoAsset, additionalVideos, fallbackImage, flashObject)
		
		outputText += '</video>';
		
		return outputText;
	}
	
	/**
	 * Call for adding additional code to inject into video element. example: params and fallback image
	 * @return string
	 */
	this.onVideoEndCallback = this.outputFallbackImage;
	
	/**
	 * Outputs the flash html and calls the callback <code>onFlashEndCallback</code> before closing the flash tag.
	 * @return string
	 */
	this.outputFlash = function(srcVideoObject, primaryVideoAsset, additionalVideos, fallbackImage, flashObject)
	{
		this.debug('HTML5Video::outputFlash()');
		var outputText = '';
		
		outputText += '<object width="' + flashObject.width + '" height="' + flashObject.height + '" type="application/x-shockwave-flash" data="' + flashObject.src + '">';
		
		if(flashObject.params['movie'] == null)
		{
			outputText += '<param name="movie" value="' + flashObject.src + '" />';
		}
		
		for(var i in flashObject.params)
		{
			outputText += '<param name="' + i + '" value="' + flashObject.params[i] + '" />';
		}
		
		outputText += this.onFlashEndCallback(srcVideoObject, primaryVideoAsset, additionalVideos, fallbackImage, flashObject)
		
		outputText += '</object>';
		
		return outputText;
	}
	
	/**
	 * Call for adding additional code to inject into flash object. example: params and fallback image
	 * @return string
	 */
	this.onFlashEndCallback = this.outputFallbackImage;

	/**
	 * Outputs the fallback image html.
	 * @return string
	 */
	this.outputFallbackImage = function(srcVideoObject, primaryVideoAsset, additionalVideos, fallbackImage, flashObject)
	{
		this.debug('HTML5Video::outputFallbackImage()');
		
		var outputText = '<img src="' + fallbackImage.src + '" width="' + fallbackImage.width + '" height="' + fallbackImage.height + '" title="' + fallbackImage.title + '" alt="' + fallbackImage.alt + '" />';
		return outputText;
	}
	
}

/**
 * HTML5VideoObject. Specifies the attributes for the video tag.
 * @param width
 * @param height
 * @param params This is the optional params for the video tag. Ex: {autoplay:"autoplay", controls:"controls", height:"100px", width:"100px", loop:"loop", preload:"preload", src:"sample_url.mp4"
 * @return
 */
function HTML5VideoObject(width, height, params)
{
	this.width = width;
	this.height = height;
	this.params = params;
}

function HTML5VideoAsset(src, type)
{
	this.src = src;
	this.type = type;
}

function HTML5VideoImage(src, width, height, alt, title)
{
	this.src = src;
	this.width = width;
	this.height = height;
	this.alt = alt;
	this.title = title;
}

function HTML5VideoFlashObject(src, width, height, params)
{
	this.src = src;
	this.width = width;
	this.height = height;
	this.params = params;
}

