/**
 * @fileoverview
 * 
 * The Frozen JavaScript library provides objects to extend in order to
 * implement event-driven applications, as well as a full XMLHttpRequest
 * wrapper object, with an accompanying class to manage garbage collection
 * and pooling.
 * 
 <pre>
 	Copyright (c) 2006 Frozen O Productions
	Written by Shawn Lauriat
	All rights reserved.
 
	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions are met:

	- Redistributions of source code must retain the above copyright notice,
		this list of conditions and the following disclaimer.
	- Redistributions in binary form must reproduce the above copyright notice,
		this list of conditions and the following disclaimer in the
		documentation and/or other materials provided with the distribution.
	- Neither the name of Frozen O Productions nor the names of its
		contributors may be used to endorse or promote products derived from
		this software without specific prior written permission.
 
	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
	POSSIBILITY OF SUCH DAMAGE.
 </pre>
 */

/**
 * The global namespace
 */
if (typeof Frozen == "undefined") {
	/**
	 * The namespace for the Frozen Toolkit
	 * @package
	 */
	Frozen = {
		"meta" : {
			"identifier" : "com.frozen-o.frozentoolkit",
			"identifierprefix" : "com.frozen-o.frozentoolkit.",
			"namespace" : "Frozen",
			"state" : "alpha",
			"url" : "http://frozentoolkit.frozen-o.com",
			"version" : "0.2"
		}
	};

	/**
	 * If the OpenAjax hub exists, register the library in
	 * its namespace.
	 */
	if (typeof OpenAjax != "undefined") {
		OpenAjax.hub.registerLibrary(
			Frozen.meta.namespace,
			Frozen.meta.url,
			Frozen.meta.version,
			{"state":Frozen.meta.state}
		);
	}
}

if (typeof Frozen.Event == "undefined") {
	/**
	 * The Frozen.Event object acts as the container for
	 * all things in the Frozen.Event library.
	 * @package
	 */
	Frozen.Event = { };

	/**
	 * The base class for all custom events, rather than attempting to extend
	 * the native JavaScript Exception object, which wouldn't work anyway.
	 * @construct
	 */
	Frozen.Event.Event = function() { }
	Frozen.Event.Event.prototype = {
		type : "custom"
	}
	
	/**
	 * Custom EventTarget equivalent
	 * @construct
	 */
	Frozen.Event.Dispatcher = function() { }
	Frozen.Event.Dispatcher.prototype = {
		/**
		 * An object literal to store arrays of listeners by type
		 */
		events : {},
		
		/**
		 * If it supports the type, add the listener (capture ignored)
		 * @param {String} type The type of event to add the listener to ("load", etc.)
		 * @param {Object} listener Either a function reference or an array containing
		 * references to the function and the object within whose context the function
		 * needs to run.
		 * @param {boolean} capture Unused, just there to emulate real events.
		 */
		addEventListener : function(type, listener, capture) {
			if (this.events[type]) {
				this.events[type].push(listener);
			}
		},
		
		/**
		 * If it supports the type, remove the listener (capture ignored)
		 * @param {String} type The type of event to add the listener to ("load", etc.)
		 * @param {Object} listener Either a function reference or an array containing
		 * references to the function and the object within whose context the function
		 * needs to run.
		 * @param {boolean} capture Unused, just there to emulate real events.
		 */
		removeEventListener : function(type, listener, capture) {
			if (this.events[type] == undefined) {
				return;
			}
			var index = this.events[type].indexOf(listener);
			if (this.events[type][index]) {
				this.events[type].splice(index, 1);
			}
		},
		
		/**
		 * Cycle through all of the event listeners, passing the event to the callbacks,
		 * generally only called internally by the class extending Dispatcher
		 * @param {String} type The type of event to add the listener to ("load", etc.)
		 * @param {Event} event The Event (or subclass of) to pass to each
		 * listener for the given event type.
		 */
		dispatchEvent : function(type, event) {
			if (this.events[type]) {
				for (i in this.events[type]) {
					if (typeof this.events[type][i] == "function") {
						this.events[type][i](event);
						// Accepts an array of the contextual object and the function to call
					} else if (typeof this.events[type][i] == "object") {
						this.events[type][i][1].call(this.events[type][i][0], event);
					}
				}
			}
		}
	}
}

if (typeof Frozen.Utilities == "undefined") {
	/**
	 * An object to hold commonly-needed functions
	 * @static
	 * @class
	 */
	Frozen.Utilities = {
		/**
		 * Keep track of files already loaded
		 */
		loadedJavaScript : { },
		/**
		 * Load the specified JavaScript file, optionally
		 * calling a callback function, passing a boolean
		 * as to whether the file loaded
		 * @method
		 */
		loadJavaScript : function(file, callback, timeout) {
			if (typeof timeout == "undefined") {
				timeout = 6000;
			}
			if (Frozen.Utilities.loadedJavaScript[file]) {
				if (callback) {
					setTimeout(callback, 10, true);
				}
				return true;
			} else {
				var head = document.getElementsByTagName("head")[0];
				var script = head.appendChild(
					document.createElement("script")
				);
				// Set timeout of a very liberal 30 seconds
				var timer = setTimeout(
						function() {
						callback(false);
					},
					timeout
				);
				script.addEventListener(
					"load",
					function() {
						clearTimeout(timer);
						Frozen.Utilities.loadedJavaScript[file] = true;
						callback(true);
					},
					false
				);
				script.type = "text/javascript";
				script.src = file;
				return true;
			}
		}
	};
}
