zCore.Tables = {
	initialize : function() {
		var tables = document.getElementsBySelector('table.highlight');
		for (var ti = 0; table = tables[ti]; ti++) zCore.Tables.Highlighter.draw(table);
		
		var tables = document.getElementsBySelector('table.sortable');
		for (var ti = 0; table = tables[ti]; ti++) new zCore.Tables.Sorter(table);
		
		var tables = document.getElementsBySelector('table.searchable');
		for (var ti = 0; table = tables[ti]; ti++) {
			new zCore.Tables.Search(table, $('criteria-for-'+table.id));
		}
	},

	getTextInColumn : function(column) {
		var node = column.firstChild;
		while (node && node.nodeType != 3) node = node.firstChild;
		
		if (!node) return '';
		
		return node.nodeValue;
	}
};

zCore.Tables.Highlighter = {
	mouseover : function(evt) {
		//if (!e) var e = window.event;
		
		var row = zCore.Events.getEventTarget(evt || window.event);
		if (!row)
			return;
		
		row = zCore.DOM.getParentWithTagName(row, 'tr');
	
		row.className += ' hover';
	},
	
	mouseout : function(evt) {
		//if (!e) var e = window.event;
		
		var row = zCore.Events.getEventTarget(evt || window.event);
		if (!row)
			return;
			
		row = zCore.DOM.getParentWithTagName(row, 'tr');
	
		row.className = row.className.replace(/ ?hover/, '');
	},
	
	click : function(evt) {
		//if (!e) var e = window.event;
		
		var row = zCore.Events.getEventTarget(evt || window.event);
		if (!row)
			return;
		
		var selected = null;
		if (row.nodeName.match(/input/i)) {
			if (row.type == 'checkbox') {
				if (row.checked) {
					selected = true;
				} else {
					selected = false;
				}
			} else {
				return;
			}
		} else if (row.nodeName.match(/^(a|img)$/i)) {
			return;
		}
		
		row = zCore.DOM.getParentWithTagName(row, 'tr');
		
		if (row.className.match(/selected/)) {
			row.className = row.className.replace(/ ?selected/, '');
			
			if (selected == null) {
				var ips = row.getElementsByTagName('input');
				for (var ipsi = 0; ipsi < ips.length; ipsi++) {
					if (ips[ipsi].type == 'checkbox') {
						ips[ipsi].checked = false;
					}
				}
			}
		} else {
			row.className += ' selected';
	
			if (selected == null) {
				var ips = row.getElementsByTagName('input');
				for (var ipsi = 0; ipsi < ips.length; ipsi++) {
					if (ips[ipsi].type == 'checkbox') {
						ips[ipsi].checked = true;
					}
				}
			}
		}
	},

	draw : function(table) {
		var bodies = table.getElementsByTagName('tbody');
		
		for (var bi = 0; body = bodies[bi]; bi++) {
			var rows = body.getElementsByTagName('tr');
			var i = 0;
			for (var ri = 0; row = rows[ri]; ri++) {
				if (row.style.display == 'none' || row.className.match(/template/)) continue;
				
				var input = null;
				if ((input = row.getElementsByTagName('input').item(0)) && input.type == 'checkbox' && input.checked && row.className.indexOf('selected') == -1) {
					row.className += ' selected';
				}
				
				if (i % 2 == 0 && rows[ri].className.indexOf('odd') == -1) {
					if (rows[ri].className.indexOf('selected') != -1) {
						rows[ri].className = rows[ri].className.replace(/ selected/, ' odd selected');
					} else {
						rows[ri].className += ' odd';
					}
				} else if (i % 2 != 0) {
					rows[ri].className = rows[ri].className.replace(/ ?odd/, '');
				}
				
				i++;
			}
		}
	}
};

zCore.Tables.Search = Class.create();
zCore.Tables.Search.prototype = {
	table : null,
	searchField : null,
	columnSelector : null,
	
	initialize : function (table, criteria) {
		this.table = table;
		
		this.searchField = criteria.getElementsByTagName('input').item(0);
		if (!this.searchField) return;
		
		this.columnSelector = criteria.getElementsByTagName('select').item(0);	
		if (this.columnSelector) {
			var thead = this.table.getElementsByTagName('thead').item(0);
			
			var columns = null;
			var rows = thead.getElementsByTagName('tr');
			for (var ri = 0; ri < rows.length; ri++) {
				var ths = rows[ri].getElementsByTagName('th');
				
				if (ths.length > 0) {
					columns = ths;
					break;
				}
			}
		
			for (var ci = 0; ci < columns.length; ci++) {
				if (columns[ci].className.indexOf('searchable') != -1) {
					var option = document.createElement('option');
					option.value = ci;
					option.appendChild(document.createTextNode(columns[ci].firstChild.nodeValue));
					this.columnSelector.appendChild(option);
				}
			}
		}
		
		zCore.Events.addEventListener(this.columnSelector, 'change', this.update.bind(this), false);
		zCore.Events.addEventListener(this.searchField, 'keyup', this.update.bind(this), false);
		zCore.Events.addEventListener(this.searchField, 'change', this.update.bind(this), false);
	},
	
	update : function (evt) {
		var searchValue = this.searchField.value.replace(/, *$/, '');
		searchValue = searchValue.replace(/, */g, '|');
		var searchRegExp = new RegExp(searchValue, 'i');
		var searchColumn = this.columnSelector.options[this.columnSelector.selectedIndex].value;
		
		var bodies = this.table.getElementsByTagName('tbody');
		for (var bi = 0; body = bodies[bi]; bi++) {
			var rows = body.getElementsByTagName('tr');
			
			for (var ri = 0; row = rows[ri]; ri++) {
				if (row.disabled) continue;
				
				var found = false;
				var columns = row.getElementsByTagName('td');
				
				if (searchColumn == -1) {
					var columnIndexes = this.columnSelector.getElementsByTagName('option');
					for (var xi = 1; xi < columnIndexes.length; xi++) {
						var data = zCore.Tables.getTextInColumn(columns[columnIndexes[xi].value]);
						if (data.match(searchRegExp)) {
							found = true;
						}
					}
				} else {
					var data = zCore.Tables.getTextInColumn(columns[searchColumn]);
					if (data.match(searchRegExp)) {
						found = true;
					}
				}
				
				if (!found) {
					row.style.display = 'none';
				} else {
					row.style.display = '';
				}
			}
		}
		
		if (this.table.className.indexOf('highlight') != -1) {
			zCore.Tables.Highlighter.draw(this.table);
		}
	},
	
	getColumnIndex : function (table, text) {
		var head = table.getElementsByTagName('thead').item(0);
		
		var rows = head.getElementsByTagName('tr');
		var column_headers = null;
		
		for (var ri = 0; ri < rows.length; ri++) {
			var h = rows[ri].getElementsByTagName('th');
			
			if (h) {
				column_headers = h;
				break;
			}
		}
		
		var index = null;
		for (var chi = 0; chi < column_headers.length; chi++) {
			if (column_headers[chi].firstChild.nodeValue.match(text)) {
				index = chi;
				break;
			}
		}
		
		return index;
	}
};

