/* version: Update November 11, 2009. ()*/
window.octopv_fileInit=false; 
window.octopv_group = ""; // global group used when group is not defined in the octolink.
window.octopvDebugDiv = "octopv_debugDiv";		// if this is set (to a divID name) we display debug in the div.
window.octopvDebugTopPost = false;	
window.octopv_baseWebPath = "www.octoshape.com";	
window.octopv_appletDisplayName = 'Octoshape Grid Delivery Enhancement';
window.octopv_abortAutoLaunch=false;
window.octopv_randomId=(Math.floor(Math.random()*1000000000)).toString(36); 
window.octopv_disableOctoWebStat2=true;

window.octopv_initjar=function(){
	return 'http://'+octopv_baseWebPath+'/plugin/util/octoinit.jar';
}; 

window.octopv_initcode=function(){
	return 'octoshape.applets.init.OctoTestApplet.class';
};

/* #################################################################################### 
						GENERAL PLUGIN INTERFACE FUNCTIONS
                      functions integrated with auto-install
   #################################################################################### */

/**  */
window.octoAbortAutoLaunch = function(){
	octopv_debug('Aborting auto-launch',"octoAbortAutoLaunch");
	window.octopv_abortAutoLaunch=true;
	window.octopv_abortAutoInstall=true;
	window.octopv_pluginLauncherApplet.resetAll(); // TODO should only be necesarry if we are currently running applet launch ...
};

/**  */
window.octoManualLaunch = function(){
	octopv_debug('Doing protocol launch',"octoManualLaunch");
	octopv_launchByProtocol();
};

/** Initialize any helper browser plugins / applets etc. used for querying the Octoshape plugin.
	Also starts up the octoshape plug-in if it is there. 
	If called with tryAutoInstall==false, this function should be primarily silent for the 
	user, meaning that it might show yellow bar, but not dialog boxes or the like.
	This means that not all helper applet will be initialized, since that might generate a 
	applet security dialog box.  */
window.octoInitializePlugin = function(tryAutoInstall, messageFunction){
	octopv_pluginLaunch(1, function(status){},null, tryAutoInstall, messageFunction);
};

/** 
	Starts up octoshape and reports the status to functionInt(status)
 */
window.octoGetPluginStatus = function(functionInt, tryAutoInstall, messageFunction){
	octopv_pluginLaunch(1, functionInt,null,tryAutoInstall, messageFunction);
};

/** 
	Starts up octoshape and reports the full ip address + port to functionIntString(status, url)
	on success status is 0
	on error status is <0 and the url may be undefined or null.	
 */
window.octoGetConnectUrl = function(functionIntString, tryAutoInstall, messageFunction){
	octopv_pluginLaunch(2, functionIntString,null,tryAutoInstall, messageFunction);
};

/** 
 */
/*doc <!--
<function id="octoGetPlayLink" group="ajavascript functions"> 
	<description>
		Call this function every time you wish to play a link. 
		It will start up the Octoshape plugin-in and report the converted play link to the supplied reply function.
		<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="replyFunctionIntString" 	>
		This must be a JavaScript function taking 2 arguments, a status (number) and the play link (string). 
		On a successfull launch (/and install) of the plug-in, the status is 0 and the string is the converted play link.
		On error status is less than 0 and the string is null or undefined. 
	</param>
	
	<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="tryAutoInstall" optional="true" >
		If true we will attempt to perform an auto-install if the plug-in if it is not there already.
	</param>
	<param id="messageFunction" optional="true" >
		A function taking a string argument. It will be called during the auto-install with various
		messages, for instance 'Initializing installation', 'Running installer' etc.
	</param>
</function> 
 --> **/
window.octoGetPlayLink = function(octolink, functionIntString, tryAutoInstall, messageFunction){
	octopv_pluginLaunch(3, functionIntString, octolink,tryAutoInstall, messageFunction);
};

/** 
	Starts up octoshape and reports the option to functionIntString(status, resultSting)
	on success status is 0	
	on error status is <0 and the string can be null	
 */
window.octoGetStringOption = function(option,functionIntString, tryAutoInstall, messageFunction){
	octopv_pluginLaunch(4, functionIntString, option, tryAutoInstall, messageFunction);
};

/** 
	Starts up octoshape and reports the sua veriosn to functionIntString(status, verisionString)
	on success status is 0
	on error status is <0 and the version may be undefined or null.	
 */
window.octoGetSuaVersion = function(functionIntString, tryAutoInstall, messageFunction){
	octopv_pluginLaunch(5, functionIntString,null,tryAutoInstall, messageFunction);
};

window.octopv_disableLaunches=new Object();

