/* version: Update September 29, 2009. */

var octopv_disabled_arr = new Array();
var octopv_globalPlayObj = null;

/* octopv_embeddedPlayObject is a global object set only once: when embeddedplay is called for the first time. 
    It knows how to play embedded in the current user setup. 
    It can be used by all embeded players on the page. */
var octopv_embeddedPlayObject = null;

/* Octopv_embeddedPlayers holds any actual embedded players started by the octoPlayEmbedded function.
	There is one object for each playerDiv. 
	playerDiv (string) -> object with methods: 
		- playerStop()
		- playerPlay() 
		- playerPause() 
		- playerVolume(number) from 0 to 100
		- playerSeek(number) from 0 to 1000
	Player objects are added in the embeddedPlay function.
*/
var octopv_embeddedPlayers = new Object;


// if this is 999, then everything is normal.
// else we will use it to override the result variable in the play_rec function
var octopvPrivate = 999;
var octopv_group = ""; // global group used when group is not defined in the octolink.
var octopvDebugDiv = false;		// if this is set (to a divID name) we display debug in the div.
var octopvDebugTopPost = false;	

// IE 4 fix. The global variable 'undefined' is not defined in  older IE browsers, so we define it here. 
this.undefined = this.undefined;

/*doc <!--
<function id="octoOK" group="autility functions">
	<description>
		If this returns false, the Octoshape plug-in is not installed, or not installed correctly.
		It also returns false in the time, just after the installation, see step four of %ahref "install/user_exp", "install process"%.
		<BR /><BR />
		Do not call this function from the head section of a document, as it might dynamically add an html element to the body section.
		If the body section is not present at that time, a JavaScript error will occur.
	</description>
	<returns>
		Returns true if Octoshape is installed and %apiref "octoUsingProtocol"% returns false.<BR/>
		Returns false if Octoshape is not installed or if %apiref "octoUsingProtocol"% returns true.
	</returns>
</function> 
 --> **/
function octoOK(group){		// argument is optional
	if (octoNoBrowserPlugin()){ return false; }
	if (octoLowLevelCheck(octoLowLevelGet(group))){ return true; }
	return octoInstalledWithoutBrowserPlugin();
}

// Note: do not change function definition
// (It has once been a part of the web integration API).
function octoDisable(octoLink){
	octopv_disabled_arr[octopv_disabled_arr.length] = octoLink;
}

/*doc <!--
<function id="octoUsingProtocol" group="autility functions">
	<description>
		This is a small utility function to quickly determine
		whether the play functions will use the Octoshape browser plug-in 
		or the Octoshape protocol (that is, the %ahref "play/nojs", "no javascript solution"%).
		See the FAQ for a definition of %ahref2 "help/faq", "browserplugin", "Octoshape browser plug-in versus Octoshape plug-in"%. 
		<BR /><BR />
		We can not use the Octoshape browser plug-in if 
		the user has disabled ActiveX controls in IE or has the browser Opera.
	</description>
	<returns>
		Returns true if the user has a setup where we can not rely on the presence of an Octoshape browser plug-in 
		when the Octoshape plug-in is installed.
	</returns>
	<comment>
		The test is performed by checking the navigator.userAgent string.
	</comment>
</function> 
 --> **/
function octoUsingProtocol(){
	return (octoNoBrowserPlugin() || octoInstalledWithoutBrowserPlugin());
}

/*doc <!--
<function id="octoNeedsNewFxWmpPlugin" group="autility functions">
	<description>
		This is a small utility function to determine if the user could 
		benefit from getting the new Firefox Windows Media Player (WMP) plug-in. 
		It is recommended to ask the user to get this plug-in if you are 
		using the %apiref "octoPlayEmbedded"% function to play an on demand stream.
		<BR /><BR />
		Windows XP and earlier has a pre-installed older Firefox WMP plug-in, but there are a few 
		issues with this plug-in so it might improve the user experience to ask the user to get the new plug-in
		if they are using the old one. Known issues with the old plug-in:
		<ul>
			<li>If an Octoshape on demand stream is played, the user can not seek in the file.
				(This is because the old WMP plug-in is not scriptable).</li>
			<li>Some users have experienced video resizing errors.
				(Notably with the combination of Firefox 2 and WMP 11).</li> 
		</ul>
		The plug-in requires Windows XP or Windows Vista. 
	</description>
	<returns>
		Returns true if all of the following conditions are met: 
		The browser is Firefox, the OS is either Windows XP or Vista, and 
		the user does not have the new Firefox WMP plug-in.
	</returns>
	<comment>
		Read about the WMP plug-in at: 
		<a href="http://kb.mozillazine.org/Windows_Media_Player">MozillaZine Knowledge Base on WMP plug-ins</a>.
		The plug-in can be downloaded from Microsoft at: 
		<pre>http://port25.technet.com/pages/windows-media-player-firefox-plugin-download.aspx</pre>
	</comment>
</function> 
 --> **/
function octoNeedsNewFxWmpPlugin(){
	if(!octopv_isFirefox()) return false;
	if(!(octopv_isVista()||octopv_isXP())) return false;
	return !octopv_has_mime("application/x-ms-wmp");
}

// dummy function to be overwritten
function octoInstalledWithoutBrowserPlugin(){ return false; }
function octoNoBrowserPlugin(){
	var text = navigator.userAgent.toLowerCase();
	if (text.indexOf("opera") >= 0 || octopv_activexdisabled()) { 
		octopv_debug('octoNoBrowserPlugin true for: '+text, arguments.callee);
		return true;
	}
	return false;
}


/* **************************** PLAY FUNCTIONS *******************************/

/*doc <!--
<function id="octoPlayEmbedded" group="aplay functions"> 
	<description>
		If the Octoshape plug-in is not running when this function is called, 
		the plug-in will launch (this might take a few seconds), and then play the stream.
		<BR />Remember to place an install link on all pages where the play-link is, 
		since this function might show an alert asking the user to perform an install or re-install.
		<BR /><BR />
		If we are on the Mac and there is no Flip4Mac media browser plug-in we call octoPlayExternal.
		<BR /><BR />
		When playing an on demand stream it is recommended to ensure that the user is not using the old 
		Firefox Windows Media Player plug-in. See comments to function %apiref "octoNeedsNewFxWmpPlugin"% 
		for details. 
		<BR /><BR />
		Do not call this function from the head section of an html document.
	</description>			
	<param id="octolink" 		description="The unique OctoLink you got from Octoshape" />
	<param id="playerDiv" 		description="The id of the html section you placed on the page for the media player" />
	<param id="player_width" 	description="The width in pixels you want the embedded media player to have" />
	<param id="player_height">
		The height in pixels you want the viewing area of the embedded media player to have. 
		The actual player (including the controls below) is an additional 46 pixels high.
	</param>
	<param id="controls" optional="true" >
		<ol class="nospace">
			<li value="0"> The default value. Shows common live stream controls beneath the video image (play/pause, stop, volume etc.).</li>
			<li value="1"> Shows on demand controls (24 pixels high) beneath the video the video image.	
				NB: If 0 is set for an on demand stream, the seek bar below the player will not function correctly.
				</li>
			<li value="2"> Shows no controls at all.</li>
		</ol>
	</param>
	<returns>
		Returns true if playback starts immediately or the plug-in is launching<br/>
		Returns false if the channel is disabled, if 
		an error occurred with the plug-in, or if %apiref "octoUsingProtocol"% returns true.
	</returns>
	<comment>
		Se %ahref "play/embedded", "embedded play"% for an example.
	</comment>
</function> 
 --> **/
function octoPlayEmbedded(arg_octolink, playerDIV_ID, arg_player_width, arg_player_height, arg_controls, cheatArg){
	octopv_debug('we were asked to play embedded link: '+arg_octolink, arguments.callee);
	var octolinkObj = new octopv_octolinkObject(arg_octolink);

	if (octopv_disabled(arg_octolink)){return false;}
	
	if (octoUsingProtocol()){
		octopv_debug('Octoshape using protocol. ', arguments.callee);
		window.location.href=octolinkObj.octolink();
		return false;
	}
	
	if(octopv_isIE()){
		octoEmbeddedPlayerStop(playerDIV_ID);
	}
	
	octopv_setEmbeddedPlayObject();
	var controls = (typeof(arg_controls) != "number")? 0: arg_controls; 
	// cheatArg may be undefined, which is OK. 
	
	var embedobj = octopv_embeddedPlayers[playerDIV_ID];

	if(typeof embedobj != 'undefined'){
		// We already have an embedobj for this div.
		octopv_embedobj_set(embedobj, arg_player_width,arg_player_height, arg_controls, cheatArg);
	}else{
		embedobj = new octopv_embedobj(playerDIV_ID,arg_player_width, arg_player_height, controls,cheatArg);
		octopv_embeddedPlayers[playerDIV_ID] = embedobj;
		octopv_debug('Adding "'+playerDIV_ID+'" player div arr: '+getPropertiesString(octopv_embeddedPlayers), arguments.callee);
	}
	return octopv_play_rec(octolinkObj, embedobj);
}


function octopv_setEmbeddedPlayObject(){
	if(octopv_embeddedPlayObject == null){
		var ob = new octopv_embedplayobj_basics();
		if(octopv_isOSX()){
			octopv_embedobj_setMac(ob);
		}else if(octopv_isFirefox() && octopv_has_mime("application/x-ms-wmp")){
	 		octopv_embedobj_setFxWithPlugin(ob);
		 	octopv_setWmpScripting(ob);
		}else if(octopv_hasWmp7()){ 
			octopv_embedobj_setIeWmp7(ob);
			octopv_setWmpScripting(ob);
		}else{
			if(octopv_isIE()){
				octopv_embedobj_setIeWmp64(ob);
			}else{
				octopv_embedobj_setEmbedTag(ob);
			}
		}
		octopv_embeddedPlayObject = ob;
	}
}


