/******************************************************************************************/

function _h1(node) {
	return application.wrapNode(node);
}

function _h2(ev) {
	return application.wrapEvent(ev);
}

function _h3(depth, node) {
	while (depth-- > 0) {
		node = node.parentNode;
	}
	return application.wrapNode(node);
}


function Application() {
	this.data = new Array();
}

Application.prototype._writeThemeForLib = function(theme, lib, base) {
	// write css
	document.writeln('<link rel="stylesheet" type="text/css" href="' + base + '/css/lib-' + lib + 
		(theme ? '.' + theme : '') + '.css" />');
}

Application.prototype._writeTheme = function(base, libs) {
	var theme = "";
/*
	// read cookie
	var cookies = document.cookie.split(';');
	for (var i=0; i < cookies.length; i++) {
		var c = cookies[i];
		while (c.charAt(0)==' ') {
			c = c.substring(1, c.length);
		}
		if (c.indexOf("theme=") == 0) {
			theme = c.substring(6, c.length);
		}
	}*/
	
	// read url
	var url = window.location.search.toString();
	if (url.indexOf('theme=') != -1) {
		theme = url.substring(url.indexOf('theme=') + 6);
		if (theme.indexOf('&') != -1) {
			theme = theme.substring(0, theme.indexOf('&'));
		}
	} 
	
	// set cookie
	/*
	var date = new Date();
	date.setTime(new Date().getTime()+(365*24*60*60*1000));
    var expires = 'expires=' + date.toGMTString() + ';';
	document.cookie = "theme="+ theme + ";" + expires;*/
	// write css
	var libsArray = libs.split(',');
	for (var i=0; i < libsArray.length; i++) {
		if (libsArray[i] != '') {
			this._writeThemeForLib(theme, libsArray[i], base);
		}
	}
	
};

Application.prototype.getElementById = function(id) {
	return application.wrapNode(document.getElementById(this.getPrefix() + id));
}

Application.prototype.wrapNode = function(node) {
	if (!node || node.outerNode) {
		return node;		
	}
	
	if (node.nodeType == 3) {
		return new TextWrapper(node);
	}	
	
	if (node.location) {
		return this.wrapHTMLNode(document.documentElement.lastChild);
	}
	
	var htmliclass = node.getAttribute('htmliclass');
	if (htmliclass) {
		var a;
		eval("a = new " + htmliclass + "(node);");
		return a;
	} else {
		return this.wrapHTMLNode(node);
	}

}

Application.prototype.wrapHTMLNode = function(node) {
	if (node.constructor && node.constructor.toString() == '[Window]') {
		return new HTMLBodyElementWrapper(document.documentElement.lastChild);
	} else if (node == document.documentElement.lastChild) {
		return new HTMLBodyElementWrapper(node);
	} else if (!node.tagName) {
		return;
	} else if (HTMLElementWrapper.classes[node.tagName.toLowerCase()]) {
		return new HTMLElementWrapper.classes[node.tagName.toLowerCase()](node);	
	} else {
		return new HTMLElementWrapper(node);
	}	
}

Application.prototype.wrapInnerNode = function(node) {
	if (node == null || !node.getAttribute) {
		return null;
	}

	if (node.getAttribute('htmliinner') == null) {
		return this.wrapNode(node);
	}
	
	var height = parseInt(node.getAttribute('htmliinner'));
	while (height-- > 0) {
		node = node.parentNode;
	}
	
	return this.wrapNode(node);
}

Application.prototype.createEvent = function(type) {
	if (type == 'HTMLiEvents') {
		return new HTMLiEvent();
	}
	if (document.createEventObject) {
		return application.wrapEvent(document.createEventObject(type), type);
	} else {
		return application.wrapEvent(document.createEvent(type), type);
	}
}

