/**
	Load on Demand: namespace to house global dependencies and a function to allow users to fire functions that are not fully loaded
	created 1/30/2009 by Brandon Medenwald (CUR-7244)

	@module Load on Demand
	@namespace loadOnDemand
*/

if (!loadOnDemand) var loadOnDemand = {};
if (!loadOnDemand.dependencies) loadOnDemand.dependencies = [];
loadOnDemand.concurrentOperations = [];


/** loadOnDemand.execute: run a function that may not be fully loaded yet
	@param funcName {Function} the callback function to execute
	@param attributes {Array} optional array of attributes to pass to the function being executed
	@param options {Object} object of additional options:
		* dependencies {Array} ignore global dependencies and just use what's passed in.  This array is populated with strings of file pathes.
		* dependencyAlias {String} the 'alias' for looking up global dependencies in the server/dependencies.html file
		* expiration {Date} the date at which this function is no longer needed
		* cancelCookie {String} the name of the cookie that, if set to anything, would abort the loading and execution of this function
		* loading {String} show a loading prompt, either 'true', 'false', or the id of an element to show/hide
		* method {String} method of loading, either 'consecutively' or 'concurrently', defaults to concurrently
*/
loadOnDemand.execute = function(funcName, attributes, options) {

	if (!options) options = {};

	// before we do anything, make sure this loading event hasn't "expired"
	if (options.expiration && loadOnDemand.isExpired(options.expiration)) return;

	// also before we go any further, make sure the user hasn't "opted out" of the loading/running of this function via a cookie
	if (options.cancelCookie && loadOnDemand.cookieExists(options.cancelCookie)) return;

	// establish dependencies
	var depends = [];
	if (options.dependencies && options.dependencies.length > 0) { // user included dependencies when this was called
		var depends = options.dependencies;
	} else if (options.dependencyAlias && loadOnDemand.dependencies.length > 0) { // filter through the globally-known dependencies and set them auto-magically
		for (var x=0; x < loadOnDemand.dependencies.length; x++) {
			if (loadOnDemand.dependencies[x].alias == options.dependencyAlias) {
				var depends = loadOnDemand.dependencies[x].dependencies;
				options.method = (options.method) ? options.method : loadOnDemand.dependencies[x].method ;
				break;
			}
		}
	} else if (options.dependencyAlias) { // we have no idea what the dependencies are, so load them
		loadOnDemand.loadScript('/cgi-bin/mainmenu.cgi?cmd=srv+dependencies.html&command_line_mode=true', {funcName:funcName, attributes:attributes, options:options}); // global dependencies are unknown, so look them up
		return;
	}

	// set the method to proceed under
	if (!options.method) options.method = 'concurrently';

	// find all loaded scripts
	var scriptArray = [];
	var scriptCollection = document.getElementsByTagName("script");
	if ((typeof scriptCollection !== "undefined") && (scriptCollection !== null)) {
		for (var k=scriptCollection.length-1; k>=0; k--) {
			if (typeof scriptCollection[k].src !== "undefined" && scriptCollection[k].src !== "")
				scriptArray.push(scriptCollection[k].src);
		}
	}

	// find all loaded stylesheets
	var sheetArray = [];
	var sheetCollection = document.getElementsByTagName("link");
	if ((typeof sheetCollection !== "undefined") && (sheetCollection !== null)) {
		for (var k=sheetCollection.length-1; k>=0; k--) {
			if (typeof sheetCollection[k].href !== "undefined" && sheetCollection[k].href !== "")
				sheetArray.push(sheetCollection[k].href);
		}
	}

	// convert loaded scripts and stylesheets into a string to make comparison a one-step operation
	var fileString = scriptArray.join('|') + '|' + sheetArray.join('|');

	// weed out dependencies that are already loaded
	for (var d=0; d < depends.length; d++) {
		if (fileString.indexOf(depends[d]) != -1) {
			depends.splice(d,1);
			d--;
		} else if (depends[d].indexOf('.css') != -1) {
			// if this dependency is not yet loaded and it's a stylesheet, load it now because there is no "onload" event on link tags on most browsers
			loadOnDemand.loadSheet(depends[0]);
			depends.splice(d,1);
			d--;
		}
	}

	// If dependencies are all loaded, execute.  Otherwise, load the next dependency
	if (depends.length == 0) {
		// hide loading div, if it was requested
		if (options.loading && options.loading == true && document.getElementById('newPleaseWait'))
			document.getElementById('newPleaseWait').style.display = 'none';
		else if (options.loading && options.loading != '' && options.loading != false && document.getElementById(options.loading))
			document.getElementById(options.loading).style.display = 'none';

		// if this is concurrent load that was runnning, make sure the other events didn't beat us here
		if (options.running) {
			// check to see if the function has actually been called already
			for (var ops=0; ops < loadOnDemand.concurrentOperations.length; ops++) {
				if (loadOnDemand.concurrentOperations[ops].id == options.running) {

					// remove this load from the loading count
					if (loadOnDemand.concurrentOperations[ops].loads > 0) loadOnDemand.concurrentOperations[ops].loads--;

					// if all the loads are completed, remove this element from the concurrentOperations array
					if (loadOnDemand.concurrentOperations[ops].loads == 0) {
						loadOnDemand.concurrentOperations.splice(ops,1);
						options.running = null; // set this back to null, which allows for the function to finally execute
					}
					break;
				}
			}
		}

		// execute the function
		if (!options.running) funcName.apply(document.body, attributes);

	} else {
		// display a "Loading" message, if requested
		if (options.loading && options.loading == true) {
			if ( !document.getElementById('newPleaseWait') ) {
				var newPleaseWaitObject = document.createElement('div');
				newPleaseWaitObject.id = 'newPleaseWait';
				newPleaseWaitObject.style.position='absolute';
				newPleaseWaitObject.style.overflow='hidden';
				newPleaseWaitObject.style.height='60px';
				newPleaseWaitObject.style.width='150px';
				newPleaseWaitObject.style.left = ( getWindowWidth() / 2 - 75 ) + 'px';
				newPleaseWaitObject.style.top = ( getWindowHeight() / 2 - 30 ) + 'px';
				newPleaseWaitObject.style.padding='8px';
				newPleaseWaitObject.style.borderRight='2px solid #444444';
				newPleaseWaitObject.style.borderBottom='2px solid #777777';
				newPleaseWaitObject.style.borderLeft='2px solid #AAAAAA';
				newPleaseWaitObject.style.borderTop='2px solid #BBBBBB';
				newPleaseWaitObject.style.backgroundColor='rgb(230,230,220)';
				newPleaseWaitObject.style.backgroundImage='url(/images/gradient-dossier.png)';
				newPleaseWaitObject.style.backgroundRepeat='repeat-y';
				newPleaseWaitObject.style.color='black';
				newPleaseWaitObject.style.zIndex='7000';
				newPleaseWaitObject.innerHTML = '<table border="0" align="center" height="100%" width="100%" cellpadding="2" cellspacing="1" style="font-family:Arial,Helvetica;font-size:10pt;"><tr><td rowspan="2"><img src="/images/blue_cube_anim.gif" border="0"></td><td><center><b>Please Wait</b></td><td rowspan=2><img src="/images/blue_cube_anim.gif" border="0"></td></tr><tr><td><center>Loading...</td></tr></table>';
				PWObj = document.body.appendChild(newPleaseWaitObject);
			} else {
				document.getElementById('newPleaseWait').style.display = '';
			}
		} else if (options.loading && options.loading != '' && options.loading != false && document.getElementById( options.loading )) {
			document.getElementById(options.loading).style.display = '';
		}

		// load the script either concurrently (all at once) or consecutively (one at a time)
		if (options.method == 'consecutively') {
			loadOnDemand.loadScript(depends[0], {funcName:funcName, attributes:attributes, options:options}); // load the next script
		} else if (!options.running) {
			// begin loading all at once, first generate a random ID to identify this load and store it
			var loadID = Math.floor(Math.random()*1000000000000);
			loadOnDemand.concurrentOperations.push({id:loadID, loads:depends.length});
			options.running = loadID;

			// now load the files
			for (var d=0; d < depends.length; d++)
				loadOnDemand.loadScript(depends[d], {funcName:funcName, attributes:attributes, options:options});
		}
	}
};



