
function xb () {
}

xb.Versions = new Array () ;
xb.Versions['base'] = '2005-11-22' ;

/*===========================================================================
 *
 * Event handling
 *
 */
xb.EventTarget = function (event) {
	if (!event) {
		event = window.event ;
	}

	if (event.srcElement) {
		return event.srcElement ;
	}
	else if (xb.Defined (event.currentTarget)) {
		return event.currentTarget ;
	}
}

xb.AddEventListener = function (element, eventType, listener) {
	var	EventType ;
	var	capture ;
	var	handler ;

	//
	// If 4th parameter is supplied, it is to select the event phase - capture or bubble.
	//
	if (arguments.length > 3) {
		capture = arguments[3] ? true : false ;
	} else {
		capture = false ;
	}

	//
	// Get a capitalized version of the event type.
	//
	EventType = eventType.substr (0, 1).toUpperCase () + eventType.substr (1) ;

	//
	// If supplied listener is an object with a handleEventType method, create a closure shim
	// to invoke it, otherwise just use the supplied listener directly.
	//
	if (typeof (listener['handle' + EventType]) == 'function') {
		handler = function (eventobj) {
			listener['handle' + EventType] (eventobj) ;
		} ;
	} else {
		handler = listener ;
	}

	//
	// DOM event model
	//
	if (element.addEventListener) {
		element.addEventListener (eventType, handler, capture) ;
	//
	// IE event model
	//
	} else if (element.attachEvent) {
		element.attachEvent ('on' + eventType, function () {return handler (window.event) ;}) ;
	//
	// Default event model
	//
	} else {
		//
		// If no handler is present, just add ours in
		//
		if (typeof (element['on' + eventType]) != 'function') {
			element['on' + eventType] = function (eventobj) {return handler (eventobj ? eventobj : window.event) ;}
		//
		// If a handler is present, chain it using a closure
		//
		} else {
			var	oldlistener ;

			oldlistener = element['on' + eventType] ;
			element['on' + eventType] = function (eventobj) {return oldlistener (eventobj) ;}
		}
	}
}

/*===========================================================================
 *
 * Miscellaneous
 *
 */
xb.Defined = function (x) {
	return !((typeof (x) == '') || (typeof (x) == 'undefined'))
}

xb.WalkTree = function (node, visitNode, leaveNode) {
	var	child ;

	if ((node.nodeType == 1) && (visitNode != null)) {
		visitNode (node) ;
	}

	child = node.firstChild ;
	while (child) {
		xb.WalkTree (child, visitNode, leaveNode) ;
		child = child.nextSibling ;
	}

	if ((node.nodeType == 1) && (leaveNode != null)) {
		leaveNode (node) ;
	}
}

/*===========================================================================
 *
 * Element retrieval
 *
 */

//
// ElementByID (id)
//
xb.ElementByID = function (id) {
	if (document.getElementById) {
		return document.getElementById (id) ;
	} else if (document.all) {
		return document.all[id] ;
	}

	return null ;
}

//
// ElementsByTagName (tagName [, rootNode])
//
xb.ElementsByTagName = function (tagName) {
	var	rootNode ;

	if (arguments.length > 1) {
		rootNode = arguments[1] ;
	}
	if (!rootNode) {
		rootNode = document ;
	}

	if (!tagName) {
		tagName = '*' ;
	}

	if (typeof tagName == 'string') {
		if (xb.IsIE4 || xb.IsIE5) {
			if (tagName == '*') {
				return rootNode.all ;
			} else {
				return rootNode.all.tags (tagName) ;
			}
		} else {
			if (rootNode.getElementsByTagName) {
				return rootNode.getElementsByTagName (tagName) ;
			}
		}
	} else if (((typeof tagName == 'function') || (typeof tagName == 'object')) && tagName.test) {
		var	candidates ;
		var	result ;
		var	i ;

		if (xb.IsIE4 || xb.IsIE5) {
			candidates = rootNode.all ;
		} else {
			candidates = rootNode.getElementsByTagName ('*') ;
		}

		result = new Array () ;
		for (i = 0 ; i != candidates.length ; i++) {
			if (tagName.test (candidates[i].tagName)) {
				result[result.length] = candidates[i] ;
			}
		}

		return result ;
	}


	return new Array () ;
}