Application.prototype.wrapEvent = function(event, group) {
	
	if (group) {
		switch (group) {
			case 'MouseEvents':
				return new MouseEventWrapper(event);
				break;
			case 'UIEvents':
				return new UIEventWrapper(event);
				break;
		}
	}
	
	
	switch (event.type) {
		
		// See MouseEvent interface at
		// http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-eventgroupings-mouseevents
		case 'click': 
		case 'dblclick':
		case 'mousedown':
		case 'mouseover':
		case 'mouseout':
		case 'mouseup':
		case 'mousemove':
			return new MouseEventWrapper(event);
		// See Keyboard events at
		// http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-eventgroupings-keyevents
		case 'keydown':
		case 'keyup':
		case 'keypress':
			return new KeyboardEventWrapper(event);
		// See html events at
		// http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-eventgroupings-htmlevents
		case 'focus':
		case 'blur':
		case 'load':
		case 'unload':
		case 'abort':
		case 'error':
		case 'submit':
		case 'reset':
		case 'select':
		case 'change':
		case 'resize':
		case 'scroll':
		default:
			return new EventWrapper(event);
	}	
}

Application.prototype.getContainerFor = function(node) {
	var parentNode = node.parentNode;
	while (parentNode != null) {	
		if (parentNode.className == 'container__') {
			return new Container(parentNode);
		}
		if (parentNode == document.documentElement) {
			return this;
		}
		parentNode = parentNode.parentNode;
	}	
	return null;
}

Application.prototype.getPrefix = function() {
	return document.documentElement.lastChild.getAttribute('htmliprefix');
}

Application.prototype.addEventListener = function(type, listener, useCapture) {

	if (useCapture) {
		throw new Error("Microsoft Internet Explorer doesn't support useCapture");
	}
	
	listener._wrappedFunction = function(e) {
		listener(application.wrapEvent(e));
	};
	
	if (document.addEventListener) {
		document.addEventListener(type, listener._wrappedFunction, false);
	} else if (document.attachEvent) {
		document.attachEvent('on' + type, listener._wrappedFunction);
	} else {
		throw new Error("Your browser doesn't support DOM events");
	}
}

Application.prototype.removeEventListener = function(type, listener, useCapture) {
	if (useCapture) {
		throw new Error("Microsoft Internet Explorer doesn't support useCapture");
	}
	
	if (document.removeEventListener) {
		document.removeEventListener(type, listener._wrappedFunction, false);
	} else if (document.detachEvent) {
		document.detachEvent('on' + type, listener._wrappedFunction);
	} else {
		throw new Error("Your browser doesn't support DOM events");
	}
}

Application.prototype.dispatchEvent = function(event)  {
	if (document.dispatchEvent) {
		document.dispatchEvent(event.event);
	} else if (document.fireEvent) {
		document.fireEvent('on' + event.getType(), event.event);
	}
}

Application.prototype.getParent = function() {
	return null;
}

Application.prototype.getDocumentElement = function() {
	return application.wrapNode(document.documentElement);
}

Application.prototype.getScrollTop = function() {
	if (self.pageYOffset){
	  return self.pageYOffset;
	}
	else if (document.documentElement && document.documentElement.scrollTop){
	  return document.documentElement.scrollTop;
	}
	else if (document.body){
	  return document.body.scrollTop;
	}
}

Application.prototype.getScrollLeft = function() {
	if (self.pageXOffset){
	  return self.pageXOffset;
	}
	else if (document.documentElement && document.documentElement.scrollTop){
	  return document.documentElement.scrollLeft;
	}
	else if (document.body){
	  return document.body.scrollLeft;
	}
}

var application = new Application();

application.nextZIndex = 1;

application.errorMessage = "";

/******************************************************************************************/

function Container(node) {
	this.node = node;	
}

Container.prototype.open = function(url, handler) {
	var httpRequest = HttpRequest.create();
	var node = this.node;
	httpRequest.open("GET", url, true);
	httpRequest.onreadystatechange = function() {			
			if (httpRequest.readyState == 4) {
			
				node.innerHTML = httpRequest.responseText;	
						
				var re = new RegExp('<[\\s]*body[^>]+htmliprefix=["|\']([a-zA-Z0-9|_]*)["|\']');
				var prefix = httpRequest.responseText.match(re)[1];
				var script = document.getElementById(prefix + '__script');
				var head = document.documentElement.firstChild;
				if (script) {
					head.appendChild(document.createElement('script'));
					head.lastChild.text = script.text;
				}
				
				node.setAttribute('name', prefix);
				
				if (handler) {
					handler();
				}		
			}
		};
	httpRequest.send("");	
}