/** loadOnDemand.loadScript: load a JavaScript document - this is quite specific to loadOnDemand currently, so do not call separately
	@param url {String} the url of the JS to load
	@param options {Object} an object of attributes to pass back to loadOnDemand
*/
loadOnDemand.loadScript = function(url, options) {
	// alert('loadOnDemand loadScript: ' + url);
	var script = document.createElement("script");
	script.type = 'text/javascript';
	script.charset = 'utf-8';
	script.options = options;
	script.onload = function() { loadOnDemand.execute(this.options.funcName, this.options.attributes, this.options.options); };
	script.onreadystatechange = function() { if (script.readyState == 'loaded' || script.readyState == 'complete') loadOnDemand.execute(this.options.funcName, this.options.attributes, this.options.options); };
	script.src = url;
	document.body.appendChild(script);
};



/** loadOnDemand.loadSheet: load a CSS stylesheet
	@param url {String} the url of the CSS to load
*/
loadOnDemand.loadSheet = function(url) {
	// alert('loadOnDemand loadSheet: ' + url);
	var link = document.createElement("link");
	link.rel = 'stylesheet';
	link.type = 'text/css';
	link.media = 'all';
	link.href = url;
	document.body.appendChild(link);
};



/** loadOnDemand.cookieExists: returns boolean if the cookie passed in exists
	@param name {String} the name of the cookie to check for
*/
loadOnDemand.cookieExists = function(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return true;
	}
	return false;
};



/** loadOnDemand.isExpired: returns boolean if date passed in has already passed
	@param expireDate {Date} the date to check for expiration
*/
loadOnDemand.isExpired = function(expireDate) {
	return (expireDate < new Date());
};