/*doc <!--
<function id="octoPlayExternal" group="aplay functions"> 
	<description>
		If the Octoshape plug-in is not running when this function is called, 
		the plug-in will launch (this might take a few seconds), and then play the stream.
		<BR /><BR />
		Do not call this function from the head section of an html document.
	</description>			
	<param id="octolink" 		description="The unique OctoLink you got from Octoshape" />
	<returns>
		Returns true if playback starts immediately or the plug-in is launching<br/>
		Returns false if the channel is disabled, if 
		an error occurred with the plug-in, or if %apiref "octoUsingProtocol"% returns true.
	</returns>
	<comment>
		Se %ahref "play/external", "external play"% for an example.
	</comment>
</function> 
 --> **/
function octoPlayExternal(OctoLink){
	var octolinkObj = new octopv_octolinkObject(OctoLink);
	
	if (octopv_disabled(OctoLink)){return false;}
	
	if (octoUsingProtocol()){
		window.location.href=octolinkObj.octolink();
		return false;
	}	
	return octopv_play_rec(octolinkObj, null)
}

// Stops all added embedded players. 
// Deprecated function.
function octoStopEmbedded() {
	for (var i in octopv_embeddedPlayers){ 
		octopv_embeddedPlayers[i].playerStop();
	}
}

/*doc <!--
<function id="octoEmbeddedPlayerStop" group="dembeded scripting">
	<description>Stooping the stream. A subsequent call to octoEmbeddedPlayerPlay will start 
	the stream from the beginning.</description>
	<param id="playerDivId" description="Id of the html section containing the player."/>
	<returns description="false on error"/>
</function> 
 --> **/
function octoEmbeddedPlayerStop(playerDivId){
	var player = octopv_embeddedPlayers[playerDivId];
	if(typeof player != 'undefined'){
		player.playerStop();
		octopv_debug('player '+playerDivId+' stopped', arguments.callee);
		return true;
	}else{
		octopv_debug('player '+playerDivId+' not in embedded players array ('+getPropertiesString(octopv_embeddedPlayers)+')', arguments.callee);
		return false;
	}
}

/*doc <!--
<function id="octoEmbeddedPlayerPlay" group="dembeded scripting">
	<description>
		This can be called after a call to octoEmbeddedPlayerStop or octoEmbeddedPlayerPause.
	</description>
	<param id="playerDivId" description="Id of the html section containing the player."/>
	<returns description="false on error"/>
</function> 
 --> **/
function octoEmbeddedPlayerPlay(playerDivId){
	var player = octopv_embeddedPlayers[playerDivId];
	if(typeof player != 'undefined'){
		player.playerPlay();
		octopv_debug('player '+playerDivId+' set to play', arguments.callee);
		return true;
	}else{
		octopv_debug('player '+playerDivId+' not in embedded players array ('+getPropertiesString(octopv_embeddedPlayers)+') ', arguments.callee);
		return false;
	}
}

/*doc <!--
<function id="octoEmbeddedPlayerPause" group="dembeded scripting">
	<description>
		This will pause the stream. It can be resumed by a call to octoEmbeddedPlayerPlay.
	</description>
	<param id="playerDivId" description="Id of the html section containing the player."/>
	<returns description="false on error"/>
</function> 
 --> **/
function octoEmbeddedPlayerPause(playerDivId){
	var player = octopv_embeddedPlayers[playerDivId];
	if(typeof player != 'undefined'){
		player.playerPause();
		octopv_debug('player '+playerDivId+' paused', arguments.callee);
		return true;
	}else{
		octopv_debug('player '+playerDivId+' not in embedded players array ('+getPropertiesString(octopv_embeddedPlayers)+') ', arguments.callee);
		return false;
	}
}

/*doc <!--
<function id="octoEmbeddedPlayerVolume" group="dembeded scripting">
	<description>
		Function to control the media player volume. 
	</description>
	<param id="playerDivId" description="Id of the html section containing the player."/>
	<param id="newVolume" description="A number from 0 to 100, where 0 is no sound at all and 100 is full volume."/>
	<returns description="false on error"/>
</function> 
 --> **/
function octoEmbeddedPlayerVolume(playerDivId, number){
	var player = octopv_embeddedPlayers[playerDivId];
	if(typeof player != 'undefined'){
		var num = octopv_toNumber(number);
		player.playerVolume(num);
		octopv_debug('player '+playerDivId+' volume set to: '+num, arguments.callee);
		return true;
	}else{
		octopv_debug('player '+playerDivId+' not in embedded players array ('+getPropertiesString(octopv_embeddedPlayers)+') ', arguments.callee);
		return false;
	}
}

function octoEmbeddedPlayerSeek(playerDivId, number){
	var player = octopv_embeddedPlayers[playerDivId];
	if(typeof player != 'undefined' ){
		player.playerSeek(number);
		octopv_debug('player '+playerDivId+' seek to: '+number, arguments.callee);
		return true;
	}else{
		octopv_debug('player '+playerDivId+' not in embedded players array ('+getPropertiesString(octopv_embeddedPlayers)+') ', arguments.callee);
		return false;
	}
}

function octoEmbeddedOctobarReady(playerDivId){
	var player = octopv_embeddedPlayers[playerDivId];
	if(typeof player != 'undefined'){
		octopv_debug('player '+playerDivId+' octobar ready ', arguments.callee);
		player.octobarReady();
		return true;
	}else{
		octopv_debug('player '+playerDivId+' not in embedded players array ('+getPropertiesString(octopv_embeddedPlayers)+')', arguments.callee);
		return false;
	}
}

/* ********************** CUSTOMIZING FUNCTIONS *******************************/

/*doc <!--
<function id="octoSetAlertTexts" group="ccustomizing">
	<description>
		When using one of the Octoshape JavaScript play functions, 
		the user is presented with some dialog boxes with information if there was some trouble playing the stream.
		Thise messages can be customized.
	</description>			
	<param id="noPlugInText">
		The text to show the user if they do not have the Octoshape plug-in.
		If null, the standard text will be used. If the empty string, no alert will be displayed. 
	</param>
	<param id="errorPlugInText">
		The text to show the user if something has gone wrong with their Octoshape plug-in installation and they have to re-install the plug-in.
		If null, the standard text will be used. 
	</param>
	<comment>
		<h2>The Standard Texts</h2>
		What your audience will see 
		<ul> 
			<li>If they do not have the plug-in:			<a href="#" ONCLICK="javascript: return missingMessage();">try</a>.</li>
			<li>If there was some error with the plug-in: 	<a href="#" ONCLICK="javascript: return errorMessage();">try</a>.</li>
		</ul>
	</comment>
</function> 
 --> **/
function octoSetAlertTexts(noPlugInText, errorPlugInText){
	octopv_Config.setAlertTexts(noPlugInText, errorPlugInText);
}

/*doc <!--
<function id="octoSetStartupPage" group="ccustomizing">
	<description>
		If the Octoshape Plug-In is closed down when a play function is called, 
		the plug-in will begin its start-up routines (this might take some seconds), 
		and when it is finished the stream will be played.
		<BR/><BR/>
		In the JavaScript external player solution there will be displayed a web page popup, 
		while the plug-in starts up. You can set this web page to what you want.
	</description>			
	<param id="startupPage" description="A complete internet address for the starting up pop-up." />
	<param id="startupWidth" description="The width in pixels you would like the starting up pop-up to have." />
	<param id="startupHeight"  description="The height in pixels you would like the starting up pop-up to have." />
	<comment>
		<h2>The Standard Startup popup: <a href="#" ONCLICK="javascript: var popup = octopv_Config.do_startup_popup();">try</a></h2>
	</comment>
</function> 
 --> **/
function octoSetStartupPage(startupPage, startupWidth, startupHeight){
	octopv_Config.setExternalWaitPopup(startupPage, startupWidth, startupHeight);
}

/*doc <!--
<function id="octoSetStartupImage" group="ccustomizing">
	<description>
		If the Octoshape Plug-In is closed down when a play function is called, 
		the plug-in will begin its start-up routines (this might take some seconds), 
		and when it is finished the stream will be played.
		<BR/><BR/>
		In the JavaScript embedded solution there will be displayed an image inside the 
		media player, while the plug-in starts up. You can set this image to what you want.
	</description>
	<param id="startupImage">
		A complete path for the startup image to be displayed in the media player. 
		A null value will display a standard 'Octoshape is starting up image' (default value). 
		The empty string will display an empty media player.
	</param> 
	<comment>
		<h2>The Standard Image</h2>
		<script>
			document.write(octopv_Config.getStartupImage(300,200));
		</script>
	</comment>
</function> 
 --> **/
function octoSetStartupImage(startupImage){
	octopv_Config.setStartupImage(startupImage);
}

/*doc <!--
<function id="octoSetInstallPopup" group="ccustomizing">
	<description>
		If the Octoshape plug-in is not installed when a play function is called, 
		normally the only thing that will happen is that an alert will be displayed to the user (see %apiref "octoSetAlertTexts"%). 
		<BR/><BR/>
		This function will allow you to also have a web page pop up to the user (presumably containing an Octoshape install link).
	</description>
	<param id="installPage" description="A complete internet address for the install pop-up." />
	<param id="installPageFeatures" >
		A string specifying the window features, such as height, width, and whether the window needs a scrollbar, of the install pop-up. 
		The string will be given directly to the JavaScript <b>window.</b><i>open</i> method. 
		For reference of this method see for instance: 
			<a href="http://wp.netscape.com/eng/mozilla/3.0/handbook/javascript/ref_m-q.htm#177627">netscape.com on window.open</a>
		or
			<a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp">microsoft.com on window.open</a>
	</param>
</function> 
 --> **/
function octoSetInstallPopup(installPage, installPageFeatures){
	octopv_Config.setInstallPopup(installPage, installPageFeatures);
}

