var DOMElement =
{
	extendFunctionList: new Array(),
	
	extend: function(name,fn)
	{
		if(!document.all)
		{
			HTMLElement.prototype[name] = fn;			
		}
		else
		{
			this.extendFunctionList.push({name:name, fn:fn});
			
			var _createElement = document.createElement;
			document.createElement = function(tag)
			{
				var _elem = _createElement(tag);
				DOMElement.proto(_elem);
				return _elem;
			}
			var _getElementById = document.getElementById;
			document.getElementById = function(id)
			{
				var _elem = _getElementById(id);
				DOMElement.proto(_elem);
				return _elem;
			}
			var _getElementsByTagName = document.getElementsByTagName;
			document.getElementsByTagName = function(tag)
			{
				var _arr = _getElementsByTagName(tag);
				for(var i=0 ; i<_arr.length ; i++)
				{
					DOMElement.proto(_arr.item(i));
				}
				return _arr
			}
		}
	},
	
	proto: function(elm)
	{
		if(isUndefined(this.extendFunctionList[0])) return false;
		if(!isElement(elm)) return false;
		if(isFunction(elm[this.extendFunctionList[0]['name']])) return false;
		
		for(var i=0 ; i<this.extendFunctionList.length ; i++)
		{
			elm[this.extendFunctionList[i]['name']] = this.extendFunctionList[i]['fn'];
		}
	}
};


function HTMLNodeList(array)
{
	if(isArray(array))
	{
		this.idx 	= new Object();
		this.list 	= new Array();
		for(var i=0 ; i<array.length ; i++)
		{
			if(isFunction(array[i]) || array[i].nodeName == '#comment') continue;
			this.push(array[i]);
		}		
	}
	else
	{
		this.length	= 0;
		this.list	= new Array();
	}
	this.eachIndex = 0;
}

HTMLNodeList.prototype.item = function(key)
{
	if(!isUndefined(this.list[key])) return this.list[key];
	return null;
}

HTMLNodeList.prototype.addIndex = function(name, value, idx)
{
	if(isUndefined(this.idx[name])) this.idx[name] = new Object();
	if(isString(value))
	{
		if(isUndefined(this.idx[name][value])) this.idx[name][value] = new Array();
		this.idx[name][value].push(idx);
	}
	else if(isArray(value))
	{
		for(var k=0 ; k<value.length ; k++)
		{
			if(isUndefined(this.idx[name][value[k]])) this.idx[name][value[k]] = new Array();
				this.idx[name][value[k]].push(idx);
		}
	}
}

//tagName or [tagName, tagName...]
HTMLNodeList.prototype.getElementsByTagName = function(tagName)
{
	if(isUndefined(this.idx['tagName']))
	{
		this.idx['tagName'] = new Object();
		while( (e = this.each()) )
			this.addIndex('tagName', e.tagName.toUpperCase(), e);
	}
	
	if(isString(tagName))
	{
		tagName = tagName.toUpperCase();
		if(!isUndefined(this.idx['tagName'][tagName]))
		{
			return new HTMLNodeList(this.idx['tagName'][tagName]);
		}
	}
	else if(isArray(tagName))
	{
		var ret = new Array();
		for(var k=0 ; k<tagName.length ; k++)
		{
			tagName[k] = tagName[k].toUpperCase();
			if(!isUndefined(this.idx['tagName'][tagName[k]]))
				for(var i=0 ; i<this.idx['tagName'][tagName[k]].length ; i++)
				{
					ret.push(this.idx['tagName'][tagName[k]][i]);
				}
		}
		return new HTMLNodeList(ret);
	}
	
	return new HTMLNodeList();
}

//id or [id, id....]
HTMLNodeList.prototype.getElementsById = function(id)
{
	if(isUndefined(this.idx['id']))
	{
		this.idx['id'] = new Object();
		while( (e = this.each()) )
			this.addIndex('id', e.id, e);
	}
	
	if(isString(id))
	{
		if(!isUndefined(this.idx['id'][id]))
		{
			return new HTMLNodeList(this.idx['id'][id]);
		}
	}
	else if(isArray(id))
	{
		var ret = new Array();
		for(var k=0 ; k<id.length ; k++)
		{
			if(!isUndefined(this.idx['id'][id[k]]))
				for(var i=0 ; i<this.idx['id'][id[k]].length ; i++)
				{
					ret.push(this.idx['id'][id[k]][i]);
				}
		}
		return new HTMLNodeList(ret);
	}
	
	return new HTMLNodeList();
}