Container.prototype.close = function() {
	this.node.innerHTML = '';
}

Container.prototype.getPrefix = function() {
	return this.node.getAttribute('name');
}

Container.prototype.getElementById = function(id) {
	return application.wrapNode(document.getElementById(this.getPrefix() + id));
}

Container.prototype.getParent = function() {
	var parentNode = this.node.parentNode;	
	
	while (parentNode = parentNode.parentNode) {	
		if (parentNode.className == 'container__') {
			return new Container(parentNode);
		}
	}		
	return application;
}

/******************************************************************************************/

function NodeListWrapper(nodeList) {
	this.nodeList = nodeList;
}

NodeListWrapper.prototype.getLength = function() {
	return this.nodeList.length;
}

NodeListWrapper.prototype.item = function(n) {
	return application.wrapNode(this.nodeList[n]);
}

/******************************************************************************************/

function HTMLCollectionWrapper(collection) {
	this.collection = collection;
}

HTMLCollectionWrapper.prototype.getLength = function() {
	return this.collection.length;
}

HTMLCollectionWrapper.prototype.item = function(n) {
	return application.wrapNode(this.collection[n]);
}

HTMLCollectionWrapper.prototype.namedItem = function(str) {
	return application.wrapNode(this.namedItem(str));
}


/******************************************************************************************/

function EventWrapper(event) {
	this.event = event;
}

EventWrapper.prototype.getType = function() {
	var type = this.event.type;
	return type.indexOf("on") == 0 ? type.substring(2) : type;
}

EventWrapper.prototype.getTarget = function() {
	return application.wrapNode(this.event.target ? this.event.target : this.event.srcElement);
}

EventWrapper.prototype.stopPropagation = function() {
	if (this.event.stopPropagation) {
		this.event.stopPropagation();
	} else {
		this.event.cancelBubble = true;
	}
}

EventWrapper.prototype.preventDefault = function() {
	if (this.event.preventDefault) {
		this.event.preventDefault();
	}
	this.event.returnValue = false;
}

EventWrapper.prototype.isDefaultPrevented = function() {
	return this.event.returnValue==false;
}


EventWrapper.prototype.initEvent = function(type) {
	if (this.event.initEvent) {
		return this.event.initEvent(type, true, false);
	} else {
		this.event.type = 'on' + type;
	}
} 

/******************************************************************************************/


function HTMLiEvent() {

}

HTMLiEvent.prototype.getType = function() {
	return this.type;
}

HTMLiEvent.prototype.getTarget = function() {
	return this.target;
}

HTMLiEvent.prototype.stopPropagation = function() {

}

HTMLiEvent.prototype.preventDefault = function() {

}

HTMLiEvent.prototype.isDefaultPrevented = function() {
	return false;
}


HTMLiEvent.prototype.initHTMLiEvent = function(type, target) {
	this.type = type;
	this.target = target;
} 

/******************************************************************************************/




function UIEventWrapper(event) {
	this.event = event;
}

UIEventWrapper.prototype = new EventWrapper();

UIEventWrapper.prototype.initUIEvent = function(type) {
	if (this.event.initUIEvent) {
		return this.event.initUIEvent(type, true, window, 1);
	} else {
		this.event.type = 'on' + type;
	}	
}

/******************************************************************************************/

function MouseEventWrapper(event) {
	this.event = event;
}

MouseEventWrapper.prototype = new UIEventWrapper();

MouseEventWrapper.prototype.getScreenX = function() {
	return this.event.screenX;
}

MouseEventWrapper.prototype.getScreenY = function() {
	return this.event.screenY;
}	

MouseEventWrapper.prototype.getClientX = function() {
	return this.event.clientX;
}

MouseEventWrapper.prototype.getClientY = function() {
	return this.event.clientY;
}

MouseEventWrapper.prototype.getCtrlKey = function() {
	return this.event.ctrlKey;
}

MouseEventWrapper.prototype.getShiftKey = function() {
	return this.event.shiftKey;
}

