var LibManager = {
	/**
	 * The include path to use (./ relative to LibManager.js)
	 * @var string
	 */
	includePath: '',
	/**
	 * This holds an alphaNumber string to be appended to the end of the includes as a queryString parameter,
	 * this will allow us to force the browser to reload cached JS just by changing this parameter (e.g. with revision number etc.)
	 * @var string
	 */
	cacheParam: '',
	/**
	 * Holds a list of all included scripts for this session
	 * @var array
	 */
	included: [],
	/**
	 * Holds a list of all variables that the isLoaded method has been asked to check and has found
	 * @var string
	 */
	loadedVars: '',

	
	/**
	 * Initializes the object by picking up the includePath
	 * 
	 * @access public
	 * @return void
	 */
	init: function() {
		var scriptEls = document.getElementsByTagName( 'script' );
		for( var i = 0; i < scriptEls.length; i++ ) {
			var src = scriptEls[i].src;
			if( src.match( /LibManager\.js/i ) ) {
				this.includePath = src.replace( /LibManager\.js(.*)?$/i, '' );
				
				// set the cacheParam
				this.cacheParam = this.getScriptParam( scriptEls[i], 'cacheParam' );
				break;
			}
		}
	
		// figure out whether we've already loaded some scripts from the include path,
		// within the source, because there is no point trying to do it again if we have
		// @TODO : that ^^ 
			
	},
	
	/**
	 * Returns the named query string parameter for the given script. 
	 * The callBack function, although optional, should be used in most cases as 
	 * if the script is in the process of being executed by JS so the script 
	 * element hasn't loaded in the DOM yet and this method won't find it. Using the
	 * callback will allows us to use timeouts to keep checking for the script element.
	 * 
	 * @access public
	 * @param string||obj script name (without path & .js) || script object
	 * @param string query string parameter to return
	 * @param callBack function to return parameter to [optional]
	 * @return void || string Depending on whether a callBack function is used
	 */
	getScriptParam: function( script, paramName, callBack ) {
		var scriptEl = null;

		// if we've passed a string of the script name then find that script first
		if( typeof(script) == 'string' ) {
			var scriptEls = document.getElementsByTagName( 'script' );

			for( var i = 0; i < scriptEls.length; i++ ) {
				var regExp = new RegExp( script + '.js', 'i' );
				if( scriptEls[i].src.match( regExp ) ) {
					scriptEl = scriptEls[i];
					break;
				}
			}
			
			// if we've not found the script element yet we need to try again, (see note
			if( scriptEl == null ) {
				setTimeout( 'LibManager.getScriptParam("' + script + '", "' + paramName + '",' + callBack + ')', 100 );
				return;
			}
			
		} else {
			// if we've passed an object of the script node
			scriptEl = script; 
		}
				
		// get the param
		var regExp = new RegExp( '\\?.*' + paramName + '=([a-zA-Z0-9]+).*', 'i' );
		scriptEl.src.match( regExp );
		
		var returnVal = '';
		if( typeof( RegExp.$1 ) != 'undefined' ) returnVal = RegExp.$1;
				
		if( typeof( callBack ) == 'function' ) callBack( returnVal );	
		else return returnVal;
	},
	
	/**
	 * Returns whether we've already included the given script for the session
	 * 
	 * @access private
	 * @param string Script path & name represented as dot notation
	 * @return boolean
	 */
	isIncluded: function( script ) {
		var scriptL = script.toLowerCase();
	
		for( var i = 0; i < this.included.length; i++ ) {
			if( this.included[i] == scriptL ) return true;
		}
		return false;		
	},
	
	/**
	 * Includes the given library script if it has not already been loaded, 
	 * this assumes that the provided script path & name is correct and relative to
	 * the LibManager script
	 * 
	 * @access public
	 * @param string Script path & name represented as dot notation (e.g. 'dir.subDir.script' )
	 * @return void
	 * @todo : allow query string parameters? might as well - be cool if could pass them as an object... that'd be sweet
	 * @todo : test test & more test (Safari especially, apparently 2.0 is bad, but now we're using xmlHTTP should be GOOOD )
	 */
	require: function( script ) {
		//console.log( 'require :: ' + script + '\n' );
		if( !this.isIncluded( script ) ) {
			var scriptPath = this.includePath + script.replace( /\./g, '/' ) + '.js';
			if( this.cacheParam.length ) scriptPath += this.cacheParam;
			
			var head = document.getElementsByTagName('head').item(0);			
			
			var newScript = document.createElement( 'script' );
			newScript.src = scriptPath;
			newScript.type = 'text/javascript';
			head.appendChild( newScript );
			//dump( 'append :: ' + script + '\n' );
									
			// Because IE 5 doesn't have push we do the index oursevles
			// We put the script name to lowercase to avoid case issues when checking if we've already loaded a script
			this.included[ this.included.length + 1 ] = script.toLowerCase(); 
		}
	},
	
	/**
	 * As the browser may take a few milliseconds to parse the scripts included via the require() method,
	 * this method can be used to ensure that all required variables/objects are loaded before you perform a funciton call.
	 * 
	 * @access public
	 * @param array List of variable names to check to see that they have loaded
	 * @param function The function to call once all required variables have loaded
	 * @return void 
	 */
	isLoaded: function( checkVars, func ) {
		//console.log( 'isLoaded :: ' + checkVars + '\n' );
		var notLoaded = '';
		for( var i = 0; i < checkVars.length; i++ ) {
			// if something else has already asked to check for this variable and we've found it 
			// we needn't both doing the work again
			if( !this.loadedVars.match( /checkVars[i]/i ) ) {
				try {
					typeof( eval( checkVars[i] ) );
					this.loadedVars += ',' + checkVars[i];
				} catch(e) {
					if( notLoaded.length ) notLoaded += ',';
					notLoaded += "'" + checkVars[i] + "'";
				}
			}
		}
		
		if( notLoaded.length ) setTimeout( 'LibManager.isLoaded( [' + notLoaded + '],' + func + ' )', 20 );
		else func();
	}
	
		
};

LibManager.init();