/*doc <!--
<function id="octoSetInstallFunction" group="ccustomizing">
	<description>
		If the Octoshape plug-in is not installed when a play function is called, 
		normally the only thing that will happen is that an alert will be displayed to the user (see %apiref "octoSetAlertTexts"%). 
		<BR/><BR/>
		This function will allow you to specify that one of your own JavaScript functions is to be called. 
	</description>
	<param id="javaScriptFunction">
		A no argument JavaScript function which will be called if the plug-in is missing or if there
		where some trouble playing the stream, that is, if the user must (re-) install the plug-in.
		<BR/><BR/>
		This function will be called as the last event, that is, after the alert and any install popup page.
		<BR/><BR/>
		If called with argument null the standard setting will be used (no function will be called). 
	</param>
</function> 
 --> **/
function octoSetInstallFunction(javaScriptFunction){
	octopv_Config.setInstallFunction(javaScriptFunction);
}

/*doc <!--
<function id="octoSetOndemandBarPath" group="ccustomizing">
	<description>
		This will set the full path of the octobar.swf file. 
		The default value is: 
		<pre>http:/www.octoshape.com/javascripts/octobar.swf</pre>
	</description>
	<param id="path" description="Full path including the name of the file." />
</function> 
 --> **/
function octoSetOndemandBarPath(path){
	octopv_Config.setOnDemandBarPath(path);
}

/* **************************************************************************************/
/* ********************************* OBSOLETE FUNCTIONS *******************************/
// Below are old configuring functions present only so users do not get errors 
// if some broadcasters still call them on thier site.

function octoSetEmbedControls(play, audio){
	/** This is now set in the embedded play function. */
}

function octoSetEmbedStatusBar(show){
	/** The status bar is always shown when the coltrols are shown. */
}

function octoSetEmbedDisplay(show){
	/** The display area is not shown. */
}

function octoSetEmbedImageResize(resize){
	/* Video will always be scaled up and down to fit the player. 
		If the user has wmp 7+ (and if fx, has wmp plugin) the aspect ratio will be preserved,
		otherwise not. */
}

function octoUseWmp7Embedded(){
	/* wmp7 is automatically detected. */
} 

/* **************************************************************************************/
/* ********************************* PRIVATE FUNCTIONS *******************************/

/* 
 @function: octopvGetPlayerID
 @param playerDiv: string id of the media player div
 @returns string id to use in object and embed tags to uniquely identify the media player
 */
function octopvGetPlayerID(playerDiv){
	return "octoPlayerObjectID" + playerDiv;
}

/* 
 @function: octopvGetOctobarID
 @param playerDiv: string id of the media player div
 @returns string id to use in object and embed tags to uniquely identify the octobar
 */
function octopvGetOctobarID(playerDiv){
	return "octobarObjectID" + playerDiv;
}


/* 
 @object: octopv_Config
 @public methods:
	- setStartupImage(startupImage)
	- getStartupImageSrc()
	- getStartupImage(w,h)
	- setExternalWaitPopup(startupPage, startupWidth, startupHeight)
	- do_startup_popup()
	- setInstallPopup(installPageArg, installPageFeaturesArg)
	- setInstallFunction(installFunctionArg)
	- do_install()
	- setAlertTexts(noPlugInText, errorPlugInText)
	- pluginAlertError(result)
	- pluginAlertMissing()
	- pluginAlertErrorSpecial(result, description)
 @public properties: 
	- embedShowControls;
 
 @description: 
 	This object holds any costomized variables the user might have set via any of the
 	octoSet* functions (and octoshape defaults). 
*/
var octopv_Config = new function(){
	this.embedShowControls = true;

	// The statup wait image.
	var embedWaitImg 		= null;
	this.setStartupImage = function(startupImage){
		embedWaitImg 		= startupImage;
	};
	this.getStartupImageSrc = function(){
		return (embedWaitImg==null)?"http://www.octoshape.com/images/upstart_16_9.GIF":embedWaitImg;
	};
	
	// functions is used in documentation.
	this.getStartupImage = function(w,h){
		return "<img src='"+this.getStartupImageSrc()+"' height='"+h+"px' width='"+w+"px'>";
	};
		
	// The external wait popup.
	var externalWaitPopup 		= null;
	var externalWaitPopupHeight = null;
	var externalWaitPopupWidth 	= null;
	
	this.setExternalWaitPopup = function(startupPage, startupWidth, startupHeight){
		externalWaitPopup 		= startupPage;
		externalWaitPopupHeight = startupHeight;
		externalWaitPopupWidth 	= startupWidth;
	};
	
	// function is used in documentation
	this.do_startup_popup = function(){
		var h = (externalWaitPopupHeight==null)? 300:	externalWaitPopupHeight; 
		var w = (externalWaitPopupWidth==null)?	 400:	externalWaitPopupWidth;
		var p = (externalWaitPopup==null)?		"http://www.octoshape.com/play/startup_popup.asp":	externalWaitPopup;
		return window.open(p, "octo_popup", "height="+h+",width="+w);
	};

	// The install popup and install function
	//var installPopupStandard = "http://www.octoshape.com/download/external_install.asp";
	//var installPopupFeaturesStandard = 'height=400,width=520';
	var installPopup = null;
	var installPopupFeatures = null;
	this.setInstallPopup = function(installPageArg, installPageFeaturesArg){
		installPopup = installPageArg;
		installPopupFeatures = installPageFeaturesArg;
	};
	var installFunction = null;
	this.setInstallFunction = function(installFunctionArg){
		installFunction = installFunctionArg;
	};
	
	this.do_install = function(){
		if (installPopup != null){
			var features = installPopupFeatures==null?"":installPopupFeatures;
			window.open(installPopup, "install_popup", features);
		}
		if(installFunction!=null){
			installFunction();
		}
	};
	
	// The alert texts
	var alertTextError 		= null;
	var alertTextMissing 	= null;
	this.setAlertTexts = function(noPlugInText, errorPlugInText){
		alertTextError 		= errorPlugInText;
		alertTextMissing 	= noPlugInText;
	};
	
	this.pluginAlertError = function(result){
		var extra = result==null?"":"\n\nError number: " + result;
		if(alertTextError==null){
			alert("An error occurred while trying to play an Octoshape stream. \nPlease re-install the plug-in."+extra);
		}else{
			alert(alertTextError+extra);
		}
	};

	this.pluginAlertMissing = function(result){
		var extra = "";
		if (result!=null){
			extra = "\n\nError number: " + result;
		}
		if(alertTextMissing==null){
			alert("Please get the Octoshape Plug-In to play."+extra);
		}else{
			alert(alertTextMissing+extra);
		}
	};
	
	this.pluginAlertErrorSpecial = function(result, description){
		alert("An un-expected error occured while trying to start up the Octoshape plug-in. \n"+
		"Please try to shut down the plug-in and then press play again. \n" + 
		"To shut down: right click the system tray icon and choose exit. \n" + 
		"\n\n\nFunction getStatus response was: " + result + 
		"\nStartup link Exception:" + description);
	};
	
	this.octobarPath = "http:/www.octoshape.com/javascripts/octobar.swf";
	this.setOnDemandBarPath = function(path){
		this.octobarPath = path;
	};
}


function octopv_disabled(octoLink){
	for (i=0;i<octopv_disabled_arr.length;i++){
		if (octoLink == octopv_disabled_arr[i]){
			alert("The stream is temporarily disabled.\n   Try again later.");
			return true;
		}
	}
	return false;
}



/* *************************************************************************************/
/* ****************************** EMBEDDED PLAY FUNCTIONS *******************************/

function octopv_embedobj_set(embedObject, widthArg,heightArg, controlsArg, cheatArg){
	embedObject.width 		= widthArg;
	embedObject.height 		= octopv_toNumber(heightArg);
	embedObject.controls 	= (typeof(controlsArg) != "number")? 0: controlsArg; 
	embedObject.cheat 		= (typeof (cheatArg) != "number")?0:cheatArg;
	octopv_debug(embedObject.embedID+' Setting new values. width: '+embedObject.width, arguments.callee);
}


/** 
 */
function octopv_embedplayobj_basics(){

	this.convertOctolink=function(octolink){
		return octolink;
	};

	/* This function should call begin on the octobar object with the 
		lenght of the playing media clip (in seconds). 
		The will initialize the octobar to move.
	*/
	this.octobarReady = function(callbackObject, playerDiv, playerObject){
		octopv_debug('No octobar duration callback implemented. Calling octobarBegin with -1', arguments.callee);
		return false;
	};
	
	this.octobarHTML = function(id, src,width,height){
		octopv_debug('No octobarHTML function implemented. ', arguments.callee);
		return '';
	};

	this.playerHTML = function(id, src, width, height, showControls){
		octopv_debug('No playerHTML function implemented. ', arguments.callee);
		return '';
	};

	this.startupHTML=function(id, width, height, showControls){
		octopv_debug('Showing startup ... ', arguments.callee);
		return this.playerHTML(id+'startup', octopv_Config.getStartupImageSrc(), width, height, showControls);
	};

	this.stop = function(player){
		octopv_debug('stopping player', arguments.callee);
		return false;
	};
	
	this.start = function(player){
		octopv_debug('starting player', arguments.callee);
		return false;
	};
	
	this.setNewUrl = function(player, url){
		octopv_debug('setting new url', arguments.callee);
		return false;
	};
	
	this.volume = function(player, numberBetween1And100){
		octopv_debug('setting volume', arguments.callee);
		return false;
	};
	
	this.playerPause = function(player){
		octopv_debug('setting pause', arguments.callee);
		return false;
	};
}
 

