/*
Script: jEnsure.js

jEnsure library
	A tiny javascript library that provides a handy function "ensure" which allows you to load 
	Javascript, HTML, CSS on-demand and then execute your code. Ensure ensures that relevent 
	Javascript and HTML snippets are already in the browser DOM before executing your code 
	that uses them.

	A great thank you to Omar AL Zabir and his ensure.js, which provided all the inspiration and
	much of the logic!

Credits:
	- Omar AL Zabir - http://msmvps.com/blogs/omar
*/

(function($) {

	// Set up the jQuery-function
	$.ensure = function( data, callback)
	{
        	load( toArray(data.js), toArray(data.css), callback);
	}

	function toArray(value) {
		if (!value) return [];
		else return (value.constructor == Array) ? value : [value];
	}

	function load(scriptList, cssList, callback)
	{
		var scriptsToLoad = 0;

		// Start loading scripts
		$.each(scriptList, function() {
			var url = this;
			if( isUrlLoaded(url) || isTagLoaded('script', 'src', url) )
			{
				log ('Already loaded: ' + url);
			}
			else
			{
				log ('Requesting script: ' + url);
				++scriptsToLoad;
				$.ajax({
					type: "GET",
					url: url,
					success: function() {
						// log ("getScript() success: " + url);
						registerUrl(url);
					},
					error: function() {
						log ("getScript() failed: " + url);
					},
					complete: function() {
						log ("getScript() complete: " + url);
						scriptsToLoad--;
					},
		                        dataType: "script",
					cache: true,
					timeout: 4000
				});
			}
		});

		// Start loading CSS
		$.each(cssList, function() {
			log ('Ensuring css: href=' + this);
			if(!isUrlLoaded(this) && !isTagLoaded('link', 'href', this))
			{            
				var link = document.createElement('link');
				link.setAttribute("href", ""+this);	// "this" may not be a string -- stringify!
				link.setAttribute("rel", "stylesheet");
				link.setAttribute("type", "text/css");
				var head = document.getElementsByTagName("head")[0] || document.documentElement;
				head.appendChild(link);
				registerUrl(this);
			}
        	});

		// wait for scripts
		var timeout=25;
		var i=0;
		var waitForScripts = function () {
		    if (scriptsToLoad <= 0) {
			callback && callback();
		    }
		    else {
			log ("waitForScripts: scriptsToLoad=" + scriptsToLoad + "; i=" + (++i) + "; timeout=" + timeout);
			timeout = Math.min(1000, timeout + 50);
			window.setTimeout(waitForScripts, timeout);
		    }
		}

		waitForScripts();
	}

	function isTagLoaded (tagName, attName, value)
	{
		var sel = tagName + "[" + attName + "=" + value + "]";
		count= $(sel).length;
		log ("isTagLoaded: result=" + (count > 0) + "; selector=" + sel);
		return count > 0;
	}

	// List of URLs loaded through jEnsure
    	var loadedUrls = []

	function isUrlLoaded (url) {
		// log ("isUrlLoaded: result=" + (loadedUrls[url] === true) + "; url=" + url);
       		return loadedUrls[url] === true;
	}

	function registerUrl (url) {
		// log ("Registering url: " + url);
		loadedUrls[url] = true;
	}

	function log (value) {
		if (window.console && console.log) console.log("jEnsure -- " + value)
		else if (window.opera && opera.postError) opera.postError("jEnsure -- " + value);
	}

})(jQuery);

