/* Array functions */
if( typeof Array.prototype.push == 'undefined' )
{
  Array.prototype.push = function( element ) { this[this.length] = element; }
}
if( typeof Array.prototype.pop == 'undefined' )
{
  Array.prototype.pop = function () 
  { 
    var last = this[ this.length - 1 ]; this.length--; return last; 
  }
}
IObject = function (){
	this.isIObject = true;
}
IObject.prototype.isIObject = true;
function copyPrototype(descendant, parent) { 
	for (var m in parent.prototype) { 
		try {
        	descendant[m] = parent.prototype[m]; 
		}catch (e){
		}
	}
}
function convertAll(obj){
	if (!obj) copyPrototype(document,IObject);
	if (!obj) obj = document.body;
	if (!obj.isIObject || obj.isIObject == "undefined") copyPrototype(obj,IObject);
	
	
	var nodes = obj.childNodes;
	for (var i = 0; i < nodes.length; i++){
		convertAll(nodes[i]);
	}
}
function $new (type){ //creates an element, with extensions
	var el = document.createElement(type)
	copyPrototype(el, IObject);
	return el;
}
function $make(el){
	if (!el) return;
	if (el.isIObject && el.isIObject != "undefined") return el;
	copyPrototype(el, IObject);
	return el;
}
function $all(el){
	//converts all objects to proper form. just a proxy for convertAll
	convertAll(el);
}
function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (typeof element == 'string')
    element = document.getElementById(element);
  return $make(element);
}
Array.prototype.foreach = function(f){
	var l = this.length;
	var values = Array();
	for (var i = 0; i < l; i++){
		values[i] = f(this[i]);
	}
	return values;
}
Array.prototype.makeNew = function(t){
	return this.foreach(function(v){return new t(v);}); 
}
Array.prototype.reverse = function(){
	var na = Array();
	var l = this.length;
	for (var i = 0; i < l; i++){
		na[l-i-1]= this[i];
	}
	for (var i = 0; i < l; i++){
		this[i] = na[i];
	}
	if (this.checkIndex) this.checkIndex();
}
Array.prototype.doesIndex = false;
Array.prototype.doIndex = function (){
	this.doesIndex = true;
	var l = this.length;
	for (var i = 0; i < l; i++){
		this[i].index = i;
	}
}
Array.prototype.checkIndex = function (debug){
	if (!this.doesIndex) return;
	var l = this.length;
	for (var i = 0; i < l; i++){
		this[i].index = i;
	}
}
Array.prototype.inArray = function(value){

	var l = this.length;
	for (var i = 0; i < l; i++){
		if (this[i] == value) return true;
	}
	return false;
}
Array.prototype.union = function(array){
	var l_m = array.length;
	var result = new Array();
	for (var i = 0; i < l; i++){
		result.push(this[i]);
	}
	for (var m = 0; m < l_m; m++){
		var l = this.length;
		var inarray = false;
		for (var i = 0; i < l; i++){
			if (this[i] == array[i]) {
				inarray = true;
				break;
			}
		}
		if (!inarray) result.push(array[m]);
	}
	return result;
}
Array.prototype.intersect = function(array){
	var result = new Array();
	var l_m = array.length;
	for (var m = 0; m < l_m; m++){
		var l = this.length;
		var inarray = false;
		for (var i = 0; i < l; i++){
			if (this[i] == array[m]) {
				inarray = true;
				break;
			}
		}
		if (inarray) result.push(array[m]);
	}
	return result;
}
Array.prototype.is_array = true;
Array.prototype.subtraction = function(array){
	if (!array.is_array) array = new Array(array);
	var result = new Array();
	var l = this.length;
	var l_m = array.length;
	for (var i = 0; i < l; i++){

		var inarray = false;
		for (var m = 0; m < l_m; m++){
			if (this[i] == array[m]) {
				inarray = true;
				break;
			}
		}
		if (!inarray) result.push(this[i]);
	}
	return result;
}
Array.prototype.insert= function (value,where){
	this.splice(where,0,value);
	this.checkIndex();
}
Array.prototype.remove = function (where){
	this.splice(where,1);
	this.checkIndex();
}
Array.prototype.move =function(from,to){
	var val = this[from];
	if (from < to) to = to - 1; //as from will remove the place we are putting it in.

	this.splice(from,1);
	this.splice(to,0,val);
	this.checkIndex();
}
Array.prototype.inClass = function (oclass,debug){

	var i = 0;
	var len = this.length;
	var vals = new Array();
	if (debug) alert(len);
	for (var i = 0; i < len; i++){
		if (!this[i] || !this[i].className || this[i].className == "undefined") continue;
		names = this[i].className.split(" ");
		if (names.inArray(oclass)){

			vals.push(this[i]);
		}
	}
	if (debug) alert("returning" + vals.length);
	return vals;
}
function arrayFrom(list){
	var l = list.length;
	var res = new Array();
	for (var i = 0; i < l; i++){
		res.push(list[i]);
	}
	return res;
}
Array.prototype.addEvent = function(name,fn){
	var l = this.length;
	for (var i = 0; i < l; i++){
		addEvent(this[i],name,fn);
	}
}
/* Object */
IObject.prototype.inited = false;
IObject.prototype.setAlpha = false;
IObject.prototype.setWidth = false;
IObject.prototype.setHeight = false;
IObject.prototype.setLeft = false;
IObject.prototype.setTop = false;
IObject.prototype.minX = -1000;
IObject.prototype.minY = -1000;
IObject.prototype.maxX = 100000;
IObject.prototype.maxY = 100000;

IObject.prototype.init = function (){
	if(!this.setLeft) this.objLeft = this.offsetLeft;
	if(!this.setTop) this.objTop = this.offsetTop;
	if (!this.setWidth) this.objWidth = this.offsetWidth;
	if (!this.setHeight) this.objHeight = this.offsetHeight;

	if (!this.setAlpha) this.objAlpha = 1;
	this.inited = true;
}
function allChildren(object,list){
	if (!list) list = new Array();
	var children = object.childNodes;
	var len = children.length;
	for (var i = 0; i < len; i ++){
		list.push(children[i]);
		allChildren(children[i],list);
	}
	return list;
}
IObject.prototype.allChildren = function (){
	return allChildren(this);
}
IObject.prototype.ofClass = function(otype, className){
	var objs;
	if (otype && otype != "") {
		objs = arrayFrom(this.getElementsByTagName(otype));
		return objs.inClass(className);
	}
	objs = allChildren(this);

	var res = objs.inClass(className);

	return res;
}
IObject.prototype.hasClass = function(className){
	if (!this.className || this.className == "undefined") return false;
	var names = this.className.split(" ");
	if (names.inArray(className)) return true;
}
IObject.prototype.addClass = function(className){
	var names;
	if (this.className && this.className != "undefined") {
		names = this.className.split(" ");
		if (names.inArray(className)) return true;
	}else{
		names = Array();
	}
	names.push(className);
	this.className=names.join(" ");
}
IObject.prototype.removeClass = function(className){
	if (!this.className || this.className == "undefined") return true;
	var names = this.className.split(" ");
	var l = names.length;
	for (var i = 0; i < l; i++){
		if (names[i] == className) {
			delete names[i];
			i--;
		}
	}
	this.className = names.join(" ");
}
IObject.prototype.getElementsByClassName = function (className){
	return this.ofClass("",className);
}
IObject.prototype.runEvent = function (val){
	if (!val) return;
	var deletea = new Array();

	var args = $A(arguments);
	args.shift();
	for (var i in val){
		if (!val[i]){
			deletea.push(i);
			continue;
		}else if (!val[i].object || val[i].disposed || val[i].object.disposed){
			deletea.push(i);
			continue;
		}else {
			var ret = val[i].apply(val[i],args);
			if (ret) return;
		}
	}
	for (var i = 0; i < deletea.length; i++){
		delete val[deletea[i]];
	}
}
IObject.prototype.deleteEvent = function(etype,val,owner){
	var i;
	if (!etype) return;
	var l = etype.length;
	for (i = 0; i < l; i++){
		if (etype[i] === val && etype[i].object === owner) {

			delete etype[i];
		}
	}
}
IObject.prototype.getOffsetLeft = function(){
	var offsetParent = this.offsetParent;
	var object = this;
	var val = object.offsetLeft;
	while (object = object.offsetParent){
		val += object.offsetLeft;
	}
	object = this;
	while (object = object.parentNode){
		object = $(object);
		if (object.getScrollLeft()) val -= object.getScrollLeft();
	}
	return val;
}
IObject.prototype.getOffsetTop = function(end){
	var offsetParent = this.offsetParent;
	var object = this;
	var val = object.offsetTop;
	while (object = object.offsetParent){
		val += object.offsetTop;
	}
	object = this;
	while (object = object.parentNode){
		object = $(object);
		if (object.getScrollTop()) val -= object.getScrollTop();
	}
	return val;
}
IObject.prototype.moveGlobal = function(end){
	if (this.isGlobal) return;
	this.formerOwner = this.offsetParent;
	this.isGlobal = true;
	this.moveLeft(this.getOffsetLeft());
	this.moveTop(this.getOffsetTop());
	document.body.appendChild(this);


}
IObject.prototype.moveLocal = function(){
	if (!this.isGlobal) return;
	this.isGlobal = false;
	this.moveLeft(this.getOffsetLeft() - this.formerOwner.getOffsetLeft() + this.formerOwner.scrollLeft);
	this.moveTop(this.getOffsetTop() - this.formerOwner.getOffsetTop() + this.formerOwner.scrollTop);
	this.formerOwner.appendChild(this);
	
}
IObject.prototype.getLeft = function(){
	if (!this.inited) this.init();
	return this.objLeft;
}
IObject.prototype.getTop = function(){
	if (!this.inited) this.init();
	return this.objTop;
}
IObject.prototype.getWidth = function(){
	if (!this.inited) this.init();
	return this.objWidth;
}
IObject.prototype.getHeight = function(){
	if (!this.inited) this.init();
	return this.objHeight;
}
IObject.prototype.getRight = function(){
	if (!this.inited) this.init();
	return this.objLeft + this.objWidth;
}
IObject.prototype.getBottom = function(){
	if (!this.inited) this.init();
	return this.objTop + this.objHeight;
}
IObject.prototype.getAlpha = function(){
	if (!this.inited) this.init();
	return this.objAlpha;
}
IObject.prototype.getScrollLeft = function(){
	return (this.scrollLeft && this.scrollLeft != "undefined") ? this.scrollLeft : false;
}
IObject.prototype.getScrollTop = function (){
	return (this.scrollTop && this.scrollTop != "undefined") ? this.scrollTop : false;
}
IObject.prototype.move = function(left,top,width,height){
	if (left !== false && left != "undefined") this.moveLeft(left);
	if (top !== false && top != "undefined") this.moveTop(top);
	if (width !== false && width != "undefined") this.moveWidth(width);
	if (height !== false && height != "undefined") this.moveHeight(height);
}
IObject.prototype.moveLeft = function (val){
try {
	if (val > this.maxX || val < this.minX) return;
	
	
	this.setLeft  =true;
	this.style.left = val + "px";
	this.objLeft = val;

	this.runEvent(this.onLeftChange);
}catch (e){
}
}
IObject.prototype.moveTop = function (val){
try {
	if (val > this.maxY || val < this.minY) return;
	this.setTop = true;
	this.style.top = val + "px";
	this.objTop = val;
	this.runEvent(this.onTopChange);
}catch (e){}
}
IObject.prototype.moveLeftEdge = function (val){
	this.setLeft = true;
	this.setWidth = true;
	var diff = this.getRight() - val;

	this.style.width = diff + "px";
	this.objWidth = diff;
	this.style.left = val + "px";
	this.objLeft = val;
	this.runEvent(this.onLeftChange);
}
IObject.prototype.moveTopEdge = function (val){
	this.setTop = true;
	this.setHeight = true;
	var diff = (this.getBottom() - val);
	this.style.height = diff + "px";
	this.objHeight = diff;
	this.style.top = val + "px";
	this.objTop = val;
	this.runEvent(this.onTopChange);
}
IObject.prototype.moveRight = function (val){
	this.setWidth = true;
	val = val - this.getLeft();
	if (val < 0) val =0;
	this.style.width = val + "px";
	this.objWidth = val;
	this.runEvent(this.onWidthChange);
	this.runEvent(this.onRightChange);
}
IObject.prototype.moveBottom = function (val){
	this.setHeight = true;
	val = val - this.getTop();
	if (val < 0) val = 0;
	this.style.height = val + "px";
	this.objHeight = val;
	this.runEvent(this.onBottomChange);
	this.runEvent(this.onHeightChange);
}
IObject.prototype.moveWidth = function (val){
	if (val < 0) val = 0;
	this.setWidth = true;
	this.style.width = val + "px";
	this.objWidth = val;
	this.runEvent(this.onWidthChange);
	this.runEvent(this.onRightChange);
}
IObject.prototype.moveHeight = function (val){
	if (val < 0) val = 0;
	this.setHeight = true;
	this.style.height = val + "px";
	this.objHeight = val;
	this.runEvent(this.onBottomChange);
	this.runEvent(this.onHeightChange);
}
function getStyle(oElm, strCssRule){
	var strValue = "";
	if(document.defaultView && document.defaultView.getComputedStyle){
		strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
	}
	else if(oElm.currentStyle){
		strCssRule = strCssRule.replace(/-(w)/g, function (strMatch, p1){
			return p1.toUpperCase();
		});
		strValue = oElm.currentStyle[strCssRule];
	}
	return strValue;
}
IObject.prototype.moveAlpha = function(val){
	this.setAlpha = true;
	val = Math.round(val * 100) / 100;
	if (val < 0.09 && this.style.visibility){
		this.style.visibility = "hidden";
	}
	else {
		this.style.visibility = "visible";
	}
	this.style.opacity = val;
	this.style["-moz-opacity"] = val;
	this.style.filter = 'alpha(opacity=' + (val * 100) + ')';
	this.objAlpha = val;
	this.runEvent(this.onAlphaChange);
}

