/** 
 * Functions for dynamic loading of Javascript files.
 * @author Rebecca Younes
 * @date 08/15/2007
 * 
 * Dynamic script loading servers two purposes:
 * (1) Load a script that attaches event listeners to elements that are inserted into the DOM 
 * via an Ajax request. Elements can have event listeners attached to them only after they are
 * inserted into the DOM, so once they are inserted into the document another script can be loaded
 * to attach the event listeners. (There are alternate solutions to this problem, such as YUI's
 * Element Utility, which is still in beta, and YUI's delayed event listener attachment, which I
 * haven't gotten to work.)
 * (2) Keep Javascript logic self-contained, so each file loads the scripts it's dependent on. Then
 * html pages don't have to track the dependencies and be updated when these change.
 * 
 * Use loadScriptsOnce() to prevent a script from being loaded more than once, either through
 * multiple Ajax requests or circular dependencies. Use loadScripts() for improved performance
 * if that is not a possibility.
 * 
 * Both functions append scripts to the document, body since they may contain executing
 * code as well as function definitions. I think this will handle all cases, but if not 
 * a member of the opts object could be used to control where the script is inserted.
 */

/**
 * @method loadScripts
 * @param {String|Array} newScripts Script file or array of script files to be loaded
 * @param {Object} opts (optional) Additional arguments, to be defined as needed.
 * @return {void}
 */
function loadScripts(newScripts, opts) {

	var i, 
		oScript;

	if (typeof newScripts == "string") {
		newScripts = [newScripts];
	}
	
	for (i = 0; i < newScripts.length; i++) {
		oScript = document.createElement("script");
		oScript.type = "text/javascript";
		oScript.src = newScripts[i];
		document.body.appendChild(oScript);
	}	
}

/**
 * @method loadScriptsOnce
 * @param {String|Array} newScripts Script file or array of script files to be loaded
 * @param {Object} opts (optional) Additional arguments, to be defined as needed.
 * @return {void}
 */
function loadScriptsOnce(newScripts, opts) {

	var i, 
		oScript,
		// get all the script element in the document
		scripts = document.getElementsByTagName("script"),
		scriptSrc = [],
		pos;

	if (typeof newScripts == "string") {
		newScripts = [newScripts];
	}
	
	// Create an array of the script src attributes
	for (i = 0; i < scripts.length; i++) {
		scriptSrc.push(scripts[i].src);
	}

	for (i = 0; i < newScripts.length; i++) {
		oScript = document.createElement("script"); 
		// This gives us the fully qualified url to compare against, so it doesn't
		// matter whether a relative or absolute path was passed in. If we just do
		// if (!scriptSrc.find(arguments[i]) we can only look at the literal string,
		// so e.g. "test.js" will not be recognized as the same src value as
		// "http://www.ilr.cornell.edu/test/test.js"
		oScript.src = newScripts[i];
		// If this script is already loaded, unload it and then reload it.
		// This seems odd, but it's critical for the attachment of event listeners to 
		// new elements put into the DOM by an xhr request. The event listeners must be
		// reattached AFTER those elements have been inserted into the DOM, even if they have
		// the same id as elements previously in the DOM that have had those event listeners
		// atached to them.
		// Array.find returns the index of the found item.
		pos = scriptSrc.find(oScript.src);
		if (pos) {				
			scripts[pos].parentNode.removeChild(scripts[pos]);	
		}
		else {
			// IN CASE the same script is passed more than once in one function call...
			// Could happen if the arguments list is assembled dynamically.
			// NB we don't have to modify scripts (nor can we), because it's a (read-only)
			// NodeList rather than an Array. It gets updated automatically as script elements
			// are removed from and added to the DOM.
			scriptSrc.push(oScript.src);			
		}
		oScript.type = "text/javascript";
		document.body.appendChild(oScript);
	}	
}


