(function() {
	window.CSCC = { };

	/**
	 * Constant containing the base URL of the library files.
	 * @constant
	 */
	CSCC.BASEPATH = '/';

	/**
	 * Constant containing the base URL of the Syllabus system.
	 * @constant
	 */
	CSCC.SYLLABUS_URL = 'http://res.clarkstate.edu/Syllabus';

	/**
	 * Registers a function to be called once the DOM has finished loading.
	 * Implementation by Jesse Skinner. Original source can be found at
	 * http://www.thefutureoftheweb.com/blog/adddomloadevent.
	 */
	CSCC.AddDomLoadEvent = (function() {
		// create event function stack
		var load_events = [],
			load_timer,
			script,
			done,
			exec,
			old_onload,
			init = function () {
				done = true;

				// kill the timer
				clearInterval(load_timer);

				// execute each function in the stack in the order they were added
				while (exec = load_events.shift())
					exec();

				if (script) script.onreadystatechange = '';
			};

		return function (func) {
			// if the init function was already ran, just run this function now and stop
			if (done) return func();

			if (!load_events[0]) {
				// for Mozilla/Opera9
				if (document.addEventListener)
					document.addEventListener("DOMContentLoaded", init, false);

				// for Internet Explorer
				/*@cc_on @*/
				/*@if (@_win32)
					document.write("<script id=__ie_onload defer src=//0><\/scr"+"ipt>");
					script = document.getElementById("__ie_onload");
					script.onreadystatechange = function() {
						if (this.readyState == "complete")
							init(); // call the onload handler
					};
				/*@end @*/

				// for Safari
				if (/WebKit/i.test(navigator.userAgent)) { // sniff
					load_timer = setInterval(function() {
						if (/loaded|complete/.test(document.readyState))
							init(); // call the onload handler
					}, 10);
				}

				// for other browsers set the window.onload, but also execute the old window.onload
				old_onload = window.onload;
				window.onload = function() {
					init();
					if (old_onload) old_onload();
				};
			}

			load_events.push(func);
		};
	})();

	/**
	 * Determines whether or not the specified script has already been inserted
	 * into the document.
	 * @param Script The URL of the script to check for.
	 * @param FullUrl If true, the Script parameter is treated as the full URL.
	 *        If false, only the filenames are compared.
	 * @returns If a script element with the specified URL is present in the
     *          document, true. Otherwise, false.
	 */
	CSCC.ScriptIsLoaded = function(Script, FullUrl) {
		var scripts = document.getElementsByTagName('script');
		
		for (var i = 0; i < scripts.length; i++) {
			if (FullUrl) {
				if (scripts[i].src === Script)
					return true;
			} else {
				if (scripts[i].src.split('/').pop() === Script)
					return true;
			}
		}
	};

	/**
	 * Inserts the script from the specified URL into the document.
	 * Based on code by Andy Idsinga of Intel.
	 * @param Url The URL of the script to insert.
	 * @param Callback Function to call once the browser has finished loading the script.
	 */
	CSCC.LoadScript = function(Url, Callback) {
		var script  = document.createElement('script');
		script.type = 'text/javascript';
		script.src  = Url;
		
		// Use an empty callback if none was specified.
		if (!Callback)
			Callback = function() { }

		var callbackWrapper = function() {
			Callback(Url);
		}
		
		// Don't load the same script twice.
		if (CSCC.ScriptIsLoaded(Url.split('/').pop(), false)) {
			Callback(Url);
			return;
		}

		// Firefox, Chrome, Safari, and Opera.
		if (typeof(script.addEventListener) != 'undefined') {
			script.addEventListener('load', callbackWrapper, false);
		}
		// IE8 and later.
		else {
			var onStateChange = function() {
				if (script.readyState === 'loaded' || script.readyState === 'complete') {
					callbackWrapper(Url);
				}
			}

			var ret = script.attachEvent('onreadystatechange', onStateChange);
		}

		document.getElementsByTagName('head')[0].appendChild(script);
	};

	/**
	 * Inserts the stylesheet from the specified URL into the document.
	 * @param Url The URL of the stylesheet to insert.
	 * @param Callback Function to call once the browser has finished loading the stylesheet.
	 */
	CSCC.LoadStylesheet = function(Url, Callback) {
		// Many of the ideas implemented in this function are from
		// http://www.phpied.com/when-is-a-stylesheet-really-loaded/

		var retry = 100;
		var callbackFired = false;
		
		var link = document.createElement("link");
		link.rel = 'stylesheet';
		link.href = Url;
		
		// Since IE will fire an event after the stylesheet is loaded we can simply hook
		// our callback onto that. For once IE is the easy one!
		if (CSCC.IsIE) {
			link.attachEvent('onreadystatechange', function() {
				if (link.readyState === 'complete') {
					Callback();
				}
			});
		}
		
		// Chrome (presumably Safari as well) will update styleSheets once the CSS is
		// completely loaded. So we'll simply poll with property until it changes.
		else if (CSCC.IsWebKit || CSCC.IsGecko) {
			var linkHref = link.href;
		
			// Our strategy for Gecko differs from WebKit only a little. We will use
			// a style element with an @import directive for the stylesheet instead of a link.
			// This allows us to poll styleSheets until the load is complete.
			if (CSCC.IsGecko) {
				link = document.createElement("style");
				link.textContent = '@import "' + Url + '";';
				linkHref = Url;
			}
		
			var intr = setInterval(function() {
				for (var i = 0; i < document.styleSheets.length; i++) {
					try {
						var href = null;
						if (CSCC.IsGecko) {
							if (document.styleSheets[i].cssRules.length > 0) {
								href = document.styleSheets[i].cssRules[0].href;
							}
						} else {
							href = document.styleSheets[i].href;
						}
					
						if (href === linkHref) {
							ruleCount = (document.styleSheets[i].cssRules ? document.styleSheets[i].cssRules.length : 0);
							
							if (ruleCount > 0) {
								retry = 0;
							}
							
							break;
						}
					} catch(e) {
						continue;
					}
				}
			
				// If we've run out of retries then give up and fire the callback anyway.
				if (retry < 1) {
					clearInterval(intr);
					Callback();
					return;
				}
			
				retry--;
			}, 10);
		}
		
		// For any other browsers we'll simply have to fire off the callback after
		// a small delay and hope everything works out all right.
		else {
			setTimeout(Callback, 50);
		}

		document.getElementsByTagName("head")[0].appendChild(link);
	};

	/**
	 * Inserts the script of stylesheet resource from the specified URL
	 * into the document.
	 * @param Url The URL of the resource to insert.
	 * @param Callback Function to call once the resource has been loaded.
	 */
	CSCC.LoadResource = function(Url, Callback) {
		// Determine whether this is a script or stylesheet. We do not
		// support any other filetypes.
		var extension = Url.split('.').pop();

		if (extension === 'js' || extension === 'b') {
			CSCC.LoadScript(Url, Callback);
		} else {
			CSCC.LoadStylesheet(Url, Callback);
		}
	}

	/**
	 * Inserts the script of stylesheet resource from the specified URL
	 * into the document.
	 * @param Urls Array containing the URLs of the resources to load.
	 * @param Callback Function to call once all of the resources have been loaded.
	 */
	CSCC.LoadResources = function(Urls, Callback) {
		var loader = function(Index) {
			CSCC.LoadResource(Urls[Index], function() {
				Index += 1;
				if (Index < Urls.length) {
					loader(Index);
				} else {
					if (Callback)
						Callback();
				}
			});
		};

		loader(0);
	};

	/**
	 * Array containing the callback function registered with the CSCC.OnReady function.
	 * @private
	 */
	var _ReadyCallbacks = [ ];

	/**
	 * Registers a function to be called once library initialization has bee completed.
	 * @param Callback Function to be called after initialization.
	 */
	CSCC.OnReady = function(Callback) {
		_ReadyCallbacks.push(Callback);
	};
	
	/**
	 * Called internally by the library once initialization has completed. Do
	 * not call this function manually from user code.
	 * @private
	 */
	CSCC._Ready = function() {
		for (var i = 0; i < _ReadyCallbacks.length; i++) {
			_ReadyCallbacks[i]();
		}
	};
})();


