//<script type="text/javascript">

//=============================================================================
function debug(txt, bClear)
{
	if ( !debug.div ) {
		debug.div = $('debug');
	}
	if ( bClear || (debug.div.innerHTML.length == 0) ) {
		debug.div.innerHTML = txt;
	} else {
		debug.div.innerHTML += '<br>' + txt;
	}
}
debug.div == null;

function debugObj(o, depth, tab)
{
	if ( !tab ) tab = '';
	var mytab = tab + '&nbsp;&nbsp;&nbsp;'
	debug(tab + '{');
	for ( var i in o )
	{
		if ( !Browser.ie && (typeof(i) == 'string') )
		{
			if ( i.substr(0,4) == 'DOM_' ) continue;
		}
		if ( typeof(o[i]) == 'function' ) continue;
		if (i == 'innerHTML') continue;
		if (i == 'outerHTML') continue;		
		if ( depth && typeof(o[i]) == 'object' ) {
			debug( mytab + i + ':');
			debugObj(o[i], depth - 1, mytab);
		} else {
			debug( mytab + i + ':' + o[i]);
		}
	}
	debug(tab + '}');
}

//=============================================================================
// return true if the string is an integer
String.prototype.isInteger = function()
{
	return (parseInt(this).toString() == this);
}

// return true if the string is numeric
String.prototype.isNumeric = function()
{
	// try these first, they will be faster than the script code below
	if ( parseInt(this).toString() == this ) return true;
	if ( parseFloat(this).toString() == this ) return true;

	// fallback test
	var bPoint = false;
	for ( var i = 0; i < this.length; i++ )
	{
		var ch = this.charAt(i);
		if ( (i == 0) && ((ch == '-') || (ch == '+')) ) continue;
		if ( ch == '.' )
		{
			if ( bPoint ) return false;
			bPoint = true;
			continue;
		}
		if ( ch < '0' ) return false;
		if ( ch > '9' ) return false;
	}
	return true;
}

//=============================================================================
// apply a functor on every element in an array
Array.prototype.apply = function(ftor)
{
	for ( var i in this )
	{
		if ( i.isInteger() ) ftor.f(this[i]);
	}
}

//=============================================================================
// convenience function to access an HTML element by ID
function $(id)
{
	return document.getElementById(id);
}

//=============================================================================
// Function extensions
Function.prototype.bindEvent = function(object) {
    var method = this;

    return function(evt) { method.call(object, evt ? evt : window.event); }
}

Function.prototype.bind = function(object) {
    var self = this;

    return function() { self.apply(object, arguments); }
}

Function.prototype.getName = function()
{
	var name = this.toString();
	var n1 = name.search("function");
	var n2 = name.search("\\(");
	return name.substr(n1+9, n2-(n1+9));
}

//=============================================================================
// JavaScript inheritance
// return the name of a function
// create a proxy class to wrap another
Function.prototype.wrap = function(subClass, functions)
{
	var name = subClass.getName();
	
	// wrap sub-class' prototype functions
	for ( var i in subClass.prototype )
	{
		// but not instanceOf and typeOf
		if ( i == 'instanceOf' ) continue;
		if ( i == 'typeOf' ) continue;
		this.prototype[i] = new Function("return " + name + ".prototype." + 
				i + ".apply(this." + name + ", arguments); " + 
				"this.onMethodCall(" + name + ".prototype." + i + ",arguments);"); 
	}
	
	// wrap any other user specified functions
	if ( functions )
	{
		for ( i = 0; i < functions.length; i++ )
		{
			var f = functions[i]
			this.prototype[f] = new Function("return " + name + ".prototype." + 
					f + ".apply(this." + name + ", arguments); " + 
				"this.onMethodCall(" + name + ".prototype." + f + ",arguments);"); 
		}
	}
}

// inherit from a base class
Function.prototype.inherit = function(baseClass)
{
	// inherit the prototype of the base class
	this.prototype = new baseClass();

	// reset the constructor property
	this.prototype.constructor = this;

	// determine base class' name
	var baseClassName = baseClass.getName();

	// reference to base class
	this.prototype[baseClassName] = baseClass.prototype;

	// code required by instanceOf()
	this.prototype.baseClass = baseClass;

	// reference to this class
	this.prototype.classType = this;
	this.prototype.typeName = this.getName();
}

// return true if instance is a specific class or inherited from that class
Object.prototype.instanceOf = function(classType)
{
	if ( !this.classType ) return this instanceof classType;
	
	var ctor = classType.prototype.constructor;
	var p = this.constructor;
	while ( p )
	{
		if ( p == ctor ) return true;
		p = p.prototype.baseClass;
	}
	return false;
}

// return the most derived class name of this instance.
Object.prototype.typeOf = function()
{
	if ( this.typeName ) return this.typeName;
	return typeof(this);
}