/* 
 @constructor: octopv_embedobj
 @param playerDivArg: string id of the media player div
 @param widthArg: width of the media content
 @param heightArg: height of the media content
 @param controls: (number) 0:normal controls 1:ondemand controls 2:no controls.
 @param cheat [optional]: (number) 
 		0 or undefined: normal play. 
 		1: start up octoshape and play the 'octolink' directly in wmp. 
 		2: do not start up octoshape but just play the 'octolink' directly.
 @public functions added: 
	- play(src)
 	- startup()			shows startup image in player.
 	- playerSeek(number)
 	- playerPlay()
 	- playerStop()
 	- playerPause()
 	- playerVolume(numberBetween1And100)
 	- octobarReady()				dummy (may be overwriten later)
 	- string convertOctolink(link)	dummy (may be overwriten later)
*/
function octopv_embedobj(playerDivArg,widthArg,heightArg, controlsArg, cheatArg){
	this.playerDiv 	= playerDivArg;
	this.embedID 	= Math.random();
	octopv_embedobj_set(this, widthArg,heightArg, controlsArg, cheatArg);

	var scriptingReady 	= false; // ensures that scripting functions are not called before play has been called
	var hasInitDiv 		= false; 
	var rewindSeek 		= false;
	var hasSeekSrc 		= false;
	
	// this must be called from body section.
	this.initPlayerDiv = function(){
		if(!hasInitDiv){
			octopv_debug(this.embedID+' inits player div ', arguments.callee);
			hasInitDiv = true;
			var wmpId = 'octopv_player_'+this.playerDiv;
			var barId = 'octopv_bar_'+this.playerDiv;
			document.getElementById(this.playerDiv).innerHTML='<div id="'+wmpId+'">begin</div><div id="'+barId+'"></div>'; 
			this.wmpDiv = document.getElementById(wmpId); 
			this.barDiv = document.getElementById(barId); 
			octopv_debug(this.embedID+' end init playerdiv: '+this.wmpDiv, arguments.callee);
		}
	};	
	
	this.play = function(src){
		octopv_debug(this.embedID+' playing: '+src, arguments.callee);
		this.initPlayerDiv();
		this.basicSrc = src;
		var id = octopvGetPlayerID(this.playerDiv);
		this.wmpDiv.innerHTML = octopv_embeddedPlayObject.playerHTML(id, this.basicSrc, this.width, this.height, this.controls==0);
		var idBar = octopvGetOctobarID(this.playerDiv);
		if(this.controls==1){
			var srcBar = octopv_Config.octobarPath + "?embedID="+this.playerDiv;
			this.barDiv.innerHTML = octopv_embeddedPlayObject.octobarHTML(idBar, srcBar, this.width, 24);
		}
		
		this.playerObject = document[id]; 
		if(this.controls==1){
			this.octobarObject = document[idBar]; 
		}
		scriptingReady = true;
		octopv_debug(this.embedID+' playerObject: '+this.playerObject, arguments.callee);
	};

	this.close=function(){
		this.initPlayerDiv();
		this.wmpDiv.innerHTML = "";
	}
	
	this.startup=function(){
		this.initPlayerDiv();
		var id = octopvGetPlayerID(this.playerDiv);
		octopv_debug(this.embedID+' showing startup ... width is: '+this.width, arguments.callee);
		this.wmpDiv.innerHTML = octopv_embeddedPlayObject.startupHTML(id, this.width, this.height, this.controls==0);
	};
	
	this.playerStop = function(){
		if(scriptingReady){
			if (hasSeekSrc){
				octopv_debug(this.embedID+' setting rewind seek', arguments.callee);
				rewindSeek = true;
			}
			if(!octopv_embeddedPlayObject.stop(this.playerObject)){
				this.wmpDiv.innerHTML='<div STYLE="height:'+this.height+'px;"></div>';
			};
		}
	};
	
	this.playerPlay = function(){
		if(scriptingReady){
			if(rewindSeek){
				octopv_embeddedPlayObject.setNewUrl(this.playerObject,this.basicSrc);
				rewindSeek = false;
				hasSeekSrc = false;
			}else{
				if(!octopv_embeddedPlayObject.start(this.playerObject)){
					this.play(this.basicSrc);
				};
			}
		}
	};
	
	this.playerSeek = function(number){
		if(scriptingReady){
			octopv_debug(this.embedID+' Seeking to '+number, arguments.callee);
			//octopv_debug('Stopping media player object. ', arguments.callee);
			//this.playerClose(this.playerObject);
			var newUrl = '';
			if(this.basicSrc.indexOf('?') >= 0){
				newUrl = this.basicSrc + '&beginat='+number+'pm';
			}else{
				newUrl = this.basicSrc + '?beginat='+number+'pm';
			}
			hasSeekSrc = (number > 0);
			octopv_debug(this.embedID+' Setting url to '+newUrl, arguments.callee);
			if(!octopv_embeddedPlayObject.setNewUrl(this.playerObject,newUrl)){
				var id = octopvGetPlayerID(this.playerDiv);
				this.wmpDiv.innerHTML=octopv_embeddedPlayObject.playerHTML(id, newUrl, this.width, this.height, this.controls==0);
				this.playerObject = document[id];
				octopv_debug(this.embedID+' inserted new player', arguments.callee);
			}
		}
	};
	
	this.playerVolume = function(numberBetween1And100){
		if(scriptingReady){
			octopv_embeddedPlayObject.volume(this.playerObject,numberBetween1And100);
		}
	};
	
	this.playerPause = function(player){
		if(scriptingReady){
			octopv_embeddedPlayObject.pause(this.playerObject);
		}
	};

	// this is called from flash octobar.
	this.octobarReady = function(){
		if(!octopv_embeddedPlayObject.octobarReady(this,this.playerDiv, this.playerObject)){
			this.octobarObject.octobarBegin("-1");
		}
	};
	
	
	/***************** event handler callbacks ******************/
	
	var hasSetDuration = false;
	this.eventCallback_duration = function(duration){
		octopv_debug("wmp event playing. we call octobar.begin("+duration+")", arguments.callee);
		try{
			var durationStr = ''+duration+'';
			this.octobarObject.octobarBegin(durationStr);
			hasSetDuration = true;
		}catch(exception){
			octopv_debug("octobar set begin exeption: "+exception,  arguments.callee);
		}
	};
	
	
	this.eventCallback_mustGetDuration = function(){
		return !hasSetDuration;
	};
	
	this.eventCallback_playing = function(){
		octopv_debug("wmp event playing. we call octobar.showPlaying() ", arguments.callee);
		this.octobarObject.octobarShowPlaying();
	};
	
	this.eventCallback_buffering = function(){
		octopv_debug("wmp event buffering. we call octobar.showBuffering().", arguments.callee);
		this.octobarObject.octobarShowBuffering();
	};
	
	this.eventCallback_ended = function(){
		try{
			octopv_debug("wmp event ended. We call octobar.stop()",  arguments.callee);
			this.octobarObject.octobarStop();
			rewindSeek = true;
		}catch(exception){
				octopv_debug("octobar stop exeption: "+exception,  arguments.callee);
		}
	};
	
	
}


/* 
 @function: octopv_embedobj_setMac 
 @param embedobj: a octopv_embedobj_basics object
 @Adds methods to param obj: 
 	- octobarHTML(id, src,width,height)
 	- playerHTML(id, src, width, height, showControls)
	- stop(player): This has odd behavier on live streams.
			Flip4mac (and quicktime) actually performs progressive download, that is, 
			the played part of the stream are saved so the user can seek in it. 
			So stop will return to the first viewed part of the stream. 
	- pause(player)
	- start(player)
	- volume(player,number): dummy function doing nothing since flip4mac does not have scriptable volume control.
	- setNewUrl(player,newUrl)	
*/
function octopv_embedobj_setMac(embedobj){
	octopv_debug('Creating embedobj: '+embedobj.embedID, arguments.callee);

	embedobj.convertOctolink=function(octolink){
		// we append the name of the player plugin to the octolink we give to the octoshape browser plugin.
		// this ensures that we get a working link back.
		octopv_debug('Mac converting octolink: '+octolink, arguments.callee);
		if(navigator && navigator.mimeTypes && navigator.mimeTypes.length){
			var mimeID = "video/x-ms-asf";
			var mime =  navigator.mimeTypes[mimeID];
			if(mime && mime.enabledPlugin){
				var playerName = mime.enabledPlugin.name;
				octopv_debug('setting playerplugin='+playerName, arguments.callee);
				return octolink+";playerplugin="+playerName;
			}
		}
		octopv_debug('Mac has converted octolink to: '+octolink, arguments.callee);
		return octolink;
	};

	embedobj.playerHTML = function(id, src, width, height, showControls){
		var html  = '';
		var embedControls=0;

		if(showControls || octopv_isFirefox()){
			// flip4mac in firefox will make space for the controls even if they are not shown!
			embedControls = 16; 
		}
		
		html += '<embed ';
       	html += ' 	src="'+src+'" ';
		html += '	name="'+id+'" ';
		html += '	SCALE="ASPECT" ';
		html += '	ENABLEJAVASCRIPT="TRUE" ';
		html += '	BGCOLOR="GRAY" ';
		html += '	AutoStart="TRUE" ';
       	html += '	width="' + width + '" ';
       	html += '	height="'+(height + embedControls)+'" ';
		html += ' 	TYPE="application/x-mplayer2" ';
		html += ' 	pluginspage="http://www.flip4mac.com/wmv_download." ';
		if(showControls){
			html += '	ShowControls="true" ';
			html += '	showStatusBar="true" ';
		}else{
			html += '	ShowControls="false" ';
			html += '	showStatusBar="false" ';
		}
       	html += ' />';
		return html;
	};




	embedobj.octobarHTML = function(id, src,width,height){
		var html  = '';
		var octobarTopMargin=0;

		if(octopv_isFirefox()){
			// flip4mac in firefox will make space for the controls even if they are not shown!
			octobarTopMargin = -38; 
		}else{
			octobarTopMargin = -5; 
		}
		html += '	<embed src="'+src+'" ';
		html += '		STYLE="margin-top:'+octobarTopMargin+'px;"'; 
		html += '		loop="false"';
		html += '		menu="false"';
		html += '		quality="high"';
		html += '		salign="lt"';
		html += '		bgcolor="#ffffff"';
		html += '		width="'+width+'"';
		html += '		name="'+id+'"';
		html += '		height="'+height+'"';
		html += '		align="middle"';
		html += '		allowScriptAccess="always"';
		html += '		allowFullScreen="true"';
		html += '		type="application/x-shockwave-flash"';
		html += '		pluginspage="http://www.macromedia.com/go/getflashplayer" />';
		return html;
	};
	
	
	embedobj.stop = function(player){
		try{
			player.Stop();
			return true;
		}catch(exception){
			octopv_debug('Could not stop: '+exception, arguments.callee);
			return false;
		}
	}
	
	embedobj.start = function(player){
		try{
			octopv_debug('should play mac script.', arguments.callee);
			player.Play();
			return true;
		}catch(exception){
			octopv_debug('Could not play: '+exception, arguments.callee);
			return false;
		}
	}
	
	embedobj.pause = function(player){
		try{
			octopv_debug('pausing from mac script ', arguments.callee);
			player.Pause();
			return true;
		}catch(exception){
			octopv_debug('Could not pause: '+exception, arguments.callee);
			return false;
		}
	}
	
	
	// We have no octobarReady function since we can not retrieve the media duration from flip4mac.
	/** There is no documentation for flip4mac script support.
	According to: http://forum.flip4mac.com/forum/messageview.aspx?catid=9&threadid=1271
		Flip4Mac supports Play, Pause, Stop, Next, Previous, Open as well as CurrentPosition, FileName, PlayState. 
	from http://msdn.microsoft.com/en-us/ms870192.aspx 
		But open and filename does not work!.
	
	*/
		
	
}