/**
 * Wait until the DOM has finished loading before initialize the library.
 */
CSCC.AddDomLoadEvent(function() {
	// Pull in the Namespace library. Once that is inserted begin loading the rest of
	// the library files.
	CSCC.LoadResource(CSCC.BASEPATH + 'scripts/Namespace.js', function() {
		var res = [ ];
		res.push(CSCC.BASEPATH + 'styles/jquery.pnotify.default.css');
		res.push(CSCC.BASEPATH + 'styles/jquery.pnotify.default.icons.css');
		res.push(CSCC.BASEPATH + 'styles/smoothness/jquery-ui-1.8.14.custom.css');
		res.push(CSCC.BASEPATH + 'styles/CSCC.css');
		res.push(CSCC.BASEPATH + 'scripts/jquery-1.6.2.js');
		res.push(CSCC.BASEPATH + 'scripts/jquery.browser.js');
		res.push(CSCC.BASEPATH + 'scripts/jquery.cookie.js');
		res.push(CSCC.BASEPATH + 'scripts/jquery.pnotify.js');
		res.push(CSCC.BASEPATH + 'scripts/jquery-ui-1.8.14.js');
		res.push(CSCC.BASEPATH + 'scripts/JSON.js');
		res.push(CSCC.BASEPATH + 'scripts/Utility.js');
		res.push(CSCC.BASEPATH + 'scripts/Ajax.js');
		res.push(CSCC.BASEPATH + 'scripts/BrowserWarning.js');
		res.push(CSCC.BASEPATH + 'scripts/Schedule.js');
		res.push(CSCC.BASEPATH + 'scripts/Programs.js');
		res.push(CSCC.BASEPATH + 'scripts/Syllabus.js');
		res.push(CSCC.BASEPATH + 'scripts/Validation.js');
		res.push(CSCC.BASEPATH + 'scripts/Application.js');
		res.push(CSCC.BASEPATH + 'scripts/Konami.js');	// Yup, I snuck in an easter egg.
		res.push(CSCC.BASEPATH + 'scripts/Calculator.js');

		CSCC.LoadResources(res, function() {
			// A small but useful addition to the jQuery library.
			jQuery.fn.exists = function() { return jQuery(this).length > 0; };
			
			// Fix fade animations in IE8 and earlier.
			if (jQuery.browser.name === 'msie' && jQuery.browser.versionNumber < 9) {
				jQuery.fn.fadeIn = function(speed, callback) {
					return this.animate({opacity: 'show'}, speed, function() {
							if ($.browser.msie )
								this.style.removeAttribute('filter');
						if ($.isFunction(callback))
							callback.call(this);
					});
				};
				jQuery.fn.fadeOut = function(speed, callback) {
					return this.animate({opacity: 'hide'}, speed, function() {
						if ($.browser.msie)
							this.style.removeAttribute('filter');
						if ($.isFunction(callback))
							callback.call(this);
					});
				};
				jQuery.fn.fadeTo = function(speed, to, callback) {
					return this.animate({opacity: to}, speed, function() {
						if (to == 1 && $.browser.msie)
							this.style.removeAttribute('filter');
						if ($.isFunction(callback))
							callback.call(this);
					});
				};
			}
		
			// Once all of our initial resources have been loaded we can call
			// the OnReady handlers.
			CSCC._Ready();
		});
	});
});

