/*
	Extending MooTools natives
*/
Element.implement({
	center: function(opts) {
		opts = opts || {};
		var coords = {
			self: this.getCoordinates(),
			win: window.getCoordinates()
		};
		var
			newTop = ((coords.win.height / 2) - (coords.self.height / 2) + window.getScroll().y),
			newLeft = ((coords.win.width / 2) - (coords.self.width / 2) + window.getScroll().x);
		newTop = newTop < 10 ? 10 : newTop;
		newLeft = newLeft < 10 ? 10 : newLeft;
		if(!$type(opts.top) || opts.top === true)
			this.setStyle('top', newTop + 'px');
		if(!$type(opts.left) || opts.left === true)
			this.setStyle('left', newLeft + 'px');
		return this;
	},
	
	hovering: function() {
		var attributes = {
			coords: this.getCoordinates(),
			pos: this.getPosition()
		}, scroll = window.getScroll();
		attributes.pos = {
			x: attributes.pos.x - scroll.x,
			y: attributes.pos.y - scroll.y
		};
		if(
			(mouse.x >= attributes.pos.x && mouse.x <= attributes.pos.x + attributes.coords.width) &&
			(mouse.y >= attributes.pos.y && mouse.y <= attributes.pos.y + attributes.coords.height)
		)
			return true;
		return false;
	},
	
	/*
		this function returns the element
		before doing so, an id is assigned to the element if it does not already have one
	*/
	identify: function() {
		if(!$type(this.get('id')))
			this.id = incrementID(0);
		return this;
		
		function incrementID(num) {
			num++;
			if(!$type($(num.toString())))
				return num;
			return incrementID(num);
		}
	},
	
	/*
		for element-based loader
	*/
	loading: function() {
		if(!$chk(this.retrieve('loadCount')))
			this.store('loadCount', 0);
		this.store('loadCount', this.retrieve('loadCount') + 1);
		if(this.retrieve('loadCount') === 1) {
			var div = new Element('div')
				.addClass('element-loader')
				.inject(document.body)
				.setStyles(this.getCoordinates());
			this.store('loadContainer', div);
		}
		return this;
	},
	
	/*
		for element-based loader
	*/
	loaded: function() {
		if(!$chk(this.retrieve('loadCount')))
			this.store('loadCount', 0);
		this.store('loadCount', this.retrieve('loadCount').toInt() - 1);
		if(this.retrieve('loadCount').toInt() === 0) {
			this
				.retrieve('loadContainer')
				.dispose();
			this.eliminate('loadContainer');
		}
		return this;
	},
	
	/*
		used to check if element is loading
	*/
	isLoading: function() {
		return (!$chk(this.retrieve('loadCount'))) ? false :
			(this.retrieve('loadCount').toInt() > 0) ? true : false;
	},
	
	/*
		applies shim
	*/
	shim: function() {
		try {
			this
				.retrieve('shim')
				.position()
				.show();
		} catch(err) { }
		return this;
	},
	
	/*
		hides shim
	*/
	unshim: function() {
		try {
			this
				.retrieve('shim')
				.hide();
		} catch(err) { }
		return this;
	},
	
	/*
		like hasChild, but checks for a parent element
	*/
	hasParent: function(sel) {
		var el = this.getParent(sel);
		return ($type(el) === false) ? el : true;
	}
});

String.implement({
	/*
		checks if string is empty
		''		=>	true
		'    '	=>	false
	*/
	empty: function() {
		return this.length === 0;
	},
	
	/*
		checks if string is blank
		''		=>	true
		'    '	=>	true
	*/
	blank: function() {
		return this.trim().length === 0;
	}
});

Array.implement({
	/*
		sorts without comparing cases
		['a', 'c', 'B'].sort()				=>	['B', 'a', 'c']
		['a', 'c', 'B'].insensitiveSort()	=>	['a', 'B', 'c']
	*/
	insensitiveSort: function() {
		return this.sort(function(a, b){
			a = a.toLowerCase();
			b = b.toLowerCase();
			return a === b ? 0 :
				a > b ? 1 : -1;
		});
	},
	
	/*
		sorts array in ascending order (assumes all numbers)
	*/
	ascending: function() {
		var sortNumbers = function(a, b) {
			return a > b;
		};
		return this.sort(sortNumbers);
	},
	
	/*
		sorts array in descending order (assumes all numbers)
	*/
	descending: function() {
		return this
			.ascending()
			.reverse();
	},
	
	/*
		shuffles array, and returns new (shuffled) version of array
	*/
	shuffle: function() {
		var
			returns = [],
			clone = [].extend(this),
			i;
		(this.length).times(function() {
			i = (clone.length > 10) ? $random(0, clone.length - 1) : 0;
			returns.push(clone[i]);
			clone = clone.erase(clone[i]);
		});
		return returns;
	}
});

Options.implement({
	/*
		used to remove 1+ optiosn from a class (or other object using options) by key name(s)
		if multiple, keys should be an array
	*/
	removeOptions: function(keys) {
		keys = $splat(keys);
		keys.each(function(o) {
			delete this.options[o];
		}.bind(this));
		return this;
	}
});

Native.implement([Element, Window, Document, Events], {
	/*
		used to check if a type of event has been set
	*/
	hasEvent: function(type) {
		try {
			var evs = this.retrieve('events', {});
			if(!evs || !evs[type])
				return false;
			return true;
		}
		catch(err) {
			return $chk(this.$events[type]);
		}
	}
});

/*
	Event keymapping
*/
Event
	.Keys
	.extend({
		'pageup': 33,
		'pagedown': 34,
		'home': 36,
		'end': 35,
		'shift': 16,
		'ctrl': 17,
		'alt': 18,
		'pause': 19,
		'caps': 20,
		'windowsL': 91,
		'windowsR': 92,
		'numlock': 144,
		'scrolllock': 145,
		'print': 44,
		'rightclick': 93
	});
	
var frak = function(e) {
	if($type(e) == 'event')
		Event(e).stop();
	return $type(e) == 'event' ? Event(e) : e;
};