IObject.prototype.moveScrollLeft = function(val){
	try { this.scrollLeft = val; }catch (e) { }
	if (this.onScrollChange) this.runEvent(this.onScrollChange);
}
IObject.prototype.moveScrollTop = function(val){
	try {  this.scrollTop = val;}catch (e) { }
	if (this.onScrollChange) this.runEvent(this.onScrollChange);
}
IObject.prototype.addLeftEvent = function (fn){
	if (!this.onLeftChange) this.onLeftChange = new Array();
	this.onLeftChange.push(fn);
}
IObject.prototype.addTopEvent = function (fn){
	if (!this.onTopChange) this.onTopChange = new Array();
	this.onTopChange.push(fn);
}
IObject.prototype.addWidthEvent = function (fn){
	if (!this.onWidthChange) this.onWidthChange = new Array();
	this.onWidthChange.push(fn);
}
IObject.prototype.addHeightEvent = function (fn){
	if (!this.onHeightChange) this.onHeightChange = new Array();
	this.onHeightChange.push(fn);
}
IObject.prototype.addRightEvent = function (fn){
	if (!this.onRightChange) this.onRightChange = new Array();
	this.onRightChange.push(fn);
}
IObject.prototype.addBottomEvent = function (fn){
	if (!this.onBottomChange) this.onBottomChange = new Array();
	this.onBottomChange.push(fn);
}
IObject.prototype.addAlphaEvent = function (fn){
	if (!this.onAlphaChange) this.onAlphaChange = new Array();
	this.onAlphaChange.push(fn);
}
IObject.prototype.addScrollEvent = function (fn){
	if (!this.onScrollChange) this.onScrollChange = new Array();
	this.onScrollChange.push(fn);
}

IObject.prototype.moveRel = function (from, sval, offset,prop){

	sval(from() + offset);
}
IObject.prototype.makeRelative = function (object, side, side2){
	var offset;
	var proportion = 1;
	if (arguments.length > 3) proportion = arguments[3];
	var fn;
	if (side == "right") fn = object.getRight.bindEventListener(object);
	if (side == "left") fn = object.getLeft.bindEventListener(object);
	if (side == "top") fn = object.getTop.bindEventListener(object);
	if (side == "bottom") fn = object.getBottom.bindEventListener(object);
	var fn2;
	if (side2 == "right") fn2 = this.getRight.bindEventListener(this);
	if (side2 == "left") fn2 = this.getLeft.bindEventListener(this);
	if (side2 == "top") fn2 = this.getTop.bindEventListener(this);
	if (side2 == "bottom") fn2 =this.getBottom.bindEventListener(this);
	
	var fn3;
	if (side2 == "right") fn3 = this.moveRight.bind(this);
	if (side2 == "left") fn3 = this.moveLeft.bind(this);
	if (side2 == "top") fn3 = this.moveTop.bind(this);
	if (side2 == "bottom") fn3 =this.moveBottom.bind(this);
	

	if (!fn || !fn2) return;
	var from = fn;
	var to = fn2;
	offset = to() - from();
	if (side == "right") object.addRightEvent(this.moveRel.bind(this,fn,fn3,offset,proportion));
	if (side == "bottom") object.addBottomEvent(this.moveRel.bind(this,fn,fn3,offset,proportion));
	if (side == "left") object.addLeftEvent(this.moveRel.bind(this,fn,fn3,offset,proportion));
	if (side == "top") object.addTopEvent(this.moveRel.bind(this,fn,fn3,offset,proportion));
}
IObject.prototype.isAbsolute = false;
IObject.prototype.makeAbsolute = function(){
	if (this.isAbsolute) return;
	var l = this.offsetLeft;
	var t = this.offsetTop;
	var w = this.offsetWidth;
	var h = this.offsetHeight;
	this.style.height = h + "px";
	this.style.left = l + "px";
	this.style.top = t + "px";
	this.style.width = w + "px";
	this.setTop = true;
	this.setHeight = true;
	this.setWidth = true;
	this.setLeft = true;
	this.style.position = "absolute";
	this.isAbsolute = true;
}

IObject.prototype.disposeChildren = function(){
	var n = this.childNodes;
	if (!n) return;
	var l = n.length;
	for (var i = 0; i < l; i++){
		var c = n[0];
		if (c.dispose) c.dispose();
		this.removeChild(c);
		if (c) delete c;
	}
}
/* Events */
function addEvent( obj, type, fn ) {
	if (obj.addEventListener) {
		obj.addEventListener( type, fn, false );
		EventCache.add(obj, type, fn);
	}
	else if (obj.attachEvent) {
		obj["e"+type+fn] = fn;
		obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
		obj.attachEvent( "on"+type, obj[type+fn] );
		EventCache.add(obj, type, fn);
	}
	else {
		obj["on"+type] = obj["e"+type+fn];
	}
}
var EventCache = function(){
	var listEvents = [];
	return {
		listEvents : listEvents,
		add : function(node, sEventName, fHandler){
			listEvents.push(arguments);
		},
		flush : function(){
			var i, item;
			for(i = listEvents.length - 1; i >= 0; i = i - 1){
				item = listEvents[i];
				if(item[0].removeEventListener){
					item[0].removeEventListener(item[1], item[2], item[3]);
				};
				if(item[1].substring(0, 2) != "on"){
					item[1] = "on" + item[1];
				};
				if(item[0].detachEvent){
					item[0].detachEvent(item[1], item[2]);
				};
				item[0][item[1]] = null;
			};
		}
	};
}();
var $A = Array.from = function(iterable) {
  if (!iterable) return [];

    var results = [];
    for (var i = 0; i < iterable.length; i++)
      results.push(iterable[i]);
    return results;

}
/* okay, done */
function cancelEvent(event){
	if (event && event.stopPropagation) {
        event.stopPropagation();
    }
    if (window.event && window.event.cancelBubble ) {
        window.event.cancelBubble = true;
    }
    
    if (event && event.preventDefault) {
        event.preventDefault();
    }
    if (window.event) {
        window.event.returnValue = false;
    }

    return false;
}

addEvent(window,'unload',EventCache.flush);

/* bind */
Function.prototype.bindEventListener = function(object){
	var __method;
	__method = this;
	var args = $A(arguments);
	if (!args) args = new Array();
	args.shift();
	if (args.length > 0){
		var val =  function (event){ 
			var arglist = new Array((event || window.event || true)).concat(args);
			var more = $A(arguments);
			if (more.length > 1) {
			more.shift();arglist = arglist.concat(more);
			}
			return  __method.apply(object, arglist);
			
		};
		val.object = object;
		return val;
	}else{
		var val =  function (event){ 
			var val = (event || window.event || true);
			var arglist = new Array();
			arglist.push(val);
			var more = $A(arguments);
			if (more.length > 1) {
			more.shift();arglist = arglist.concat(more);
			}
			return __method.apply(object, arglist);
		};
		val.object = object;
		return val;
	}
}
Function.prototype.bind = function(object){
	var __method;
	__method = this;
	var args = $A(arguments);
	args.shift();
	var val = function (event){ 
		this.object = object;
		__method.object = object;
		return __method.apply(object, args.concat($A(arguments)));
	};
	val.object = object;
	return val;
}
/* Browser */
var clientPC = navigator.userAgent;
browser = new IObject();
browser.isWebkit = /WebKit\/\d+/.test(navigator.appVersion);

if (browser.isWebkit) browser.webkitVersion = navigator.appVersion.match(/WebKit\/(\d+)/)[1];
browser.isOpera = (clientPC.indexOf("Opera") != -1);
browser.isGecko = ((clientPC.indexOf('gecko') != -1) && (clientPC.indexOf('spoofer') == -1));

function windowWidth(){
	var scrollWidth;
	var scrollHeight;
	scrollWidth = document.body.scrollWidth;
	scrollHeight = document.body.scrollHeight;
	if (self.innerWidth)
	{
		frameWidth = self.innerWidth;
		frameHeight = self.innerHeight;

	}
	else if (document.documentElement && document.documentElement.clientWidth)
	{
		frameWidth = document.documentElement.clientWidth;
		frameHeight = document.documentElement.clientHeight;

	}
	else if (document.body)
	{
		frameWidth = document.body.clientWidth;
		frameHeight = document.body.clientHeight;

	}
	if (scrollWidth > frameWidth) frameHeight -= 16;
	if (scrollHeight > frameHeight) frameWidth -= 16;
	return frameWidth;
}
function windowHeight(){
	var scrollWidth;
	if (self.innerWidth)
	{
		frameWidth = self.innerWidth;
		frameHeight = self.innerHeight;
		scrollWidth = self.scrollWidth;
	}
	else if (document.documentElement && document.documentElement.clientWidth)
	{
		frameWidth = document.documentElement.clientWidth;
		frameHeight = document.documentElement.clientHeight;
		scrollWidth = document.documentElement.scrollWidth;
	}
	else if (document.body)
	{
		frameWidth = document.body.clientWidth;
		frameHeight = document.body.clientHeight;
		scrollWidth = document.body.scrollWidth;
	}
	if (scrollWidth > frameWidth) frameHeight -= 16;
	return frameHeight;
}
browser.getScrollTop = function (){
	var val = (document.body.scrollTop ? document.body.scrollTop : self.pageYOffset);
	val = (val ? val : document.documentElement.scrollTop);
	return val;
}
browser.getScrollLeft = function(){
	var val = (document.body.scrollLeft ? document.body.scrollLeft : self.pageXOffset);
	val = (val ? val : document.documentElement.scrollLeft);
	return val;
}
browser.onResize = function(event){
	this.moveWidth();
	this.moveHeight();
}

browser.init = function (){
	this.inited = true;
	this.objLeft = 0;
	this.objHeight = windowHeight();
	this.objWidth = windowWidth();
	this.objTop = 0;
	this.alpha = 0;
 
}
browser.moveWidth = function (){
	this.objWidth = windowWidth();
	this.runEvent(this.onWidthChange);
	this.runEvent(this.onRightChange);
}
browser.moveHeight = function (){
	this.objHeight = windowHeight();
	this.runEvent(this.onHeightChange);
	this.runEvent(this.onBottomChange);
}
browser.getHeight = function (){
	return windowHeight();
}
browser.getWidth = function (){
	return windowWidth();
}
browser.getBottom = function (){
	return browser.getHeight();
}
browser.getRight = function (){
	return browser.getWidth();
}
addEvent(window,"resize",browser.onResize.bindEventListener(browser));

