var valuadder;
if (!valuadder) valuadder = {};

valuadder.listenEvents = function(node, event, listener) {
	if (!node)
		node = document;
	
	if (node.addEventListener)
		node.addEventListener(event, listener, true);
	else if (node.attachEvent)
		node.attachEvent("on" + event, listener);
	else
		throw new Error("Unsupported event model");
}

valuadder.listenEventsWithMethod = function(node, event, object, method) {
	listenEvents(node, event, function() {
		method.call(object);
	});
}

valuadder.runOnLoad = function(f) {
	if (valuadder.runOnLoad.loaded) f();
	else valuadder.runOnLoad.funcs.push(f);
}
valuadder.runOnLoad.funcs = [];
valuadder.runOnLoad.loaded = false;
valuadder.runOnLoad.run = function() {
	if (valuadder.runOnLoad.loaded) return;
	
	var funcs = valuadder.runOnLoad.funcs;
	for (var i = 0; i < funcs.length; i++) {
		funcs[i]();
	}
	
	valuadder.runOnLoad.loaded = true;
	delete valuadder.runOnLoad.funcs;
	delete valuadder.runOnLoad.run;
};
valuadder.listenEvents(window, "load", valuadder.runOnLoad.run);

valuadder.isDescendantOf = function(node, ancestor) {
	for (var e = node.parentNode; e; e = e.parentNode)
		if (e == ancestor)
			return true;
	
	return false;
}

valuadder.getAbsoluteX = function(node, relativeTo) {
	var x = 0;
	
	if (!relativeTo)
		relativeTo = document.body;
	else if (!valuadder.isDescendantOf(node, relativeTo))
		throw new Error("Node " + node + " is not a descendant of " + relativeTo);
	
	for (var e = node; e && valuadder.isDescendantOf(e, relativeTo); e = e.offsetParent)
		x += e.offsetLeft;
	
	for (e = node.parentNode; e && e != relativeTo; e = e.parentNode)
		if (e.scrollLeft)
			x -= e.scrollLeft;
	
	return x;
}

valuadder.getAbsoluteY = function(node, relativeTo) {
	var y = 0;
	
	if (!relativeTo)
		relativeTo = document.body;
	else if (!valuadder.isDescendantOf(node, relativeTo))
		throw new Error("Node " + node + " is not a descendant of " + relativeTo);
	
	for (var e = node; e && valuadder.isDescendantOf(e, relativeTo); e = e.offsetParent)
		y += e.offsetTop;
	
	for (e = node.parentNode; e && e != relativeTo; e = e.parentNode)
		if (e.scrollTop)
			y -= e.scrollTop;
	
	return y;
}

valuadder.isInClass = function(node, c) {
	if (!node.className)
		return false;
	else if (node.className == c)
		return true;
	else
		return node.className.search("(^|\\s)" + c + "($|\\s)") != -1;
}

valuadder.addClass = function(node, c) {
	if (valuadder.isInClass(node, c))
		return;
	else if (node.className)
		node.className += " " + c;
	else
		node.className = c;
}

valuadder.removeClass = function(node, c) {
	if (node.className)
		node.className.replace(new RegExp("(^|\\s+)" + c + "($|\\s+)", "g"), "");
}

valuadder.getElementsByClass = function(node, className, tagName) {
	if (!node)
		node = document;
	if (!tagName)
		tagName = "*";
	
	var all = node.getElementsByTagName(tagName);
	
	if (!className)
		return all;
	
	var elements = [];
	
	for (var i = 0; i < all.length; i++) {
		var element = all[i];
		if (valuadder.isInClass(element, className))
			elements.push(element);
	}
	
	return elements;
}

valuadder.runOnLoad(function() {
	var buttons = valuadder.getElementsByClass(document, "button");
	
	for (var i = 0; i < buttons.length; i++) {
		var button = buttons[i];
		
		if (
			i == 0 &&
			(button.style.borderRadius != undefined || button.style.MozBorderRadius != undefined || button.style.WebkitBorderRadius != undefined) &&
			(button.style.boxShadow != undefined || button.style.MozBoxShadow != undefined || button.style.WebkitBoxShadow != undefined)
		)
			return;
		
		var doc = button.ownerDocument ? button.ownerDocument : document;
		
		valuadder.addClass(button, "button-compat");
		
		var edgeLeft = doc.createElement("div");
		edgeLeft.className = "button-edge-left";
		var edgeRight = doc.createElement("div");
		edgeRight.className = "button-edge-right";
		var content = doc.createElement("div");
		content.className = "button-content";
		
		while (button.firstChild != null) {
			var node = button.firstChild;
			button.removeChild(node);
			content.appendChild(node);
		}
		
		button.appendChild(edgeLeft);
		button.appendChild(edgeRight);
		button.appendChild(content);
	}
});

valuadder.TransBox = function(node) {
	if (!node)
		throw new Error("new TransBox called with no node");
	
	this.node = node;
	
	valuadder.addClass(node, "transbox-compat");
	
	var compatEffects;
	if (node.ownerDocument)
		compatEffects = node.ownerDocument.createElement("div");
	else
		compatEffects = document.createElement("div");
	valuadder.addClass(compatEffects, "transbox-compat-effects");
	node.appendChild(compatEffects);
	this.compatEffects = compatEffects;
	
	var createEffect = function(c) {
		var doc;
		
		if (node.ownerDocument)
			doc = node.ownerDocument;
		else
			doc = document;
		
		var e = doc.createElement("div");
		e.className = "transbox-compat-" + c;
		
		compatEffects.appendChild(e);
		
		return e;
	};
	
	this.effectBackground = createEffect("background");
	this.effectTop = createEffect("top");
	this.effectLeft = createEffect("left");
	this.effectTopLeft = createEffect("top-left");
	this.effectBottomLeft = createEffect("bottom-left");
	this.effectBottom = createEffect("bottom");
	this.effectBottomRight = createEffect("bottom-right");
	this.effectRight = createEffect("right");
	this.effectTopRight = createEffect("top-right");
	this.updatePositions();
};

valuadder.TransBox.prototype.updatePositions = function() {
	var x = valuadder.getAbsoluteX(this.node);
	var y = valuadder.getAbsoluteY(this.node);
	var w = this.node.offsetWidth;
	var h = this.node.offsetHeight;
	
	this.effectLeft.style.height = this.effectRight.style.height = (h - 44) + "px";
	this.effectTop.style.width = this.effectBottom.style.width = (w - 44) + "px";
	this.effectBackground.style.width = (w - 44) + "px";
	this.effectBackground.style.height = (h - 44) + "px";
};

valuadder.runOnLoad(function() {
	var elements = document.body.getElementsByTagName("*");
	var checkedNativeSupport = false;
	
	for (var i = 0; i < elements.length; i++) {
		if (valuadder.isInClass(elements[i], "transbox")) {
			if (!checkedNativeSupport) {
				if (elements[i].style.borderImageSource != undefined || elements[i].style.MozBorderImage != undefined || elements[i].style.WebkitBorderImage != undefined)
					return;
				else
					checkedNativeSupport = true;
			}
			
			new valuadder.TransBox(elements[i]);
		}
	}
});