/* 
 @function: octopv_embedobj_setFxWithPlugin
	For Firefox browser with the wmp plugin installed
 @param embedobj
 @Adds public methods to embedobj:
 	- void playerHTML(id, src, width, height, showControls) 
 	- void octobarHTML(id, src,width,height) 
*/
function octopv_embedobj_setFxWithPlugin(embedobj){
	octopv_debug('Creating embedobj ', arguments.callee);
	
	embedobj.playerHTML = function(id, src, width, height, showControls){
		var paramUiMode = '';
		var controls = 0;
		if(showControls){
			paramUiMode += '	<PARAM name="uimode" value="mini" >';
			controls += 45; 
		}else{
			paramUiMode += '	<PARAM name="uimode" value="none" >';
		}
		octopv_debug('inserting. h:'+height+" cntrls: "+controls+" ", arguments.callee);
		var html  = '';
		html += '	<OBJECT ID="'+id+'" ';
		html += '	height="'+(height + controls)+'" width="'+width+'" ';
        html += ' 	type="application/x-ms-wmp"'; 
		html += '   STANDBY="Loading Octoshape plugin and client" >';
		html += '		<param name="Loop" value="0">';
		html += '       <param name="Repeat" value="false">';
		html += '	    <param name="rate" value="True">';
		html += '	    <param name="defaultFrame" value="">';
		html += '	    <param name="playCount" value="False">';
		html += '	    <param name="mute" value="False">';
		html += '	    <param name="enableErrorDialogs" value="False">';	
		html += '       <param name="autostart" value="true">';
		html += '       <param name="PlayCount" value="1">';
		html += '       <param name="AutoRewind" value="false">';
		html += '	    <param name="URL" value="'+src+'">';
		html += '	    <param name="src" value="'+src+'">';
		
		// StretchToFit will scale up the video if the player is larger than the content, 
		// 	but the aspect ratio will be preserved. 
		// There is no ShrinkToFit like for IE, the behavior is just always to shrink to fit. 
		html += '   	<param name="stretchToFit" value="1" />';	
		html += paramUiMode;
		html += '</OBJECT>';
		return html;
	};

	embedobj.octobarHTML = function(id, src,width,height){
		var html  = '';
			html += '	<embed src="'+src+'"';
			html += '		STYLE="margin-top:-4px;"'; // for some reason fx inserts a spacing between the objects.
			html += '		loop="false"';
			html += '		menu="false"';
			html += '		quality="high"';
			html += '		salign="lt"';
			html += '		bgcolor="#ffffff"';
			html += '		width="'+width+'"';
			html += '		height="'+height+'"';
			html += '		name="'+id+'"';
			html += '		align="middle"';
			html += '		allowScriptAccess="always"';
			html += '		allowFullScreen="false"';
			html += '		type="application/x-shockwave-flash"';
			html += '		pluginspage="http://www.macromedia.com/go/getflashplayer" />';
			return html;
	};
}

/* 
 @function: octopv_embedobj_setIeWmp7
	 For Internet Explorer at least with wmp 7.
 @param embedobj
 @Adds public methods to embedobj:
 	- void playerHTML(id, src, width, height, showControls) 
 	- void octobarHTML(id, src,width,height) 
*/
function octopv_embedobj_setIeWmp7(embedobj){
	octopv_debug('Creating embedobj ', arguments.callee);
	
	embedobj.playerHTML = function(id, src, width, height, showControls){
		var html  = '';
		var paramUiMode = '';
		var controls = 0;
		
		if(showControls){
			paramUiMode += '	<PARAM name="uimode" value="mini" >';
			controls += 45; 
		}else{
			paramUiMode += '	<PARAM name="uimode" value="none" >';
		}
		
		octopv_debug('inserting. h:'+height+" cntrls: "+controls+" ", arguments.callee);
		html += '<OBJECT ID="'+id+'" ';
		html += 'height="'+(height + controls)+'" width="'+width+'" ';
		html += 'classid="CLSID:6BF52A52-394A-11D3-B153-00C04F79FAA6" ';
		html += 'STANDBY="Loading Octoshape plugin and client" ';
		html += 'pluginspage="http://microsoft.com/Windows/MediaPlayer/" ';
		html += 'codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,4,7,1112" '; // checks if wmp is installed, if not it is installed automaticly 
		html += 'type="application/x-oleobject">';
		html += '	<param name="rate" value="True" />';
		html += '	<param name="enableErrorDialogs" value="False" />';	
		html += '   <param name="autostart" value="True" />';
		html += '	<param name="URL" value="'+src+'" />';
		
		// StretchToFit will scale up the video if the player is larger than the content, 
		// 	but the aspect ratio will be preserved.
		// The matching shrinkToFit has default value true so it is not necessary to add it.
		html += '   <param name="StretchToFit" value="True" />';

		
		html += paramUiMode;
		html += '</OBJECT>';
		return html;
	};
	
	embedobj.octobarHTML = function(id, src,width,height){
		var html='';
		html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
		html += 'codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" ';
		html += 'width="'+width+'" height="'+height+'" id="'+id+'" align="middle">';
		html += '	<param name="allowScriptAccess" value="always" />';
		html += '	<param name="allowFullScreen" value="false" />';
		html += '	<param name="movie" value="'+src+'" />';
		html += '	<param name="loop" value="false" />';
		html += '	<param name="menu" value="false" />';
		html += '	<param name="quality" value="high" />';
		html += '	<param name="salign" value="lt" />';
		html += '	<param name="bgcolor" value="#ffffff" />';
		html += '</object>';
		return html;
	};
	
	
}


/* 
 @function: octopv_embedobj_setIeWmp64
 		For Internet Explorer with WMP version 6.4 or lower
 @param embedobj
 @Adds public methods to param embedobj:
 	- void playerHTML(id, src, width, height, showControls) 
 	- void octobarHTML(id, src,width,height) 
	- playerStop2()
	- playerPause()
	- playerPlay2()
	- playerVolume(number)
	- playerSetNewUrl(newUrl)	
 @issues:
 	1) Video content scalling: (StretchToFit parameter)
	  	- scales up and down 	
	  	- but does not keep aspect ratio
*/
function octopv_embedobj_setIeWmp64(embedobj){
	octopv_debug('Creating embedobj: ', arguments.callee);
	
	embedobj.playerHTML = function(id, src, width, height, showControls){
		var html  = '';
		var objectParamsUiMode = '';
		var objectControls = 0;

		objectParamsUiMode += '<PARAM name="showtracker" value="false" >';
		objectParamsUiMode += '<PARAM name="showdisplay" value="false" >';
		
		if(showControls){
			objectParamsUiMode += '<PARAM name="showcontrols" value="true" >';
			objectControls += 26; 
			objectParamsUiMode += '<PARAM name="showstatusbar" value="true" >';
			objectControls += 24; 
		}else{
			objectParamsUiMode += '<PARAM name="showcontrols" value="false" >';
			objectParamsUiMode += '<PARAM name="showstatusbar" value="false" >';
		}
		
		html += '<OBJECT ID="'+id+'" ';
		html += 'height="'+(height + objectControls)+'" width="'+width+'"';
		html += 'classid="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95"';
		html += 'STANDBY="Loading Octoshape plugin and client"';
		html += 'pluginspage="http://microsoft.com/Windows/MediaPlayer/" ';
		html += 'codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,4,7,1112"'; // checks if wmp is installed, if not it is installed automaticly 
		html += 'type="application/x-oleobject">';
		html += '	<param name="rate" value="True" />';
		html += '	<param name="enableErrorDialogs" value="False" />';	
		html += '   <param name="autostart" value="true" />';
		html += '   <param name="PlayCount" value="1" />';
		html += '   <param name="AutoRewind" value="false" />';
		html += '	<param name="URL" value="'+src+'" />';
		html += '	<param name="src" value="'+src+'" />';
		html += objectParamsUiMode;
		html += '   <param name="stretchToFit" value="true" />';
		html += '</OBJECT>';
		return html;
	};

	embedobj.octobarHTML = function(id, src,width,height){
		var html = '';
		html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
		html += 'codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" ';
		html += 'width="'+width+'" height="'+height+'" id="'+id+'" align="middle">';
		html += '	<param name="allowScriptAccess" value="always" />';
		html += '	<param name="allowFullScreen" value="false" />';
		html += '	<param name="movie" value="'+src+'" />';
		html += '	<param name="loop" value="false" />';
		html += '	<param name="menu" value="false" />';
		html += '	<param name="quality" value="high" />';
		html += '	<param name="salign" value="lt" />';
		html += '	<param name="bgcolor" value="#ffffff" />';
		html += '</object>';
		return html;
	}


	embedobj.stop = function(player){
		try{
			player.stop();
			return true;
		}catch(exception){
			octopv_debug('Could not stop: '+exception, arguments.callee);
			return false;
		}
	};
	
	embedobj.start = function(player){
		try{
			player.play();
			return true;
		}catch(exception){
			octopv_debug('Could not play: '+exception, arguments.callee);
			return false;
		}
	};
	
	embedobj.pause = function(player){
		try{
			player.pause();
			return true;
		}catch(exception){
			octopv_debug('Could not pause: '+exception, arguments.callee);
			return false;
		}
	}
	
	embedobj.volume = function(player,number){
		try{
			// volume min is -10.000, max is 0, and mmedium is -600.
			// mapping below is heuristic
			var num = octopv_toNumber(number);
			if(num!=0){
				num = Math.log(num) * (100/Math.log(100));
				num = Math.sqrt(num) * 10;
				num = ((num)-100)*100;
			}
			player.Volume=num;
			octopv_debug('volume is after : '+player.Volume, arguments.callee);
			return true;
		}catch(exception){
			octopv_debug('Could not volume: '+exception, arguments.callee);
			return false;
		}
	};
	
	embedobj.setNewUrl = function(player, newUrl){
		try{
			octopv_debug('Setting url to '+newUrl, arguments.callee);
			player.Open(newUrl);
			return true;
		}catch(exception){
			octopv_debug('Could not seek: '+exception, arguments.callee);
			return false;
		}
	};
}