//
// ElementsByClassName (className [, tagName [, rootNode]])
//
xb.ElementsByClassName = function (className) {
	var	rootNode ;
	var	tagName ;
	var	candidates ;
	var	result ;
	var	i ;

	if (arguments.length > 1) {
		tagName = arguments[1] ;
	}
	if (arguments.length > 2) {
		rootNode = arguments[2] ;
	}

	candidates = xb.ElementsByTagName (tagName, rootNode) ;
	result = new Array () ;
	for (i = 0 ; i != candidates.length ; i++) {
		if (typeof className == 'string') {
			if (candidates[i].className == className) {
				result[result.length] = candidates[i] ;
			}
		} else if (((typeof className == 'function') || (typeof className == 'object')) && className.test) {
			if (className.test (candidates[i].className)) {
				result[result.length] = candidates[i] ;
			}
		}
	}

	return result ;
}

//
// ElementsByName (name [, tagName [, rootNode]])
//
xb.ElementsByName = function (name) {
	var	rootNode ;
	var	tagName ;
	var	candidates ;
	var	result ;
	var	i ;

	if (arguments.length > 1) {
		tagName = arguments[1] ;
	}
	if (arguments.length > 2) {
		rootNode = arguments[2] ;
	}

	candidates = xb.ElementsByTagName (tagName, rootNode) ;
	result = new Array () ;
	for (i = 0 ; i != candidates.length ; i++) {
		if (typeof name == 'string') {
			if (candidates[i].name == name) {
				result[result.length] = candidates[i] ;
			}
		} else if ((typeof name == 'function') && name.test) {
			if (name.test (candidates[i].name)) {
				result[result.length] = candidates[i] ;
			}
		}
	}

	return result ;
}

/*===========================================================================
 *
 * Element dimensions
 *
 */
xb.Width = function (node) {
	var	width = null ;
	if (arguments.length > 1) {
		width = arguments[1] ;
	}

	if (xb.Defined (node.offsetWidth) && (typeof (node.style.width) == 'string')) {
		if (width !== null) {
			var	pl, pr, bl, br ;
			pl = pr = bl = br = 0 ;
			if (xb.Defined (document.defaultView) && document.defaultView && xb.Defined (document.defaultView.getComputedStyle)) {
				var	cs ;
				cs = document.defaultView.getComputedStyle (node, '') ;
				try {
					pl = parseInt (cs.getPropertyValue ('padding-left')) ;
					pr = parseInt (cs.getPropertyValue ('padding-left')) ;
					bl = parseInt (cs.getPropertyValue ('border-left-width')) ;
					br = parseInt (cs.getPropertyValue ('border-right-width')) ;
				} catch (err) {
					// Ignore errors, but ..
					//TODO: Work out why the hell we even get here
				}
			} else if (xb.Defined (node.currentStyle) && xb.Defined (document.compatMode)) {
				if (document.compatMode == 'CSS1Compat') {
					pl = parseInt (node.currentStyle.paddingLeft) ;
					pr = parseInt (node.currentStyle.paddingRight) ;
					bl = parseInt (node.currentStyle.borderLeftWidth) ;
					br = parseInt (node.currentStyle.borderRightWidth) ;
				}
			} else if (xb.Defined (node.style.width)) {
				node.style.width = width + 'px' ;
				pl = node.offsetWidth - width ;
			}
			//TODO: Work out why the following doesn't work properly.
			//node.style.width = width - (pl + pr + bl + br) + 'px' ;
			node.style.width = width + 'px' ;
		}
		return node.offsetWidth ;
	} else if (xb.Defined (node.style.pixelWidth)) {
		if (width !== null) {
			node.style.pixelWidth = width ;
		}
		return node.style.pixelWidth ;
	}
}

/*===========================================================================
 *
 * Browser sniffing
 *
 */
xb.IsOpera7			= navigator.userAgent.match (/opera(?:\/|\s)4/i) ;
xb.IsIE4OrBetter	= navigator.userAgent.match (/msie/i) && (parseInt (navigator.appVersion) >= 4) ;
xb.IsIE4			= navigator.userAgent.match (/msie\s+4/i) ;
xb.IsIE5			= navigator.userAgent.match (/msie\s+5/i) ;
xb.IsMac			= navigator.userAgent.match (/mac/i) ;
xb.IsNN4			= document.layers ? true : false ;

function xb_BrowserCheck () {
	var	useragent ;
}

/*===========================================================================
 *
 * Date formatting
 *
 */
xb.Days = new Array (
	'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
) ;

xb.Months = new Array (
	'January',	'February',	'March',
	'April',	'May',		'June',
	'July',		'August',	'September',
	'October',	'November',	'December'
) ;