MouseEventWrapper.prototype.getAltKey = function() {
	return this.event.altKey;
}

MouseEventWrapper.prototype.getMetaKey = function() {
	return this.event.metaKey;
}

/* @deprecated*/
MouseEventWrapper.prototype.getButtonKey = function() {
	var button = this.event.button;
	if (document.all) {
		return (button & 1) ? 0 : ((button & 2) ? 2: 1);	
	}
	
	return this.event.button;	
}

MouseEventWrapper.prototype.getButton = function() {
	var button = this.event.button;
	if (document.all) {
		return (button & 1) ? 0 : ((button & 2) ? 2: 1);	
	}	
	return this.event.button;	
}

MouseEventWrapper.prototype.initMouseEvent = function(type, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button) {
	if (this.event.initMouseEvent) {
		this.event.initMouseEvent(type, true, false, window, 1, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, null);
	} else {
		this.event.type = 'on' + type;
		this.event.altKey = altKey;
		this.event.ctrlKey = ctrlKey;
		this.event.shiftKey = shiftKey;
		this.event.metaKey = metaKey;
		this.event.button = button;
		this.event.clientX = clientX;
		this.event.clientY = clientY;
		this.event.screenX = screenX;
		this.event.screenY = screenY;
	}		
}

/******************************************************************************************/

function KeyboardEventWrapper(event) {
	this.event = event;
}

KeyboardEventWrapper.prototype = new UIEventWrapper();

KeyboardEventWrapper.prototype.getKeyCode = function() {
	return this.event.keyCode;
}

KeyboardEventWrapper.prototype.getCtrlKey = function() {
	return this.event.ctrlKey;
}

KeyboardEventWrapper.prototype.getShiftKey = function() {
	return this.event.shiftKey;
}

KeyboardEventWrapper.prototype.getAltKey = function() {
	return this.event.altKey;
}

KeyboardEventWrapper.prototype.getMetaKey = function() {
	return this.event.metaKey;
}

/* keyCode should be used on keydown and keyup, charCode on key press */
KeyboardEventWrapper.prototype.initKeyboardEvent = function(type, ctrlKey, altKey, shiftKey, metaKey, keyCode, charCode) {
   if (this.event.initKeyEvent) {
		this.event.initKeyEvent(type, true, false, window, ctrlKey, altKey, shiftKey, metaKey, keyCode, charCode);
	} else {
		this.event.type = 'on' + type;
		this.event.altKey = altKey;
		this.event.ctrlKey = ctrlKey;
		this.event.shiftKey = shiftKey;
		this.event.metaKey = metaKey;
		this.event.keyCode = keyCode ? keyCode : charCode;
	}		
}

/******************************************************************************************/

function NodeWrapper() {

};

NodeWrapper.prototype.getNodeName = function() {
	return this.outerNode.nodeName;
};

NodeWrapper.prototype.getNodeValue = function() {
	return this.innerNode.nodeValue;
};

NodeWrapper.prototype.setNodeValue = function(value) {
	this.innerNode.nodeValue = value;
};

NodeWrapper.prototype.getNodeType = function() {
	return this.outerNode.nodeType;
};
 
NodeWrapper.prototype.getParentNode = function() {
	return application.wrapInnerNode(this.outerNode.parentNode);
};

NodeWrapper.prototype.getChildNodes = function() {
	return new NodeListWrapper(this.innerNode.childNodes);
};

NodeWrapper.prototype.getFirstChild = function() {
	return application.wrapNode(this.innerNode.firstChild);
};

NodeWrapper.prototype.getLastChild = function() {
	return application.wrapNode(this.innerNode.lastChild);
};

NodeWrapper.prototype.getPreviousSibling = function() {
	return application.wrapNode(this.outerNode.previousSibling);
};

NodeWrapper.prototype.getNextSibling = function() {
	return application.wrapNode(this.outerNode.nextSibling);
};

NodeWrapper.prototype.insertBefore = function(newChild, refChild) {
	if (refChild) {
		return application.wrapNode(this.innerNode.insertBefore(newChild.outerNode, refChild.outerNode));
	}
	return application.wrapNode(this.innerNode.insertBefore(newChild.outerNode, null));	
};

