function _$( id ) {
	return document.getElementById( id );
}

Log = {
	events: [],
	clock: new Date,
	add: function ( stamp ) {
		this.events[ this.events.length ] = { time: this.clock.getTime(), stamp: stamp };
	},
	get: function () {
		var result = '';
		for( var i = 0, len = this.events.length; i < len; i ++ ) {
			result += "["+ this.events[ i ].time + "]: " + this.events[ i ].stamp + "\n";
		}
		alert( result );
		return result;
	}
}

function getElementsByClassName( classname, node ) {
	node = node || document.getElementsByTagName("body")[0];
	var a = [];
	var re = new RegExp('\\b' + classname + '\\b');
	var els = node.getElementsByTagName("*");
	for(var i=0,j=els.length; i<j; i++)
	if(re.test(els[i].className))a.push(els[i]);
	return a;
}

function addEventHandler( obj, event, handler ) {
	if ( obj.addEventListener ) {
		obj.addEventListener ( event, handler, false );
	} else if ( obj.attachEvent ) {
		obj.attachEvent ( 'on' + event , handler );
	} else {
		obj[ 'on' + event ] = handler;
	}
}


function Class() {
	construct = function() {
		if( this.initialize ) this.initialize.apply( this, arguments );
	};
	return construct;
}

Class.create = function ( parent, definition ) {
	construct = Class();
	if( typeof( definition ) != 'undefined'  ) {
		construct.extend( parent );
		construct.define( definition );
	} else {
		construct.define( parent );
	}
	return construct;
}

Function.prototype.applyTo = function ( obj, arg1, arg2, arg3, arg4, arg5, arg6 ) {
	if( !obj ) return;
	obj.initialize = null;
	var x;
	for(x in this.prototype) {
		obj[x] = this.prototype[x];
		if((x == 'onclick'
			|| x == 'onmouseover'
			|| x == 'onmouseout'
			|| x == 'onmouseup'
			|| x == 'onmousedown'
			|| x == 'onmousemove'
			|| x == 'oncontextmenu'
			) && obj[x]) {
			obj[x] = obj[x].bindEvent(obj);
		}
	}
	this.apply(obj, [arg1, arg2, arg3, arg4, arg5, arg6]);
	return obj;
}

Function.prototype.extend = function( parent ){
	if ( parent.constructor == Function ) {
		var obj = function() {}
		obj.prototype = parent.prototype;
		Log.add( 'extend' );
		this.prototype = new obj;
		this.prototype.constructor = this;
		this._parent = parent.prototype;
	}
	else {
		this.prototype = parent;
		this.prototype.constructor = this;
		this._parent = parent;
	}
	return this;
}

Function.prototype.define = function ( body ) {
	for( var func in body ) {
		this.prototype[ func ] = body[ func ];
	}
	return this;
}

Function.prototype.bind = function ( obj ) {
	var _self = this;
	return function () { return _self.apply( obj, arguments ) };
}

// TODO check for memory leaks cause by the new operator
Function.prototype.bindEvent = function ( obj ) {
	var _self = this;
	return function ( e ) { return _self.call( obj, new BrowserEvent( e ) ) };
}

BrowserEvent = Class.create({
	e: null,
	mousex: 0,
	mousey: 0,
	button: null,
	target: null,
	initialize: function ( e ) {
		this.e = e = e || window.event;
		this.mouseX = e.clientX || e.pageX;		// mouse X
		this.mouseY = e.clientY || e.pageY;		// mouse y
		this.button = e.which || e.button;		// mouse button
		this.target = e.target || e.srcElement;	// target element recieving the event
	}
});

var Glyph = Class.create( {
	drawn: false,
	_width: 0,
	_height: 0,
	// public properties
	xpos: 0,
	ypos: 0,
	show: function () { this.style.display = "block"; return this; },
	hide: function () { this.style.display = "none"; return this; },
	getWidth: function () { return this.clientWidth; },
	getHeight: function () { return this.clientHeight; },
	width: function () { return this._width; },
	height: function () { return this._height; },
	setWidth: function( w ) { w = w || 0; this._width = w; this.style.width = w + "px"; return this; },
	setHeight: function( h ) { h = h || 0; this._height = h; this.style.height = h + "px"; return this; },
	setClass: function( className ) { this.className = className; return this; },
	zIndex: function () { return this.style.zIndex; },
	setZIndex: function ( zIndex ) { this.style.zIndex = zIndex; return this; },
	redraw: function() { return this; },
	visible: function () { return this.style.display != "none"; },
	create: function () {},
	remove: function() { /*RemoveElementTree( this.canvas );*/ },
	moveTo: function (x, y) {
		x = x || 0;
		y = y || 0;
		this.xpos = x;
		this.ypos = y;
		this.style.left = x + "px";
		this.style.top = y + "px";
		return this;
	},
	getPosition: function ( root ) {
		root = root || null;
		var obj = this;
		var x = 0;
		var y = 0;
		if(obj.offsetParent) {
			do {
				x += obj.offsetLeft;
				y += obj.offsetTop;
			} while ( (obj = obj.offsetParent) && obj != root );
		}
		return { x: x, y: y };
	},
	center: function() {
		var screenWidth = document.documentElement.clientWidth;
		var screenHeight = document.documentElement.clientHeight;

		this.moveTo(
			Math.floor( ( screenWidth - this.getWidth() ) / 2 ),
			Math.floor( ( screenHeight - this.getHeight() ) / 2 )
		);
		return this;
	}
} );

Glyph.create = function( className, type, p1, p2, p3, p4, p5, p6, p7 ) {
	type = type || 'div';
//	alert( type );
	var element = document.createElement( type );
	return className.applyTo( element, p1, p2, p3, p4, p5, p6, p7 );
}


//(function() {
//  var element = this.Element;
//  this.Element = function(tagName, attributes) {
//    attributes = attributes || { };
//    tagName = tagName.toLowerCase();
//    var cache = Element.cache;
////    if (Prototype.Browser.IE && attributes.name) {
////      tagName = '<' + tagName + ' name="' + attributes.name + '">';
////      delete attributes.name;
////      return Element.writeAttribute(document.createElement(tagName), attributes);
////    }
//    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
//    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
//  };
//  Object.extend(this.Element, element || { });
//}).call(window);

Glyph.prototype.position = function ( root ) {
	root = root || null;
	var obj = this;
	var x = 0;
	var y = 0;
	if( obj.offsetParent ) {
		do {
			x += obj.offsetLeft;
			y += obj.offsetTop;
		} while (obj != root && (obj = obj.offsetParent));
	}
	return { 0: x, 1: y, x: x, y: y };
}

// Object.prototype.debug = function () {
// 	var s = ''
// 	for( a in this ) s+= a + ' ';
// 	alert( s );
// }

function json2raw( obj ) {
	if( obj instanceof String ) {
		return '"' + escape(obj) + '"';
	} else if( obj instanceof Array ) {
		var result = '[';
		for( var i = 0; i < obj.length; i ++ ) {
			result += json2raw( obj[i] ) + ','
		}
		result.length--;
		return result + ']';
	} else if( obj instanceof Object ) {
		var result = '{';
		for( var i in obj ) {
			result += i + ':' + json2raw( obj[i] ) + ',';
		}
		result.length--;
		return result + '}';
	} else {
		return obj;
	}
}

function raw2json( data ) {
	var obj;
	try {
		eval( 'obj = ' + data );
	} catch( e ) {
		obj = false;
	}
	return obj;
}