/* PRIVATE function  
	There are 4 different possible argument sets of the first 3 arguments: 
	(1,functionInt,null): 			startup up octoshape and return status.
	(2,functionIntString,null):		Starts up octoshape and reports the connect url
	(3,functionIntString,octolink):	Starts up octoshape and reports the converted link
	(4,functionIntString,option):	Starts up octoshape and reports the option
	NB: If the status argument to the reply function is negative(indicates an error state), 
		any subsequent argments may be undefined!
	
	tryAutoInstall:	may be undefined or boolean
	messageFunction: may be undefined or null or a function taking a string.
	
	Status reply to replyFunction:
  	  <=-100: Octoshape can not be access with the methods we have. It may or may not be installed..
  -29 to -20: User cancelled run/installation. 
			  -21: user denied applet secutiry
			  -22: user dismissed eula (only with autoinstall)
  -19 to -10: There was some error on the web-page. User should try to reload the page, or on repeate, restart the browser.
  			  -11: applet timeout.
  			  -12: appelet reply error (applet - web page interface broken).
    		  -13: applet launch disk write error.
    -9 to -1: Octoshape is installed but it is in some error state. The user should re-install manually.
    		  -9: auto-install error.
	   	  -1: Octoshape is not installed (or auto-install tried but failed to install), that is, the user should perform
				manuel install
	       0: Octoshape is installed and running.
	       
       (stat will get a '3' code if we are aborted, but reply function will not be called).
*/
window.octopv_pluginLaunch = function(replyKind, replyFunction, arg, tryAutoInstall, messageFunction, statObj, theStatId){
	window.octopv_abortAutoLaunch=false;
	var stat = typeof(statObj)=='undefined'?octopv_webIntegrationStatistics():statObj;
	var statId = typeof(theStatId)=='string'?theStatId:"launcher"+replyKind;
	var funcArr = new Array();
	var funcArrCount=-1;
	var doNextSemiTrustedAnswer=-999;
	var doAutoInstall = typeof(tryAutoInstall)=='boolean' && tryAutoInstall;
	
	/** Call this after each iteration. 
		trustMe:   -1: Dont trust me at all. Proceed with next attempt
					0: this is the asured final answer. No more attempts should be made
					1: Only trust me if no one else can answer (saved for later in doNextSemiTrustedAnswer).
		theState:   <-1: octoshape error		
					 -1: octoshape not installed	
					  0: success, this means that the replyFunction is not called by doNext */
	function doNext(trustMe, theState){
		if(window.octopv_abortAutoLaunch){
			octopv_debug('Aborting next execution',"plauginLaunch");
			stat.add(statId,"Aborted",0,true);
			stat.send(3); 
			return;
		}
		if(trustMe==0&&theState==0){
			// all is well
			stat.send(0);
		}
		if(trustMe==1){
			doNextSemiTrustedAnswer=theState;
		}
		var theEnd = (trustMe==0);
		if(!theEnd){
			funcArrCount++;
			if(typeof(messageFunction)=='function'){
				messageFunction("Launching Octoshape");
			}
			if(funcArrCount<funcArr.length){
				var debugString = 'attempt '+(funcArrCount+1)+' of '+funcArr.length+': '+funcArr[funcArrCount].name+'';
				octopv_debug('Doing '+debugString,"plauginLaunch");
				funcArr[funcArrCount](); 
			}else{
				// There are no more ways to try to launch the plugin.
				// if we priviously (or this time) got a semi-trustworthy answer we use that one.
				if(doNextSemiTrustedAnswer!=-999){
					theEnd=true;
					theState=doNextSemiTrustedAnswer;
				}else{
					// We should not reach this if one of the attempts is one that can give a certain or 
					//	semi-certain reply. (i.e. tell us that octoshape is not installed, and not just 
					//	that we couldent find it.) Applet can give certian and browser plugin can give 
					//  semi-certain (in ie.) negative replies.
					stat.add(statId, "NoAnswer",theState,true);
					stat.send(theState);
					replyFunction(theState);
				}
			}
		}
		if(theEnd){
			if((theState==-1) && doAutoInstall && window.octopv_fileInitInstaller){
				// We try to run auto-install
				window.octopv_stat2obj=stat;
				octopv_doAutoInstall(function(result){
					window.octopv_stat2obj=null;
					
					if(window.octopv_abortAutoLaunch){
						octopv_debug('Aborting next execution after install',"plauginLaunch");
						stat.add(statId,"AbortedAfterInstall",0,true);
						stat.send(3);
						return;
					}
					
					/* If result>=0 then all went well
					   If result<=-10 then the installation ran, but afterwards there was some error 
					   accessing the plugin; in that case we try to access it one more time here. */
					if(result>=0 || result<=-10){
						// we ensure that we do not repeatedly attempt auto-install by setting last param to false
						octopv_debug('Now after autoinstall we again call '+replyKind+' ',"plauginLaunch");
						octopv_pluginLaunch(replyKind, replyFunction, arg, false, messageFunction, stat, statId+'x');
					}else{
						// Auto-install failed or could not be done, we return that to the caller.
						switch(result){
						case -1:
							// could not do auto-install
							stat.send(-1);
							replyFunction(-1);
							break;
						case -2:
						 	// -2: eula not accepted
							stat.send(-22);
							replyFunction(-22);
							break;
						case -3:
							// user denied some security box
							stat.send(-21);
							replyFunction(-21);
							break;
						case -4:
						  // installation error ... disk?
							stat.send(-9);
							replyFunction(-9);
							break;
						default:
							// error reply from browser plugin
							stat.send(result-10);
							replyFunction(result-10);
						}
					}
				}, function(stringAttempt, intCount){}, function(message){
					if(typeof(messageFunction)=='function'){
						messageFunction(message);
					}
				});
			}else if(theState<0){
				stat.send(theState);
				replyFunction(theState);
			}
		}
	}
	
	function simplePortHttpXml(){
		octopv_debug('Doing simplePortHttpXml',"plauginLaunch");
		var canDo = window.octoJavaScriptHttpAll(function(urlReply, version){
			octopv_debug('Doing simplePortHttpXml. ip+port reply was: '+urlReply,"plauginLaunch");
			var theResultString = (replyKind==5)?version:urlReply;
			var theResultCode = (theResultString==null)?-1:0;
			stat.add(statId,"JavaScriptHttp",theResultCode);
			if(theResultString!=null){
				doNext(0,0);	// stat is send in here.
				if(replyKind==1){
					replyFunction(0);
				}else if(replyKind==2||replyKind==5){
					replyFunction(0, theResultString);
				}
			}else{
				doNext(-1,-101);
			}
		});
		octopv_debug('Doing simplePortHttpXml. cando: '+canDo,"plauginLaunch");
		if(!canDo){
			doNext(-1,-102);
		}
	}
	
	function simplePortFlash(){
		if(window.octopv_flashOctoIsRunningTester.init()){
			window.octopv_flashOctoIsRunningTester.getPort(function(portReply){
				octopv_debug('reply from octopv_flashOctoIsRunningTester.getPort:'+portReply,"plauginLaunch");
				if(portReply>0){
					stat.add(statId,"FlashGetPort",0);
					doNext(0,0);	// stat is send in here.
					if(replyKind==1){
						replyFunction(0);
					}else if(replyKind==2||replyKind==5){
						replyFunction(0, '127.0.0.1:'+portReply);
					}
				}else{
					stat.add(statId,"FlashGetPort",portReply);
					doNext(-1,portReply-100);
				}
			});
		}else{
			doNext(-1, -103);
		}
	}
	
	function isSilentInitMode(){
		return replyKind==1 && !doAutoInstall;
	}

	function appletSilent(){
		/* If we should only perform initialization and not try autoinstall, we must be fairly silent.
		 	This means that we must not start up the AppletPluginLauncher, since it might display a 
		 	security dialog to the user.  */
		window.octoPluginTestApplet(function(status){
			octopv_debug('Applet test status '+status+' replyKind: '+replyKind,"octoPluginTestApplet");
			stat.add(statId,"AppletTest",status);
			
			// we whant to continue with the next attempt under all circumstances.
			// and we dont know anything about octoshape being installed or not 
			doNext(1,-104);	
		});
	}
	
	
	function applet(){
		window.octoPluginLauncherApplet(function(status, fromPlugin){
			/* For some odd reason the getStatus replies from jni has 2 as success. 
				(both applet and browser plugin uses the same code) */
			var pluginStatus = status==2?0:status;	
			var appletStatus = status-1000;			// we set -1000 to distinguish it from plugin errors.
			var statStatus = fromPlugin?pluginStatus:appletStatus;
			var debugString = 'pluginStatus '+pluginStatus+' appletStatus: '+appletStatus+' statStatus:'+statStatus+'';
			octopv_debug('fromPlugin('+fromPlugin+'): '+debugString,"pluginLaunch - applet");
			stat.add(statId,"AppletLauncher",statStatus);
			if(fromPlugin){
				doNext(0,pluginStatus);
				// The applet was initialized ok and the reply is from jni. 
				// If the status is an error reply, it is not going to be different from the browser plugin reply.
				if(pluginStatus==0){
					// Applet replied that octoshape is up and running
					window.octopv_preferencePluginLaunch_cookieSetCanUse("Applet");
					switch(replyKind){
					case 1: replyFunction(0); break;
					case 2: 
						var xml = window.octopv_pluginLauncherApplet.getStringOption('xmlbound');
						replyFunction(0,xml); 
						break;
					case 3: replyFunction(0, window.octopv_pluginLauncherApplet.getPlayLink(arg)); break;
					case 4: replyFunction(0, window.octopv_pluginLauncherApplet.getStringOption(arg)); break;
					case 5: 
						var xml = window.octopv_pluginLauncherApplet.getStringOption('suaversion');
						replyFunction(0,xml); 
						break;
					}
				}else{
					// Applet replied that octoshape is in some error state (or not installed).
					octopv_debug('Replying with error('+typeof(pluginStatus)+') '+pluginStatus+' ',"appletErr");
					// the above call to doNext handels the reply to the caller.
				}
			}else{
				// we got error reply from applet launcher
				switch(status){
					case -10:
						// -10: timeout reached.
						doNext(-1,-11);
						break;
					case -2:
						//   -2: there was some error in initializing the applet (writing to disk)
						doNext(-1,-13);
						break;
					case -3:
						//   -3: applet not trusted by user
						doNext(-1,-21);
						break;
					case -4:
						//   -4: applet reply error
						doNext(-1,-12);
						break;
					default:
						//  -1: we can not do applet launch
						doNext(-1,status-200);
						break;
				}
			}
		});
	}
	

	
	function browserPlugin(){
		// If we priviosly instantiated a browser plugin and there was some error with it,
		// 	we try agian since we might have re-installed since last time.
		if(!octoLowLevelCheck(window.octopv_browserPluginInstance)){
			window.octopv_browserPluginInstance = octoLowLevelGet(octopv_group);
		}
		var plug = window.octopv_browserPluginInstance;
		if(octoLowLevelCheck(plug)){
			var error = octoLowLevelReady(plug, function(){
				stat.add(statId,"BrowserPlugin",0);
				doNext(0,0);
				window.octopv_preferencePluginLaunch_cookieSetCanUse("BrowserPlugin");
				switch(replyKind){
				case 1: replyFunction(0); break;
				case 2: 
					var xml = plug.getString('xmlbound');
					replyFunction(0,xml); 
					break;
				case 3: 	
					var playlink = plug.getLink(arg,false);
					octopv_debug('Got play link from browser plugin: '+playlink+'.',"plauginLaunch");
					replyFunction(0, playlink); 
					break;
				case 4: replyFunction(0, plug.getString(arg)); break;
				case 5:
					var xml = plug.getString('suaversion');
					replyFunction(0,xml); 
					break;
				}
			});
			if(error<0){
				stat.add(statId,"BrowserPlugin",error);
				doNext(0,error);
			}
		}else{
			// This probably means that octoshape is not installed,
			stat.add(statId,"BrowserPlugin",-1);
			if(isSilentInitMode()){
				// we want to continue with the next initialization even if the answer was no Octoshape.
				doNext(1,-1);
			}else if(window.octopv_isWindows()&& navigator.userAgent.toLowerCase().indexOf("msie")!= -1){
				// But it might mean that a yellow bar is showing in IE ... 
				// So if we have windows and ie we do not trust the negative answer completly.
				doNext(1,-1);
			}else{
				// We should be able to trust the 'no octo' answer, but 
				// 		super-tester-1 had an issue in fx where this did not work (after an install, without browser re-start).
				//doNext(0,-1); 
				doNext(1,-1);
			}
		}
	}
	
	function launchByProtocol(){
		octopv_launchByProtocol(function(){
			doNext(1,-1);
		});
	}
	
	
	var statAttempts ="";
	if(replyKind<3||replyKind==5){
		// We try a simple port attepmt if we only need to start up the plugin or get the port.
		// If we need to convert an octolink or get a string option this function can not help us.
		if(octoJavaScriptHttpCanDo()){
			statAttempts += "http-";
			funcArr.push(simplePortHttpXml);
		}else if(replyKind<3 && typeof(window.octopv_disableLaunches["FlashGetPort"])=='undefined'){
			// we can not use the flash simple port get to get the sua version.
			statAttempts += "flas-";
			funcArr.push(simplePortFlash);
		}
	}
	
	/** Indications that it is ok to use the browser plugin are: 
		 - that we have used it successfully before
		 - that the browser is not IE (and we will then not have any yellow bar problems).	*/
	var browserNotIE=navigator.userAgent.toLowerCase().indexOf("msie") == -1;
	var trustBrowserPlugin = 	octopv_preferencePluginLaunch_cookieCanUse("BrowserPlugin") || browserNotIE;
	var useApplet = octopv_preferencePluginLaunch_cookieCanUse("Applet");
	if(octopv_isOSX()){
		/*  On mac the browser plugin works without any yellow bars or the like (and we have no applet launcher).*/
		statAttempts += "brpl-";
		funcArr.push(browserPlugin);
	}else if(isSilentInitMode()){
		/*  In silent init mode we want to initialze both the init applet and the browser plugin */
		statAttempts += "applsil-";
		funcArr.push(appletSilent);
		statAttempts += "brpl-";
		funcArr.push(browserPlugin);
	}else if(!doAutoInstall){
		/*	If we should not try to auto install, then we want to avoid that the user 
			should accept the applet security. */
		statAttempts += "brpl-";
		funcArr.push(browserPlugin);
		if(!trustBrowserPlugin){
			/*	Unless we dont trust the browser plugin. */
			statAttempts += "appl-";
			funcArr.push(applet);
		}
	}else{
		if(trustBrowserPlugin){
		/** If we trust the browser plugin, we want to try that before the applet since the java virtual machine 
			takes a while to start up. (this benifits user who already have octoshape installed).
			In this case we throw in the applet test aswell just to make 100% sure we are not installed.
			The users who do not have the plugin will not be bothered by the applet security because the applet 
			installer will run just after this. */
			statAttempts += "brpl-";
			funcArr.push(browserPlugin);
			if(useApplet){
				statAttempts += "appl-";
				funcArr.push(applet);
			}
		}else{
			/* If we do not trust the browser plugin then we try the applet first. 
				Maybe this way we can avoid yellow bars alltogether. */
			if(useApplet){
				statAttempts += "appl-";
				funcArr.push(applet);
			}
			statAttempts += "brpl-";
			funcArr.push(browserPlugin);
		}
	}
	statAttempts += (''+funcArr.length);
	
	if(!doAutoInstall){
		var debugString = typeof(tryAutoInstall)+'/'+tryAutoInstall;
		stat.add(statId,"doinstalldebug",debugString,true);
	}
	
	stat.add(statId,"doinstall",(doAutoInstall?0:-1),true);
	stat.add(statId,"attempts",statAttempts);
	
	octopv_debug('Plugin launch:'+replyKind+' (arg: '+arg+'), '+funcArr.length+' attempts.',"plauginLaunch");
	doNext(true,-100);
};