NodeWrapper.prototype.replaceChild = function(newChild, oldChild) {
	return application.wrapNode(this.innerNode.replaceChild(newChild.outerNode, oldChild.outerNode));
};

NodeWrapper.prototype.removeChild = function(oldChild) {
	return application.wrapNode(this.innerNode.removeChild(oldChild.outerNode));
};

NodeWrapper.prototype.appendChild = function(newChild) {
	return application.wrapNode(this.innerNode.appendChild(newChild.outerNode));
};

NodeWrapper.prototype.hasChildNodes = function() {
	return this.innerNode.hasChildNodes();
};

NodeWrapper.prototype.cloneNode = function(deep) {
	return application.wrapNode(this.outerNode.cloneNode(deep));
};

function TextWrapper(text) {
	this.outerNode = this.innerNode = text;
}

TextWrapper.prototype = new NodeWrapper();

/******************************************************************************************/
 
function HTMLiElement(outerNode) {
	this.outerNode = outerNode;
	if (outerNode && outerNode.id) {
		var inner = document.getElementById(outerNode.id + '__inner');
		this.innerNode = inner ? inner : outerNode;		
	} else {
		this.innerNode = outerNode;
	}
}

HTMLiElement.prototype = new NodeWrapper();

HTMLiElement.prototype.init = function(node, className, tagName) {
	this.outerNode = node;
	this.className = className;
	this.tagName = tagName;
	this.innerNode = node;
}

HTMLiElement.prototype.getTagName = function() {
	return this.tagName;
}

HTMLiElement.prototype.getAttribute = function(name) {
	return this.outerNode.getAttribute(name);
}

HTMLiElement.prototype.setAttribute = function(name, value) {
	this.outerNode.setAttribute(name, value);
}

HTMLiElement.prototype.removeAttribute = function(name) {
	this.outerNode.removeAttribute(name);
}

HTMLiElement.prototype.getElementsByTagName = function(name) {
	return new NodeListWrapper(this.innerNode.getElementsByTagName(name));
}

HTMLiElement.prototype.getId = function() {
	return this.outerNode.id.replace(this.getPrefix(), "");
}

HTMLiElement.prototype.setId = function(id) {
	this.outerNode.id = this.getPrefix() + id;
}

HTMLiElement.prototype.getTitle = function() {
	return this.outerNode.title;
}

HTMLiElement.prototype.setTitle = function(title) {
	this.outerNode.title = title;
}

HTMLiElement.prototype.getLang = function() {
	return this.outerNode.lang;
}

HTMLiElement.prototype.setLang = function(lang) {
	this.outerNode.lang = lang;
}

HTMLiElement.prototype.getDir = function() {
	return this.outerNode.dir;
}

HTMLiElement.prototype.setDir = function(dir) {
	this.outerNode.dir = dir;
}

HTMLiElement.prototype.getClassName = function() {
	return this.outerNode.className;
}

HTMLiElement.prototype.setClassName = function(className) {
	this.outerNode.className = className;
}

HTMLiElement.prototype.getStyle = function() {
	return this.outerNode.style;
}

HTMLiElement.prototype.getClass = function() {
	return this.className;
}

HTMLiElement.prototype.addEventListener = function(type, listener, useCapture) {
	if (useCapture) {
		throw new Error("Microsoft Internet Explorer doesn't support useCapture");
	}
	
	listener._wrappedFunction = function(e) {
		listener(application.wrapEvent(e));
	};
	
	if (this.outerNode.addEventListener) {
		this.outerNode.addEventListener(type, listener._wrappedFunction, false);
	} else if (this.outerNode.attachEvent) {
		this.outerNode.attachEvent('on' + type, listener._wrappedFunction);
	} else {
		throw new Error("Your browser doesn't support DOM events");
	}
	
}

