/**
 * @author tfuhlroth maxomedia - agentur für crossmedia-kommunikation bsw
 */

/* -------------------------------------------------- */
/* =Console */

if (!$defined(window['console'])) window.console = { log: $empty };


/* -------------------------------------------------- */
/* =Events */

Events.implement({
	
	relayEvent: function (type, targetType, bind) {
		if (arguments.length === 2) { // type and targetType are the same
			bind = arguments[1];
			targetType = arguments[0];
		}
		this.addEvent(type, function () {
			bind.fireEvent(targetType, arguments);
		}.bind(bind));
	}
	
});


/* -------------------------------------------------- */
/* =Array */

Array.implement({
	
	shuffle: function () {
		if (this.length > 1) {
			var results = [];
			while (this.length) {
				var index = $random(0, this.length - 1);
				results.push(this[index]);
				this.splice(index, 1);
			}
			this.combine(results);
		}
		return this;
	}
	
});


/* -------------------------------------------------- */
/* =String */

(function () {
	
	var charTable = {
		'-': [' '],
		'': ['.'],
		'a': ['&aacute;', '&agrave;', '&acirc;', '&atilde;'],
		'ae': ['&auml;'],
		'c': ['&ccedil;'],
		'e': ['&euml;', '&eacute;', '&egrave;', '&ecirc;'],
		'i': ['&iuml;', '&iacute;', '&igrave;', '&icirc;'],
		'o': ['&oacute;', '&ograve;', '&ocirc;', '&otilde;'],
		'oe': ['&ouml;'],
		'u': ['&uacute;', '&ugrave;', '&ucirc;'],
		'ue': ['&uuml;'],
		'ss': ['&szlig;']
	};
	/*var charTable = {
		'-': [' '],
		'': ['.'],
		'a': ['á', 'à', 'â', 'ã'],
		'ae': ['ä'],
		'c': ['ç'],
		'e': ['ë', 'é', 'è', 'ê'],
		'i': ['ï', 'í', 'ì', 'î'],
		'o': ['ó', 'ò', 'ô', 'õ'],
		'oe': ['ö'],
		'u': ['ú', 'ù', 'û'],
		'ue': ['ü'],
		'ss': ['ß']
	};*/
	
	var newCharTable = new Hash({});
	new Hash(charTable).forEach(function (value, key) {
		value.forEach(function (char) {
			newCharTable.include(char, key);
		});
	}, this);
	charTable = newCharTable;
	
	
	String.implement({
		
		getSlug: function () {
			return this.replace(new RegExp('[' + charTable.getKeys().join('') + ']', 'g'), function (str) {
				return charTable[str];
			});
		}
		
	});
	
	
})();


/* -------------------------------------------------- */
/* =Dictionary */

var Dict = new Class({
	
	Implements: Events,
	
	initialize: function (dictJSON) {
		this.items = new Hash(dictJSON);
		this.fireEvent('complete');
	},
	
	get: function (key) {
		return (this.items.has(key)) ? this.items.get(key) : '[' + key + ']';
	}
	
});


Dict.Remote = new Class({
	
	Extends: Dict,
	
	initialize: function (serviceurl) {
		new Request({
			url: serviceurl,
			async: false,
			onSuccess: this.parse.bind(this)
		}).send();
	},
	
	parse: function (responseText, responseXML) {
		this.items = new Hash();
		var items = responseXML.getElementsByTagName('item');
		for (var i = 0, len = items.length; i < len; i++) {
			this.items.include(items[i].getAttribute('key'), this.getNodeValue(items[i]));
		}
	},
	
	getNodeValue: function (node) {
		if (node.textContent) return node.textContent;
		else if (node.nodeValue) return node.nodeValue;
		else if (node.text) return node.text;
	}
	
});


/* -------------------------------------------------- */
/* =Math.Vector */

Math.Vector = {
	add: function (vector1, vector2) {
		return new Vector(vector1.x + vector2.x, vector1.y + vector2.y, vector1.z + vector2.z);
	},
	subtract: function (vector1, vector2) {
		return new Vector(vector1.x - vector2.x, vector1.y - vector2.y, vector1.z - vector2.z);
	},
	scale: function (vector, scalar) {
		return new Vector(vector.x * scalar, vector.y * scalar, vector.z * scalar);
	},
	normalize: function (vector) {
		return (new Vector(vector.x, vector.y, vector.z)).normalize();
	},
	dotProduct: function (vector1, vector2) {
		return vector1.x * vector2.x + vector1.y * vector2.y + vector1.z * vector2.z;
	},
	crossProduct: function (vector1, vector2) {
		return new Vector(vector1.y * vector2.z - vector2.y * vector1.z, vector2.x * vector1.z - vector1.x * vector2.z, vector1.x * vector2.y - vector2.x * vector1.y);
	},
	project: function (vector1, vector2) {
		var scalar = Math.Vector.dotProduct(vector2, vector2);
		if (scalar) return Math.Vector.scale(vector2, Math.Vector.dotProduct(vector1, vector2) / scalar);
		return new Math.Vector();
	},
	component: function (vector1, vector2) {
		return Math.Vector.dotProduct(vector1, Math.Vector.normalize(vector2));
	},
	perpendicular: function (vector1, vector2) {
		return Math.Vector.subract(vector1, Math.Vector.project(vector1, vector2));
	}
};


var Vector = new Class({
	initialize: function (x, y, z) {
		this.x = isNaN(x) ? 0 : x;
		this.y = isNaN(y) ? 0 : y;
		this.z = isNaN(z) ? 0 : z;
	},
	clone: function () {
		return new Vector(this.x, this.y, this.z);
	},
	add: function (vector) {
		this.x += vector.x;
		this.y += vector.y;
		this.z += vector.z;
		return this;
	},
	subtract: function (vector) {
		this.x -= vector.x;
		this.y -= vector.y;
		this.z -= vector.z;
		return this;
	},
	scale: function (scalar) {
		this.x *= scalar;
		this.y *= scalar;
		this.z *= scalar;
		return this;
	},
	length: function () {
		return Math.sqrt(this.x * this.x + this.y * this.y + this.z + this.z);
	},
	isZero: function () {
		return (this.x || this.y || this.z) ? false : true;
	},
	normalize: function () {
		var length = this.x * this.x + this.y * this.y + this.z * this.z;
		if (length && Math.abs(length - 1) > 0.01) {
			length = Math.sqrt(length);
			this.x /= length;
			this.y /= length;
			this.z /= length;
		}
		return this;
	}
});