//=============================================================================
// Browser detection
var Browser = {
    mac: null,
    ie: null,
    macie: null,
    ns4: null,
    op5: null,
    op6: null,

    init: function() {
        var agt = navigator.userAgent.toLowerCase();

        this.mac = (agt.indexOf("mac") != -1);
        this.ie = (agt.indexOf("msie") != -1);
        this.macie = this.mac && this.ie;
        this.ns4 = document.layers;
        this.op5 = (navigator.userAgent.indexOf("Opera 5") != -1) || (navigator.userAgent.indexOf("Opera/5") != -1);
        this.op6 = (navigator.userAgent.indexOf("Opera 6") != -1) || (navigator.userAgent.indexOf("Opera/6") != -1);
    }
}

Browser.init();

//=============================================================================
// DHTML based functions

var dhtmlIE = {
	getElementLeft: function(elt) {
		return elt.offsetLeft;
	},

	getElementRight: function(elt) {
		return dhtmlIE.getElementLeft(elt) + dhtmlIE.getElementWidth(elt);
	},

	getElementTop: function(elt) {
		return elt.offsetTop;
	},

	getElementBottom: function(elt) {
		return dhtmlIE.getElementTop(elt) + dhtmlIE.getElementHeight(elt);
	},

	getElementHeight: function(elt) {
		return elt.offsetHeight;
	},

	getElementWidth: function(elt) {
		return elt.offsetWidth;
	},

	getScrollPos: function() {
		return {
			left:document.body.scrollLeft, 
			top:document.body.scrollTop
		};
	},

	getElementPosition: function (elt) {
		var offsetLeft = 0;
		var offsetTop = 0;
		while (elt) {
			offsetLeft += elt.offsetLeft + elt.clientLeft;
			offsetTop += elt.offsetTop + elt.clientTop;
			elt = elt.offsetParent;
		}
		if (navigator.userAgent.indexOf("Mac") != -1 &&
			typeof document.body.leftMargin != "undefined") {
			offsetLeft += document.body.leftMargin;
			offsetTop += document.body.topMargin;
		}
		return {left:offsetLeft, top:offsetTop};
	}
};

var dhtmlMoz = {
	getElementLeft: function(elt) {
		return (typeof elt.offsetLeft != 'undefined' ? elt.offsetLeft : elt.style.pixelLeft);
	},

	getElementRight: function(elt) {
		return dhtmlMoz.getElementLeft(elt) + dhtmlMoz.getElementWidth(elt);
	},

	getElementTop: function(elt) {
		return (typeof elt.offsetTop != 'undefined' ? elt.offsetTop : elt.style.pixelTop);
	},

	getElementBottom: function(elt) {
		return dhtmlMoz.getElementTop(elt) + dhtmlMoz.getElementHeight(elt);
	},

	getElementHeight: function(elt) {
		return (typeof elt.offsetHeight != 'undefined' ? elt.offsetHeight : elt.style.pixelHeight);
	},

	getElementWidth: function(elt) {
		return (typeof elt.offsetWidth != 'undefined' ? elt.offsetWidth : elt.style.pixelWidth);
	},
	
	getScrollPos: function() {
		return {
			left: (document.documentElement.scrollLeft ?
				document.documentElement.scrollLeft :
				document.body.scrollLeft),
			top: (document.documentElement.scrollTop ?
				document.documentElement.scrollTop :
				document.body.scrollTop)
		};
	},

	parseBorder: function(borderStyle) {
		if ( borderStyle == '' ) return 0;
		var n = parseInt(borderStyle);
		if ( isNaN(n) ) return 0;
		return n;
	},

	getElementPosition: function(elt) {
		var offsetLeft = 0;
		var offsetTop = 0;
		while (elt) {			
			switch ( elt.style.position ) {
			case 'absolute':
				offsetLeft += elt.offsetLeft;
				offsetTop += elt.offsetTop;
				break;
			default:
				if ( elt.offsetLeft > 0 ) offsetLeft += elt.offsetLeft;
				if ( elt.offsetTop > 0 ) offsetTop += elt.offsetTop;
				break;
			}
			
			offsetLeft += dhtmlMoz.parseBorder(elt.style.borderLeft);
			offsetTop += dhtmlMoz.parseBorder(elt.style.borderTop);
			elt = elt.offsetParent;
		}
		if (navigator.userAgent.indexOf("Mac") != -1 && 
			typeof document.body.leftMargin != "undefined") {
			offsetLeft += document.body.leftMargin;
			offsetTop += document.body.topMargin;
		}
		return {left:offsetLeft, top:offsetTop};
	}
};

var dhtml = Browser.ie ? dhtmlIE : dhtmlMoz;

//</script>