HTMLiElement.prototype.removeEventListener = function(type, listener, useCapture) {
	if (useCapture) {
		throw new Error("Microsoft Internet Explorer doesn't support useCapture");
	}
	
	if (this.outerNode.removeEventListener) {
		this.outerNode.removeEventListener(type, listener._wrappedFunction, false);
	} else if (this.outerNode.detachEvent) {
		this.outerNode.detachEvent('on' + type, listener._wrappedFunction);
	} else {
		throw new Error("Your browser doesn't support DOM events");
	}
}

HTMLiElement.prototype._addEventListenerFor = function(event, func) {
	if (!this.outerNode._listeners) {
		this.outerNode._listeners = new Array();
	}
		
	if (!this.outerNode._listeners[event]) {
		this.outerNode._listeners[event] = new Array();
	}
			
	this.outerNode._listeners[event][this.outerNode._listeners[event].length] = func;
};

HTMLiElement.prototype.dispatchEvent = function(event)  {
	if (this.outerNode.dispatchEvent) {
		this.outerNode.dispatchEvent(event.event);
	} else if (this.outerNode.fireEvent) {
		this.outerNode.fireEvent('on' + event.getType(), event.event);
	}
}

HTMLiElement.prototype.getContainer = function() {
	return application.getContainerFor(this.outerNode);
}

HTMLiElement.prototype.getPrefix = function() {
	var container = this.getContainer();
	return container? container.getPrefix() : null;	
}

HTMLiElement.prototype.getIndex = function() {
	try {
		return this.outerNode.id.split('[')[1].split(']')[0];
	} catch (e) {
		return 0;
	}
}

HTMLiElement.prototype.getInnerHTML = function() {
	return this.innerNode.innerHTML;	
}

HTMLiElement.prototype.setInnerHTML = function(value) {
	this.innerNode.innerHTML = value;	
}

// DEPRECATED !!!
//  if the node has position absolute set by a class or other css selector, it doesn't work
HTMLiElement.prototype.getOffsetParent = function() {
	var node = this.outerNode.parentNode;
	
	while (node != null) {
		if (node.style && node.style.position == 'absolute') {
			return application.wrapNode(node);
		}
		node = node.parentNode;
	}
	return application.wrapNode(document.documentElement);
}

HTMLiElement.prototype.getContainingBlock = function() {
	var node = this.outerNode.parentNode;
	
	if (document.defaultView) {
		var view = document.defaultView;
		while (node != null && node != document) {
			var position = view.getComputedStyle(node, '').getPropertyValue("position");
			if (position == 'absolute' || position == 'relative') {
				return application.wrapNode(node);
			}		
			node = node.parentNode;
		}	
	} else {
		while (node != null && node != document) {
			var position = node.currentStyle.position;
			if (position == 'absolute' || position == 'relative') {
				return application.wrapNode(node);
			}		
			node = node.parentNode;
		}	
	}
	
	return application.wrapNode(document.documentElement);
}

HTMLiElement.prototype.getRelativeX = function() {
	return this.getX() - this.getContainingBlock().getX();
}

HTMLiElement.prototype.getX = function() {
	if (document.getBoxObjectFor) {
		return document.getBoxObjectFor(this.outerNode).x;
	} else if (this.outerNode.getBoundingClientRect) {
		return this.outerNode.offsetLeft + (this.outerNode.offsetParent ? application.wrapNode(this.outerNode.offsetParent).getX() : 0);
	}
}

HTMLiElement.prototype.getRelativeY = function() {
	return this.getY() - this.getContainingBlock().getY();
}

HTMLiElement.prototype.getY = function() {
	if (document.getBoxObjectFor) {
		return document.getBoxObjectFor(this.outerNode).y;
	} else if (this.outerNode.getBoundingClientRect) {
		return this.outerNode.offsetTop + (this.outerNode.offsetParent ? application.wrapNode(this.outerNode.offsetParent).getY() : 0);
	}
}


HTMLiElement.prototype.getWidth = function() {
	if (document.getBoxObjectFor) {
		return document.getBoxObjectFor(this.outerNode).width;
	} else if (this.outerNode.getBoundingClientRect) {
		return this.outerNode.getBoundingClientRect().right - this.outerNode.getBoundingClientRect().left;
	}
}

