/* 
Initialize the TL namespace
*/

if(typeof(TL) == "undefined") var TL = new Object();

TL.Utilities = function(){
	
	return {
		

		
		/*
		
		addCSSRule
		
		Add CSS Rule to StyleSheet
		
		UNUSED
		*/
		
		addCSSRule: function(selectorText, declarations) {
			var styleSheet;
			if (document.styleSheets) {
				if (document.styleSheets.length === 0) {
					var styleElement;
						if (document.createElement && (styleElement = document.createElement('style'))) {
							styleElement.type = 'text/css';
							document.getElementsByTagName('head')[0].appendChild(styleElement);
							styleSheet = styleElement.sheet;
						}
				}
				if (document.styleSheets.length > 0) {
					styleSheet = document.styleSheets[document.styleSheets.length - 1];
					if (styleSheet.insertRule) {
						styleSheet.insertRule(selectorText + ' { ' + declarations + ' }',styleSheet.cssRules.length);
					} else if (styleSheet.addRule) {
						styleSheet.addRule(selectorText, declarations);
					}
				}
			}
		},
		
		/*
		
		getElementsByClass
		
		Returns an array of elements that have a given element name and CSS class.
		
		Usage:
		getElementsByClass(element name, class name);
		
		Example:
		getElementsByClass("h2","blue");
		*/
		
		getElementsByClass: function($tag,$class){
			
			if($tag == "Hn"){
				var tags = TL.Utilities.getHeadingElements();
			}else{
				var tags = document.getElementsByTagName($tag);
			}
			
			if((tags.length == 0)&&($tag === "*")&&(document.all)){
				var tags = document.all;
			}
			
			var coll = [];
			
			
			var pattern = new RegExp($class,"i");
			for(var i=0; i<tags.length; i++){
				var classes = tags[i].className;
				
				if(pattern.test(classes)){
					coll[coll.length] = tags[i];
				}
			}
		
			return coll;
		},
		
		/*
		
		getElementStyle
		
		Cross-platform function to get the computed style of a given element.
		
		Usage:
		getElementStyle(element object, IE style name, Standard style name);
		
		Example:
		getElementStyle(document.getElementById("myDiv"), "fontSize", "font-size");
		*/
		
		getIEPropertyName: function($property){
			if($property == 'float'){
				return 'styleFloat';
			}
			if($property.match("-")){
				var tmp = $property.split("-");
				var prt2 = tmp[1].substr(0,1).toUpperCase()+tmp[1].substr(1);
				var r = tmp[0]+prt2;
				return r;
			}
			
			return $property;
		},
		
		
		getElementStyle: function($element, $property) {
			if($element.nodeType == 3){
				return false;
			}
			if ($element.currentStyle) {
				return $element.currentStyle[TL.Utilities.getIEPropertyName($property)];
			} else if (window.getComputedStyle) {
				var compStyle = window.getComputedStyle($element, "");
				return compStyle.getPropertyValue($property);
			}else if (document.defaultView.getComputedStyle) {
				var compStyle = document.defaultView.getComputedStyle($element, "");
				return compStyle.getPropertyValue($property);
				
			} else {
				return false;
			}
			return "";
		},
		
		
		/* 
		
		getHeadingElements
		
		Returns an array of all the H# tags in the document.
		*/
		
		getHeadingElements: function(){
			
			var r = [];
			for( var i = 1; i < 7; i++ ) {
			  var headers = document.getElementsByTagName('h'+i);
			  for( var j = 0, e; e = headers[j]; j++ ) {
				r[r.length] = e;
			  }
			}
			
			return r;
		},
		
		joinNodeLists: function($list1,$list2){
			var i = $list2.length - 1;
			do{
				$list1[$list1.length] = $list2[i];
			}
			while(i--);
			return $list1;
		}
	}
}();
	