/* 
 @function: octopv_embedobj_setEmbedTag
 	Uses an <embed> tag
 	Used for Firefox without wmp plugin and for unknown browsers.
	Adds simple scripting by removing and inserting the player on the page.
 @param embedobj
 @Adds public methods to param embedobj:
 	- void playerHTML(id, src, width, height, showControls) 
	- startup()	: shows html img tag this startup image.
	- playerStop2(): removes the player.
	- playerPause(): dummy.
	- playerPlay2(): inserts a new player on the page
	- playerVolume(number): dummy.
	- playerSetNewUrl(newUrl): inserts a new player on the page
 @issues:
 	1) Video content scalling: 
	  	There are no usefull parameters.  Stretchtofit parameter does not work, 
	  	and autosize wil resize the PLAYER to fit the content (unless height and width are specified)).
	  	- only scales down 
	  	- keeps aspect ratio
	
 	2) Firefox + wmp 11: video content scalling (embed tag):
		Windows media player 11 has stretch and resize error with firefox embed plugin. 
 
 	3) None of the controls can be removed. 
	
*/
function octopv_embedobj_setEmbedTag(embedobj){
	octopv_debug('Creating embedobj: ', arguments.callee);
	
	embedobj.playerHTML = function(id, src, width, height, showControls){
		var html  = '';
		var embedControls = 51;	

		html += '<embed ';
		html += ' 	type="application/x-mplayer2" ';
		html += ' 	pluginspage="http://microsoft.com/Windows/MediaPlayer/" ';
		html += ' 	filename="'+src+'" ';
       	html += ' 	src="'+src+'" ';
		html += '	name="'+id+'" ';
       	html += '	width="' + width + '" ';
       	html += '	height="'+(height + embedControls)+'" />';
		return html;
	};

	embedobj.startupHTML=function(id, width, height, showControls){
		octopv_debug('startup from no plugin fx', arguments.callee);
		return octopv_Config.getStartupImage(width,height);
	};

}

/* 
 @function: octopv_setWmpScripting
 @param embedobj
 @Adds public methods to param embedobj:
	- stop(player)
	- pause(player)
	- start(player)
	- volume(player,number)
	- setNewUrl(player,newUrl)
	- octobarReady()
*/
function octopv_setWmpScripting(embedobj){
	octopv_debug('Adding scripting functions embedobj. octobar: '+(embedobj.controls==1), arguments.callee);
	
	embedobj.octobarReady = function(callbackObject, playerDiv, playerObject){
		callbackObject.playStateHandler = function(newState){
			switch(newState){
			case 3:	// playing state
				if(this.eventCallback_mustGetDuration()){
					var duration = this.playerObject.currentMedia.duration;
					this.eventCallback_duration(duration);
				}else{
					this.eventCallback_playing();
				}
				return true;
			case 8:	 // media ended state. 
				this.eventCallback_ended();
				return false;
			case 6: // buffering state
				this.eventCallback_buffering();
				return false;
			case 1:
				octopv_debug("wmp event stopped. ",  arguments.callee);
				return false;
			case 9:  
				octopv_debug("wmp event transitioning.", arguments.callee);
				return false;
			case 10:  
				octopv_debug("wmp event ready to play.", arguments.callee);
				return false;
			default:
				octopv_debug("wmp event "+newState, arguments.callee);
				return false;
			}
		};

		callbackObject.playStateHandlerNoArg = function(){
			var state = this.playerObject.playState;
			if((typeof(this.previousPlayState) == 'undefined' )|| (this.previousPlayState != state)){
				this.previousPlayState = state;
				this.playStateHandler(state);
			}
		};
		
		function setEventListener(eventName, handlerName, thisplayerDiv, thisplayerObject){
			octopv_debug("testing this.playerDiv: "+thisplayerDiv+" .", arguments.callee);
			var event = '';
			event += 	'var player = octopv_embeddedPlayers["'+thisplayerDiv+'"];';
			event += 	'if(typeof player != "undefined"){';
			event += 	'try{';
			event += 		'player.'+handlerName+'(NewState);';
			event += 	'}catch(ex){ ';
			event += 		'octopv_debug("Error calling '+handlerName+' with "+NewState+". Ex:"+ex, alert);';
			event += 	'}';
			event += 	'}else{';
			event += 		'octopv_debug("Could not find player in '+eventName+' event handler. state:"+NewState, alert);';
			event += 	'}';
			try{
				if(octopv_isFirefox3()){
					/**
					 The windows media player plugin object oriented event handlers does not work in Firefox 3.
					 For unknown reasons. No web documentation exists on this (acording to miscrosofts docu it should work).
					 TODO:
					 1) test with to players in one page!
					 2) new update in br-we-int pages.
					*/
					//we only add this once since it loops through all active players 
					if(typeof(window['octopv_hasSetFx3EventHandler']) == 'undefined'){
						window['octopv_hasSetFx3EventHandler'] = true;
						octopv_debug("Firefox 3 adding simple onState change for: "+thisplayerDiv+" .", arguments.callee);
						var scriptText = 'function OnDSPlayStateChangeEvt(NewState){';
						scriptText += '		for (var i in octopv_embeddedPlayers){';
						scriptText += '			try{';
						scriptText += '				octopv_embeddedPlayers[i].playStateHandlerNoArg();';
						scriptText += '			}catch(ex){';
						scriptText += '				octopv_debug("ERROR: "+ex+" Full embedded players array ("+getPropertiesString(octopv_embeddedPlayers)+")", arguments.callee);'; 
						scriptText += '			}';
						scriptText += '		}';
						scriptText += '}';
						var script = document.createElement('script');
						script.type = 'text/javascript';
						script.text = scriptText;
						document.getElementById(thisplayerDiv).appendChild(script);
					}
				}else if(octopv_isFirefox()){
					octopv_debug("Adding wmp event "+eventName+" listener firefox.", arguments.callee);
					var script = document.createElement('script');
					script.type = 'text/javascript';
					script.setAttribute('for', octopvGetPlayerID(thisplayerDiv));
					script.setAttribute('event', eventName+'(NewState)');
					script.text = event;
					document.getElementById(thisplayerDiv).appendChild(script);
				}else{
					// Internet Explorer can not use setAttribute for event handlers.
					// Dynamically adding a script inside another
					// attachEvent works for IE5+
					// attachEvent only works for IE
					/* About the second argument to attachEvent:
					  	It will be referenced not copied (the 'this' variable refers to the window element).
					  	There is appearently no way of getting a reference to the element that caused the event. 
					*/
					octopv_debug("Attaching wmp event "+eventName+" listener ie.", arguments.callee);
					var func = new Function("NewState", event);
					thisplayerObject.attachEvent(eventName, func);
				}
			}catch(ex){
				octopv_debug('Error adding '+eventName+' event listener: '+ex, arguments.callee);
			}
		};

		octopv_debug("Adding wmp event listeners.", arguments.callee);
		if(!callbackObject.playStateHandler(playerObject.playState)){
			setEventListener('PlayStateChange', 'playStateHandler', playerDiv,playerObject);
		};
		
		return true;
	}
	
	embedobj.stop = function(player){
		try{
			player.controls.stop();
			return true;
		}catch(exception){
			octopv_debug('Could not stop: '+exception, arguments.callee);
			return false;
		}
	}
	
	embedobj.start = function(player){
		try{
			player.controls.play();
			return true;
		}catch(exception){
			octopv_debug('Could not play: '+exception, arguments.callee);
			return false;
		}
	}
	
	embedobj.pause = function(player){
		try{
			player.controls.pause();
			return true;
		}catch(exception){
			octopv_debug('Could not pause: '+exception, arguments.callee);
			return false;
		}
	}
	
	embedobj.volume = function(player,number){
		try{
			octopv_debug('volume is before : '+player.settings.volume, arguments.callee);
			player.settings.volume=number;
			octopv_debug('volume is after : '+player.settings.volume, arguments.callee);
			return true;
		}catch(exception){
			octopv_debug('Could not volume: '+exception, arguments.callee);
			return false;
		}
	}
	
	embedobj.setNewUrl = function(player, newUrl){
		try{
			octopv_debug('Setting url to '+newUrl, arguments.callee);
			player.URL=newUrl;
			return true;
		}catch(exception){
			octopv_debug('Could not seek: '+exception, arguments.callee);
			return false;
		}
	}
}






/* *************************** END EMBEDDED PLAY FUNCTIONS *****************************/
/* **************************************************************************************/


