//	mootools.js: moo javascript tools
//	by Valerio Proietti (http://mad4milk.net) MIT-style license.
	
//  CREDITS:

//	Class is based on Base.js : http://dean.edwards.name/weblog/2006/03/base/
//		(c) 2006 Dean Edwards, License: http://creativecommons.org/licenses/LGPL/2.1/

//	Some functions are based on those found in prototype.js : http://prototype.conio.net/
//		(c) 2005 Sam Stephenson <sam@conio.net>, MIT-style license


//Class.js : My Object Oriented javascript. Has no dependancies

var Class = function(properties){
	if (properties) {
		return this.extend(properties);
	} else {
		var klass = function(){
			if (!Class.prototyping && this.initialize) this.initialize.apply(this, arguments);
		};
		klass.extend = this.extend;
		klass.implement = this.implement;
		return klass;
	}
};

Class.create = function(properties){
	return new Class(properties);
};

Class.prototype = {
	implement: function(properties){
		for (property in properties) this.prototype[property] = properties[property];
	},
	
	extend: function(properties){
		if (this.prototype) {
			Class.prototyping = true;
			var prototype = new this;
			Class.prototyping = false;
			for (property in properties){
				var previousValue = prototype[property];
				var currentValue = properties[property];
				if (previousValue) currentValue = previousValue.parentize(properties[property]) || currentValue;
				prototype[property] = currentValue;
			}
			properties = prototype;
		}
		var klass = new Class;
		klass.prototype = properties;
		return klass;
	}
};

var Native = function(obj){
	obj.extend = Class.prototype.implement;
};

new Native(Function);
new Native(Array);
new Native(String);

Function.extend({
	parentize: function(current){
		if (current.parentize && this.valueOf() != current.valueOf() && /\bparent\b/.test(current)){
			var previous = this;
			var method = current;
			current = function() {
				this.parent = previous;
				return method.apply(this, arguments);
			};
			current.valueOf = function() {
				return method;
			};
			return current;
		}
	}
});

//Object.js : object functions. Has no dependancies

Object.extend = function(){
	if (arguments.length == 1){
		var destination = this;
		var source = arguments[0];
	} else {
		var destination = arguments[0];
		var source = arguments[1];
	}
	for (property in source) destination[property] = source[property];
	return destination;
};

Object.toQueryString = function(source){
	var queryString = [];
	for (property in source) queryString.push(property+'='+source[property]);
	return queryString.join('&');
};

//Function.js : Function extension. Depends on Class.js

Function.extend({
		
	bind: function(object){
		var __method = this;
		return function(){
			return __method.apply(object, arguments);
		}
	},
	
	bindAsEventListener: function(object){
		return function(event){
			this.call(object, event || window.event);
			return false;
		}.bind(this);
	},
	
	later: function(secs, bind){
		var bind = bind || this;
		return setTimeout(this.bind(bind), secs*1000);
	},
	
	periodical: function(secs, bind){
		var bind = bind || this;
		return setInterval(this.bind(bind), secs*1000);
	}

});

clearPeriodical = function(interval){
	clearInterval(interval);
	return null;
};

clearLater = function(timeout){
	clearTimeout(timeout);
	return null;
};

//Array.js : Array extension. Depends on Class.js

Array.extend({
	
	each: function(func){
		for(var i=0;ob=this[i];i++) func(ob, i);
	},
	
	copy: function(){
		var nArray = [];
		for (i=0;el=this[i];i++) nArray.push(el);
		return nArray;
	},
	
	remove: function(item){
		for (i=0;myItem=this[i];i++) {
			if (myItem == item) this.splice(i, 1);
		}
	},
	
	test: function(item){
		for (i=0;myItem=this[i];i++) {
			if (myItem == item) return true;
		}
		return false;
	},
	
	extend: function(nArray){
		nArray.each(function(el){
			this.push(el);
		}.bind(this));
	}
	
});

function $c(array){
	return Array.prototype.copy.call(array);
};

//String.js : String extension. Depends on Class.js