/* #################################################################################### 
				PULL VERSIONS OF GENERAL PLUGIN INTERFACE FUNCTIONS
                      			for use by osas 
   #################################################################################### */

window.octopv_pullObject = new Object();
window.octopv_pullObjectInit = function(pullId, numAnswers){
	window.octopv_pullObject[pullId] = 1;
	window.octopv_pullObject[pullId+'message'] = "";
	for(var i=1;i <= numAnswers;i++) {
		window.octopv_pullObject[pullId+'answer'+i] = null;
	}
}
window.octopv_pullObjectExists = function(pullId){
	return (typeof(window.octopv_pullObject[pullId])=='number');
}

/** called by osa */
window.octopv_pullObjectClear = function(pullId){
	delete window.octopv_pullObject[pullId];
	delete window.octopv_pullObject[pullId+'message'];
	delete window.octopv_pullObject[pullId+'answer'];
}


/** called by osa.
	currently called by silverlight osa, see comment in
	window.octopv_flashOctoIsRunningTester.callSwf
	for explanation.
 */
window.octopv_disableLaunches_flashGetPort = function(){
	window.octopv_disableLaunches["FlashGetPort"] = true;
};

window.octopv_disableLaunches_autoinstallEula = function(){
	octopve_disableEula = true;
}

/** called by osa */
window.octopv_pullObjectRequest = function(pullId, type){
	switch(type){
	case 0:
		if(octopv_pullObjectExists(pullId)){
			return window.octopv_pullObject[pullId];
		}else{
			return -1;
		}
	case -1:
		if(octopv_pullObjectExists(pullId)){
			return window.octopv_pullObject[pullId+'message'];
		}else{
			return "";
		}
	default:
		if(octopv_pullObjectExists(pullId)){
			return window.octopv_pullObject[pullId+'answer'+type];
		}else{
			return null;
		}
	}
}

/** called by osa */
window.octoGetPluginStatusPull = function(pullId, tryAutoInstall){
	if(octopv_pullObjectExists(pullId)) return;
	window.octopv_pullObjectInit(pullId,1);
	window.octoGetPluginStatus(function(intReply){
		if(octopv_pullObjectExists(pullId)){
			window.octopv_pullObject[pullId+'answer1'] = intReply;
			window.octopv_pullObject[pullId] = 0;
		}
	},tryAutoInstall,
	function(message){
		if(octopv_pullObjectExists(pullId)){
			window.octopv_pullObject[pullId+'message'] = message;
		}
	});
};

/** called by osa */
window.octoGetConnectUrlPull = function(pullId, tryAutoInstall){
	if(octopv_pullObjectExists(pullId)) return;
	window.octopv_pullObjectInit(pullId,2);
	window.octoGetConnectUrl(function(intStatus, stringReply){
		if(octopv_pullObjectExists(pullId)){
			window.octopv_pullObject[pullId+'answer1'] = intStatus;
			window.octopv_pullObject[pullId+'answer2'] = stringReply;
			window.octopv_pullObject[pullId] = 0;
		}
	},tryAutoInstall,
	function(message){
		if(octopv_pullObjectExists(pullId)){
			window.octopv_pullObject[pullId+'message'] = message;
		}
	});
};


/** called by osa */
window.octoGetStringOptionPull = function(option, pullId, tryAutoInstall){
	if(octopv_pullObjectExists(pullId)) return;
	window.octopv_pullObjectInit(pullId,2);
	window.octoGetStringOption(option, function(intStatus, stringReply){
		if(octopv_pullObjectExists(pullId)){
			window.octopv_pullObject[pullId+'answer1'] = intStatus;
			window.octopv_pullObject[pullId+'answer2'] = stringReply;
			window.octopv_pullObject[pullId] = 0;
		}
	},tryAutoInstall,
	function(message){
		if(octopv_pullObjectExists(pullId)){
			window.octopv_pullObject[pullId+'message'] = message;
		}
	});
};



/* #################################################################################### 
                                 USER PREFERENCES
                             variables and functions
   #################################################################################### */

window.octopv_preferencePluginLaunch_cookieCanUse=function(id){
	return octopv_hasCookie("octoweb"+id+"=true");
};

// TODO should also be called by windows applet install when installer tells us that we are preaproved.
window.octopv_preferencePluginLaunch_cookieSetCanUse=function(id){
	octopv_debug('Setting cookie for: '+id+' ',"cookieSetCanUse");
	var date = new Date();
	date.setTime(date.getTime()+(31*24*60*60*1000)); // one month expiry
	document.cookie = "octoweb"+id+"=true; expires="+date.toGMTString()+"; path=/";
};