HTMLiElement.prototype.getHeight = function() {
	if (document.getBoxObjectFor) {
		return document.getBoxObjectFor(this.outerNode).height;
	} else if (this.outerNode.getBoundingClientRect) {
		return this.outerNode.getBoundingClientRect().bottom - this.outerNode.getBoundingClientRect().top;
	}
}

HTMLiElement.prototype.center = function() {	
	var style = this.outerNode.style;
	var containingBlock = this.getContainingBlock();
	
	if (document.getBoxObjectFor) {
		// TODO
	//	style.top = (me.getOffsetParent().getHeight() / 2 - this.getHeight() / 2) + 'px';
	//	style.left = (me.getOffsetParent().getWidth() / 2 - this.getWidth() / 2) + 'px';
	} else if (this.outerNode.getBoundingClientRect) {
		var htmlElement = application.getDocumentElement();
		style.top = (htmlElement.getHeight() / 2 - this.getHeight() / 2 - containingBlock.getY() + document.documentElement.scrollTop)  + 'px';
		style.left = (htmlElement.getWidth() / 2 - this.getWidth() / 2 - containingBlock.getX() + document.documentElement.scrollLeft) + 'px';
	}
	
}

/*
HTMLiElement.prototype.resizeTo = function(width, height, speed) {
	var style =	this.outerNode.style;
	
	if (height != null) {
		style.height = (!style.height ? this.getHeight() : style.pixelHeight-5) + "px";
	}
	
	if (width != null) {
		style.width = (!style.width ? this.getWidth() : style.pixelHeight-5) + "px";
	}	
	
	var obj = this;
	setTimeout(function() {
		obj.resizeTo(width, height);
	}, speed ? speed : 25);
}*/


HTMLiElement.prototype.addHeight = function(pixels, style) {
	return this.changeHeight('add', pixels, style);
}

HTMLiElement.prototype.subHeight = function(pixels, style) {
	return this.changeHeight('sub', pixels, style);
}

HTMLiElement.prototype.changeHeight = function(method, pixels, style) {
	if (!style) {
		style = this.getStyle();
	}
	var newHeight = 0;
	if (!pixels) {
		pixels = 20;
	}
	if (method=='add') {
		newHeight = new Number(style.height.substring(0, style.height.indexOf("px"))) + pixels;
	}
	else if (method=='sub') {
		newHeight = new Number(style.height.substring(0, style.height.indexOf("px"))) - pixels;
	}
	if (newHeight<0) {
		newHeight = 0;
	}
	style.height = newHeight + 'px';
	return newHeight;
}


HTMLiElement.prototype.fadeIn = function(style) {
	if (style == null) {
		style = this.getStyle();
	}

	if(typeof(style.filter) == 'undefined') {
		style.MozOpacity = .99;
	} else {
		style.filter="alpha(opacity=100)";
	}
}

HTMLiElement.prototype.fadeOut = function(style) {
	if (style == null) {
		style = this.getStyle();
	}

	if(typeof(style.filter) == 'undefined') {
		style.MozOpacity = .00;
	} else {
		style.filter="alpha(opacity=0)";		
	}
}

HTMLiElement.prototype.fadeInBy = function(step, style) {
	return this.fade('in', step, style);
}

HTMLiElement.prototype.fadeOutBy = function(step, style) {
	return this.fade('out', step, style);
}

HTMLiElement.prototype.fade = function(method, step, style) {
	if (style == null) {
		style = this.getStyle();
	}
	var newFade = 0;
	if (!step) step = 2;
	newFade = this.getFade();
	if (method=='in') {
		newFade = newFade? parseFloat(newFade) + step : step;
	}
	else if (method=='out') {
		newFade = newFade? parseFloat(newFade) - step : 100-step;
	}
	if (newFade<0) {
		newFade = 0;
	}
	if (typeof(style.filter) == 'undefined') {
		style.MozOpacity = newFade/100;
	} else {
		style.filter="alpha(opacity="+ newFade +")";
	}
	return newFade;
}


HTMLiElement.prototype.getFade = function() {
	var	style = this.getStyle();
	var fade;
	if (typeof(style.filter) == 'undefined') {
		fade = style.MozOpacity * 100;
	}
	else {
		fade = style.filter? parseInt(style.filter.substring(style.filter.indexOf("=")+1, style.filter.lastIndexOf(")"))): 0;
	}
	return fade;
}