String.extend({
	
	trim: function(){
		return this.replace(/^\s*|\s*$/g,'');
	},
	
	test: function(val){
		if (this.indexOf(val) > -1) return true;
		else return false;
	},
	
	camelCase: function(){
		return this.replace(/-\D/gi, function(sMatch){
			return sMatch.charAt(sMatch.length - 1).toUpperCase();
		});
	},
	
	toHex: function(){
		var N = parseInt(this);
		if (N==0 || isNaN(N)) return "00";
		N = Math.round(Math.min(Math.max(0,N),255));
		return "0123456789ABCDEF".charAt((N-N%16)/16) + "0123456789ABCDEF".charAt(N%16);
	},
	
	rgbToHex: function(){
		var rgb = this.slice(4,(this.length)-1).split(',');
		return rgb[0].toHex()+rgb[1].toHex()+rgb[2].toHex();
	}
	
});

//Element.js : Element methods. Depends on level 1 scripts

var Element = new Class({
	
	classNames: [],
	
	remove: function(){
		this.parentNode.removeChild(this);
	},
	
	readClassName: function(){
		this.classNames = this.className.trim().split(' ');
		this.classNames.each(function(name){
			name = name.trim();
		});
	},
	
	writeClassName: function(){
		this.className = this.classNames.join(' ');
		this.readClassName();
	},
	
	hasClassName: function(className){
		className = className.trim();
		this.readClassName();
		return this.classNames.test(className);
	},
	
	addClassName: function(className){
		if (!this.hasClassName(className)) {
			this.classNames.push(className);
			this.writeClassName();
		}
	},
  
	removeClassName: function(className){
		if (this.hasClassName(className)) {
			this.classNames.remove(className);
			this.writeClassName();
		}
	},
	
	toggleClassName: function(className){
		if (this.hasClassName(className)) this.removeClassName(className);
		else this.addClassName(className);
	},
	
	setStyle: function(property, value){
		if (property == 'opacity') this.setOpacity(value);
		else this.style[property.camelCase()] = value;
	},
	
	setOpacity: function(opacity){
		if (opacity == 0 && this.style.visibility != "hidden") this.style.visibility = "hidden";
		else if (this.style.visibility != "visible") this.style.visibility = "visible";
		if (window.ActiveXObject) this.style.filter = "alpha(opacity=" + opacity*100 + ")";
		this.style.opacity = opacity;
	},
	
	setStyles: function(source){
		for (property in source) this.setStyle(property, source[property]);
	},
	
	removeStyles: function(){
		$c(arguments).each(function(property){
			this.style[property.camelCase()] = '';
		}.bind(this));
	},
	
	readStyle: function(property, integer){
		if (document.defaultView){
			var sty = document.defaultView.getComputedStyle(this,null).getPropertyValue(property);
			if (sty.test('rgb(') || sty.test('rgba(')) return sty.rgbToHex();
			else return sty;
		}
		else if (this.currentStyle) return this.currentStyle[property.camelCase()];
		else return false;
	},
	
	addEvent: function(action, fn){
		if (this.addEventListener) {
			this.addEventListener(action, fn, false);
			if (this != window) Memory.events.push([this, action, fn]);
		} else {
			this[action+fn] = fn.bind(this);
			this.attachEvent('on'+action, this[action+fn]);
			if (this != window) Memory.events.push([this, action, this[action+fn], true]);
		}
	},
	
	removeEvent: function(action, fn){
		if (this.removeEventListener) this.removeEventListener(action, fn, false);
		else this.detachEvent('on'+action, this[action+fn]);
	}
});

new Native(Element);

function $(el){
	if (el){
		if (typeof el == 'string') el = document.getElementById(el);
		if (!el.extend){
			el.extend = Object.extend;
			el = el.extend(new Element);
			Memory.elements.push(el);
		}
		return el;
	}
};

//garbage collector

var Memory = { elements: [], events: [], functions: [] };

window.addEvent = Element.prototype.addEvent;
window.removeEvent = Element.prototype.removeEvent;

window.removeFunction = function(){
	Memory.functions.each(function(fn){
		fn();
	});
	
	Memory.events.each(function(ar){
		ar[0].removeEvent(ar[1], ar[2]);
		if (ar[3]) ar[0][ar[1]+ar[2]] = null;
	});
	
	Memory.elements.each(function(el){
		for(p in Element.prototype) el[p] = null;
		for(p in el.effect) el.effect[p] = null;
		el.extend = null;
	});
	
	window.removeEvent('unload', window.removeFunction);
	window.removeFunction = null;
};

window.addEvent('unload', window.removeFunction);