//moo.dom

function $S() {
	var els = [];
	$c(arguments).each(function(sel){
		if (typeof sel == 'string') els.extend(new Selector(sel).getElementsBySelector());
		else els.push(sel);
	});
	return $$(els);
};

function $ES(selector, filter){
	if (typeof selector == 'string') return new Selector(selector, filter).getElementsBySelector();
	else return [$(selector)];
};

function $E(selector, filter){
	return $ES(selector, filter)[0];
};

function $$(array){
	array = $c(array);
	array.implement = Object.extend;
	array = array.implement(new Elements);
	
	array.each(function(el){
		el = $(el);
	});

	return array;
};

var Selector = new Class({

	initialize: function(selector, filter){
		this.str = selector;
		this.filter = filter || document;
	},

	getElements: function(){
		
		//quick id
		if (!this.str.test(' ') && !this.str.test(',') && this.str.test('#')) {
			var bits = this.str.split('#');
			var el = this.filter.getElementById(bits[1]);
			if (bits[0].length == 0 || el.tagName.toLowerCase() == bits[0]) return [$(el)];
			else return;
		}

		var params = [];
		this.str.split(' ').each(function(arg, j){
			params[j] = param = [];
			
			//attribute
			if (arg.test('[') && arg.test(']')){
				var inside = arg.split('[')[1].split(']')[0].trim();
				arg = arg.split('[')[0].trim();
				if (inside.test('=')) {
					var bits = inside.split('=');
					bits[0] = bits[0].trim();
					if (bits[0].slice(bits[0].length-1) == '~') {
						param['partial'] = true;
						param['attribute'] = bits[0].substring(bits[0].length-1, 0);
					} else {
						param['partial'] = false;
						param['attribute'] = bits[0];
					}
					param['value'] = bits[1].trim().replace(/"/gi, '').trim();
				} else {
					param['attribute'] = inside;
					param['value'] = false;
					param['partial'] = false;
				}
			}

			//id
			if (arg.test('#')){
				var bits = arg.split('#');
				param['tag'] = bits[0] || '*';
				param['id'] = bits[1];
			}

			//class
			else if (arg.test('.')){
				var bits = arg.split('.');
				param['tag'] = bits[0] || '*';
				param['class'] = bits[1];
			}
			
			//tag
			else param['tag'] = arg;
		});

		params.each(function(param, k){
			if (k == 0) filters = $$(this.filter.getElementsByTagName(param['tag']));
			else filters = $$(filters).getElementsByTagName(param['tag']);
			if (param['id']) filters = $$(filters).filterById(param['id']);
			if (param['class']) filters = $$(filters).filterByClassName(param['class']);
			if(param['attribute']) filters = $$(filters).filterByAttribute(param['attribute'], param['value'], param['partial']);
		}.bind(this));

		return $$(filters);
	},

	getElementsBySelector: function(){
		var els = [];
		this.str.split(',').each(function(selector){
			els.extend(new Selector(selector.trim(), this.filter).getElements());
		}.bind(this));
		return $$(els);
	}
	
});

new Native(Selector);

var Elements = new Class({
	
	action: function(actions){
		this.each(function(el){
			el = $(el);
			if (actions.initialize) actions.initialize.apply(el);
			for(action in actions){
				if (action.slice(0,2) == 'on'){
					evt = action.substring(2, action.length);
					el.addEvent(evt, actions[action]);
				}
			}
		});
	},
	
	filterById: function(id){
		var found = [];
		this.each(function(el){
			if (el.id == id) found.push(el);
		});
		return found;
	},
	
	filterByClassName: function(className){
		var found = [];
		this.each(function(el){
			if (el.hasClassName(className)) found.push(el);
		});
		return found;
	},

	filterByAttribute: function(attribute, value, partial){
		var found = [];
		this.each(function(el){
			if (!value) {
				if (el.getAttribute(attribute)) found.push(el);
			} else {
				if (partial){
					if (el.getAttribute(attribute) && el.getAttribute(attribute).test(value)) found.push(el);
				} else {
					if (el.getAttribute(attribute) && el.getAttribute(attribute) == value) found.push(el);
				}
			}
		});
		return found;
	},

	getElementsByTagName: function(tagName){
		var found = [];
		this.each(function(el){
			found.extend($$(el.getElementsByTagName(tagName)));
		});
		return found;
	}
	
});

new Native(Elements);

//element creation

String.extend({

	createElement: function(){
		var el = $(document.createElement(this));
		$c(arguments).each(function(arg){
			if (typeof arg == 'object' && !arg.nodeName) {
				for (prop in arg) {
					if (prop == 'class') el.className = arg[prop];
					else el.setAttribute(prop, arg[prop]);
				}
			} else {
				if (typeof arg == 'string') var nEl = document.createTextNode(arg);
				else var nEl = arg;
				el.appendChild(nEl);
			}
		});
		return $(el);
	}

});