/* 
 @contructor: octolinkObject
 @param link: either a full octolink or just an octo-id
 @public properties: 
	- group
	- octoid
 @public methods:
	- octolink(): returns full octolink (ie. OCTOSHAPE[group]:[octoid])
 @description: Simple object that splits an octolink into group and octoid.
    If the argument is not a full octolink but only an octoid, 
	the global octopv_group is used as group.
*/
function octopv_octolinkObject(link){
	var low = link.toLowerCase();
	if(low.indexOf("octoshape") == 0){
		var endGroup = low.indexOf(':',0);
		this.group = low.substring(8,end).toUpperCase();
		this.octoid = link.substring(endGroup+1);
	}else{
		this.group = octopv_group;
		this.octoid = link;
	}
	
	this.octolink = function(){
		return "OCTOSHAPE"+this.group+":"+this.octoid;
	};
}


/* 
 @function: octopv_play_rec
 @param octolinkObjArg: an object of type octolinkObject.
 @param embedObjArg: null or an object with methods 
 	- void play(src) 
 	- void startup()
 	- string convertOctolink(link)
 @returns boolean: true if we will begin to play the link at some time.
 @description: If param embedObjArg is null we play in an external player.
*/
function octopv_play_rec(octolinkObjArg, embedObjArg){
	if(octopv_globalPlayObj==null){
		// There is currently no other active play call.
		octopv_debug('beginning new rec call', arguments.callee);
		octopv_globalPlayObj=new Object();
		octopv_globalPlayObj.embedObj = embedObjArg;
		octopv_globalPlayObj.octolinkObj = octolinkObjArg;
		octopv_globalPlayObj.externalplay = function(){
			return this.embedObj==null;
		};
		octopv_globalPlayObj.numRecur=0;
		octopv_globalPlayObj.oldStatus = 999;
		octopv_globalPlayObj.plugin_instance = null;
	}else if(octopv_globalPlayObj){
		// There is another active play call that has not begun to play yet 
		//   (most likely it is waiting in loop for the octoshape plugin to start up).
		// We should replace any user input specific variables in the global arguments,
		// but not start up a new recursive call.
		octopv_globalPlayObj.octolinkObj = octolinkObjArg;
		if(!octopv_globalPlayObj.externalplay()){
			octopv_globalPlayObj.embedObj.close();
		}
		octopv_globalPlayObj.embedObj = embedObjArg;
		return true; 
	}
	
	if(octopv_play_rec2()){
		return true;
	}else{
		// There was some playing error (maybe the user needs to install octoshape)
		octopv_globalPlayObj=null;
		return false;
	}
}

/* 
 @function: octopv_play_rec2
 @returns boolean: true if we will begin to play at some time.
 @description: 
 	This function is called by octopv_play_rec and by itself via setTimeout.
 	This function calls itself with the JavaScript function setTimeout when waitng 
 	for the octoshape plugin to start up. SetTimeout unfortunately always executes 
 	in top level scope and so we can not parse any arguments from one execution of 
 	octopv_play_rec2 to the next. 
 	This is resolved by setting the nescesary arguments in the global object 
 	octopv_globalPlayObj before calling this function the first time. 
 */
function octopv_play_rec2(){
	octopv_debug('recursiv play begin', arguments.callee);

	// from -4 to 2: answer from octoclient
	// -10: no octoclient present
	// -20: octoclient had no getStatus function
	// -30: we had special error case where browser plug-in first answered 'starting up' and then was not installed
	// This function might throw an exception (?)
	// NB: IF octopvPrivate < 100, this will overrule anything else (used in web setup pages only)
	function getStatus(){
		var status = -10;
		
		octopv_debug('getting the status', arguments.callee);
		
		if(!octopv_globalPlayObj.externalplay()){
			if(octopv_globalPlayObj.embedObj.cheat == 2) return 2;	// circumventing regular octoshape startup in cheat mode.
		}
		
		if (!octoLowLevelCheck(octopv_globalPlayObj.plugin_instance)){ 
			octopv_debug('in getStatus() octoLowLevelCheck was false', arguments.callee);
			octopv_globalPlayObj.plugin_instance = octoLowLevelGet(octopv_globalPlayObj.octolinkObj.group);
		}
		if (octopvPrivate < 100){ return octopvPrivate; }
		
		if (octoLowLevelCheck(octopv_globalPlayObj.plugin_instance)){ 
			// We query the activeX object to se what status the octoshape program is in
			// The parameter indicates whether we want the octoshape program to begin starting up, if it is not already running ...
			
			octopv_debug('calling client.getStatus(true) ', arguments.callee);
			
			status = octopv_globalPlayObj.plugin_instance.getStatus(true);

			
		}else{
			status = octoLowLevelCheckErrorCode;
		}

		// some users have experienced that when plugin installed but closed then:
		// pressing play the user gets 'octoshape is starting up' (status 1), 
		// but after a while the user gets 'please install' (status -10) and no music is played. 
		// solution: if we get -10 after we have gotten 2, we wait a while to see if we get something other than -10
		if (octopv_globalPlayObj.oldStatus == 1 && (status == -10 || status == -20)) {
			octopv_globalPlayObj.numRecur++;
			if (octopv_globalPlayObj.numRecur < 4){ 
				return 1;
			}else{
				// we have waited 8 seconds with no success
				return -30;
			}
		} 
				
		octopv_globalPlayObj.numRecur=0;
		octopv_globalPlayObj.oldStatus = status;
		return status;	
	}
	
	try {
		var result = getStatus();
	
		octopv_globalPlayObj.recursive_waiting = false;
		octopv_debug('getStatus result: '+result, arguments.callee);
	
		switch (result){
			case -100:	octopvPrivate = 999; 
				return false; 	// do nothing: for web integration pages
			case -30:	// special error case 
				alert("An error occurred while trying to play an Octoshape stream.\nTry to refresh your browser window and play again.\n(error -30)");
				return false;	
			case -20:	// octoclient has no getStatus
				octopv_Config.pluginAlertMissing(-20);
				octopv_Config.do_install();
				return false;	
				case -10:	// no octoclient
				octopv_Config.pluginAlertMissing(null);
				octopv_Config.do_install();
				return false;
				// case 0 will not happen since we call getStatus with true
 			case 1:
 				// octoshape is starting up, so we show some message to the user while s/he waits
 				octopv_debug("starting up", arguments.callee);

				if (octopv_globalPlayObj.externalplay()){
					if (octopv_globalPlayObj.startup_popup == undefined){
						octopv_globalPlayObj.startup_popup = octopv_Config.do_startup_popup();
					}
				} else {
					octopv_globalPlayObj.embedObj.startup();
				}

				// we call our self again in 2000 milli-seconds
				setTimeout("octopv_play_rec2();",2000);
				octopv_globalPlayObj.recursive_waiting = true;
	 			return true;
			case 2:
				// octoshape is already started up, so we just play the link
 				octopv_debug("should begin to play", arguments.callee);
			
				// We get the link to play from the activeX object. The second parameter indicates whether we want to play in an external player.
				
				if (octopv_globalPlayObj.externalplay()){
					octoStopEmbedded();
					if (octopv_globalPlayObj.startup_popup != undefined){
						if(!octopv_globalPlayObj.startup_popup.closed){
							octopv_globalPlayObj.startup_popup.close();
						}
						octopv_globalPlayObj.startup_popup = undefined;
					}

					octopv_debug("should begin to play external: "+octopv_globalPlayObj.octolinkObj.octolink(), arguments.callee);
					window.location.href=octopv_globalPlayObj.octolinkObj.octolink();
				}else {
					var embedPlaylink = "";
					if (octopv_globalPlayObj.embedObj.cheat == 0){	
						// if not in cheat mode we ask the browser plugin to translate the octolink to a media player link. 
						var newOctolink = octopv_embeddedPlayObject.convertOctolink(octopv_globalPlayObj.octolinkObj.octolink());
						embedPlaylink = octopv_globalPlayObj.plugin_instance.getLink(newOctolink,false);
					}else{
						// if in cheat mode we just play the given link directly. 
						embedPlaylink = octopv_globalPlayObj.octolinkObj.octoid;
					}
 					octopv_debug("should begin to play embedded: '"+embedPlaylink+"'", arguments.callee);
					octopv_globalPlayObj.embedObj.play(embedPlaylink);	
				}
			
				octopv_globalPlayObj=null;
 				return true;
 			default:
				// there was an error from the octoshape plug-in, we need to ask the user to re-install
				octopv_Config.pluginAlertError(result);
	 			octopv_Config.do_install();
	 			return false;
		}
	}catch (exception) {
		// This should really not happen, but just in case something went completely un-expectedly wrong, 
		// we must present the user with some form of crash recover help message.
		if(!octopv_debug("Exception occcered: "+exception, arguments.callee)){
			octopv_Config.pluginAlertErrorSpecial(result, exception.description);
			octopv_Config.do_install();
		}
		return false;
	}	
}


/* *************************************************************************************/
/* ********************************* LOW LEVEL FUNCTIONS *******************************/

var octoLowLevelPlayHelperObject = new Array(2);

function octopv_octoLowLevelPlayReset(){
	octoLowLevelPlayHelperObject.upstart=function(){};
	octoLowLevelPlayHelperObject.play=function(){};
	octoLowLevelPlayHelperObject.status=function(){};
}

octopv_octoLowLevelPlayReset();

// theOctoshapeClient is assumed to be a valid octoshape browser plug-in. 
// playfunction must be a function taking a link to be played.
function octoLowLevelPlay(theOctoshapeClient, fullOctoLink, getExternalLink, playfunction){
	octoLowLevelPlayHelperObject.play = function(){
		if(getExternalLink){
			playfunction(fullOctoLink);
		}else{
			var link = theOctoshapeClient.getLink(fullOctoLink, getExternalLink);
			playfunction(link);
		}
	};
	
	octoLowLevelPlayHelperObject.status = function(){
		return theOctoshapeClient.getStatus(true);
	}
	
	try {
		return octopv_octoLowLevelPlayRepeat();
	}
	catch (exception) {
		return -6;
	}
}