/* #################################################################################### 
                                    STATISTICS 
                             variables and functions
   #################################################################################### */

/** Returns an object with 2 functions:
	- void add(String attemptId, int resultCode)
	- void send()
 */
window.octopv_webIntegrationStatistics=function(){
	var obj = new Object();
	obj.ranId = (Math.floor(Math.random()*1000000000)).toString(36); 
	obj.cookieId = octopv_webIntegrationStatisticsUserId();
	obj.str='';
	obj.begin=new Date();
	obj.finished=false;

	obj.add=function(statID,stringAttempt,intResult,holdBack){
		this.append(statID,stringAttempt,intResult);
		var holdBack2 = typeof(holdBack)=='boolean' && holdBack;
		if(!holdBack2){
			this.sendReal();
		}
	};
	
	obj.send=function(finalResult){
		if(this.finished)return;
		var time = (new Date().getTime())-(this.begin.getTime());
		this.append("stat","millis",time);
		if(typeof(finalResult)=='number'){
			this.append("stat","result",finalResult);
		}
		this.sendReal();
		this.finished=true;
	};

	/* private function*/
	obj.append=function(statID,stringAttempt,intResult){
		this.str+='~'+statID+'_'+stringAttempt+'.'+intResult;
	};
	
	/* private function*/
	obj.sendReal=function(){
		if(this.finished){
			octopv_debug('ERROR: trying to append stat '+this.str+' to closed stat obj',"stat3");
			return;
		}
		
		this.append("stat","id",this.ranId);
		this.append("stat","jsid",window.octopv_randomId);
		this.append("stat","cookid",this.cookieId);
		this.append("stat","version",3);
		
		var doSend = !octopv_debugDo();
		if(doSend && !window.octopv_disableOctoWebStat2){
			var html = '<img src="http://www.octoshape.com/images/stat2.gif?'+this.str+'" />';
			octopv_writeToIdLessDiv(html);
		}
		octopv_debug("Sent stats("+doSend+"): "+this.str, "stat3");
		this.str='';
	};
	
	return obj;
}


window.octopv_webIntegrationStatisticsUserId=function(){
	var statId = octopv_getCookie("octowebstatid");
	if(statId!=null&&statId!=""){
		return statId;
	}else{
		var id = (Math.floor(Math.random()*1000000000)).toString(36);
		var date = new Date();
		date.setTime(date.getTime()+(365*24*60*60*1000)); // one year expiry
		document.cookie = "octowebstatid="+id+"; expires="+date.toGMTString()+"; path=/";
		return id; 
	}
}


/* #################################################################################### 
                                 BROWSER PLUGIN 
                             variables and functions
   #################################################################################### */

window.octopv_browserPluginInstance = null;
window.octoLowLevelPlayHelperObject = new Array(2);

window.octopv_octoLowLevelPlayReset = function(){
	octoLowLevelPlayHelperObject.upstart=function(){};
	octoLowLevelPlayHelperObject.play=function(){};
	octoLowLevelPlayHelperObject.status=function(){};
};


window.octopv_octoLowLevelPlayReset();

// theOctoshapeClient is assumed to be a valid octoshape browser plug-in. 
// playfunction must be a function taking a link to be played.
window.octoLowLevelPlay = function(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.
window.octoLowLevelReady=function(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) {
		octopv_debug('octoLowLevelReady exception '+exception, arguments.callee);
		return -6;
	}
}