xb.FormatDate = function (specifier) {
	var	d ;
	var	n ;
	var	result ;
	var	match ;
	var	pattern ;

	if (arguments.length > 1) {
		d = arguments[1] ;
	} else {
		d = this ;
	}
	result = '' ;
	pattern = /\\\\|\\?./g ;
	while ((match = pattern.exec (specifier)) != null) {
		switch (match[0]) {
			case 'a':
			case 'A': {
				n = (d.getHours () < 12) ? 'am' : 'pm' ;
				if (match[0] == 'A') {
					n = n.toUpperCase () ;
				}
				result += n ;
				break ;
			}
			case 'd': {
				n = d.getDate () ;
				result += ((n < 10) ? '0' : '') + n ;
				break ;
			}
			case 'D': {
				result += xb.Days[d.getDay ()].substring (0, 3) ;
				break ;
			}
			case 'F': {
				result += xb.Month[d.getDate ()] ;
				break ;
			}
			case 'g': {
				n = d.getHours () % 12 ;
				if (n == 0) {
					n = 12 ;
				}
				result += n ;
				break ;
			}
			case 'G': {
				result += d.getHours () ;
				break ;
			}
			case 'h': {
				n = d.getHours () % 12 ;
				if (n == 0) {
					n = 12 ;
				}
				result += ((n < 10) ? '0' : '') + n ;
				break ;
			}
			case 'H': {
				n = d.getHours () ;
				result += ((n < 10) ? '0' : '') + n ;
				break ;
			}
			case 'i': {
				n = d.getMinutes () ;
				result += ((n < 10) ? '0' : '') + n ;
				break ;
			}
			case 'j': {
				result += d.getDate () ;
				break ;
			}
			case 'l': {
				result += xb.Days[d.getDay ()] ;
				break ;
			}
			case 'm': {
				n = d.getMonth () ;
				result += ((n < 10) ? '0' : '') + n ;
				break ;
			}
			case 'M': {
				result += xb.Months[d.getMonth ()].substring (0, 3) ;
				break ;
			}
			case 'n': {
				result += d.getMonth () ;
				break ;
			}
			case 's': {
				n = d.getSeconds () ;
				result += ((n < 10) ? '0' : '') + n ;
				break ;
			}
			case 'S': {
				n = d.getDate () ;
				if (n > 20) {
					n %= 10 ;
				}
				switch (n) {
					case 1: {
						result += 'st' ;
						break ;
					}
					case 2: {
						result += 'nd' ;
						break ;
					}
					case 3: {
						result += 'rd' ;
						break ;
					}
					default: {
						result += 'th' ;
						break ;
					}
				}
				break ;
			}
			case 'w': {
				result += d.getDay () ;
				break ;
			}
			case 'Y': {
				result += d.getFullYear () ;
				break ;
			}
			case 'y': {
				n = d.getFullYear () % 100 ;
				result += ((n < 10) ? '0' : '') + n ;
				break ;
			}
			default: {
				if (match[0].charAt (0) == '\\') {
					result += match[0].charAt (1) ;
				} else {
					result += match[0] ;
				}
			}
		}
	}

	return result ;
}

/*===========================================================================
 *
 * Stylesheet manipulation
 *
 */

xb.CSSRules = function (styleSheet) {
	return xb.Defined (styleSheet.cssRules) ? styleSheet.cssRules : (xb.Defined (styleSheet.rules) ? styleSheet.rules : null) ;
}

xb.InsertRule = function (styleSheet, selector, declaration) {
	var	index = (arguments.length > 3) ? arguments[3] : xb.CSSRules (styleSheet).length ;

	if (styleSheet.insertRule) {
		styleSheet.insertRule (selector + '{' + declaration + '}', index) ;
	} else {
		styleSheet.addRule (selector, declaration, index) ;
	}
}

xb.FindRule = function (styleSheet, selector) {
	var	rules = xb.CSSRules (styleSheet) ;

	if (typeof selector == 'string') {
		for (var i = 0 ; i != rules.length ; i++) {
			if (rules[i].selectorText == selector) {
				return rules[i] ;
			}
		}
	} else if (((typeof selector == 'function') || (typeof selector == 'object')) && tagName.test) {
		for (var i = 0 ; i != rules.length ; i++) {
			if (selector.test (rules[i].selectorText)) {
				return rules[i] ;
			}
		}
	}

	return null ;
}

xb.EncodeURIComponent = function (text) {
	if (encodeURIComponent) {
		return encodeURIComponent (text) ;
	} else {
		return escape (text) ;
	}
}