// theOctoshapeClient is assumed to be a valid octoshape browser plug-in. 
// playfunction must be a function with no arguments.
function octoLowLevelReady(theOctoshapeClient, readyfunction, startingupFunction){
	octopv_octoLowLevelPlayReset();
	octoLowLevelPlayHelperObject.play = readyfunction;
	
	octoLowLevelPlayHelperObject.status = function(){
		return theOctoshapeClient.getStatus(true);
	}
	if(typeof(startingupFunction) != 'undefined'){
		octopv_debug('setting startingupFunction to '+startingupFunction, arguments.callee);
		octoLowLevelPlayHelperObject.upstart = startingupFunction;
	}
	
	try {
		return octopv_octoLowLevelPlayRepeat();
	}
	catch (exception) {
		return -6;
	}
}

function octopv_octoLowLevelPlayRepeat(){
	var result = octoLowLevelPlayHelperObject.status();
		
	switch (result){
 		case 1:
			// we call our self again in 2000 milli-seconds
			var id = setTimeout("octopv_octoLowLevelPlayRepeat();",2000);
			octoLowLevelPlayHelperObject.upstart();
			return result;
		case 2:
			// octoshape is already started up, so we just play the link
			
			octoLowLevelPlayHelperObject.play();
			octopv_octoLowLevelPlayReset();
 			return result;
 		default:
 			return result;
	 }
}

var octoLowLevelCheckErrorCode=0;	// 0: all ok; -10: no plugin; -20 missing getStatus.

/* Getting the activeX object */
function octoLowLevelCheck(octoobject){
	if (octoobject==null || typeof(octoobject) == "undefined"){
		octoLowLevelCheckErrorCode = -10;
		octopv_debug('octoobject is typeof undefined', arguments.callee);
		return false;
	}
	if (typeof(octoobject.getStatus) == "undefined") {
		octoLowLevelCheckErrorCode = -20;
		octopv_debug('octoobject.getStatus is typeof undefined', arguments.callee);
		return false;	
	}
	octoLowLevelCheckErrorCode = 0;
	octopv_debug('octoobject is fine', arguments.callee);
	return true;
}


// Get the octoshape activeX object with this function
// If we fail and have Firefox, we refresh the plug-ins, and try once more
// can be called with zero or one argument.
// The group argument is optional. If not provided the octopv_group will be used.
function octoLowLevelGet(group){
	var local_group;
	if(arguments[0] instanceof String){
		local_group = group;
	}else{
		local_group = octopv_group;
	}
	// Do not call this from the head section of a document.
	octopv_debug('calling octoLowLevelGet', arguments.callee);
	
	function octopv_get_octoclient_sub(){
	
		// Do not call this from the head section of a document.
		function octopv_get_octoclient_mimetype() {
			var octomime = "application/x-octoshapeplugin"+local_group+"-client";
			
			if (navigator && navigator.mimeTypes && navigator.mimeTypes.length > 0) {
				var mimetype = navigator.mimeTypes[octomime];

				if (!mimetype) {
					octomime = octomime.toLowerCase();
					mimetype = navigator.mimeTypes[octomime];
				}

				if (mimetype) {
					var octoshape = document.getElementById('octoshapeclientobject');
					if (!octoshape) {
						var oDiv = document.createElement("DIV");
						document.body.appendChild(oDiv);
					
						if(octopv_isOSX()){
							oDiv.innerHTML = "<embed id=octoshapeclientobject type=\""+octomime+"\" hidden=\"true\"></embed>";
						}else{
							oDiv.innerHTML = "<object id=octoshapeclientobject type=\""+octomime+"\" style=\"height: 0px; width:1px;\" hidden=\"true\"></object>";
						}
						octoshape = document.getElementById('octoshapeclientobject');
					}

					if (octoLowLevelCheck(octoshape)) {
						octopv_debug("Client loaded using mimeTypes:" + octomime, arguments.callee);
						return octoshape;
					}else{
						octopv_debug("Have inserted html mime type object, but mime type was not known. :"+octoshape, arguments.callee);
					}
				} 
			}
			return undefined;
		}

		try {
			if (window.ActiveXObject) {
				try {
					var octoshape = new ActiveXObject("octoshapeplugin"+local_group+".client");
					if  (octoLowLevelCheck(octoshape)){ return octoshape; }
				} catch(exception) {}
			}
		
			if (window.GeckoActiveXObject) {
				try {
					var octoshape = new GeckoActiveXObject("octoshapeplugin"+local_group+".client");
					if  (octoLowLevelCheck(octoshape)){ return octoshape; }
				} catch(exception) {}
			}
			
			// Crashes opera
			if (false && navigator && navigator.plugins && navigator.plugins.length) {
				var octoshape = navigator.plugins["application/x-octoshapeplugin"+local_group+".client"];
				if  (octoLowLevelCheck(octoshape)){ return octoshape; }
			}		
		
			if (navigator && navigator.mimeTypes && navigator.mimeTypes.length) {
				var octoshape = octopv_get_octoclient_mimetype();
				if  (octoLowLevelCheck(octoshape)){ return octoshape; }
			}
			octopv_debug("Client loading failed all together.", arguments.callee);
			return undefined;
		} catch (exception) {
			return octopv_get_octoclient_mimetype();
		}
	}


	var obj = octopv_get_octoclient_sub();
	if (octoLowLevelCheck(obj)){
		return obj;
	}
	else {
		if(navigator.plugins){
			navigator.plugins.refresh(false);
			return (octopv_get_octoclient_sub());
		}
		return obj;
	}
}



/* **************************************************************************************/
/* ********************************* UTILITY FUNCTIONS *******************************/

function octopv_activexdisabled(){
	var text = navigator.userAgent.toLowerCase();
	if (text.indexOf("msie") >= 0){ 
		try{
			var test = new ActiveXObject("Scripting.Dictionary");
		}catch(e){
			return true;
		}
	}
	return false;
}


// returns true iff there is a plugin registered for the mime type mimeID and
//  the name of this plugin contains pluginName (case oblivious).
function octopv_mime_plugin_is(mimeID, pluginName){
	if(navigator && navigator.mimeTypes && navigator.mimeTypes.length){
		var mime =  navigator.mimeTypes[mimeID];
		if(mime){
			var text  = mime.enabledPlugin.name.toLowerCase();
			return (text.indexOf(pluginName.toLowerCase()) >=0);
		}
	}
	return false;
}

// returns true if there is a plug-in installed that can handle the video/x-ms-asf mime-type
function octopv_has_mime(mimeID){
	if(navigator && navigator.mimeTypes && navigator.mimeTypes.length){
		var mime =  navigator.mimeTypes[mimeID];
		if(mime && mime.enabledPlugin){
			return true;
		}
	}
	return false;
}

function octopv_isOSX(){
	return navigator.userAgent.toLowerCase().indexOf("mac os x") != -1;
}

function octopv_isFirefox(){
	return navigator.userAgent.toLowerCase().indexOf("firefox") != -1;
}

function octopv_isFirefox3(){
	return navigator.userAgent.toLowerCase().indexOf("firefox/3") != -1;
}

function octopv_isIE(){
	return navigator.userAgent.toLowerCase().indexOf("msie") != -1;
}

function octopv_isVista(){
	return navigator.userAgent.toLowerCase().indexOf("windows nt 6.0") != -1;
}

function octopv_isXP(){
	var str = navigator.userAgent.toLowerCase();
	return (str.indexOf("windows nt 5.1") != -1 || str.indexOf("windows nt 5.2") != -1);
}


function octopv_hasWmp7(){
	var wmp7;
	try{
		if(window.ActiveXObject){
    		wmp7 = new ActiveXObject("WMPlayer.OCX.7");
		} else if (window.GeckoActiveXObject) {
	    	 wmp7 = new GeckoActiveXObject("WMPlayer.OCX.7");
		}
	}catch(ex){
		octopv_debug("Could not instantiate (gecko) activex object: "+ex, arguments.callee);
		return false;
	}
	if (wmp7) return true; 
	return false;
}


function octopv_toNumber(numArg){
	if(numArg == null){
		return 0;
	} else if (typeof numArg == "number"){
		return numArg;
	} else {
		var num = parseInt(numArg, 10); 
		if (isNaN(num))	{ 
			octopv_debug("Error parsing "+(typeof numArg)+" to number: "+numArg, arguments.callee);
			return 0;
		} else { 
			return num; 
		}
	}
}


/* returns true if we are in debug mode. use: 
octopv_debug('', arguments.callee);
*/
function octopv_debug(str, func){
	if(typeof(octopvDebugDiv) == 'boolean' && !octopvDebugDiv){ return false;  }
	try{
		//opera.postError(func +" | "+str);
		var	div = document.getElementById(octopvDebugDiv);
		if(div){
			var begin = "<table>";
			var end = "</table>";
			var contents = div.innerHTML;
			if(octopvDebugTopPost){
				if(contents.toLowerCase().indexOf("<table>")>=0){
					end = contents.substring(7);
				}
			}else{
				var index = contents.toLowerCase().indexOf("</table>");
				if(index >=0){
					begin = contents.substring(0,index);
				}
			}
			if( arguments.length == 1 ) {
	 			div.innerHTML = begin + "<TR><TD>[unknown]<TD>|<TD>" + str+"</TR>"+end;
 				return true;
 			}else if(arguments.length == 2){
 				var funcStr = '' + func;
 				var a = funcStr.indexOf("{");
 				if(a>0){
	 				funcStr = funcStr.substring(0,a);
 				}
				div.innerHTML = begin  + "<TR ><TD>[" + funcStr + "]<TD>|<TD>" + str + "</TR>"+end;
 				return true;
	 		}
		}
	}catch (exception) { }
	return false;
}

function octopv_codeout(str){
	var str2=str.replace(/</g,"&lt;");
	str2=str2.replace(/>/g,"&gt;");
	return "<pre>"+str2+"</pre>";
}


function hasProperty(obj, element){
	for (var i in obj){ 
		if(obj[i].toLowerCase() == element.toLowerCase()){
			return true;
		}
	}
	return false;
}

function getPropertiesString(obj){
	var result = "[";
	var delim = "";
	for (var i in obj){ 
		result += (delim + i);
		delim = ",";
	}
	return result+"]";
}