/* Ajax */
function get_req() 
{
    // branch for native XMLHttpRequest object
    if (window.XMLHttpRequest) {
        req = new XMLHttpRequest();
        return req;
    // branch for IE/Windows ActiveX version
    } else if (window.ActiveXObject) {
        req = new ActiveXObject("Microsoft.XMLHTTP");
        if (req) {
        	return req;
        }
    }
}
function can_ajax(){
	var req = get_req();
	if (req) return true; else return false;
}
function request(url,method){
	this.url = url;
	this.method = method;
	this.data = "";
}
request.prototype.loadForm = function(form){
	form = $(form);
	var inputs = form.getElementsByTagName("input");
	var selects = form.getElementsByTagName("select");
	var textareas = form.getElementsByTagName("textarea");
	var i, str;
	str = "";
	for (i = 0; i < inputs.length; i++){
		str += "&" + inputs[i].name + "=" + encodeURL(inputs[i].value);
	}
	for (i = 0; i < selects.length; i++){
		str += "&" + selects[i].name + "=" + encodeURL(selects[i].value);
	}
	for (i = 0; i < textareas.length; i++){
		str += "&" + textareas[i].name + "=" + encodeURL(textareas[i].value);
	}
	if (str.length > 0) str=str.substr(1);
	this.data = str;
	this.url=form.action;
	this.method = "POST";
}
request.prototype.send =function(){
	this.req = get_req();
	this.req.open(this.method, this.url,true);
	this.processBound = this.process.bind(this);
	this.req.onreadystatechange = this.processBound;
	if (this.method == "POST"){
		this.req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		this.req.setRequestHeader("Content-length", this.data.length);
		this.req.setRequestHeader("Connection", "close");
	}
	this.req.send(this.data);
}
request.prototype.error = alert;
request.prototype.process = function(){
	if (this.req.readyState == 4){
		if (this.req.status == 200){

			this.content = this.req.responseText;
			this.xml = this.req.responseXML;
			this.complete = true;
			if (this.onFinish) this.onFinish();
			this.processBound.disposed = true;
			delete this.processBound;
			delete this.req;
		}else{
			request.error("Error getting content");
		}
	}
}
function encodeURL(text) {
	var eurl = text;
	eurl = eurl.replace(/ /g,"+");
	eurl = escape(eurl);
	eurl = eurl.replace(/\//g,"%2F");
	eurl = eurl.replace(/\?/g,"%3F");
	eurl = eurl.replace(/=/g,"%3D");
	eurl = eurl.replace(/&/g,"%26");
	eurl = eurl.replace(/@/g,"%40");

	return eurl;
}
function decodeURL(text){
	durl = unescape(text);
	return durl;
}
function getNodeText(node){
	if (node.childNodes.length > 1){
		return node.childNodes[1].nodeValue;
	}else{
		if (node.firstChild) return node.firstChild.nodeValue;
	}
}


var historyManager = {
	"stack": false,
	"stackPosition": 0,
	"startHistoryPosition": 0,
	"current": "",
	"init": function (url,callback){

		/* Initialize variables */
		this.callback = callback;
		window.historyManager = this;
		var newPage = false; //will we need to load a new page?
		
		/* Clean up URL */
		if (url) if (url != "undefined") if (url.length>0) if (url.substring(0,1) != "/") url = "/" + url;		//Because "/" is what we use to know it is a url following the #
		if (!url || url == "undefined") url = "/";

		/* Figure out the current hash */
				//Make sure to support #url:, as it is the old way of doing it.

		this.current = window.location.hash;
		if (!this.current || this.curreent == "undefined") this.current = "#" + url;
		if (this.current == "" || this.current == "#/" || this.current == "#") this.current = window.location.pathname + window.location.search;

		if ((this.current != "#" + url && this.current.substr(0,2) == "#/") || (this.current != "#url:" + url && this.current.substr(0,5) == "#url:")){
			this.current = this.current.substring(1);
			if (this.current.substring(0,4) == "url:") this.current = this.current.substring(4);
			newPage = true;
		}
		
		/* Set up the stack */
		if (browser.isWebkit || (document.all)){ //we use our own history stack for older webkit and all IE.
			this.stack = new Array();
			this.stack.push(this.current);
			this.startHistoryPosition = history.length;
			this.stackPosition = 1;
			if (browser.isWebkit) this.hashCheck = this.hashCheckOldWebkit;
			else this.hashCheck = function() { };
		}else{
			this.hashCheck = this.hashCheckGeneral;
			window.location.hash = "#" + this.current;
		}
		

		
		/* Set up an iFrame for IE */
		if (document.all){
			var ifr = document.createElement("iframe");
			ifr["name"] = "history_frame";
			ifr["id"] = "history_frame";
			ifr.style.filter = "alpha(opacity=0)";
			ifr.style.opacity = 0;
			document.body.insertBefore(ifr, document.body.firstChild);
			this.iframe = ifr;
			if (this.current.substr(this.current.length - 1) != "/") this.current += "/";
			this.iframe.src = (this.current == "/" ? "" : this.current) + "::show-type=global,show=history,hashno=" + (this.stackPosition) + "";

		}		
		if (newPage)
			this.callback(this.current,true);
		

		
		window.setInterval(this.hashCheck.bind(this),100);

	},
	"hashCheckOldWebkit": function(){
		if (history.length - this.startHistoryPosition != this.stackPosition - 1){
			this.stackPosition = history.length - this.startHistoryPosition + 1;

			this.callback(this.getHash(),true);
			this.current = window.location.hash;
		}
	},
	"hashCheckGeneral": function(){
	
		if (window.location.hash != "#" + this.current){
			this.current = (window.location.hash.substring(1));
			this.callback (this.current);
		}
	},
	"setURL": function (url){
		/* Clean the URL */
		if (url.substring(0,1) != "/") url = "/" + url;		//Because "/" is what we use to know it is a url following the #		
		
		/* First, make sure we have an anchor, as some browsers need one to exist */
		if (document.getElementsByName(this.current).length == 0){
			var a =$new("a");
			a.name = this.current;
			a.innerHTML = "";
			a.style.position = "absolute";
			a.style.top = "0px";
			a.style.left = "0px";
			document.body.appendChild(a);
		}
		
		/* Don't add the same page twice. */
		if (url == this.current) return;

		/* Trim the stack */
		if (this.stack) this.stack.length = this.stackPosition;
		
		/* Certain Safari versions have difficulty recognizing hash changes, so a form must be used. */
		if (/WebKit\/\d+/.test(navigator.appVersion) && navigator.appVersion.match(/WebKit\/(\d+)/)[1] < 420) {
			if (!this.form){
				this.form = $new("form");
				this.form.method = "get";
			}
			this.form.action = "#" + url;
			this.form.submit();
		}else{
			window.location.hash = "#" + url;
		}
		
		if (this.stack){
			this.stack.push(url);
			this.stackPosition = this.stack.length;
		}
		this.current = url;
		
		if (this.iframe) {
			if (this.current.substr(this.current.length - 1) != "/") this.current += "/";
			this.iframe.src = this.current + "::show=history,hashno=" + (this.stackPosition) + "";
		}
	},
	"setHashNumber":function (number){
		if (number == this.stack.length) return;
		this.stackPosition = number;
		window.location.hash = "#" + this.getHash();
		this.callback(this.getHash(),true);
	},
	"getHash":function(){
		if (this.stack){
			this.current = this.stack[this.stackPosition - 1];
			return this.current;
		}else{
			return this.current;
		}
	}
};

/* It should be noted that this is not thread-safe. Still, threading is practically impossible in javascript anyway. */
measure = {
	"init": function (){
		/* Find out if we have our measure box yet */
		if (!this.positionBox){
			this.positionBox = document.createElement("div");
			this.positionBox.style.position = "absolute";
			this.positionBox.style.left = "-5000px";
			this.positionBox.style.top = "-5000px";
			document.body.appendChild(this.positionBox);
		}
	},
	"setClass": function (className){
		this.init();
		this.positionBox.className = className;
	},
	"measureText": function (text, width, height){
		this.init();

		this.positionBox.style.width = width;
		this.positionBox.style.height = height;
		this.positionBox.innerHTML = text;
		return {"width": this.positionBox.clientWidth, "height": this.positionBox.clientHeight};
	},
	"measure": function (width, height){
		return this.measureText("", width, height);
	},
	"measureClass": function(className){
		this.setClass(className);
		return this.measureText("","","");
	},
	"measureNestedClass": function (className, inside, width, height, type){
		this.setClass(inside);
		this.positionBox.innerHTML = "";
		
		var nest = $new((type ? type : "div"));
		nest.className = className;
		
		var width = (width ? width : 500);
		var height = (height ? height : 500);
		
		this.positionBox.style.width = width + "px";
		this.positionBox.style.height = height + "px";
		
		this.positionBox.appendChild(nest);

		return {
			"leftPadding": nest.offsetLeft,
			"topPadding": nest.offsetTop,
			"rightPadding": width - nest.offsetWidth - nest.offsetLeft,
			"bottomPadding": height - nest.offsetHeight - nest.offsetTop
		};
	}
};

var preloader = {
	"classes": new Array(),
	"hasLoaded": false,
	"preloadImage": function (images, callback){
		var preloader = new imagePreloader(images, callback);
	},
	"loadClass": function (className){
		var div = document.createElement("div");
		div.className = className;
		div.style.left = "-5000px";
		div.style.top = "-5000px";
		div.style.width = "1000px";
		div.style.height = "1000px";
		div.style.position = "absolute";
		
		this.preloadContainer.appendChild(div);
	},
	"preloadClass": function (className){
		if (!this.hasLoaded) {
			this.classes.push(className);
		}else{
			this.loadClass(className);
		}
	},
	"load": function (){
		if (!this.preloadContainer) {
			this.preloadContainer = document.createElement("div");
			this.preloadContainer.id = "_preloadContainer";
			this.preloadContainer.setAttribute("id", "_preloadContainer");
			document.body.appendChild(this.preloadContainer);
		}
		for (var i = 0; i < this.classes.length; i++){
			this.loadClass(this.classes[i]);
		}
		this.classes = new Array();
	}
};
addEvent(window, "load", preloader.load.bind(preloader));
function imagePreloader (preloadList,callback){
	this.callback = callback;
	this.preloadProcessed = 0;
	
	if (preloadList.length == 0) {
		callback();
		return;
	}
	
	this.preloadList = new Array();
	for (var i = 0; i < preloadList.length; i++){
		var image = new Image();
		image.onload = this.preloadWait.bind (this);
		image.onabort = this.preloadWait.bind (this);
		image.onerror = this.preloadWait.bind (this);
		image.application = this;
		image.hasLoaded = false;
		this.preloadList.push(image);
	}
	for (var i = 0; i < preloadList.length; i++){
		image = this.preloadList[i];
		image.src = preloadList[i].src;
	}
}
imagePreloader.prototype.preloadWait = function(){
	if (this.disposed) return;
	this.preloadProcessed ++;
	if (this.preloadProcessed >= this.preloadList.length){
		this.dispose();
		this.callback();
	}
}
imagePreloader.prototype.dispose = function (){

	if (this.disposed) return;
	this.preloadList = null;
	delete this.preloadList;
	this.disposed = true;
}


timer = {
	"current_id": 0,
	"timer_count": 0,
	"timers": new Object(),
	"unused": new Array(),
	"addTimer": function (timeFunction) {
		if (!this.interval) this.init();
		var id;

			this.current_id ++;
			id = this.current_id;


		this.timers[this.current_id] = (timeFunction);
		this.timers.length++;

		return this.current_id;
	},
	"clearTimer": function (id){
		if (id <= 0) return;
		try {
			if (this.timers[id]){
				this.timers.length--;
				delete this.timers[id];
				this.unused.push(id);
			}
		}catch (e){
		}
		
	},
	"stop":function(){
		window.clearInterval(this.interval);
		this.interval = false;
		this.timers = new Object();
	}
	,"time": function (){
		var len = this.timers.length;
		var i = 0;
		var deletea = Array();
		var toti = 0;
		for (var name in this.timers){
			if (name == "length") continue;
			toti++;
			var ttimer = this.timers[name];
			if (!ttimer || typeof ttimer == "undefined" || ttimer.finished){
					deletea.push(name);
			}else{
				var res;
				res =ttimer();
				i++;
				if (!res){
					deletea.push (name);
				}
			}

		}

		for (var ii = 0; ii < deletea.length; ii++){
			this.timers.length --;
			this.unused.push(deletea[ii]);			
			delete this.timers[deletea[ii]];

		}
		if (i == 0) this.stop();
	},
	"init": function() {
		this.timers = new Object();
		this.timers.length = 0;
		this.interval = window.setInterval(timer.time.bindEventListener(timer),10);
	}
};




function animator (length, frames){
	var start = 0;
	var end = 1;
	if (arguments.length > 2) start=arguments[2];
	if (arguments.length > 3) end=arguments[3];
	if (start == end){
		start = 0;
		end = 1;
	}
	this.startv = start;
	this.end = end;
	if (length < 0) length = 0;
	length = length * 1000.0;
	if (frames <= 0) frames = 1;
	var time = (length * 1.0) / (frames * 1.0);

	this.length = length;
	this.time = Math.floor(time);

	this.frames = frames;
	
	
	this.increment = (this.end - this.startv) / frames;
	this.increment = Math.round(this.increment * 100) / 100;
	this.iterators = new Array();
	var it = animator.linearIterator;
	var ni = new animator.iterator(it);
	ni.name = "default";
	this.iterators.push(ni);
}
animator.prototype.setDefaultIterator = function(iteratorfn){
	this.iterators[0].fn = iteratorfn;
}
animator.prototype.addIterator = function(iteratorfn,name){
	var ni = new animator.iterator(iteratorfn);
	ni.name = name;
	this.iterators.push(ni);
}
animator.prototype.addMove = function(move,iname){
	var index = 0;
	if (iname){
		var l = this.iterators.length;
		for (var i =0; i < l; i++){
			if (this.iterators[i].name == iname) {
				index = i;
				break;
			}
		}
	}
	this.iterators[index].moves.push(move);
}
animator.prototype.addMoves = function(move,iname){
	var index = 0;
	if (iname){
		var l = this.iterators.length;
		for (var i =0; i < l; i++){
			if (this.iterators[i].name == iname) {
				index = i;
				break;
			}
		}
	}
	var l = move.length;
	for (var i = 0; i < l; i++){
		this.iterators[index].moves.push(move[i]);
	}

}
animator.prototype.clearMoves = function(iname){
	var index = 0;
	if (iname){
		var l = this.iterators.length;
		for (var i =0; i < l; i++){
			if (this.iterators[i].name == iname) {
				index = i;
				break;
			}
		}
	}
	if (index > 0) this.iterators[index].moves = new Array();
	else {
		var l = this.iterators.length;
		for (var i =0; i < l; i++){
			this.iterators[i].moves = new Array();
		}
	}
}
animator.prototype.stop = function(){
	this.finished = true;
	if(this.currentInterval) timer.clearTimer(this.currentInterval);
	this.currentInterval = -1;
}
animator.prototype.start = function (){

	if (arguments.length > 0){
		
		window.setTimeout(this.start.bind(this), arguments[0] * 1000);
		return;
	}
	if(this.currentInterval) timer.clearTimer(this.currentInterval);
	this.currentInterval = -1;
	this.value = this.startv;
	
	//this.currentInterval = window.setInterval(this.animate.bindEventListener(this),this.time);
	var anim = this.animate.bindEventListener(this);
	anim.message = "Animator: " + this.messages;
	this.currentInterval = timer.addTimer(anim);
}
animator.prototype.iterate = function(value){
	var il = this.iterators.length;
	for (var i = 0; i < il; i++){
		var it = this.iterators[i];
		it.iterate(value);
	}
}
animator.prototype.animate = function (){

	this.value += this.increment;
	if ((this.increment > 0 && this.value >= this.end) || (this.increment < 0 && this.value <= this.end)) {
		var il = this.iterators.length;
		for (var i = 0; i < il; i++){
			var it = this.iterators[i];
			it.iterateEnd();
		}
		timer.clearTimer(this.currentInterval);
		this.currentInterval = -1;
		
		if (this.onfinish) setTimeout(this.onfinish, 10); //let things settle after our modifications
		this.finished = true;
		return false;
	}
	this.iterate(this.value);
	return true;
}
animator.iterator = function(fn){
	this.fn = fn;
	this.moves = new Array();
}
animator.iterator.prototype.iterate = function (val){
	val = this.fn(val);
	var l = this.moves.length;
	for (var i = 0; i < l; i++){
		this.moves[i].run(val);
	}
}
animator.iterator.prototype.iterateEnd = function (){

	var l = this.moves.length;
	for (var i = 0; i < l; i++){
		this.moves[i].finish();
	}
}
animator.bounceIterator = function (strength, val){
	if (!val) {
	val = strength;
	strength = .1;
	}
	val = -(val * (1 + strength * 2)) + 1 + strength; //1.5 - -.5
	val = Math.abs(val);
	return (1 + strength) - val;
}
animator.getBounceIterator = function(strength){
	return animator.bounceIterator.bind(this, strength);
}
animator.linearIterator = function (val){
	return val;
}
animator.sineIterator = function (val){

	return Math.sin(val * (Math.PI / 2));
}
animator.cosineIterator = function(val){


	return 1-Math.cos(val * (Math.PI / 2));
}
animator.nullCommand = function(){
}
animator.move = function (object, component, target){
	this.object = object;


	this.target = target;
	this.command = animator.nullCommand;

	if (component == "alpha" || component == "opacity") {
		this.command = object.moveAlpha.bind(object);
		this.start = object.getAlpha();
	}
	if (component == "width") {
		this.command = object.moveWidth.bind(object);
		this.start = object.getWidth();
	}
	if (component == "height") {
		this.command = object.moveHeight.bind(object);
		this.start = object.getHeight();
	}
	if (component == "left") {
		object.makeAbsolute();
		this.command = object.moveLeft.bind(object);
		this.start = object.getLeft();
	}
	if (component == "scrollLeft") {
		this.command = object.moveScrollLeft.bind(object);
		this.start = object.getScrollLeft();
	}
	if (component == "scrollTop") {
		this.command = object.moveScrollTop.bind(object);
		this.start = object.getScrollTop();
	}
	if (component == "top") {
		object.makeAbsolute();
		this.command = object.moveTop.bind(object);
		this.start = object.getTop();
	}
	if (component == "lefte") {
		object.makeAbsolute();
		this.command = object.moveLeftEdge.bind(object);
		this.start = object.getLeft();
	}
	if (component == "tope") {
		object.makeAbsolute();
		this.command = object.moveTopEdge.bind(object);
		this.start = object.getTop();
	}
	if (component == "right") {
		object.makeAbsolute();
		this.command = object.moveRight.bind(object);
		this.start = object.getRight();
	}
	if (component == "bottom") {
		object.makeAbsolute();
		this.command = object.moveBottom.bind(object);
		this.start = object.getBottom();
	}
	this.diff = target - this.start;

}
animator.move.prototype.run = function(val){
	this.command(this.start + (this.diff * val));
}
animator.move.prototype.finish = function(){
	this.command(this.target);
}
animator.groupMoves = function (objects, component, target){
	var l = objects.length;
	var moves = new Array();
	for (var i = 0; i < l; i++){
		moves.push(new animator.move(objects[i],component,target));
	}
	return moves;
}
IObject.prototype.animate = function(args){
	if (!args.time) args.time = .5;
	if (!args.frames) args.frames = 10;
	if (this.animator) this.animator.stop();
	if (this.animator) this.animator = null;
	
	if (!currentAnimator) var anim = new animator(args.time, args.frames);
	else anim = currentAnimator; 
	if (args.onFinish) anim.onfinish = args.onFinish;
	var moves = new Array();
	anim.messages = args.toString();
	if (args.left != "undefined" && args.left != this.objLeft && args.left) moves.push( new animator.move(this,"left",args.left));
	if (args.top != "undefined" && args.top != this.objTop && args.top) moves.push( new animator.move(this,"top",args.top));
	if (args.width != "undefined" && args.width != this.objWidth && args.width) moves.push( new animator.move(this,"width",args.width));
	if (args.height != "undefined" && args.height != this.objHeight && args.height) moves.push( new animator.move(this,"height",args.height));
	if (args.scrollLeft != "undefined" && args.scrollLeft != this.scrollLeft && args.scrollLeft) moves.push( new animator.move(this,"scrollLeft",args.scrollLeft));
	if (args.scrollTop != "undefined" && args.scrollTop != this.scrollTop && args.scrollTop) moves.push( new animator.move(this,"scrollTop",args.scrollTop));
	if (args.alpha != "undefined" && args.alpha != this.objAlpha) moves.push( new animator.move(this,"alpha",args.alpha));
	

	anim.addMoves(moves);
	if (args.iterator) anim.setDefaultIterator(args.iterator);
	if (!currentAnimator) anim.start();
	this.animator = anim;
}

IEffect = {
	"hide":function (obj){
		obj.oldHeight = obj.getHeight();
		obj.animate({"alpha":0,"height":1});
	},
	"show":function (obj){
		obj.animate({"alpha":1.0,"height":obj.oldHeight});
	},
	"effects": function (args){
		var moves = new Array();
		var hides = args.hides;
		if (!hides) hides = new Array();
		var shows = args.shows;
		if (!shows) shows = new Array();
		for (var i = 0; i < hides.length; i++){
			if (hides[i].isHidden) continue;
			hides[i].style.overflow = "hidden";
			hides[i].oldHeight = hides[i].getHeight();
			moves.push(new animator.move(hides[i],"height",1));
			hides[i].oldWidth = hides[i].getWidth();
			//moves.push(new animator.move(hides[i],"width",1));
			moves.push(new animator.move(hides[i],"alpha",0.0));
			
			hides[i].isHidden = true;
			hides[i].isShown = false;
		}
		
		for (var i = 0; i < shows.length; i++){
			if (shows[i].isShown) continue;
			moves.push(new animator.move(shows[i],"height",shows[i].scrollHeight));
			//moves.push(new animator.move(shows[i],"width",shows[i].oldWidth));
			moves.push(new animator.move(shows[i],"alpha",1.0));
			shows[i].isHidden = false;
			shows[i].isShown = true;
		}
		
		var anim = new animator(.5, 7);
		if (args.onfinish) anim.onfinish = args.onfinish;
		anim.addMoves(moves);
		anim.start();
	}
}


var animatorPools = new Array();
var currentAnimator = null;
animationPool.prototype = animator.prototype;
function animationPool(frames){
	if (!frames) frames = 10;
	if (window.event && window.event.shiftKey) frames *= 10;
	animator.call(this, 0, frames);
	animatorPools.push(currentAnimator);
	currentAnimator = this;
}

function freeAnimationPool(){
	currentAnimator = animatorPools.pop();
}

//example: object.animate ({"top":15,"left":25,"width":150,"height":120,"alpha":280,"time":.5,"frames":15});

//var drag = {"drag":"drag","current":null,"handlers":{"all": new Array()}};
var drag = new IObject();
drag.current = null;
drag.handlers = {"all": new Array()};
drag.mouseMove = function (event){
	if (this.current == null) return;

	if (this.real_drag_start == false && Math.abs(event.screenX - this.startx) < 5 && Math.abs(this.starty - event.screenY) < 5) return;
	if (!this.real_drag_start){
		if(this.current.beforeDrag) this.current.beforeDrag();
		this.real_drag_start = true;
		this.objstartx = this.current.getLeft();
		this.objstarty = this.current.getTop();

	}
//	alert (this.current + " " + event.screenX + ", " + event.screenY + " from " + this.startx + ", " + this.starty + "; starts at " + this.objstartx + ", " + this.objstarty);
	
	this.current.moveLeft(event.screenX - this.startx + this.objstartx,true);
	this.current.moveTop(event.screenY - this.starty + this.objstarty,true);
	
	
	if (this.current.onDrag) this.current.onDrag();
	if (this.current.dragType){
		if (this.handlers[this.current.dragType]){

			this.runEvent(this.handlers[this.current.dragType],this.current);
		}
	}
	cancelEvent(event);
	return false;
}
drag.addDragHandler = function (handler,type){
	if (!this.handlers[type]) this.handlers[type] = new Array();
	var l =this.handlers[type].length;
	var list = new Array();
	for (var i in this.handlers[type]){
		if (this.handlers[type][i].disposed){
			list.push(i);
		}else if (this.handlers[type][i].object){
			if (this.handlers[type][i].object.disposed){
				list.push(i);
			}
		}
	}
	for (var i = 0; i < list.length; i++){
		delete this.handlers[type][i];
	}
	var func = handler.onDrag.bind(handler);
	this.handlers[type].push(func);
	return func;
}
drag.mouseUp = function(event){
	var oldIgnore = this.ignore;
	this.ignore = false;
	if (this.oldIgnore) return;
	
	var was = this.current;
	if (this.current == null) was = false;
	if (!this.real_drag_start) was = false;
	this.current = null;
	if (was == false) return;
	cancelEvent(event);
	if(was.afterDrag) was.afterDrag();
	return false;
}
drag.mouseDown = function (event, object){
	if (this.ignore){
		return;
	}
	this.real_drag_start = false;
	this.current = object;
	if (object.dragObject) this.current = object.dragObject;
	this.startx = event.screenX;
	this.starty = event.screenY;

	cancelEvent(event);
	return false;
}
IObject.prototype.allowDrag = function(dragObject){
	if (dragObject) this.dragObject = dragObject;
	if (this.doesAllowDrag) return;	
	this.doesAllowDrag = true;
	addEvent(this,"mousedown",drag.mouseDown.bindEventListener(drag,this));
}

addEvent(document, "mousemove", drag.mouseMove.bindEventListener(drag));
addEvent(document, "mouseup", drag.mouseUp.bindEventListener(drag));

_uacct = "UA-189309-6";
var moduleTypes = {};
var overlay;

var debug = false;
if (!window.XMLHttpRequest) debug = true;

//constants
var transparent_image = "/templates/aiskander/images/transparent.gif";
var transparent_alpha = .1;

function aModule(element){

	this.zIndex = 0;
	this.element = $(element);
	this.element.module = this;
	this.element.moveAlpha(transparent_alpha);
	addEvent(this.element, "mouseover", this.mouseOver.bindEventListener(this));
	addEvent(this.element, "mouseout", this.mouseOut.bindEventListener(this));
	
	this.handlers = {};
	
	if (this.element.hasClass("fade-instant")) this.fadeInstant = true;
	if (this.element.hasClass("no-fade")) this.noFade = true;
	for (var i in moduleTypes){

		if (this.element.hasClass(i)) {
			this.handlers[i] = new moduleTypes[i](this.element);
			this.handlers[i].module = this;
		}
	}	
}
aModule.prototype.mouseOver = function(event){
	if (this.noFade) return;
	if (this.fadeInstant) {
		this.element.moveAlpha(1.0);
		return;
	}
	this.element.animate({"alpha":1.0, "frames":7});
}
aModule.prototype.mouseOut = function(event){
	if (this.noFade) return;
	if (this.fadeInstant) {
		this.element.moveAlpha(transparent_alpha);
		return;
	}
	this.element.animate({"alpha":transparent_alpha,"frames":7});
}


/* Image Module */
goToImage = function (path){
	window.location = path.replace("/:thumb:100", "");
}
aImageModule = function(element){

	addEvent(document.body, "mousemove", this.hideAll.bindEventListener(this));
	this.element = element;
	this.element.dashboardModule = this;
	var imgs = this.element.getElementsByTagName("img");
	this.images = new Array();
	var l = imgs.length;
	for (var i = 0; i < l; i++){
		if (imgs[i].isControl) continue;
		var image = new aModuleImage(imgs[i]);
		image.module = this;
		this.images.push(image);
		image = null;
	}
}
aImageModule.prototype.registerImage = function (img){
	if (img.isControl) return;
	if (img.isModuleImage) return;
	var image = new aModuleImage (img);
	image.module = this;
	img.isModuleImage = true;
	this.images.push(image);
	image = null;
}
aImageModule.prototype.unregisterImage = function(i){
	this.images.remove(i);
}
aImageModule.prototype.hideAll = function(event){
	if (app.lastMouseOver){
		var current = new Date();
		var res = current.getTime() - app.lastMouseOver.getTime();
		if (res < 500) return;
	}
	if (this.current) this.current.mouseOut();
}
moduleTypes["dashboard-images-module"] = aImageModule;

var allowHover = true;
/* Image Module Image */
function aModuleImage(element){

	this.element = $(element);
	addEvent(this.element, "mouseover", this.mouseOver.bindEventListener(this));
	addEvent(this.element, "mousemove", this.mouseOver.bindEventListener(this));

	this.clone = false;	

}
aModuleImage.prototype.mouseOver = function(event){
	app.lastMouseOver = new Date();
	if (this.element.disabled) return;
	if (this.isMouseOver) return;
	this.isMouseOver = true;
	if (!allowHover) return;



	if (this.clone && this.clone.src != this.element.src){
		document.body.removeChild(this.clone);
		this.clone = null;
	}
	if (!this.clone){
		this.clone = $(this.element.cloneNode(true));
		
		this.clone.moveAlpha(0);
		this.clone.style.position = "absolute";
		addEvent(this.clone, "mousemove", function(event){cancelEvent(event); return false;});
		addEvent(this.clone, "mouseout", this.mouseOut.bindEventListener(this));
		document.body.appendChild(this.clone);
		
		if (this.element.onclick){
			this.clone.onclick = this.element.onclick;
		}
	}
	if (document.all){
		if  (!this.clone.isTransparent){
			this.clone.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.clone.src + "',sizingMethod='scale')";
			this.clone.src=transparent_image;
			this.clone.isTransparent = true;
		}else{

			this.clone.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.clone.o_src + "',sizingMethod='scale')";
		}
	}

	if (this.module.current && this.module.current != this) this.module.current.mouseOut();
	this.module.current = this;
	
	this.offsetLeft = this.element.getOffsetLeft() + browser.getScrollLeft();
	this.offsetTop = this.element.getOffsetTop() + browser.getScrollTop();
	this.clone.style.display = "block";

	this.clone.move(
		this.offsetLeft,
		this.offsetTop,
		this.element.getWidth(),
		this.element.getHeight()
	);
	this.clone.style.zIndex = 100 + this.module.zIndex;
	this.clone.moveAlpha(1.0);
	
	/* Calculate new size */
	var expandWidth = 100, expandHeight = 100;
	if (this.element.expandSize){
		expandWidth = this.element.expandSize.width;
		expandHeight = this.element.expandSize.height;
	}
	
	var iter = animator.getBounceIterator(.4);
	var framecount = 7;
	if (event.shiftKey) framecount *= 10;
	this.clone.animate(
		{
			"left": this.clone.getLeft() - (expandWidth - this.element.getWidth()) / 2,
			"top": this.clone.getTop() - (expandHeight - this.element.getHeight()) / 2,
			"width": expandWidth,
			"height": expandHeight,
			"frames": framecount,
			"iterator": iter
		}
	);
	var expr = /\/\:file.*/;
	if (!this.clone.onclick) this.clone.onclick = goToImage.bind(this,this.element.src.replace(expr, ""));
	this.showTip();
	if (event) cancelEvent(event);

	return false;
}
aModuleImage.prototype.showTip = function(){
	if (!this.clone) return;
	tipManager.showTip(this.clone, false, 150, 10);
}
aModuleImage.prototype.mouseOut = function(event){
	this.isMouseOver = false;
	if (this.module.current == this) this.module.current = null;
	tipManager.hideTip(this.clone);
	this.onFinishOut();
	if (event) cancelEvent(event);
	return false;
}
aModuleImage.prototype.onFinishOut = function (){
	this.clone.style.visibility = "hidden";
	this.clone.style.display = "none";
}
/* Gallery: */

function gallery (element){
	
	//we have not initialized
	this.loaded = false;
	
	//get a proper version of the element
	element = $(element);
	
	
	//double-check: is there an actual image? If not, we can forget this.
	var exists = element.ofClass("div","gallery-image");
	if (exists.length == 0){
		return;
	}
	
	//get DOM objects we need
	this.element = element;
	this.imageElement = element.ofClass("img","gallery-image")[0];
	this.title = $(element.ofClass("div","gallery-image")[0].getElementsByTagName("h2")[0]);
	this.description = $(element.ofClass("div","description")[0]);
	
	//try to get edit/delete buttons. These may not exist
	try {
		this.fullSizeElement = document.getElementById("gallery-fullsize-picture");
		this.editElement = document.getElementById("gallery-edit-picture");
		this.deleteElement = document.getElementById("gallery-delete-picture");
	} catch (e) {}	
	
	//store the current window title
	this.galleryTitle = document.title;

	//get the url for the gallery itself
	this.galleryPath = document.getElementById("gallery_path").value;
	path = this.galleryPath;
	
	//and set imageDownloadManager's getPath function to get paths from the right place.
	imageDownloadManager.getPath = function (number) {
		return path + "/::show-type=xml,page=" + (number + 1) + ",all=true";
	};
	
	// If we are not at the gallery's root, redirect to the gallery.
	var newpath = window.location.pathname.replace(this.galleryPath, "");
	if (newpath[0] == "/") newpath= newpath.substr(1);
	//a path should always be YYYY/mm/dd/name
	if (newpath.split("/").length != 3) newpath = "";
	if (window.location.pathname != this.galleryPath) window.location= (this.galleryPath + "#/" + newpath);
	
	//reset goToImage to use a special function
	var nt = this.navigateTo.bind(this);
	goToImage = function(path) { nt(path, false); };
	
	//initialize the history manager.
	var ieSrc = this.imageElement.src;
	if (ieSrc.indexOf("://") > -1)
		ieSrc = ieSrc.substring(path.substring(8).indexOf("/") + 8);
	historyManager.init(ieSrc, this.navigateTo.bind(this));
	
	//initialize the gallery
	this.imageGallery = new imageGallery($("image-gallery"));

	//initialize the gallery image
	this.galleryImage = new galleryImage(this.imageElement, element, $("image-gallery"));
	this.imageGallery.onResize = this.bottomResize.bind(this);
	this.galleryImage.onResize = this.imageResize.bind(this);
	// add event handlers
	browser.addWidthEvent(this.browserResize.bindEventListener(this));
	browser.addHeightEvent(this.browserResize.bindEventListener(this));
	
	// set up an update for the image gallery's layout
	window.setTimeout(this.imageGallery.widthChange.bindEventListener(this.imageGallery), 10);
	
	// get rid of the HTML pagers, if theey exist.
	var pagers = element.getElementsByClassName("pager");
	for (var i = 0; i < pagers.length; i++){
		pagers[i].parentNode.removeChild(pagers[i]);
	}
	
	/* Now for some heavy-duty rearrangement of items */
	this.container = $new("div");
	this.container.className = "gallery-text-container";
	this.element.appendChild(this.container);

	var theader = this.element.ofClass("div", "gallery-image")[0].getElementsByTagName("h2")[0];
	var description = $(this.element.ofClass("div", "gallery-image")[0]).ofClass("div","description")[0];
		var controls = this.element.ofClass("div", "controls");
	if (controls.length > 0){
		this.controls = $(controls[0]);
		this.container.appendChild(this.controls);
	}
	this.container.appendChild(theader);

	this.container.appendChild(description);
	this.container.style.position = "absolute";
	this.container.style.overflow = "auto";
	this.container.init();
	this.container.moveLeft(0);
	this.container.moveTop(0);
	this.container.moveWidth(300 - app.padding);
	this.container.moveHeight(browser.getHeight() - $("image-gallery").getHeight() - app.padding * 4);
	
	// we have loaded
	this.loaded = true;

	app.relayoutFunctions.push(this.browserResize.bind(this));
	// if there was an image pending load, load it.
	if (this.loadImage) this.navigateTo(this.loadImage, true);
}
gallery.prototype.bottomResize = function (){
	this.container.moveHeight(browser.getHeight() - $("image-gallery").getHeight() - app.padding * 4);
	this.galleryImage.resize();
}
gallery.prototype.imageResize = function (){
	this.container.moveWidth(browser.getWidth() - 200 - app.padding * 5 - this.imageElement.offsetWidth);
	if (this.controls){

	}
}
gallery.prototype.fillOut = function (ajax){
	var item = ajax.xml.getElementsByTagName("item")[0];
	var title = getNodeText(item.getElementsByTagName("title")[0]);
	var text = getNodeText(item.getElementsByTagName("text")[0]);
	this.title.innerHTML = title;
	document.title = this.galleryTitle + " : " + title;
	this.description.innerHTML = text;
	this.galleryImage.resize();
}
gallery.prototype.navigateTo = function(path, callback){

	if (!this.loaded) {
		var img = $(document).ofClass("img","gallery-image")[0];
		img.style.width = "100px";
		img.style.height = "100px";
		img.src = "/templates/aiskander/images/transparent.gif";
		this.loadImage = path;
		return;
	}
	this.title.innerHTML = "Loading...";
	this.description.innerHTML = "";
	var path = path;
	if (path.indexOf("://") > -1) {
		path = path.substring(path.substring(8).indexOf("/") + 8);
	} else {
		//we are probably missing the gallery path.
		if (path.substr(0,1) == "/") path = path.substr(1);
		path = this.galleryPath + path;
	}
	if (path.indexOf("/:thumb") > -1) path = path.substr(0, path.indexOf("/:thumb"));


	path = path.replace(this.galleryPath, "");
	var reqpath = this.galleryPath + path + "/::show-type=xml;content,show=content";
	var ajax = new request(reqpath,"GET");
	ajax.onFinish = this.fillOut.bind(this,ajax);
	ajax.send();
	
	if (this.deleteElement) this.deleteElement.href = this.galleryPath + path + "/::show=delete-check";
	if (this.editElement) this.editElement.href = this.galleryPath + path + "/::edit=true,show=gallery-image";
	if (this.fullSizeElement) this.fullSizeElement.href = this.galleryPath + path + "/:file";
	if (!callback) historyManager.setURL(path);

	if (path.substr(path.length - 1) != "/") path += "/";

	this.galleryImage.resize();
	this.galleryImage.setImage(path + ":file:1024");
}
gallery.prototype.browserResize = function(){
	this.galleryImage.resize();
}
function galleryImage (element,container, bottom){
	this.bottom = bottom;
	this.loaded = false;
	this.img = $(element);
	this.container = container;

	// load image rep
	if (this.img.imgRep){
		this.imgRep = this.img.imgRep;
	}else{
		this.imgRep = getExtImage(this.img.src, this.callBack.bind(this));
	}
}
galleryImage.prototype.setImage = function(path){
	app.showLoading();
	this.imgRep = getExtImage(path, this.callBack.bind(this, path));
}
galleryImage.prototype.callBack = function(path){
	if (!this.imgRep || !this.imgRep.originalWidth) return;
	app.hideLoading();
	if (path) this.img.src = path;
	this.img.style.position="absolute";
	this.img.moveLeft(0);
	this.img.moveTop(0);
	if (!this.loaded) this.imgRep.originalWidth = this.img.width;
	if (!this.loaded) this.imgRep.originalHeight = this.img.height;
	this.img.moveWidth(this.imgRep.originalWidth);
	this.img.moveHeight(this.imgRep.originalHeight);
	this.loaded = true;

	this.resize();
}
galleryImage.prototype.resize = function(){

	if (!this.imgRep.finished) return;
	if (this.loaded){

		var ow = this.imgRep.originalWidth;
		var oh = this.imgRep.originalHeight;
		var offset =  this.bottom.offsetHeight - app.padding;
		var height = (browser.getHeight()) - (this.container.getOffsetTop() + app.padding * 3 + offset);
		var availHeight = height;
		var width = Math.floor(ow * height / oh);
		if (width > browser.getWidth() - (200 + app.padding * 5 + 300)){
			ow = width;
			width = browser.getWidth() - (200 + app.padding * 5 + 300);
			height = height * width / ow;
		}
		if (width > this.imgRep.originalWidth || height > this.imgRep.originalHeight){
			width = this.imgRep.originalWidth;
			height = this.imgRep.originalHeight;
		}

		this.img.moveWidth(width);
		this.img.moveLeft((browser.getWidth() - this.container.getOffsetLeft()) -app.padding - width);
		this.img.moveTop(availHeight / 2 - height / 2);
		// this.img.moveLeft((browser.getWidth() - 360) / 2 - (width / 2));
		this.img.moveHeight(height);
		if (this.onResize) this.onResize();
	}
}

/* ExtImage stuff */
extImage.prototype.error = function (message) {alert ("ExtImage error: " + message);};
extImageManager = {"imgReps": Array(), "maxImages":20 };
function sortExtImages(a,b){
	return b.lastUsed - a.lastUsed;
}
function getExtImage(src,callback){
	if (extImageManager.imgReps["src"]){
		extImageManager.imgReps["src"].lastUsed = new Date();
		window.setTimeout(callback, 10);
		return extImageManager.imgReps["src"];
	}
	var extI = new extImage(src, callback);
	extI.lastUsed = new Date();
	extImageManager.imgReps[src] = extI;
	if (extImageManager.imgReps.length > extImageManager.maxImages) {
		extImageManager.imgReps.sort(sortExtImages);
		extImageManager.imgReps.pop();
	}
	return extI;
}
function extImage (src,callback){
	
	this.callback = callback;
	this.src = src;
	this.img = new Image();
	this.img.onload = this.onLoad.bindEventListener(this);
	this.img.onabort = this.onError.bindEventListener(this);
	this.img.onerror = this.onAbort.bindEventListener(this);
	this.finished = false;
	this.error = true; //success
	this.img.src=src;
}
extImage.prototype.finish = function(){
	this.finished = true;
	this.error = false;
	if (this.callback) window.setTimeout(this.callback.bind(this,this.error),10);
}
extImage.prototype.onLoad = function (){
	this.originalWidth = this.img.width;
	this.originalHeight = this.img.height;

	this.finish();
}
extImage.prototype.onAbort = function(){
	this.error = false;
	this.finish();
}
extImage.prototype.onError = function (){
	this.finish();
}




imageDownloadManager = {
	"path": ".",
	"blocks": {},
	"total": 0,
	"taski": 0,
	"tasks": {},
	"blockSize": 25,
	"getPath": function (blockNumber){
		return "nowhere";
	},
	"gotBlock": function (task, number, request){
		var xml = request.xml;
		var items = xml.getElementsByTagName("item");
		var ilen = items.length;
		var result = {"isBlock":true};
		for (var i = 0; i < ilen; i++){
			var item = items[i];
			var container = document.createElement("div");
			var title = getNodeText(item.getElementsByTagName("title")[0]);
			/* We must find the picture inside description. Why? Because otherwise we may
			 * get the proper path for the picture, but we will not know whether the picture actually exists.
			 */
			var description = item.getElementsByTagName("description")[0];
			var link = item.getElementsByTagName("link")[0];
			container.innerHTML = getNodeText(description);
			var children = container.getElementsByTagName("img");
			var path = "";
			var link = "";
			if (children.length > 0){
				path = children[0].src.substring(children[0].src.substring(8).indexOf("/") + 8);
				//getExtImage(path.replace("/:thumb","") + "/:file");
				link = link.substring(link.substring(8).indexOf("/") + 8);
			}else{
				path = "";
			}
			
			var text = item.getElementsByTagName("text");
			if (text.length > 0){
				text = text[0];
				text = getNodeText(text);
			}
			result[i] = {"name": title, "path": path, "link": link, "text": text};
		}
		this.blocks[number] = result;
		task.complete();
	},
	"getBlock": function (number, task){
		var ajax = new request(this.getPath(number),"GET");
		ajax.onFinish = this.gotBlock.bind(this, task, number, ajax);
		ajax.send();
	},
	"getImages": function (start, length, callback){
		var t = new task (null, true);
		t.addCallback(callback);
		var start_block = Math.floor(start / this.blockSize);
		var end_block = Math.ceil((start + length) / this.blockSize);
		var length_block = end_block - start_block;
		for (var bnum = start_block; bnum < start_block + length_block; bnum++) {
			if (!this.blocks[bnum] || !this.blocks[bnum].isBlock){
			var blockg = new task(this.getBlock.bind(this, bnum), false);
			t.addTask(blockg);
			blockg.start();
			}
		}
		t.tasksAdded();
	},
	"getImage": function (offset){
		var block_number = Math.floor(offset / this.blockSize);
		var block = this.blocks[block_number];
		var num = offset - (block_number * this.blockSize);
		if (!block || num >= block.length) {
			alert("error: " + block_number + "; " + offset + "; " + this.blockSize);
			return;
		}
		var rec = block[num];

		return rec;
	}
};
function imageDownloader(blockFunction){
	this.getPath = blockFunction;
}
imageDownloader.prototype = imageDownloadManager;

function imageGallery (element){
	var galleryHeight = 100;

	this.browserHeight = browser.getHeight();
	this.element = element;

	
	/* Get and parse header */
	this.header = $(this.element.getElementsByTagName("h2")[0]);
	this.currentShowing = $(this.header.getElementsByTagName("span")[0]);
	var matches = this.currentShowing.innerHTML.match(/([0-9]*) - ([0-9]*) of ([0-9]*)/);
	this.start = matches[1] - 1;
	this.count = matches[2] - this.start;
	this.total = matches[3];


	/* Position stuff */
	var totalHeight =  galleryHeight + this.header.offsetHeight;
	this.element.makeAbsolute();
	this.element.moveHeight(totalHeight);
	this.element.moveTop(this.browserHeight - totalHeight - app.padding);
	this.element.beforeDrag = function () {allowHover = false;};
	this.element.afterDrag = function (){ allowHover = true; };
	this.element.allowDrag();
	this.element.onDrag = this.onDrag.bind(this);
	
	/* Add event handlers */
	browser.addWidthEvent(this.widthChange.bind(this));
	
	/* Initialize contents */
	//add spinners
	var previous = $new("img");
	previous.src = "/templates/aiskander/images/arrows/left_arrow.png";
	previous.style.position = "absolute";
	previous.style.left = "0px";
	previous.style.top = "50px";
	previous.style.height="32px";
	previous.style.width="16px";
	previous.moveAlpha(1);
	previous.setAttribute("alt","previous");
	previous.expandSize = {"width":16, "height":32};
	previous.disabled = true;
	previous.onclick =  this.previous.bind(this);
	
	this.element.appendChild(previous);	
	this.previousButton = previous;
	//next
	var next = $new("img");
	next.src = "/templates/aiskander/images/arrows/right_arrow.png";
	this.element.appendChild(next);
	next.style.position = "absolute";
	next.style.left = (this.element.offsetWidth - 16) + "px";
	
	next.style.top = "50px";
	next.style.height="32px";
	next.style.width = "16px";
	next.setAttribute("alt", "next");
	next.moveAlpha(.3);
	next.expandSize = {"width":16, "height":32};
	next.disabled = true;
	
	next.onclick =  this.next.bind(this);
	
	this.nextButton = next;

	
	//add padding for spinners
	this.padding = 32;

	//clear out the existing images
	var list = this.element.getElementsByTagName("ul")[0];
	var l = list.childNodes.length;
	for (var i = 0; i < l; i++){
		list.removeChild(list.childNodes[0]);
	}
	
	this.sizeChange();
	app.relayoutFunctions.push(this.widthChange.bind(this));
}
imageGallery.prototype.onDrag = function (){
	/* When dragging the image */
	allowHover = false;
	//Check to ensure we are not going to high
	if (this.element.getTop() < 200) this.element.moveTop(200);
	
	//or too low
	var wasHidden = this.hidden;
	if (this.element.getOffsetTop() > browser.getHeight() - 60 - this.header.offsetHeight) {

		this.hidden = true;
		this.element.moveTop(browser.getHeight() - 60 - (this.element.getOffsetTop() - this.element.getTop()));

	}else{
		this.hidden = false;
	}
	
	//Change the height
	this.element.moveHeight(browser.getHeight() + this.header.offsetHeight - this.element.getOffsetTop() - 60);
	
	//alert onResize handler (for the galleryImage)
	if(this.onResize) this.onResize();
	
	//update our contents
	this.sizeChange();
}
imageGallery.prototype.widthChange = function(){
	this.element.moveWidth(browser.getWidth() - this.element.getOffsetLeft() - app.padding);
	this.element.moveTop(browser.getHeight() + this.header.offsetHeight - this.element.getHeight() - $(this.element.offsetParent).getOffsetTop() - 60);
	this.nextButton.style.left = (this.element.offsetWidth - 16) + "px";
	this.onResize();
	this.sizeChange();
}
imageGallery.prototype.gotImages = function(start, count){
	/* Check if we are retrieving what needs to be retrieved. */
	if (start == this.start && count == this.currentCount){
		var list_items = this.element.getElementsByTagName("li");
		for (var i = this.start; i < this.currentCount + this.start; i++){
			if (i - this.start > list_items.length) return;
			var list_item = list_items[i - this.start];
			if (!list_item) return;
			//get the image which this list item contains, if any
			var images = list_item.getElementsByTagName("img");
			
			//if one exists, use it
			if (images.length > 0) image = images[0];
			else {
				//otherwise, add one
				image = $new("img");
				list_item.appendChild(image);
			}
			
			//get the image representation from the downloaded content
			var imageRep = imageDownloadManager.getImage(i);
			image.src = imageRep.path;
			image.setAttribute("alt", imageRep.name);
			image.setAttribute("text", imageRep.text);
			//register this as a dashboard module style image.
			this.element.dashboardModule.registerImage(image);
		}
	}else{
		//we have updated since.
		return;
	}
}
imageGallery.prototype.previous = function (){
	//for now, simply increase start and recompute
	if (this.previousButton.disabled) return;
	this.start = Math.max(this.start - this.maxCount, 0);
	this.sizeChange();
}
imageGallery.prototype.next = function (){
	if (this.nextButton.disabled) return;
	this.start += this.maxCount;
	this.sizeChange();
}
imageGallery.prototype.deleteItem = function(li){
	li.parentNode.removeChild(li);
}
imageGallery.prototype.sizeChange = function (){
	/* First, figure out what images we are covering */
	
	//what is the size of our images?
	var imageWidth = 60; var imageHeight = 60;
	var imagePadding = 10;
	var imageTotalWidth = (imageWidth + (imagePadding * 2));
		
	//how large is a row?
	var rowWidth = this.element.getWidth() - (this.padding * 2);

	//how many images can fit there?
	var imagesPerRow = Math.floor((rowWidth) / imageTotalWidth);
	
	//calculate free space. We subtract 1 from the number of images per row
	//because we are looking for space which goes BETWEEN images

	var imagesSpace = imagesPerRow * imageTotalWidth;
	var freeSpace = rowWidth - imagesSpace;

	var extraSpacePerImage = Math.floor(freeSpace / (imagesPerRow - 1));

	//how many rows can we fit? Have 10px padding below header.
	var panelTop = this.header.getHeight() + 10;
	var panelHeight = this.element.getHeight() - panelTop;
	var rowHeight = (imageHeight + imagePadding * 2);
	var rowCount = Math.floor(panelHeight / rowHeight);
	var actualRowCount = 1;
	//how many images total?
	var totalImages = imagesPerRow * rowCount;
	
	//ensure we have valid values
	if (totalImages != 0 && !totalImages) return;
	
	/* Compute based on how many images we can really use */
	this.maxCount = totalImages;
	totalImages = Math.min (totalImages, this.total - this.start);
	this.currentCount = totalImages;
	if (totalImages == 0) actualRowCount = 0;
	
	/* Set up our animation pool */
	if (this.animator) this.animator.stop();
	var pool = new animationPool();
	
	/* Remove images if we have too many */
	var list = this.element.getElementsByTagName("ul")[0];
	var list_items = list.getElementsByTagName("li");
	var length = list_items.length;
	for (var i = 0; i < length; i++){
		if (i >= this.currentCount){
			/* remove this image */
			//first check if there is an image inside
			
			var img = list_items[i].getElementsByTagName("img");
			if (img.length > 0) {
				//if so, deregister it from the module image
				this.element.dashboardModule.unregisterImage(img[0]);
				
				//also, make the width/height an inline style as the css rule will soon not apply.
				img[0].style.width = "60px";
				img[0].style.height = "60px"
			}
			var list_item = $(list_items[i]);
			list.removeChild(list_item);
			
			//the following should not be necessary, but I am paranoid.
			var list_items = list.getElementsByTagName("li");
			
			//change length and i to accomadate for removal
			length--;
			i--;
		}
	}
	
	/* Add new images if needed, and position all images. */

	var list_items = list.getElementsByTagName("li");

	this.animator = pool;
	//positioning variables
	var currentLeft = 0;
	var currentTop = panelTop;
	
	for (var i = this.start; i < this.currentCount + this.start; i++) {
		if (i - this.start >= list_items.length) {
			//add list item
			
			var list_item = $new("li");
			list.appendChild(list_item);
			
			//note it should not be necessary to reset list_items. But I'm paranoid.
			list_items = list.getElementsByTagName("li");
			list_item.moveAlpha(0);
		}else list_item = $(list_items[i - this.start]);
		//remove image if one exists and we are changing offset.
		if (!list_item.imageIndex || list_item.imageIndex != i){
			list_item.imageIndex = "";
			var img = list_item.getElementsByTagName("img");
			if (img.length==0){
				img = $new("img");
				list_item.appendChild(img);
			}else img = img[0];
				
			img.src = "/templates/aiskander/images/loading.gif";
			
		}
		
		
		//calculate new position
		var left = this.padding + imagePadding + currentLeft;
		var top = currentTop + imagePadding;
		
		//move the picture
		list_item.init();
		list_item.makeAbsolute();

		list_item.animate({"left": left, "top": top,"alpha":1.0});
		
		//calculate new left position
		currentLeft += imagePadding * 2 + imageWidth + extraSpacePerImage;
		if (currentLeft + imagePadding * 2 + imageWidth > rowWidth && i - this.start < this.currentCount - 1){
			//move to a new row
			currentLeft = 0;
			currentTop += rowHeight;
			actualRowCount++;
		}
	}

	/* Load the images from the server now */
	imageDownloadManager.getImages(this.start, this.currentCount, this.gotImages.bind(this, this.start, this.currentCount));
	
	/* Update the current images shown display */
	var text = "showing: " + (this.start + 1) + " - " + (this.start + this.currentCount) + " of " + this.total;
	if (this.currentCount <= 0) text = "showing none";
	this.currentShowing.innerHTML = text;
	
	/* Update next/previous buttons */
	var top = ((actualRowCount * rowHeight) / 2) + panelTop;
	if (this.hidden) top = panelTop;
	var pa = {"top":top - (this.previousButton.getHeight() / 2)};
	var na = {"top":top - (this.nextButton.getHeight() / 2)};

	if (this.start > 0){
		//previous is enabled
		this.previousButton.disabled = false;
		pa.alpha = 1.0;
	}else{
		this.previousButton.disabled = true;
		pa.alpha = 0.3;
	}
	
	if (this.currentCount + this.start < this.total){
		this.nextButton.disabled = false;
		na.alpha = 1.0;		
	}else{
		this.nextButton.disabled = true;
		na.alpha = 0.3;
	}
	
	if (this.currentCount <= 0) {na.alpha = 0; pa.alpha = 0;}
	this.nextButton.animate(na);
	this.previousButton.animate(pa);
	pool.start();
	freeAnimationPool(); //be courteous!
}
var app = { 
	"padding": 0,
	"transparency": .2,
	"relayoutFunctions": new Array(),
	"loadingScripts": {},
	"currentScript": 0,
	"relayout": function () {
		for (var i = 0; i < this.relayoutFunctions.length; i++){
			this.relayoutFunctions[i]();
		}
	},
	"init": function(){
		if (document.all){
			var val = $(document.body).getElementsByTagName("img");
			for (var i = 0; i<val.length;i++){

				val[i].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + val[i].src + "',sizingMethod='scale')"
				val[i].style.height = val[i].offsetHeight + "px";
				val[i].style.width = val[i].offsetWidth + "px";
				val[i].o_src = val[i].src;
				val[i].src = transparent_image;
				val[i].isTransparent = true;
			}
		}

		/* IF IE 6 DISABLE MOST JAVASCRIPT */
		if (window.XMLHttpRequest){
			
		}else{
			//return;
		}

		this.padding = measure.measureClass("padding").width;
		window.setInterval(
			function () {
				tpadding = measure.measureClass("padding").width;
				if (tpadding != app.padding) {
					app.padding = tpadding;
					app.relayout();
				}
			}
			, 300
		);

		var val = $("dashboard").getElementsByClassName("dashboard-module").makeNew(aModule);
		var val = $(document.body).getElementsByClassName("gallery-content").makeNew(gallery);
		var val = $(document.body).getElementsByClassName("gallery-content");
//		if (val.length > 0){
			$(val[0])//
			$(document.body).getElementsByClassName("dashboard-style").makeNew(aModule);
//		}
		addEvent(document.body, "keypress", this.keyPress.bindEventListener(this));
		unobtrusive.scan();
		
		$(document.body).getElementsByClassName("autofocus").foreach(function(e){
				e.focus();
			});

		request.prototype.error = windowManager.alert.bind(windowManager, "Error loading content.");
		
		var val = $(document.body).ofClass("form","orderable").makeNew(orderableList);
		var val = $(document.body).ofClass("ul","blog");
		
		if (val.length == 1){
			this.processPosts(val[0]);
		}
//		window.setTimeout(this.analytics.bind(this), 100); //allow any time-delayed initializations, etc. to complete.
		
	},
	"loadScript": function(id, path, test, callback){
		script = document.createElement('script');
		script.setAttribute("id", id);
		script.setAttribute("type", 'text/javascript');
		script.setAttribute("src", path);
		document.getElementsByTagName('head')[0].appendChild(script);
		this.currentScript++;
		
		this.loadingScripts[this.currentScript] = window.setInterval(this.loadTest.bind(this, test, this.currentScript,callback), 100);
	},
	"loadTest": function (test, sid, onfinish){
		if (test()){
			window.clearInterval(this.loadingScripts[sid]);
			delete this.loadingScripts[sid];
			onfinish();
		}
	},
	"analytics": function(){
		this.loadScript(
			"google-analytics",
			"http://www.google-analytics.com/urchin.js",
			function(){
				try {
					if(urchinTracker) return true;
				}catch(e){
				}
				return false;
			},
			function(){
				urchinTracker(window.location.pathname);
			}
		);
		
		
	},
	"processPosts":function(element){
		var posts = element.getElementsByTagName("li");
		for (var i = 0; i < posts.length; i++){
			var link = $(posts[i]).ofClass("a", "more-link");
			if (link.length > 0){
				link=link[0];
				link.onclick = this.expandPost.bindEventListener(this, posts[i], link);
				posts[i].path = link.href;
				link.href="javascript:void(0);";
			}
		}
	},
	"doExpandPost": function(req, post, link){

		var xml = req.xml;
		var text = xml.getElementsByTagName("text")[0];
		text = getNodeText(text);
		var textdiv = $(post.ofClass("div","text")[0]);
		textdiv.moveHeight(textdiv.offsetHeight);
		textdiv.style.overflow = "hidden";
		post.originalText = textdiv.innerHTML;
		textdiv.innerHTML = text;
		measure.setClass("text");
		var size = measure.measureText(text,textdiv.offsetWidth + "px","auto");
		textdiv.animate({"height":size.height,"iterator":animator.sineIterator,"frames":17,"onFinish":function(){textdiv.style.height="auto";}});
		link.innerHTML = '<img src = "/templates/aiskander/images/arrows/up_arrow.png" />read less';
		link.onclick = this.hidePost.bindEventListener(this,post,link);
		this.hideLoading();
	},
	"expandPost": function(event, post, link){
		var url = post.path;
		if (url.substr(url.length - 1, 1) != "/") url += "/";
		var req = new request(url + "::show-type=xml;content,show=content", "GET");
		req.onFinish = this.doExpandPost.bind(this,req,post,link);
		this.showLoading();
		req.send();
		cancelEvent(event);
		return false;
	},
	"hidePost": function(event, post, link){
		var textdiv = $(post.ofClass("div","text")[0]);
		textdiv.moveHeight(textdiv.offsetHeight);
		textdiv.style.overflow = "hidden";

		measure.setClass("text");
		var size = measure.measureText(post.originalText,textdiv.offsetWidth + "px","auto");
		textdiv.animate({"height":size.height, "frames":17,"iterator":animator.sineIterator,"onFinish":function(){textdiv.innerHTML = post.originalText;}});
		link.innerHTML = 'read more<img src = "/templates/aiskander/images/arrows/down_arrow.png" />';
		link.onclick = this.expandPost.bindEventListener(this,post,link);
	},
	"keyPress": function(event){
	
		var key = (event.keyCode ? event.keyCode : event.charCode);
		
		var value = String.fromCharCode(key);
		if (value == ("\r" || "\n") && event.shiftKey) {
			var _this = this;
			window.setTimeout(function(){windowManager.prompt ("quickli", "enter command", _this.commandEntered.bind(_this))}, 10);
		}
	},
	"commandEntered": function (value){
		if (value == "login"){
			var window = new windowManager.newWindow(
				{
					"url":"./::show-type=content,show=login",
					"title":"log in",
					"onload":function(layer){
						layer.getElementsByClassName("autofocus").foreach(
							function(e){e.focus()}
						)
					}
				}
			);
		}else if (value == "logout"){
			window.location = "/::show=logout";
		}else{
			this.selectImage(function(){});
		}
	},
	"showLoading":function(){
		if (!this.loadingWindow){
			this.loadingWindow = new windowManager.newWindow(
				{
					"width": 400,
					"height": 150,
					"x": 60 + (browser.getWidth() - 300) / 2,
					"title": "Loading...",
					"modal":true,
					"drawContent": function(settings,layer){
						layer.innerHTML = "please wait...";
					}
				}
			);
		}
	},
	"hideLoading":function(){
		if (this.loadingWindow) this.loadingWindow.close();
		this.loadingWindow =null;
	},
	"selectImage": function (callback){
		new selectWindow(callback);
	}
};
function selectWindow (callback){
	this.callback = callback;
	this.downloader = new imageDownloader(this.blockURL.bind(this));

	this.window = new windowManager.newWindow(
	{
		"width":764,
		"height": 500,
		"title": "select image", "url": "/::show-type=content",
		"drawContent": this.drawContent.bind(this)
	}
	);	
}
selectWindow.prototype.blockURL = function (number){
	return "/uploads/::show-type=xml,page=" + (number + 1) + ",all=true";
}
selectWindow.prototype.drawContent = function (settings, layer){
	this.container = $new("div");
	layer.appendChild(this.container);
	this.images = $new("ul");
	this.container.appendChild(this.images);
	this.container.className="images-window";
	this.container.style.position = "absolute";
	this.container.style.left = "32px";
	this.container.style.width = "600px";
	
	var previous = $new("img");
	previous.src = "/templates/aiskander/images/arrows/left_arrow.png";
	previous.style.width = "16px";
	previous.style.height = "32px";
	previous.style.position = "absolute";
	previous.style.left = "0px";
	previous.style.top = "164px";
	previous.moveAlpha(.3);
	previous.disabled = true;
	previous.onmouseover = function(){if (!previous.disabled) previous.moveAlpha(1);};
	previous.onmouseout = function(){previous.moveAlpha(.3);};
	layer.appendChild(previous);
	
	
	var next = $new("img");
	next.src = "/templates/aiskander/images/arrows/right_arrow.png";
	next.style.width = "16px";
	next.style.height = "32px";
	next.style.position = "absolute";
	next.style.right = "0px";
	next.style.top = "164px";
	next.moveAlpha(.3);
	next.disabled = false;
	next.onmouseover = function(){if (!next.disabled) next.moveAlpha(1);};
	next.onmouseout = function(){next.moveAlpha(.3);};
	layer.appendChild(next);

	this.start = 0;
	this.count = 15;
	this.downloader.getImages(this.start, this.count, this.gotImages.bind(this));

}
selectWindow.prototype.gotImages = function (){
	this.images.innerHTML = "";
	for (var i = this.start; i < this.start + this.count; i++){
		var li = $new("li");
		var img = $new("img");
		li.appendChild(img);
		var struct = this.downloader.getImage(i);
		img.src = struct.path;
		img.alt = struct.name;
		img.description = struct.text;
		this.images.appendChild(li);
	}

}

document.write ('<link rel = "stylesheet" href = "/templates/aiskander/alexjs.css" />'); //update the js-specific stylesheet options
//addEvent(window, "load", app.init.bindEventListener(app));


Array.prototype.gridLayout = function(container, padding, width){
	if (!width){
		//autowidth sizes columns by the WIDEST width item, min width of 50.
		width = 50;
		var l = this.length;
		for (var i = 0; i < l; i++){
			width = Math.max(width,this[i].offsetWidth);
		}
	}
	var rowHeight = 0;
	var itemHeight;
	var itemWidth;
	var item;
	l = this.length;
	
	var cwidth = container.getWidth();
	var colwidth = width + padding * 2;
	var colcount = Math.floor(cwidth / (colwidth)) ;
	colcount = Math.max(colcount, 1);
	var uw = colcount * colwidth;
	var ew = cwidth - uw;
	var ep = Math.floor(ew / colcount);
	colwidth += ep;
	var coli = 0;
	
	var cy = 0;
	cy += padding;

	var result = {"lefts": new Array(), "tops": new Array(),"colwidth": colwidth, "rows":new Array(),"aleft":container.getOffsetLeft(),"atop": container.getOffsetTop(),"colcount":colcount,"height":0};
	for (var i = 0; i < l; i++){
		item = this[i];
		itemWidth = item.offsetWidth;
		itemHeight = item.offsetHeight;
		
		rowHeight = Math.max(itemHeight, rowHeight);
		

		left = (coli * colwidth) + padding;
		result.lefts.push(new animator.move(item, "left", Math.round(left)));
		result.tops.push(new animator.move(item, "top", Math.round(cy)));
		
		coli++;
		if (coli >= colcount){
			result.rows.push(cy);
			coli = 0;
			cy += padding * 2;
			cy += rowHeight;
			rowHeight = 0;

		}
	}
	result.rows.push(cy);
	cy += rowHeight + padding;

	result.height = cy;
	result.width = width;
	return result;
}
function getIndexFromLayout(object,layout){
	if (!object) alert("in getIndexFromLayout object does not exist");
	if (!layout) alert("in getIndexFromLayout layout does not exist");
	var left = object.getOffsetLeft() - layout.aleft;
	var top = object.getOffsetTop() - layout.atop;
	top += object.offsetHeight / 2;
	var pos = Math.floor(left / layout.colwidth); //number of columns
	pos = Math.max(0, pos);

	for (var i = layout.rows.length - 1; i >= 0 ;i--){

		if (top > layout.rows[i]){
			break;
		}

		
	}

	i = i * layout.colcount;
	i += Math.round(pos);
	return i;
}


function orderableList (form){
	this.form = $(form);
	var list = this.form.getElementsByTagName("ul")[0];
	this.list = $(list);
	this.list.style.position="relative";
	var items = Array.from(list.getElementsByTagName("li"));
	for (var i = items.length -1; i >= 0; i--){

		if (!items[i] || !items[i].parentNode || items[i].parentNode != list) {
			items.remove(i);
			continue;
		}
		items[i] = $(items[i]);
		items[i].makeAbsolute();
		items[i].init();
		items[i].moveHeight(items[i].offsetHeight);
		items[i].moveTop(0);
		items[i].allowDrag();
		items[i].onDrag = this.drag.bind(this, items[i]);
		items[i].beforeDrag = this.beforeDrag.bind(this, items[i]);
		items[i].afterDrag = this.afterDrag.bind(this, items[i]);
	}

	this.items = items;
	this.items.doIndex();
	this.layout();
}
orderableList.prototype.beforeDrag = function(item){
	//item.moveGlobal();
	item.isDragging = true;
}
orderableList.prototype.drag = function(item){
	var top = item.getTop();// - item.offsetHeight / 2;
	for (var i = this.rows.length - 1; i >= 0; i--){
		if (top >= this.rows[i].top){
			if (item.index != this.rows[i].rowIndex) {
				this.items.remove(item.index);
				this.items.insert(item, this.rows[i].rowIndex);
			}
			break;
		}
	}
	this.layout();
}
orderableList.prototype.afterDrag = function (item){
	item.isDragging = false;
	this.layout(true);
}
orderableList.prototype.layout = function(debug){
	this.items.doIndex();
	if (this.pool) this.pool.stop();
	this.pool = new animationPool();
	this.rows = Array();
	var cy = 1;
	for (var i = 0; i < this.items.length; i++){
		this.rows[i] = {"top": cy, "bottom":cy + this.items[i].getHeight(),"rowIndex": this.items[i].index};
		if (!this.items[i].isDragging) {
		this.items[i].animate({"top":cy});
		}
		cy += this.items[i].getHeight() + 100;
		this.items[i].ofClass("input", "order-field")[0].setAttribute("value", i);
	}
	this.pool.start();
	freeAnimationPool();
};



var windowManager = {
	"preloadPartNames": new Array("upper_left","upper_right","bottom_left", "bottom_right", "left", "right", "top", "bottom", "title", "inner"),
	"defaultPrefix": "window",
	"startZ": 5000,
	"zWindow": 10,
	"windows": new Array(),
	"handles": {},
	"handleCount": 0,
	"init": function(){

		if (this.inited) return;
		this.windows.doIndex();
		this.inited = true;
	},
	"updatez": function(){
		var l = this.windows.length;
		var offset = 0;
		for (var i = l - 1; i >= 0; i--){
			offset++;
			var w = this.windows[i];
			w.updateZ(this.startZ + (offset * this.zWindow));
		}
	},
	"getContentSize": function(className){
		return measure.measureNestedClass(className + "_content", "");
	},
	"getMinSize": function (className){
		var left = measure.measureClass(className + "_left").width;
		var right = measure.measureClass(className + "_right").width;
		var top = measure.measureClass(className + "_top").height;
		var bottom = measure.measureClass(className + "_bottom").height;
		return {"width": left + right, "height": top + bottom};
	},
	"preloadWindowClasses": function(className){
		for (var i = 0; i < this.preloadPartNames.length; i++){
			var partName = this.preloadPartNames[i];
			preloader.preloadClass(className + "_" + partName);
		}
	}
};
windowManager.preloadWindowClasses("window");
windowManager.prompt = function (title,message, callback){
	var promptWindow = new windowManager.newWindow({
			"title":title,
			"modal":true,
			"width":520,
			"height":250,
			"drawContent": function (settings,layer){
				layer.innerHTML = message + "<br /><input type='text' id='wm-prompt-value' />";
				var select = $new("div");
				select.innerHTML = "ok";
				var input = document.getElementById("wm-prompt-value");
				select.onclick = 
				function(){
					var value=input.value;
					promptWindow.close();
					callback(value);
				};
				
				
				input.onkeypress =
				function (event){
					event = event ? event : window.event;
					var key = event.keyCode ? event.keyCode : event.charCode;
					if (key == 13){
						select.onclick(event);
					}else if (key == 27) {
						promptWindow.close();
					}
				};
				
				select.className = "window-button";
				select.style.position = "absolute";
				select.style.bottom = "0px";
				select.style.right = "0px";
				layer.appendChild(select);
				var cancel = $new("div");
				cancel.onclick = function (){promptWindow.close();};
				cancel.className = "window-button";
				cancel.innerHTML = "cancel";
				cancel.style.position = "absolute";
				cancel.style.bottom = "0px";
				cancel.style.left = "0px";
				layer.appendChild(cancel);
				var promptval = document.getElementById("wm-prompt-value");
				promptval.focus();
				
			}});
			
}
windowManager.alert = function (message, title){
		var promptWindow = new windowManager.newWindow({
			"title":title,
			"modal":true,
			"width":600,
			"height":150,
			"drawContent": function (settings,layer){
				layer.innerHTML = message;
				var select = $new("div");
				select.innerHTML = "ok";
				var odkp = document.onkeypress;
				select.onclick = 
				function(){
					promptWindow.close();
					document.onkeydown = odkp;
				};
				
				select.className = "window-button";
				select.style.position = "absolute";
				select.style.bottom = "0px";
				select.style.right = "0px";

				document.onkeydown = function(event){
					event = event ? event : window.event;
					var key = event.keyCode ? event.keyCode : event.charCode;
					if (key == 13) {
						promptWindow.close();
						document.onkeydown = odkp;
					}
					
				}
				layer.appendChild(select);
			}});
}
windowManager.newWindow = function (settings){
	windowManager.init();
	this.handle = windowManager.handleCount++;
	windowManager.handles[this.handle] = this;
	/* Get a class prefix for use in all generated tags */
	if (!settings) settings = {};
	if (!settings.classPrefix) settings.classPrefix = windowManager.defaultPrefix;
	this.classPrefix = settings.classPrefix;
	
	var classPrefix = this.classPrefix;
	
	var minSize = windowManager.getMinSize(classPrefix);
	
	
	this.top = (settings.y ? settings.y : "centered");
	this.left = (settings.x ? settings.x : "centered");

	this.width = Math.max((settings.width ? settings.width : 800), minSize.width);
	this.height = Math.max((settings.height ? settings.height : 600), minSize.height);
	
	
	if (this.left == "centered"){
		this.left = Math.max(0,Math.round((browser.getWidth() / 2) - (this.width / 2))) + document.body.scrollLeft;
		
	}
	if (this.top == "centered"){
		this.top = Math.max(0,Math.round((browser.getHeight() / 2) - (this.width / 2))) + document.body.scrollTop;
	}
	
	this.windowLayers = {};

	this.settings = settings;
	if (settings.drawControls) this.drawControls = settings.drawControls;
	if (settings.drawModal) this.drawModal = settings.drawModal;
	if (settings.drawBackground) this.drawBackground = settings.drawBackground;
	if (settings.drawContent) this.drawContent = settings.drawContent;

	windowManager.windows.insert(this,0);
	
	if (this.settings.modal) this.drawModal();
	this.drawBackground();
	this.drawControls();
	
	windowManager.updatez();
}

windowManager.newWindow.prototype.close = function(){
	this.dispose();
}
windowManager.newWindow.prototype.dispose = function(){
	windowManager.windows.remove(this.index);
	delete windowManager.handles[this.handle];
	for (var i in this.windowLayers){
		if (!this.windowLayers[i].disposed){
			this.windowLayers[i].disposeChildren();
			this.windowLayers[i].disposed = true;
		}
		if (this.windowLayers[i].parentNode){
			this.windowLayers[i].parentNode.removeChild(this.windowLayers[i]);
		}
		delete this.windowLayers[i];
	}
}

/* User-overridable functions */
windowManager.newWindow.prototype.drawModal = function(){
	var layer = $new("div");
	layer.className = this.classPrefix + "_modal";
	this.windowLayers.modalLayer = layer;
	layer.style.left = "0px";
	layer.style.top = "0px";
	layer.style.width="100%";
	layer.style.height = "100%";
	layer.style.position="fixed";
	layer.style.zIndex = "5000";
	document.body.appendChild(layer);
}
windowManager.newWindow.prototype.drawBackground = function (){
	var layer = $new("div");
	layer.className = this.classPrefix + "_background";
	layer.style.position = "absolute";
	layer.style.top = this.top +"px";
	layer.style.left = this.left +"px";
	layer.style.width = this.width +"px";
	layer.style.height = this.height +"px";
	layer.style.zIndex = "5001";
	this.windowLayers.backgroundLayer = layer;

	
	var upper_left = $new("div");
	var upper_right = $new("div");
	var bottom_left = $new("div");
	var bottom_right = $new("div");
	var top = $new("div");
	var left = $new("div");
	var right = $new("div");
	var bottom = $new("div");
	var inner = $new("div");
	var title = $new("div");

	upper_left.className = this.classPrefix + "_upper_left";

	upper_right.className = this.classPrefix + "_upper_right";
	bottom_left.className = this.classPrefix + "_bottom_left";
	bottom_right.className = this.classPrefix + "_bottom_right";
	top.className = this.classPrefix + "_top";
	left.className = this.classPrefix + "_left";
	right.className = this.classPrefix + "_right";
	bottom.className = this.classPrefix + "_bottom";
	inner.className = this.classPrefix + "_inner";
	inner.innerHTML = "";
	title.className = this.classPrefix + "_title";
	title.innerHTML = this.settings.title;
	this.titleElement = title;
	
	layer.appendChild(upper_left);
	layer.appendChild(upper_right);
	layer.appendChild(bottom_left);
	layer.appendChild(bottom_right);
	layer.appendChild(top);
	layer.appendChild(left);
	layer.appendChild(right);
	layer.appendChild(bottom);
	layer.appendChild(inner);
	layer.appendChild(title);

	document.body.appendChild(layer);
	layer.allowDrag();
	layer.onDrag = this.windowDrag.bind(this);
	layer.beforeDrag = this.beforeDrag.bind(this);

}

windowManager.newWindow.prototype.beforeDrag = function(){
	windowManager.windows.remove(this.index);
	windowManager.windows.insert(this,0);
	windowManager.updatez();
}

windowManager.newWindow.prototype.windowDrag = function(){
	if (!(this && this.windowLayers && this.windowLayers.backgroundLayer)) return;
	var layer = this.windowLayers.backgroundLayer;
	if (layer.getLeft() < browser.getScrollLeft()) layer.moveLeft(browser.getScrollLeft());
	if (layer.getTop() < browser.getScrollTop()) layer.moveTop(browser.getScrollTop());
	var left = layer.getLeft();
	var top = layer.getTop();

	var browserWidth = browser.getWidth() + browser.getScrollLeft();
	var browserHeight = browser.getHeight() + browser.getScrollTop();
	left = Math.min(left, browserWidth - layer.getWidth());
	top = Math.min(top, browserHeight - layer.getHeight());
	
	layer.moveLeft(left);
	layer.moveTop(top);
}

windowManager.newWindow.prototype.drawControls = function (url){
	//By default, this function should load the url "url" into the window's content area.
	var layer = $new("div");
	layer.className = this.classPrefix + "_container";
	layer.style.position = "absolute";
	layer.style.top = this.top +"px";
	layer.style.left = this.left +"px";
	layer.style.width = this.width +"px";
	layer.style.height = this.height +"px";

	
	this.windowLayers.controlLayer = layer;
	
	var content = $new("div");
	content.className = this.classPrefix + "_content";
	this.windowLayers.contentLayer = content;
	
	this.windowLayers.backgroundLayer.appendChild(content);
	addEvent(content,"mousedown", function(){drag.ignore = true;});
	
	this.drawContent(this.settings,this.windowLayers.contentLayer);

}
windowManager.newWindow.prototype.drawContent = function(settings,layer){
	this.contentRequest = new request(settings.url,"GET");
	this.contentRequest.onFinish = this.contentReceived.bind(this,layer);
	this.contentRequest.send();
}
windowManager.newWindow.prototype.contentReceived = function(layer){
	var content = this.contentRequest.content;
	layer.innerHTML = content;
	if (this.settings.onload) this.settings.onload(layer);
}
windowManager.newWindow.prototype.updateZ = function(zBase){

	if (this.windowLayers.modalLayer) {
		this.windowLayers.modalLayer.style.zIndex = zBase;
	}
	this.windowLayers.backgroundLayer.style.zIndex = zBase + 1;
	this.zBase = zBase;
}


/* Example class name:
 * "class :unobtrusive =type +arg=var +arg=var +arg=var =type +arg=var"
 */
var unobtrusive = {
	"hooks": {},
	"scan": function(object){
		if (!object) object = document.body;
		var extenders = object.getElementsByClassName(":unobtrusive");
		var len = extenders.length;
		for (var i = 0; i < len; i++){
			var extend = extenders[i];
			if (extend.extended) return;
			var arglist = extend.className;
			if (arglist){
				/*
				 * 1. We find :unobtrusive for start of unobtrusive list
				 * 2. We find by =([^\s]*)\s*\+([^=]*=[^\s]*), types, and their argument lists. we ignore the argument list.
				 * 3. We parse the argument lists.
				 */
				
			}
		}
	},
	"hook": function (type, callback){
		this.hooks[type] = callback;
	}
};


windowManager.preloadWindowClasses("top tooltip");
windowManager.preloadWindowClasses("bottom tooltip");
var tipManager = {
	"width": 500,
	"showTip": function(object, tip, width, pad){
		if (object.tip) return;
		if (!tip) {
			tip = (object.getAttribute("alt") ? object.getAttribute("alt") : object.getAttribute("title"));
		}
		if (!tip) return;
		if (!width) width = this.width;
		if (!pad) pad = 0;
		
		var padding = windowManager.getContentSize("tooltip");
		var vpadding = padding.topPadding + padding.bottomPadding;
		var hpadding = padding.leftPadding + padding.rightPadding;

		var leftSide = measure.measureNestedClass("tooltip_title","tooltip_background").leftPadding;
		var rightSide = measure.measureClass("tooltip_right").width;
		measure.setClass(object.className);
		var size = measure.measureText(tip, (width - hpadding) + "px", "");
		


		var left = (object.getWidth() / 2) - (width / 2) + object.getOffsetLeft();
		var top = object.getOffsetTop() + object.getHeight() + pad + browser.getScrollTop();

		
		var point = "top";
		
		var bottom = top + size.height + vpadding - browser.getScrollTop();
		if (bottom > browser.getHeight()){
			top = object.getOffsetTop() - size.height - vpadding - pad;
			point = "bottom";
		}
		
		var targetX = left;
		if (left + width > browser.getWidth()) left = browser.getWidth() - width;
		targetX -=  left;
		targetX = Math.min(targetX, (width - hpadding )/ 2);
		object.tip = new windowManager.newWindow({
			"classPrefix":point + " tooltip",
			"title":"",
			"x": left,
			"y": top,
			"width":width,
			"height":size.height + vpadding,
			"modal":false,
			"drawContent":
				function(settings,layer){
					layer.innerHTML = tip;
					this.titleElement.style.left = (width / 2) + targetX + "px";
				}
			}
		);
	},
	"hideTip": function(object){
		if (object.tip){
			object.tip.close();
			object.tip = null;
		}
	}
};

taskManager = {
	"currentTask": 0,
	"tasks": {},
	"addTask": function (task){
		this.tasks[this.currentTask] = task;
		task.id = this.currentTask;
		this.currentTask ++;
	},
	"completeTask": function (task){
		if (task.id){
			delete this.tasks[task.id];
		}
	}
};
function task (procedure, wait, async,delay){
	this.tasks = new Array();
	this.callbacks = new Array();
	
	this.taskCount = 0;
	
	this.waitForSubsidiaries = wait;
	this.completedProcess = false;
	this.async = async;
	this.delay = delay;
	if (!this.delay) this.delay = 100;
	
	this.procedure = procedure;
	if (!this.procedure) this.completedProcess = true;
	
	taskManager.addTask(this);
	
	this.completeDelegate = this.complete.bind(this);

}
task.prototype.tasksAdded = function(){
	this.waitForSubsidiaries = false;
	this.docomplete();
}
task.prototype.start = function(){
	if (this.procedure){
		if (this.async){
			/* Give the illusion of multi-threadedness */
			window.setTimer(this.process.bind(this), delay);
		}else{
			this.process();
		}
	}else this.completedProcess = true;
}
task.prototype.process = function (){
	this.procedure(this);

}
task.prototype.complete = function (){
	this.completedProcess = true;
	this.docomplete();
}
task.prototype.addTask = function (task){
	/* Add subsidiary task */
	this.waitForSubsidiaries = false;
	this.tasks[task.id] = task;
	task.addCallback(this.completeTask.bind(this));
	this.taskCount++;
}
task.prototype.completeTask = function (task){
	if (this.tasks[task.id]){
		delete this.tasks[task.id];
		this.taskCount--;
	}
	this.docomplete();
}
task.prototype.addCallback = function (callback){
	this.callbacks.push(callback);
}
task.prototype.docomplete = function (){
	if (!this.completedProcess) return;
	if (this.waitForSubsidiaries) return;
	if (this.taskCount != 0) return;
	for (var i = 0; i < this.callbacks.length; i++){
		this.callbacks[i](this);
	}
	taskManager.completeTask(this);
}