zCore.Tables.Sorter = Class.create();
zCore.Tables.Sorter.prototype = {
	table : null,
	current_sorted : null,
	
	initialize : function(table) {
		this.table = table;
		
		var head = this.table.getElementsByTagName('thead').item(0);
		var rows = head.getElementsByTagName('tr');
		var columns = null;
		
		for (var ri = 0; row = rows[ri]; ri++) {
			var ths = row.getElementsByTagName('th');
			if (ths.length > 0) {
				columns = ths;
				break;
			}
		}
		
		if (columns) {
			for (var ci = 0; column = columns[ci]; ci++) {
				column.index = ci;
				
				if (column.className.indexOf('sortable') != -1) {
					zCore.Events.addEventListener(column, 'click', this.byColumn.bind(this), false);
					zCore.Events.addEventListener(column, 'mouseover', this.mouseover.bind(this), false);
					zCore.Events.addEventListener(column, 'mouseout', this.mouseout.bind(this), false);
				}
			}
		}
	},

	mouseover : function (evt) {
		//if (!e) var e = window.event;
		
		var th = zCore.Events.getEventTarget(evt || window.event);
		if (!th)
			return;
	
		th.className += ' hover';
	},
	
	mouseout : function (evt) {
		//if (!e) var e = window.event;
		
		var th = zCore.Events.getEventTarget(evt || window.event);
		if (!th)
			return;
	
		th.className = th.className.replace(/ ?hover/, '');
	},
	
	byColumn : function (evt) {
		//if (!e) var e = window.event;
		
		var th = zCore.Events.getEventTarget(evt || window.event);
	
		if (th == this.current_sorted) {
			th.ascending = !th.ascending;
		} else if (!th.ascending) {
			th.ascending = true;
		}
	
		var bodies = this.table.getElementsByTagName('tbody');
		for (var bi = 0; body = bodies[bi]; bi++) {
			var rows = body.getElementsByTagName('tr');
	
			for (var i = 0; i < rows.length - 1; i++) {
				for (var j = 1; j < rows.length; j++) {
					var column_a = rows[j-1].getElementsByTagName('td').item(th.index);
					var column_b = rows[j].getElementsByTagName('td').item(th.index);
					var ca = cb = null;
					if ((ca = this.getComparable(column_a)) != null && (cb = this.getComparable(column_b)) != null) {
						var a = ca.firstChild.nodeValue;
						var b = cb.firstChild.nodeValue;
					} else {
						var a = zCore.Tables.getTextInColumn(column_a);
						var b = zCore.Tables.getTextInColumn(column_b);
					}
					
					if (a.match(/^[0-9]+$/) && b.match(/^[0-9]+$/)) {
						a = parseFloat(a);
						b = parseFloat(b);
					}

					if ((b < a) && th.ascending) {
						bodies[bi].insertBefore(rows[j], rows[j - 1]);
					} else if ((b > a) && !th.ascending) {
						bodies[bi].insertBefore(rows[j], rows[j - 1]);
					}
				}
			}
		}
		
		if (this.current_sorted) {
			this.current_sorted.className = this.current_sorted.className.replace(/ ?(ascending|descending)/, '');
		}
		th.className = th.className.replace(/ ?(ascending|descending)/, '');
		if (th.ascending) {
			th.className += ' ascending';
		} else {
			th.className += ' descending';
		}
		this.current_sorted = th;
					
		if (this.table.className.indexOf('highlight') != -1) {
			zCore.Tables.Highlighter.draw(this.table);
		}
	},
	
	getComparable : function (element) {
		var children = element.childNodes;
		for (var i = 0; i < children.length; i++) {
			if (children[i].nodeType == 1 && children[i].className.match(/\bcompare\b/)) {
				return children[i];
			}
		}
		
		return null;
	}
};

Behaviour.register({
	'table.highlight tbody tr' : {
		mouseover : zCore.Tables.Highlighter.mouseover,
		mouseout : zCore.Tables.Highlighter.mouseout,
		click : zCore.Tables.Highlighter.click
	}
});

zCore.Events.addEventListener(window, 'load', zCore.Tables.initialize, false);