window.octopv_octoLowLevelPlayRepeat=function(){
	var result = octoLowLevelPlayHelperObject.status();
		
	switch (result){
 		case 1:
			// we call our self again in 2000 milli-seconds
			var id = setTimeout("octopv_octoLowLevelPlayRepeat();",2000);
			if(typeof(octoLowLevelPlayHelperObject.upstart) == 'function'){
				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;
	 }
}

window.octoLowLevelCheckErrorCode=0;	// 0: all ok; -10: no plugin; -20 missing getStatus.

/* Getting the activeX object */
window.octoLowLevelCheck=function(octoobject){
	if (octoobject==null || typeof(octoobject) == "undefined"){
		octoLowLevelCheckErrorCode = -10;
		octopv_debug('Octoobject('+octoobject+'): is typeof undefined', arguments.callee);
		return false;
	}
	if (typeof(octoobject.getStatus) == "undefined") {
		octoLowLevelCheckErrorCode = -20;
		octopv_debug('Octoobject('+octoobject+'): has no getStatus method', arguments.callee);
		return false;	
	}
	octoLowLevelCheckErrorCode = 0;
	octopv_debug('Octoobject('+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.
window.octoLowLevelGet=function(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.
	
	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');
					}

					octopv_debug("Have inserted html mime type object, now checking object. ", arguments.callee);
					if (octoLowLevelCheck(octoshape)) {
						octopv_debug("Client loaded using mimeTypes:" + octomime, arguments.callee);
						return octoshape;
					}else{
						octopv_debug("Mime type was not known. inserted object was: "+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 > 0) {
				var octoshape = navigator.plugins["application/x-octoshapeplugin"+local_group+".client"];
				if  (octoLowLevelCheck(octoshape)){ return octoshape; }
			}		
		
			if (navigator && navigator.mimeTypes && navigator.mimeTypes.length > 0) {
				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();
		}
	}

	octopv_debug('We try to instantiate the browser plugin for group:'+local_group, arguments.callee);
	var obj = octopv_get_octoclient_sub();
	if (octoLowLevelCheck(obj)){
		return obj;
	}
	else {
		if(navigator.plugins){
			octopv_debug("We refresh plugins and try again.", arguments.callee);
			navigator.plugins.refresh(false);
			return (octopv_get_octoclient_sub());
		}
		return obj;
	}
}


window.octoCanHaveBrowserPlugin=function(){
	var text = navigator.userAgent.toLowerCase();
	if (text.indexOf("windows") >= 0 || text.indexOf("mac os x") >= 0 ) {
		return (text.indexOf("opera") == -1);
	} 
	return false;
}


/* #################################################################################### 
                                 APPLET LAUNCHER                                        
                             variables and functions
   #################################################################################### */

window.octopv_pluginLauncherApplet=new Object();

/*
  -10: timeout reached.
   -4: applet reply error
   -3: applet not trusted by user
   -2: there was some error in initializing the applet (writing to disk)
   -1: we can not do applet install

	0: init finished answer from applet

	1: not written to page
	2: test applet written to page, but no answer from it yet
    3: test applet have answered.
    4: real applet written to page
    5: real applet init answer, still waiting for finish
*/ 
window.octopv_pluginLauncherApplet.status=1;
window.octopv_pluginLauncherApplet.timeout=6000;
window.octopv_pluginLauncherApplet.name = 'octopv_pluginLauncherAppletApplet';

window.octopv_pluginLauncherApplet.resetAll=function(){
	window.octopv_pluginLauncherApplet.readyFunctions=new Array();
	window.octopv_pluginLauncherApplet.semiReadyFunctions=new Array();
}
window.octopv_pluginLauncherApplet.resetAll();


window.octopv_pluginLauncherApplet.doReadyFunctions=function(){
	/* This function is actually called from the applet start() function,
	but we dont want to continue till after that function has returned. 
	So we postpone replying half a second .*/
	setTimeout("window.octopv_pluginLauncherApplet.doReadyFunctionsReal();",500);
};
window.octopv_pluginLauncherApplet.doReadyFunctionsReal=function(){
	for(i in this.readyFunctions){
		octopv_debug('Launcher applet: calling ready function number '+i, "AppletDoReady");
		this.readyFunctions[i]();
	}
	this.readyFunctions=new Array();
};

window.octopv_pluginLauncherApplet.doSemiReadyFunctions=function(){
	setTimeout("window.octopv_pluginLauncherApplet.doSemiReadyFunctionsReal();",500);
};
window.octopv_pluginLauncherApplet.doSemiReadyFunctionsReal=function(){
	for(i in this.semiReadyFunctions){
		octopv_debug('Test applet: calling semi ready function number '+i, "AppletDoSemiReady");
		this.semiReadyFunctions[i]();
	}
	this.semiReadyFunctions=new Array();
};

/* 	
	Inserts the applet in the container.
*/
window.octopv_pluginLauncherApplet.insert=function(){
try{
	this.status=4;
	var html='';
	var mainClass = 'octoshape.applets.OctoPluginLauncherApplet.class';	
	var jarFile = 'http://'+window.octopv_baseWebPath+'/plugin/util/octolauncher.jar';
	if(navigator.userAgent.toLowerCase().indexOf("msie") != -1){
		// browser is IE:
		html += '<OBJECT ';
		html += 'NAME="'+this.name+'" ';
		html += 'ID="'+this.name+'" ';
	  	html += 'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ';
		html += 'width="1" height="1"> ';
		html += '<PARAM NAME="code" value="'+mainClass+'" /> ';
		html += '<PARAM NAME="archive" VALUE="'+octopv_initjar()+','+jarFile+'" />';
	  	html += '<PARAM NAME="mayscript" VALUE="true" />';
	  	html += '<PARAM NAME="scriptable" VALUE="true" />';
	  	html += '<PARAM NAME="callbackstring" VALUE="launcher" />';
	  	html += '<PARAM NAME="initfunction" VALUE="octopv_pluginLauncherAppletInited" />';
	  	html += '<PARAM NAME="NAME" VALUE="'+octopv_appletDisplayName+'">';
	  	html += octopv_appletDebugParams(true);
		html += '</OBJECT> ';
	}else{
		// not IE:
		html += '<embed code="'+mainClass+'" '; 
		html += 'width="1" height="1" type="application/x-java-applet;version=1.1" ';
		html += 'pluginspage="http://java.sun.com/javase/downloads/" ';
        html += 'id="'+this.name+'" ';
		html += 'NAME="'+octopv_appletDisplayName+'" ';
		html += 'archive="'+octopv_initjar()+','+jarFile+'" ';
        html += 'scriptable="true" ';
        html += 'mayscript="true" ';
		html += 'callbackstring="launcher" ';
	  	html += 'initfunction="octopv_pluginLauncherAppletInited" ';
	  	html += octopv_appletDebugParams(false);
		html += '/>';
	}
	if(!octopv_writeToDiv('octopv_pluginLauncherAppletDiv', html, true)){
		return false;
	}
	return true;
	
	}catch(ex){ 
		octopv_debug('JavaScript error: '+ex.message,"pluginLauncherApplet.insert");
		return false;
	}
}


/** if indiv is null, we write directly 
	Firefox needs two different div for the applets.  
		If an applet is remove by overwriting its parent div (with innerHTML), firefox crashes!
	onComplete must be a function taking an int (or not defined):
		-1: we could not use applet install
		 0: testing is done ok
		>0: we are testing
*/
// inserts the small init applet to test if there is applet support.
window.octopv_pluginLauncherApplet.insertTest=function(){
	this.status=2;
	var html='';
	var html='';
	if(navigator.userAgent.toLowerCase().indexOf("msie") != -1){
		// browser is IE:
		html += '<OBJECT ';
	  	html += 'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ';
		html += 'width="1" height="1"> ';
		html += '<PARAM NAME="code" value="'+octopv_initcode()+'" /> ';
		html += '<PARAM NAME="archive" VALUE="'+octopv_initjar()+'" />';
	  	html += '<PARAM NAME="mayscript" VALUE="true" />';
	  	html += '<PARAM NAME="initfunction" VALUE="octopv_pluginTestAppletInited" />';
	  	html += '<PARAM NAME="callbackstring" VALUE="init" />';
	  	html += octopv_appletDebugParams(true);
		html += '</OBJECT> ';
	}else{
		// not IE:
		html += '<applet code="'+octopv_initcode()+'" '; 
		html += 'width="1" height="1" ';
		html += 'archive="'+octopv_initjar()+'" ';
        html += 'scriptable="true" ';
        html += 'mayscript="true" ';
		html += 'callbackstring="init" ';
	  	html += 'initfunction="octopv_pluginTestAppletInited" ';
	  	html += octopv_appletDebugParams(false);
		html += '></applet>';
	}
	if(!octopv_writeToDiv('octopv_pluginLauncherAppletTestDiv', html, true)){
		return false;
	}
	setTimeout("window.octopv_pluginLauncherApplet.timeoutReached();",this.timeout);
}


//private function
window.octopv_pluginLauncherApplet.timeoutReached=function(){
	if(this.status==2){
		octopv_debug('Launcher applet timeout reached before any word from test applet.', arguments.callee);
		this.status=-10;
		this.doSemiReadyFunctions();
	}
}

window.octopv_pluginTestAppletInited=function(callbackstring, javaMajor, javaMinor, javaMicro, osVersion){
	var javaVersionString = 'java version '+javaMajor+'.'+javaMinor+'.'+javaMicro+'';
	octopv_debug('Test applet inited. '+javaVersionString+'. osVersion '+osVersion, "pluginTestAppletInited");
	if(window.octopv_pluginLauncherApplet.status==2){
		window.octopv_pluginLauncherApplet.status=3;
		window.octopv_pluginLauncherApplet.doSemiReadyFunctions();
	}else if (window.octopv_pluginLauncherApplet.status==-10){
		window.octopv_pluginLauncherApplet.status=3;
		octopv_debug('ERROR: timeout was reached but now test applet is inited ok. ', "octopv_pluginTestAppletInited");
	}else{
		octopv_debug('Test applet inited, but status is:'+window.octopv_pluginLauncherApplet.status, "pluginTestAppletInited");
	}
}

/* called from applet. called with 
   <0: error happend
	0: finished init
   >0: still running init
*/
window.octopv_pluginLauncherAppletInited=function(reply){
	var init = octopv_convertToNumber(reply, -4);
	var stat = window.octopv_pluginLauncherApplet.status;
	octopv_debug('Launcher applet inited with '+init+'. Status is '+stat, arguments.callee);
	if(init>0){
		window.octopv_pluginLauncherApplet.status=5;
	}else{
		window.octopv_pluginLauncherApplet.status=init;
		window.octopv_pluginLauncherApplet.doReadyFunctions();
	}
}
	
/* PUBLIC function for starting up both applet and octoshape
 functIntBool if a function taking an int status and a bool 
 		if the status is an error status, 
			then if bool is true the error is from the octoshape plugin
			else the error is from the applet.
*/ 
window.octoPluginLauncherApplet=function(functIntBool){
		window.octopv_pluginLauncherApplet.registerReadyFunction(function(){
		try{
			var s = window.octopv_pluginLauncherApplet.status;
			if(s<0){
				functIntBool(s,false);
			}else{
				window.octopv_loopUntil("appletPluginLaunch",function(count){
					var os = window.octopv_pluginLauncherApplet.getStatus(count==1);
					if(os==0 ||os==1){
						return 1000; // run again in 1000 millis
					}else{
						functIntBool(os,true);
						return 0; // done
					}
				});
			}
		}catch(ex){ 
			octopv_debug('JavaScript error: '+ex.message,"octoPluginLauncherApplet");
		}
	});
}

/* PUBLIC function for starting up only the test applet (and thus the jvm).
 functInt is a function taking an int status. 0 indicates success, <0 an applet error.  */ 
window.octoPluginTestApplet=function(functInt){
	octopv_pluginLauncherApplet.registerSemiReadyFunction(function(){
		var s = octopv_pluginLauncherApplet.status;
		if(s<0){
			functInt(s);
		}else{
			functInt(0);
		}
	});
}

/* Returnes true if it seems to be ok to use the applet launcher */
window.octopv_pluginLauncherApplet.cando=function(){
	if(window.octopv_isWindows()){
		octopv_debug('Java is enabled: '+window.navigator.javaEnabled(), arguments.callee);
		if (navigator.userAgent.toLowerCase().indexOf("firefox") >= 0){ 
			// firefox sometimes reports that java is disabled, but is isent.
			return true;
		}
		return window.navigator.javaEnabled();
	}
	return false;
}


/** whenReady must be a function taking no arguments.
	when it is called the status variable can be accessed  */
window.octopv_pluginLauncherApplet.registerReadyFunction=function(whenReady){
	this.registerSemiReadyFunction(function(){
		if(octopv_pluginLauncherApplet.status<=0){
			whenReady();
		}else{
			octopv_pluginLauncherApplet.readyFunctions.push(whenReady);
			if(octopv_pluginLauncherApplet.status==3){
				octopv_pluginLauncherApplet.insert();
			}
		}
	});
}

/** whenReady must be a function taking no arguments.
	when it is called the status variable can be accessed and it can be any value 
	execpt 1 and 2. */
window.octopv_pluginLauncherApplet.registerSemiReadyFunction=function(whenReady){
	if(!this.cando()){
		this.status = -1;
	}
	if(this.status<=0||this.status>=3){
		// it status is <0 there is an applet error. 
		// If 3 the test applet has already been initialized
		// If >3 we are waiting for plugin startup.
		whenReady();
	}else {
		this.semiReadyFunctions.push(whenReady);
		if(this.status==1){
			this.insertTest();
		}
	}
}

window.octopv_pluginLauncherApplet.getPlayLink=function(octolink){
	if(this.status!=0) return "";
	return document[this.name].getLink(octolink, false);
}

window.octopv_pluginLauncherApplet.getStringOption=function(option){
	if(this.status!=0) return "";
	return document[this.name].getString(option);
}

window.octopv_pluginLauncherApplet.getStatus=function(startup){
	try{
		if(this.status!=0) return -9;
		var reply = document[this.name].getStatus(startup);
		octopv_debug('stat: '+this.status+'. Reply from getStatus('+typeof(reply)+'): '+reply, arguments.callee);
		return reply;
	}catch(ex){ 
		octopv_debug('JavaScript error: '+ex.message,"LauncherApplet.getStatus");
		return -5;
	}
}


/* #################################################################################### 
                         JAVASCRIPT HTTP-REQUEST PORT TEST                                        
                              variables and functions
   #################################################################################### */

/** used by both octopv_flashOctoIsRunningTester and octoJavaScriptHttpAll */
window.octopv_defaultPorts = new Array(6498,8247);


window.octoJavaScriptHttpCanDo=function(){
	return window.XDomainRequest;
}

/** 
Testing if octoshape is running by http request from JavaScript. 
May return false negative, but not false positive.<b> 
Primary function returns true if this method can be used, otherwise false.
If it returns true the reply function will be called at some time, otherwise it will not be called.

For test to be performed we need:
 	- IE 8
 	- a sua > 090512
 And it still may falsely return false (if octoshape is bound on some secondary port).

  ipport is the ip addres + port to connect to.
  timeout is in millis. (2000 should be ok)
  replyFunction must take 1 int argument (the status) + 1 string argument (the plugin version).
	 0: succes.
	-2: error on connect (This is the standard reply when octoshape is not running).
	-3: timeout on connect.
	-4: fail since wrong reply from octoshape (not xml doc)
	-5: fail since wrong reply from octoshape (not correct base node tag)
	-6: exception while connecting.
	-7: javascript time reached ... 
*/
window.octoJavaScriptHttp=function(ipport, timeout, replyFunction){
	if (!window.octoJavaScriptHttpCanDo())	return false;
	octopv_debug('Trying ip+port: '+ipport, 'XDomainRequest');
	var finished=false;
	try{
		// we need a single run object since we always reach the javascript timeout.
		//var replyOnce = octopv_toSingleRunFunction(this, replyFunction);
		octopv_debug('Making XDomainRequest object ...', 'XDomainRequest');
		var xdr=new XDomainRequest(); 
		if(!xdr){
			octopv_debug('Could not make object.', 'XDomainRequest');
			return false;
		}
		xdr.onload=function(){
			octopv_debug('onload called', 'XDomainRequest');
			var reply = -7;
			var version = "";
			try {
				var xmlDoc=new ActiveXObject('Microsoft.XMLDOM');
				xmlDoc.async='false';
				var text = xdr.responseText;
				xmlDoc.loadXML(text);
				if(xmlDoc.documentElement.tagName=='octoshapesua'){
					reply = 0;
					version = xmlDoc.documentElement.getAttribute('version');
				}else{
					reply = -4;
				}
			}catch(e){
				octopv_debug('Err '+e.name+': '+e.message, arguments.callee);
				reply = -5;
			}
			finished=true;
			replyFunction(reply,version);
		};
		xdr.onerror = function(){
			octopv_debug('onerror called', 'XDomainRequest');
			finished=true;
			replyFunction(-2,null);
		};
        xdr.ontimeout = function(){
			octopv_debug('ontimeout called', 'XDomainRequest');
			finished=true;
			replyFunction(-3,null);
		};
  		xdr.timeout = timeout;
  		var req = 'http://'+ipport+'/octoshapeprobe.xml';
  		// we use post to make sure that the answer is not cached.
  		xdr.open('POST', req);
		
		octopv_setTimeoutFunction(timeout+1500, function(){
			if(finished){
				octopv_debug('We reached javascript timeout, but have already answered.', 'XDomainRequest');
			}else{
				finished=true;
				replyFunction(-7,null);
			}
		});
  		var randomStr = 'random'+(Math.floor(Math.random()*100000));
		octopv_debug('Sending request: '+req+' post: '+randomStr, 'XDomainRequest');
		xdr.send(randomStr);
	}catch(ex){
		octopv_debug('Caught exception: '+e, 'XDomainRequest');
		finished=true;
		replyFunction(-6,null);
	}
	return true;
}

/**
	replyFunction must take (string url, string version), the url string is null on no luck.
	returns true if replyFunction will be called.
*/
window.octoJavaScriptHttpAll=function(replyFunction){
	if(window.octopv_defaultPorts.length==0) return false;
	if (!window.octoJavaScriptHttpCanDo())	return false;
	var x=0;
	function tryNext(){
		try{
			if(window.octopv_defaultPorts.length==x){
				// we have reached the end.
				octopv_debug('octopv_defaultPorts.length:'+window.octopv_defaultPorts.length+', x is: '+x, "octoJavaScriptHttpAll");
				replyFunction(null,null);
			}else{
				var tryUrl = '127.0.0.1:'+window.octopv_defaultPorts[x];
				window.octoJavaScriptHttp(tryUrl,2000,function(p,version){
					if(p==0){
						octopv_debug('Found ipport by XDomainRequest: '+tryUrl, "octoJavaScriptHttpAll");
						replyFunction(tryUrl,version);
					}else{
						octopv_debug('Reply from XDomainRequest('+tryUrl+') was: '+p,"octoJavaScriptHttpAll");
						x++;
						tryNext();
					}
				});
			}
		}catch(ex){
			octopv_debug('Execution error: '+ex.message,"octoJavaScriptHttpAll");
		}
	}
	tryNext();
	return true;
}


/* #################################################################################### 
                                FLASH PORT TEST                                        
                            variables and functions
   #################################################################################### */

	window.octopv_flashOctoIsRunningTester = new Object();
	// private variables and functions
	window.octopv_flashOctoIsRunningTester.count=0;
	window.octopv_flashOctoIsRunningTester.swfname=null;
	window.octopv_flashOctoIsRunningTester_replyfunction=null;
	window.octopv_flashOctoIsRunningTester.initDone=false;
	window.octopv_flashOctoIsRunningTester.callSwf=function(){
		octopv_debug('callSwf. replyfunc null:'+(octopv_flashOctoIsRunningTester_replyfunction==null)+' swf null:'+(this.swfname==null), "callSwf");
		if(octopv_flashOctoIsRunningTester_replyfunction==null||this.swfname==null) return;
		var dims=null;
    	if (navigator.appName.indexOf("Microsoft") != -1) {
        	dims=window[this.swfname];
    	} else {
	        dims=document[this.swfname];
    	}
		octopv_debug('Calling flash bp: '+dims, arguments.callee);
		// TODO currently when called from silverlight osa the call to the flash function 
		// never generates a return call to the replyFunction. 
		// temp solotion is to avoid the flash tester when calling from silverlight
		try{
    		dims.octopvAS_beginCheck('octopv_flashOctoIsRunningTester_replyfunction',2000,window.octopv_defaultPorts);
    	}catch(ex){
			octopv_debug('ex:'+ex, "flashOctoIsRunningTester");
			var funct = window.octopv_flashOctoIsRunningTester_replyfunction;
			window.octopv_flashOctoIsRunningTester_replyfunction=null;
			funct(-1);
    	}
	};
	
	// private function; called by flash
	window.octopv_flashOctoIsRunningTester.initFinished = function(swfName){
		this.swfname=swfName;
		this.callSwf();
	}
	
	// private function
	window.octopv_flashOctoIsRunningTester_timeoutReached = function(){
		if(window.octopv_flashOctoIsRunningTester_replyfunction!=null&&window.octopv_flashOctoIsRunningTester.swfname==null){
			octopv_debug('Timeout has been reached and we had no answer from flash. ', "flashOctoIsRunningTester");
			var funct = window.octopv_flashOctoIsRunningTester_replyfunction;
			window.octopv_flashOctoIsRunningTester_replyfunction=null;
			funct(-2);
		}
	}
	
	// PUBLIC FUNCTION; called by user code.
	// replyfunc must be a function taking 1 int argument (the port, or <0 on error).
	window.octopv_flashOctoIsRunningTester.getPort = function(replyfunc){
		window.octopv_flashOctoIsRunningTester_replyfunction=replyfunc;
		this.callSwf();
	};
	
	// PUBLIC FUNCTION; called by user code.
	// Inserts the swf file on the page 
	// returns true if flash browserplugin is possible
	window.octopv_flashOctoIsRunningTester.init = function(){
		/** It doesent work to use the same flash movie, if the first could not connect.
		    So we must always make a new one.
		if(this.initDone){
			octopv_debug('Not inserting flash bp, since it has been done already.', "octopv_flashOctoIsRunningTester.init");
			return true;
		}*/
		if((!window.DetectFlashVer) || (!window.DetectFlashVer(9,0,0))){
			/** Returns false if the adobe JavaScript file AC_OETags.js has not been included
				or ActioScript 3 is not availerble  */
			if(!window.DetectFlashVer){
				octopv_debug('User has no flash or only old flash.', "octopv_flashOctoIsRunningTester.init");
			}else{
				octopv_debug('User has no flash or only old flash.', "octopv_flashOctoIsRunningTester.init");
			}
			return false;
		}
		var path = "http://"+window.octopv_baseWebPath+"/plugin/util/octofbp.swf";	 
	  	var html  = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
    	html += ' id="octopv_flash_bp" width="0" height="0"';
	    html += ' codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">';
	    html += ' <param name="movie" value="'+path+'" />';
	    html += ' <param name="wmode" value="transparent" />';
	    html += ' <param name="AllowScriptAccess" value="always" />';
	    html += ' <embed src="'+path+'"';
	    html += ' width="1" height="1" name="octopv_flash_bp"';
	    html += ' AllowScriptAccess="always"';
	    html += ' play="true" loop="false" wmode="transparent"';
	    html += ' type="application/x-shockwave-flash" ';
	    html += ' pluginspage="http://www.adobe.com/go/getflashplayer">';
	    html += ' </embed></object>';
	    
		octopv_debug('Inserts flash helper from '+path, "octopv_flashOctoIsRunningTester.init");
		var name = "octopv_flashOctoIsRunningTesterDiv"+this.count;
		this.count++;
	    if(octopv_writeToDiv(name, html, true)){
			this.initDone=true;
			// We set a timeout here just in case there is something wrong with the swf,
			//  and it does not get initialized. It should never happen though.
			setTimeout("window.octopv_flashOctoIsRunningTester_timeoutReached();",4000);
			return true;
	    }else{
			octopv_debug('Could not write to div octopv_flashOctoIsRunningTesterDiv', "octopv_flashOctoIsRunningTester.init");
	    	return false;
	    }
	};


/*
	window.octopv_flashOctoIsRunningTester.run = function(replyStringFunction){
		if(window.octopv_flashOctoIsRunningTester.init()){
			window.octopv_flashOctoIsRunningTester.getPort(function(portReply){
				var urlReply = portReply<0?null:'127.0.0.1:'+portReply;
				replyStringFunction(urlReply);
			});
			return true;
		}else{
			return false;
		}
	};*/

/* #################################################################################### 
                               FORCE SUA UPDATE 
                            variables and functions
   #################################################################################### */


/**
	replyFunction must be a function taking an int argument indicating:
		<0: if octoshape not installed or there was some error with the browser plugin
		 0: the current sua version was ok
		 1: we have updated the sua, and are now ready again.
*/
window.octopv_forceSuaUpdateIfNeeded=function(updatelink, okSuaVersion, replyFunction){
	octopv_debug("Function called. updatelink: "+updatelink+" sua:"+okSuaVersion, arguments.callee);
	
	octoGetSuaVersion(function(intStatus, stringVersion){
		if(intStatus==0){
			var ver = stringVersion;
			var doUpdate = false;
	   		if (ver.Length == okSuaVersion.Length) {
			    	doUpdate = ver < okSuaVersion; // lexicographical javascript compare!
		    } else {
    			doUpdate = ver.Length < okSuaVersion.Length;
    		}
    		if(doUpdate){
    			octopv_debug("Doing sua update since current ver is "+ver+" and marker is "+okSuaVersion, arguments.callee);
    			octoGetPlayLink(updatelink, function(intStatus2,playlink){
    				if(intStatus2<0){
    					replyFunction(intStatus2);
    				}else{
    					// we have the update playlink.
						octopv_insertInvisibleIframe(playlink);
						window.octopv_forceSuaUpdateIfNeededLoopReply=replyFunction;
						setTimeout("octopv_forceSuaUpdateIfNeededLoop();",3000);
    				}
    			}, false);
    		}else{
				replyFunction(0);
    		}
		}else{
			replyFunction(intStatus);
		}
	}, false);
}

window.octopv_forceSuaUpdateIfNeededLoopReply=null;
window.octopv_forceSuaUpdateIfNeededLoop=function(){
	octopv_debug("calling after wait.", "octopv_forceSuaUpdateIfNeededLoop");
	octoGetPluginStatus(function(intStatus){
		if(intStatus<0){
			octopv_debug("calling reply functiopn with error: "+intStatus, "octopv_forceSuaUpdateIfNeededLoop");
			window.octopv_forceSuaUpdateIfNeededLoopReply(intStatus);
		}else{
			octopv_debug("success, returning 1 ", "octopv_forceSuaUpdateIfNeededLoop");
			window.octopv_forceSuaUpdateIfNeededLoopReply(1);
		}
	}, false);
}


// pull version for osa:
window.octopv_forceSuaUpdateIfNeededOsaReply=-99;
window.octopv_forceSuaUpdateIfNeededOsa=function(updatelink, okSuaVersion){
	window.octopv_forceSuaUpdateIfNeeded(updatelink, okSuaVersion, function(reply){
		window.octopv_forceSuaUpdateIfNeededOsaReply=reply;
	});
}
window.octopv_forceSuaUpdateIfNeededOsaReplyPull=function(){
	return window.octopv_forceSuaUpdateIfNeededOsaReply;
}

/* #################################################################################### 
                               SIMPLE LAUNCH 
                            variables and functions
   #################################################################################### */


/**
if callback is a function then it must be a function taking no argument. 
It will be called after a delay, where we might be started up.
*/
window.octopv_launchByProtocol=function(callback){
	try{
		var name = "octopv_launchByProtocolFrame";
		var e = document.getElementById(name);
		if(e==null){
			e = document.createElement("iframe");
			e.id=name;
			e.name=name;
			e.width=0;
			e.height=0;
			e.style.display = "none";
			e.src="OCTOSHAPE:";
			document.body.insertBefore(e,document.body.firstChild);
		}else{
			e.src="OCTOSHAPE:";
		}
		if(typeof(callback)=='function'){
			octopv_debug("After lauch by protocol we wait for 3 secs before returning ...",'octopv_launchByProtocol');
			octopv_setTimeoutFunction(3000, callback);
		}
		
	}catch(ex){
		octopv_debug("Exeption "+ex, 'octopv_launchByProtocol');
		if(typeof(callback)=='function'){
			callback();
		}
	}
}


/* #################################################################################### 
                               UTILITY FUNCTIONS

   #################################################################################### */
   
/* 
  functions named octopvpv* are internal unility functions 
*/



/** 
  Helper to set a function to be called after timeout. 
 */
window.octopv_setTimeoutFunction=function(millis, func){
	octopv_setTimeoutFunctionObject.count++;
	var name = "name"+octopv_setTimeoutFunctionObject.count;
	window.octopv_setTimeoutFunctionObject[name] = function(){
		func();
	};
	setTimeout("octopv_setTimeoutFunctionObject."+name+"();",millis);
}
window.octopv_setTimeoutFunctionObject = new Object();
window.octopv_setTimeoutFunctionObject.count=0;


/**	
	This wrapper will ensure that the argument function only will be called 1 time.
	The returned object has a function .callme, that calls the function 
	(and returns true if the function was called).
*/
window.octopv_toSingleRunFunction=function(thisReference, func){
	var obj = new Object();
	obj.done = false;
	obj.func = func;
	obj.thisref=thisReference;
	obj.callme=function(){
		if(this.done){
   			octopv_debug("Stopping multiple calls to "+obj.thisref, 'toSingleRunFunction');
			return false;
		}
		this.done=true;
		this.func.apply(this.thisref,arguments);
		return true;
	};
	return obj;
};


window.octopv_getCookie=function(name){
	var cs = document.cookie.split(';');
	for(var i=0;i < cs.length;i++) {
		var c = cs[i];
		// trimming c
		while (c.charAt(0)==' '){
			c = c.substring(1,c.length);
		}
		if (c.indexOf(name) == 0) {
			// we need to split the key from the value
			var kv = c.split('=');
			if(kv.length >= 1&&kv[0]==name){
				if(kv.length==2){
					return kv[1];
				}else{
					return"";
				}
			}
		}
	}
	return null;
}

window.octopv_hasCookie=function(name){
	var cs = document.cookie.split(';');
	for(var i=0;i < cs.length;i++) {
		var c = cs[i];
		while (c.charAt(0)==' '){
			c = c.substring(1,c.length);
		}
		if (c.indexOf(name) == 0) {
			return true;
		}
	}
	return false;
}


window.octopv_portFromXmlBoundString=function(xmlBoundReply){
	if((typeof (xmlBoundReply)=='undefined') || xmlBoundReply==null || xmlBoundReply==""){
		return -1;
	}
	try{
		var p = xmlBoundReply.substring(xmlBoundReply.indexOf(":",0)+1,xmlBoundReply.length);
		var port = parseInt(p); 
		return port;
	}catch(e){
		return -1;
	}
}



window.octopv_insertInvisibleIframe=function(source){
	var iframe = document.createElement("iframe");
	iframe.setAttribute("width", 0);
	iframe.setAttribute("height", 0);
	iframe.setAttribute("src", source);
	document.body.insertBefore(iframe,document.body.firstChild);
}

window.octopvpv_postponedError = null;
window.octopv_includeJSFile=function(path){
	var script = document.createElement("script");
	script.setAttribute("language", "JavaScript");
	script.setAttribute("type", "text/javascript");
	script.setAttribute("src", path);
	try{
		var head = document.getElementsByTagName("head")[0];
		head.insertBefore(script,head.lastChild);
	}catch(e){
		octopvpv_postponedError="ERROR inserting js in head: "+e.name+"; "+e.message;
	}
}


window.octopvpv_loopArray = new Object();

/** name is a string id for the loop
	theFunction is a int function taking 1 int argument, 
		the argument is the count of times the loop has run (the first time it gives 1)
		the return value must be number of millis to loop next (0 or negative when loop no more). 
		NB: the function will be assigned to a special (global) object when run, 
			so it should only reference global functions and variables.  */
window.octopv_loopUntil=function(name, theFunction){
	octopvpv_loopArray[name]=theFunction;
	octopvpv_loopArray[name+"Count"]=0;
	window.octopvpv_loopUntilDo(name);
}

/** private */
window.octopvpv_loopUntilDo=function(name){
	octopvpv_loopArray[name+"Count"]++;
	var time = octopvpv_loopArray[name](octopvpv_loopArray[name+"Count"]);
	if(time>0){
		setTimeout("octopvpv_loopUntilDo('"+name+"');",time);
	}
}

window.octopv_appletDebugParams=function(paramParams){
	if(octopvDebugDiv && document.getElementById(octopvDebugDiv)!=null){
		if(paramParams){
			return '<param name="display" value="debug_console_div"/>';
		}else{
			return 'display="debug_console_div" ';
		}
	}else{
		 return '';
	}
}

window.octopv_convertToNumber=function(reply, def){
	var intReply=def;
	if(typeof reply == 'number'){
		intReply=reply;
	}else{
		var parsed=parseInt(reply);
		if(!isNaN(parsed)){
			intReply=parsed;
		}
	}
	return intReply;
}


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+"]";
}

window.octopv_createNewDiv2=function(idName){
	var elem = document.getElementById(idName);
	if(elem==null){
		var oDiv = document.createElement("div");
		oDiv.id=idName;
		document.body.insertBefore(oDiv,document.body.firstChild);
		return true;
	}else{
		return false;
	}
}

window.octopv_createNewDiv=function(idName){
	try{
		var elem = document.getElementById(idName);
		if(elem==null){
			var oDiv = document.createElement("div");
			oDiv.id=idName;
			oDiv.style.height = "0px";
			oDiv.style.width = "1px";
			document.body.insertBefore(oDiv,document.body.firstChild);
			return true;
		}else{
			return false;
		}
	}catch(ex){ 
		octopv_debug('JavaScript error: '+ex.message,"createNewDiv");
		return false;
	}
}

window.octopv_writeToDiv=function(indiv, html, create){
	try{
		if( arguments.length == 3 &&  create) {
			octopv_createNewDiv(indiv);
		}
	 	var div = null;
	 	if(indiv!=null){
	 		div = document.getElementById(indiv);
	 		if(div ==null){
	 			octopv_debug("div "+indiv+" does not exist.", arguments.callee);
	 			return false;
	 		}
	 	}
	 	if(indiv==null){
	 		document.write(html);
	 	}else{
	 		div.innerHTML=html;
	 	}
	 	octopv_debug("inserted HTML into div "+indiv, arguments.callee);
	 	return true;

	}catch(ex){ 
		octopv_debug('JavaScript error: '+ex.message,"writeToDiv");
		return false;
	}
}

window.octopv_writeToIdLessDiv=function(html){
	var oDiv = document.createElement("div");
	oDiv.style.height = "0px";
	oDiv.style.width = "1px";
	oDiv.innerHTML=html;
	document.body.insertBefore(oDiv,document.body.firstChild);
 	octopv_debug("inserted HTML into nameless div ", arguments.callee);
 	return true;
}

window.octopv_activexdisabled=function(){
	var text = navigator.userAgent.toLowerCase();
	if (text.indexOf("msie") >= 0){ 
		try{
			var test = new ActiveXObject("Scripting.Dictionary");
		}catch(e){
			return true;
		}
	}
	return false;
}

window.octopv_isOSX=function(){
	return navigator.userAgent.toLowerCase().indexOf("mac os x") != -1;
}

window.octopv_isOSX106=function(){
	var str = navigator.userAgent.toLowerCase();
	return str.indexOf("mac os x 10_6") != -1 || str.indexOf("mac os x 10.6") != -1;
}

window.octopv_isWindows=function(){
	return navigator.userAgent.toLowerCase().indexOf("windows") != -1;
}

window.octopv_isSafari=function(){
	return navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1;
}

window.octopv_isFirefox=function(){
	return navigator.userAgent.toLowerCase().indexOf("firefox") != -1;
}

window.octopv_isFirefox3=function(){
	return navigator.userAgent.toLowerCase().indexOf("firefox/3") != -1;
}

window.octopv_isIE=function(){
	return navigator.userAgent.toLowerCase().indexOf("msie") != -1;
}

window.octopv_isVista=function(){
	return navigator.userAgent.toLowerCase().indexOf("windows nt 6.0") != -1;
}

window.octopv_isXP=function(){
	var str = navigator.userAgent.toLowerCase();
	return (str.indexOf("windows nt 5.1") != -1 || str.indexOf("windows nt 5.2") != -1);
}





// returns true iff there is a plugin registered for the mime type mimeID and
//  the name of this plugin contains pluginName (case oblivious).
window.octopv_mime_plugin_is=function(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
window.octopv_has_mime=function(mimeID){
	if(navigator && navigator.mimeTypes && navigator.mimeTypes.length){
		var mime =  navigator.mimeTypes[mimeID];
		if(mime && mime.enabledPlugin){
			return true;
		}
	}
	return false;
}

window.octopv_debugDo=function(){
	if(typeof(octopvDebugDiv) == 'boolean' && !octopvDebugDiv){
		return false;
	}
	try{
		var	div = document.getElementById(octopvDebugDiv);
		if(div)return true;
	}catch (exception) { }
	return false;
}


window.octopv_debug=function(str, func){
	if(octopvpv_postponedError!=null){
		window.octopv_debug2(octopvpv_postponedError,"postponed");
		octopvpv_postponedError=null;
	}
	window.octopv_debug2(str,func);
}

/* returns true if we are in debug mode. use: 
octopv_debug('', arguments.callee);
*/
window.octopv_debug2=function(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;
}
// This adobe JavaScript file is included to be able to test if the user has Flash Player installed.
window.octopv_includeJSFile("http://"+octopv_baseWebPath+"/javascripts/AC_OETags.js");
window.octopv_fileInit=true; 