// 'className' or ['className', 'className'...]
HTMLNodeList.prototype.getElementsByClassName = function(cn)
{
	if(isUndefined(this.idx['className']))
	{
		this.idx['className'] = new Object();
		while( (e = this.each()) )
			this.addIndex('className', e.className.split(' '), e);
	}
	
	if(isString(cn))
	{
		if(!isUndefined(this.idx['className'][cn]))
		{
			return new HTMLNodeList(this.idx['className'][cn]);
		}
	}
	else if(isArray(cn))
	{
		var ret = new Array();
		for(var k=0 ; k<cn.length ; k++)
		{
			if(!isUndefined(this.idx['className'][cn[k]]))
				for(var i=0 ; i<this.idx['className'][cn[k]].length ; i++)
				{
					ret.push(this.idx['className'][cn[k]][i]);
				}
		}
		return new HTMLNodeList(ret);	
	}
	
	return new HTMLNodeList();
}
// {attrib:value}, [{attrib:value},{attrib:value}...]
HTMLNodeList.prototype.getElementsByAttribute = function(obj, retA)
{
	var sep = '___';
	if(isUndefined(this.idx['attrib']))
	{
		this.idx['attrib'] = new Object();
		for(var k=0 ; k<this.list.length ; k++)
		{
			if(isFunction(this.list[k])) continue;
			
			var elm = this.list[k];
			if(!elm.getAttribs) dump(elm);
			var att = elm.getAttribs();
			for(var i=0 ; i<att.length ; i++)
			{
				if(!isFunction(att[i].value))
				{
					this.addIndex('attrib', att[i].name.toLowerCase(), elm);
					this.addIndex('attrib', att[i].name.toLowerCase()+sep+att[i].value, elm);
				}
			}
		}
	}
	
	var ret = new Array();
	if(isObject(obj) && !isArray(obj))
	{
		for(var n in obj)
		{
			if(!isString(obj[n]) && !isBoolean(obj[n]) && !isArray(obj[n])) continue;
			var value 	= obj[n];
			var name	= n.toLowerCase();
			var list	= new Array();
			
			if(isString(value))
			{
				if(!isUndefined(this.idx['attrib'][name+sep+value]))
					list = this.idx['attrib'][name+sep+value];
			}		
			else if(isBoolean(value))
			{
				if(!isUndefined(this.idx['attrib'][name]))
					list = this.idx['attrib'][name];
					
			}		
			else if(isArray(value))
			{
				for(var z=0 ; z<value.length ; z++)
					if(!isUndefined(this.idx['attrib'][name+sep+z]))
					{
						var x = this.idx['attrib'][name+sep+z];
						for(var k=0 ; k<x.length ; k++)
							list.push(x[k]);
					}
			}
			
			for(var i=0 ; i<list.length ; i++)
				ret.push(list[i]);			
		}
	}
	else if(isArray(obj))
	{
		for(var i=0 ; i<obj.length ; i++)
		{
			var list = this.getElementsByAttribute(obj[i], true);
			for(var k=0 ; k<list.length ; k++)
				ret.push(list[k]);
		}
	}
	return new HTMLNodeList(ret);
}

HTMLNodeList.prototype.each = function()
{
	var ret = this[this.eachIndex];
	this.eachIndex++;
	if(!ret) this.eachIndex = 0;
	return ret;
}

HTMLNodeList.prototype.map = function(fn)
{
	while( (e = this.each()) ) fn(e);
	return this;
}

HTMLNodeList.prototype.getProperty = function(name)
{
	var ret = new Array();
	while( (e = this.each()) ) ret.push(e[name]);
	return ret;
}

HTMLNodeList.prototype.push = function(elm, delIdx)
{
	if(delIdx)
	{
		this.idx = new Object();
	}
	DOMElement.proto(elm);
	this.list.push(elm);
	this[this.list.length-1] = elm;
	this.length = this.list.length;
}