TL.Events = function(){
		
		return{
			/*
			addOnDOMReadyEvent
			
			Adds a function and its arguments to an array of functions to be called when the 
			Document Object Model is ready to be modified.
			
			Usage:
			addOnDOMReadyEvent(function);
			
			*/
			
			DOMReadyEvents:[],
			
			addOnDOMReadyEvent: function($function){
				TL.Events.DOMReadyEvents[TL.Events.DOMReadyEvents.length] = $function;
			},
			
			DOMReady: function(){
				for(var i=0; i<TL.Events.DOMReadyEvents.length; i++){
					TL.Events.DOMReadyEvents[i]();
				}
			},
			
			
			/**
			  * Crossbrowser event handling functions.
			  *
			  * A set of functions to easily attach and detach event handlers to HTML elements.
			  * These functions work around the shortcomings of the traditional method ( element.onevent = function; )
			  * where only 1 handler could be attached for a certain event on the object, and mimic the DOM level 2
			  * event methods addEventListener and removeEventListener for browsers that do not support these
			  * methods (e.g. Internet Explorer) without resorting to propriety methods such as attachEvent and detachEvent
			  * that have a whole set of their own shortcomings.
			  * Created as an entry for the 'contest' at quirksmode.org: http://www.quirksmode.org/blog/archives/2005/09/addevent_recodi.html
			  *
			  * @author Tino Zijdel ( crisp@xs4all.nl )
			  * @version 1.2
			  * @date 2005-10-21
			  */
			
			
			/**
			  * addEvent
			  *
			  * Generic function to attach event listeners to HTML elements.
			  * This function does NOT use attachEvent but creates an own stack of function references
			  * in the DOM space of the element. This prevents closures and therefor possible memory leaks.
			  * Also because of the way the function references are stored they will get executed in the
			  * same order as they where attached - matching the behavior of addEventListener.
			  *
			  * @param obj The object to which the event should be attached.
			  * @param evType The eventtype, eg. 'click', 'mousemove' etcetera.
			  * @param fn The function to be executed when the event fires.
			  * @param useCapture (optional) Whether to use event capturing, or event bubbling (default).
			  */
	  
			addEvent: function(obj, evType, fn, useCapture){  
			
				//-- Default to event bubbling
				if (!useCapture) useCapture = false;
			
				//-- DOM level 2 method
				if (obj.addEventListener)
				{   
					obj.addEventListener(evType, fn, useCapture);
				}
				else
				{
					//-- event capturing not supported
					if (useCapture)
					{
						//alert('This browser does not support event capturing!');
					}
					else
					{
						var evTypeRef = '__' + evType;
			
						//-- create function stack in the DOM space of the element; seperate stacks for each event type
						if (obj[evTypeRef])
						{
							//-- check if handler is not already attached, don't attach the same function twice to match behavior of addEventListener
							if (this.array_search(fn, obj[evTypeRef]) > -1) return;
						}
						else
						{
							//-- create the stack if it doesn't exist yet
							obj[evTypeRef] = [];
			
							//-- if there is an inline event defined store it in the stack
							if (obj['on'+evType]) obj[evTypeRef][0] = obj['on'+evType];
			
							//-- attach helper function using the DOM level 0 method
							obj['on'+evType] = this.IEEventHandler;
						}
			
						//-- add reference to the function to the stack
						obj[evTypeRef][obj[evTypeRef].length] = fn;
					}
				}
			},
			
			/**
			  * removeEvent
			  *
			  * Generic function to remove previously attached event listeners.
			  *
			  * @param obj The object to which the event listener was attached.
			  * @param evType The eventtype, eg. 'click', 'mousemove' etcetera.
			  * @param fn The listener function.
			  * @param useCapture (optional) Whether event capturing, or event bubbling (default) was used.
			  */
			removeEvent: function(obj, evType, fn, useCapture){
				//-- Default to event bubbling
				if (!useCapture) useCapture = false;
			
				//-- DOM level 2 method
				if (obj.removeEventListener)
				{
					obj.removeEventListener(evType, fn, useCapture);
				}
				else
				{
					var evTypeRef = '__' + evType;
			
					//-- Check if there is a stack of function references for this event type on the object
					if (obj[evTypeRef])
					{
						//-- check if function is present in the stack
						var i = this.array_search(fn, obj[evTypeRef]);
						if (i > -1)
						{
							try
							{
								delete obj[evTypeRef][i];
							}
							catch(e)
							{
								obj[evTypeRef][i] = null;
							}
						}
					}
				}
			},
			
			/**
			  * IEEventHandler
			  * 
			  * IE helper function to execute the attached handlers for events.
			  * Because of the way this helperfunction is attached to the object (using the DOM level 0 method)
			  * the 'this' keyword will correctely point to the element that the handler was defined on.
			  *
			  * @param e (optional) Event object, defaults to window.event object when not passed as argument (IE).
			  */
			IEEventHandler: function(e){
				e = e || window.event;
				var evTypeRef = '__' + e.type, retValue = true;
			
				//-- iterate through the stack and execute each function in the scope of the object by using function.call
				for (var i = 0, j = this[evTypeRef].length; i < j; i++)
				{
					if (this[evTypeRef][i])
					{
						if (Function.call)
						{
							retValue = this[evTypeRef][i].call(this, e) && retValue;
						}
						else
						{
							//-- IE 5.0 doesn't support call or apply, so use this
							this.__fn = this[evTypeRef][i];
							retValue = this.__fn(e) && retValue;
						}
					}
				}
			
				if (this.__fn) try { delete this.__fn; } catch(e) { this.__fn = null; }
			
				return retValue;
			},
			
			/**
			  * array_search
			  * 
			  * Searches the array for a given value and returns the (highest) corresponding key if successful, -1 if not found.
			  *
			  * @param val The value to search for.
			  * @param arr The array to search in.
			  */
			array_search: function(val, arr){
				var i = arr.length;
			
				while (i--)
					if (arr[i] && arr[i] === val) break;
			
				return i;
			}
	  }
}();