/* Utility object for executing JSON requests */
var JsonRequest = JsonRequest||{};
JsonRequest.throwOnFailure = function(request) {
	if( request.status!=200 ) {
		throw {
			message: "JsonRequest failed",
			status: request.status,
			message: request.statusMessage,
			body: request.responseText
		}
	}
}
JsonRequest.unbrace = function(val) {
	var match = (/^\/\*(.*)\*\/$/).exec(val);
	if(match) {
		return match[1];
	} else {
		return null;
	}
}
JsonRequest.createXmlHttp = function() {
	if( window.XMLHttpRequest ) {
		return new XMLHttpRequest();
	} else if( window.ActiveXObject!=null ) {
		return new ActiveXObject("Microsoft.XMLHTTP");
	} else {
		throw "No XMLHttpRequest available.";
	}
}
JsonRequest.sendGet = function(url,callback) {
	var request = JsonRequest.createXmlHttp();
	request.open("GET",url,callback!=null);
	if(callback) {
		request.onreadystatechange = function() {
			if( request.readyState==4 ) {
				JsonRequest.throwOnFailure(request);
				callback( eval("("+JsonRequest.unbrace(request.responseText)+")") );
			}
		}
	}
	request.send("");
	if(!callback) {
		JsonRequest.throwOnFailure(request);
		return eval("("+JsonRequest.unbrace(request.responseText)+")");      
	}
}

/* Adding and removing classes from an element */
var Element = Element||{};
Element.addClassName = function( element, className ) {
	if(!Element.hasClassName(element,className)) {
		element.className += (element.className?" ":"")+className;
	}
}
Element.removeClassName = function( element, className ) {
	if(element.className) {
	  element.className = element.className.replace(new RegExp("(^|\\s)"+className+"(\\s|$)")," ");
	  if(element.className=="") element.removeAttribute("class");
	}
}
Element.hasClassName = function( element, className ) {
	if(!element.className) return false;
 	return element.className.match(new RegExp("(^|\\s)"+className+"(\\s|$)"));
}

/* Event handling */
var Element = Element||{};
Element.addEventListener = function( element, event, callback, capture ) {
  if( element.addEventListener ) {
    element.addEventListener( event, callback, capture );
  } else if( element.attachEvent ) {
    element.attachEvent("on"+event, callback);
  } else {
    throw "Neither addEventListener() nor attachEvent() supported";
  }
  return callback;
}
Element.removeEventListener = function( element, event, callback ) {
  if( element.removeEventListener ) {
    element.removeEventListener( event, callback );
  } else if( element.detachEvent ) {
    element.detachEvent("on"+event, callback);
  } else {
    throw "Neither removeEventListener() nor detachEvent() supported";
  }
  return callback;
}
Element.createEventHandler = function( obj, method, tag ) {
  return function( event ) {
    return obj[method](event||window.event,tag);
  }
}

/* DOM shortcut functions */
function $(id) { return document.getElementById(id); }
function $T(tag,where) { return (where||document).getElementsByTagName(tag); }

/* Assisted DOM building */
function $Bt(text) {
	return document.createTextNode(text);
}
function $B(tag,properties) {
	var e = document.createElement(tag);
	var hasProperties = properties&&properties.toString()=="[object Object]";
	if( hasProperties ) {
		for( var i in properties ) {
			if( i.toLowerCase()=="class" ) {
				e.className = properties[i];
			} else if( i.toLowerCase()=="style" ) {
				e.setAttribute("style",properties[i]);
				e.style.cssText = properties[i];
			} else {
				e.setAttribute(i,properties[i]);
			}
		}
	}
	for( var i=hasProperties?2:1; i<arguments.length; i++ ) {
		if(typeof(arguments[i])=="string") {
			e.appendChild($Bt(arguments[i]));
		} else if(arguments[i]) {
			e.appendChild(arguments[i])
		}
	}
	return e;
}
function $Bf() {
	var e = document.createDocumentFragment();
	for( var i=0; i<arguments.length; i++ ) {
		if(typeof(arguments[i])=="string") {
			e.appendChild($Bt(arguments[i]));
		} else if(arguments[i]) {
			e.appendChild(arguments[i])
		}
	}
	return e;
}

/* Class inheritance */
var Class = Class||{};
Class.create = function() {
	switch( arguments.length ) {
		case 1:
			return Class.create( arguments[0].base||function(){}, arguments[0].ctor||{}, arguments[0].methods||{} );
		case 2:
			arguments[0].prototype = arguments[1];
			return arguments[0];
		case 3:
			Class.extend( arguments[0], arguments[1] );
			for( var i in arguments[2] ) {
				arguments[1].prototype[i] = arguments[2][i];
			}
			return arguments[1];
	}
}
Class.extend = function( baseClass, subClass ) {
	function inheritance() {}
	inheritance.prototype = baseClass.prototype;
	subClass.prototype = new inheritance();
	subClass.prototype.constructor = subClass;
	subClass._base = baseClass.prototype;
	return subClass;
}