/******************************************************************************************/

function HTMLElementWrapper(node) {
	this.innerNode = node;
	this.outerNode = node;
}

HTMLElementWrapper.prototype = new HTMLiElement();

HTMLElementWrapper.classes = new Array();

/******************************************************************************************/

function HttpRequest() {
	
}

HttpRequest.create = function() {
	try {
		var o = new XMLHttpRequest();
		return o;
	} catch (e) {		
	}
	
	
	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
	for (var i=0; i < prefixes.length; i++) {
		try {
			var o = new ActiveXObject(prefixes[i] + ".XmlHttp");
			return o;
		} catch (e) {		
		}	
	} 	
}

/******************************************************************************************/

function XmlDocument() {

}

XmlDocument.create = function() {
	if (document.implementation && document.implementation.createDocument) {
		var doc = document.implementation.createDocument("", "", null);
		if (doc.readyState == null) {
			doc.readyState = 1;
			doc.addEventListener("load", function () {
				doc.readyState = 4;
			if (typeof doc.onreadystatechange == "function")
					doc.onreadystatechange();
			}, false);
		}
		return doc;
	}  else { 
		try {
			var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
			for (var i = 0; i < prefixes.length; i++) {
				try {
					var o = new ActiveXObject(prefixes[i] + ".DomDocument");
					o.setProperty("SelectionLanguage", "XPath");				
					return o;					
				} catch (ex) {}
			}
		} catch (e) {} 
	}
}


if (window.DOMParser &&	window.XMLSerializer &&	window.Node && Node.prototype && Node.prototype.__defineGetter__) {
	XMLDocument.prototype.loadXML = Document.prototype.loadXML = function (s) {
		var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
		while (this.hasChildNodes())
			this.removeChild(this.lastChild);
		for (var i = 0; i < doc2.childNodes.length; i++) {
			this.appendChild(this.importNode(doc2.childNodes[i], true));
		}

	};

	XMLDocument.prototype.selectSingleNode = Document.prototype.selectSingleNode = function(xpath) {
		var result = this.evaluate(xpath, this, null, XPathResult.SINGLE_NODE_TYPE, null);
		if (item = result.iterateNext()) {
			return item;
		}
		return null;
	};


	XMLDocument.prototype.selectNodes = Document.prototype.selectNodes = function(xpath) {

		var nodes = new Array();
		var result = this.evaluate(xpath, this, null, XPathResult.ANY_TYPE, null);
		var i = 0;

		while(item = result.iterateNext()) {
			nodes[i++] = item;

		}		

		return nodes;
	};

	XMLDocument.prototype.transformNode = Element.prototype.transformNode = function(xslt) {
		var processor = new XSLTProcessor();
		processor.importStylesheet(xslt);
		
		// FIXME improve this patch
		/*var doc = document.createElement('div');
		alert(xslt.xml);
		var root = processor.transformToDocument(this).documentElement;
		alert(processor.transformToDocument(this).xml);
		var m = root.childNodes.length;
		for (var i=0; i < m; i++) {
			doc.appendChild(root.childNodes[0]);
		}
		alert(doc.innerHTML);
		return doc.innerHTML;*/
		
		var doc = document.createElement('div');
		doc.appendChild(processor.transformToDocument(this).documentElement);
		return doc.innerHTML;
	};

	XMLDocument.prototype.__defineGetter__("xml", function () {
		return (new XMLSerializer()).serializeToString(this);
	});
	
	HTMLDocument.prototype.__defineGetter__("xml", function () {
		return (new XMLSerializer()).serializeToString(this);
	});
	
	HTMLElement.prototype.__defineGetter__("outerHTML", function () {
		var attrs = this.attributes;
 		var str = "<" + this.tagName;
		for (var i = 0; i < attrs.length; i++) {
			str += " " + attrs[i].name + "=\"" + attrs[i].value + "\"";
		}
		return str + ">" + this.innerHTML + "</" + this.tagName + ">";
	});	
}




