if (typeof(Intrigo) == 'undefined') Intrigo = {};
Intrigo.addClassName = function(elt, className) {
	if (typeof elt == 'string')
		var elt = document.getElementById(elt);
	if (elt.className.indexOf(className) > -1)
		return;
	else elt.className += ' ' + className;
}

Intrigo.removeClassName = function (elt, className) {
	if (typeof elt == 'string')
		var elt = document.getElementById(elt);
	if (elt.className.indexOf(className) > -1) {
		var classes = elt.className.split(' ');
		var tmp = '';
		for (var i = 0; i < classes.length; i++) {
			if (classes[i] != className) {
				tmp += classes[i];
				if (i + 1 < classes.length) tmp += ' ';
			}
		}
		elt.className = tmp;
	}
}

Intrigo.setAttribute = function(elt, attribs) {
	if (typeof(attribs) == 'object') {
		for(var i in attribs) {
			if (i == 'class') {
				elt.setAttribute('className', attribs[i]);
			}
			elt.setAttribute(i, attribs[i]);
		}
	}
	return elt;
}

// number_format(number, decimals, comma, formatSeparator)
Intrigo.number_format = function(a, b, c, d) {
	if (!c)
		c = '.';
	if (!d)
		d = ',';
	a = Math.round(a * Math.pow(10, b)) / Math.pow(10, b);
	e = a + '';
	f = e.split('.');
	if(!f[0]) f[0] = '0';
	if(!f[1]) f[1] = '';
	if(f[1].length < b){
		g = f[1];
		for(i = f[1].length + 1; i <= b; i++) {
			g += '0';
		}
		f[1] = g;
	}
	if(d != '' && f[0].length > 3) {
		h = f[0];
		f[0] = '';
		for(j = 3; j < h.length; j += 3) {
			i = h.slice(h.length - j, h.length - j + 3);
			f[0] = d + i +  f[0] + '';
		}
		j = h.substr(0, (h.length % 3 == 0) ? 3 : (h.length % 3));
		f[0] = j + f[0];
	}
	c = (b <= 0) ? '': c;
	return f[0] + c + f[1];
}
function Table(container, attribs) {
	var table = document.createElement('table');
	
	Intrigo.setAttribute(table, attribs);
	
	document.getElementById(container).appendChild(table);
	
	this._container = container;
	this._table = table;
	this._rows = [];
	this._filters = '';
	this._headers = [];
	this._sums = {};
	this._tagFilters = {};
}
Table.prototype = {
	_container:null,
	_table:null,
	_thead:null,
	_tbody:null,
	_tfoot:null,
	
	_theadRow:null,
	_tfootRow:null,
	_rows:null,
	
	_headers: null,
	_sums: null,
	
	_sortKey:null,
	_sortDir:null,
	
	_filters:null,
	_tagFilters:null,
	
	_onAddHeader:null,
	_onShowColumn:null,
	_onHideColumn:null,
	
	createThead: function(attribs) {
		try {
			if (!this._thead) {
				this._thead = document.createElement('thead');
				this._theadRow = document.createElement('tr');
				
				Intrigo.setAttribute(this._theadRow, attribs);
				
				this._thead.appendChild(this._theadRow);
				this._table.appendChild(this._thead);
			}
		} catch (e) {
			alert('Table.createThead error: ' + e)
		}
	},

	createTbody: function(attribs) {
		if (!this._tbody) {
			var tbody = document.createElement('tbody');
			
			Intrigo.setAttribute(tbody, attribs);
			
			this._table.appendChild(tbody);
			this._tbody = tbody;
		}
	},
	
	createTfoot: function(attribs) {
		try {
			if (!this._tfoot) {
				this._tfoot = document.createElement('tfoot');
				this._tfootRow = document.createElement('tr');
				
				Intrigo.setAttribute(this._tfootRow, attribs);
				
				this._tfoot.appendChild(this._tfootRow);
				this._table.appendChild(this._tfoot);
			}
		} catch (e) {
			alert('Table.createTfoot error: ' + e)
		}
	},
	
	addHeader: function(label, data, commonAttribs) {
		var self = this;
		var header = document.createElement('th');
		
		if (typeof(data) == 'string') {
			data = {
				display:data,
				sort:true
			}
		}
		
		this._sums[label] = {};
		this._sums[label].total = 0;
		this._sums[label].elt = null;
		if (data.type == 'number' && data.sum !== false) {
			this._sums[label].enabled = true;
		}
		else {
			this._sums[label].enabled = false;
		}
			
		Intrigo.setAttribute(header, commonAttribs);
		Intrigo.setAttribute(header, data.attrib);

		if (typeof(data.display) == 'string') 
			header.innerHTML = data.display;
		else header.appendChild(data.display);
		
		if (data.sort == true) {
			header.onclick = function(){
				self.sortBy(label, data.type);
			};
			Intrigo.addClassName(header, 'sortable');
		}
		
		if (data.hidden == true) {
			header.style.display = 'none';
		}
		
		this.createThead();
		this._theadRow.appendChild(header);
		this._headers[label] = {};
		this._headers[label].html = header;
		this._headers[label].data = data;
		
		if (this._onAddHeader) {
			this._onAddHeader(label, data, header, this);
		}
	},

	addHeaders: function(data, commonAttribs) {
		try {
			for (var label in data) {
				this.addHeader(label, data[label], commonAttribs);
			}
		}
		catch (e) {
			alert('Table.addHeaders error: ' + e);
		}
	},
	
	onAddHeader: function(funcName) {
		if (INTRIGO.isFunction(funcName)) {
			this._onAddHeader = funcName;
		}
		return this;
	},
	
	addRow: function(attribs) {
		var row = new Table.row(attribs, this);
		
		if (this._rows.length % 2 == 0) row.setParity('even');
		else row.setParity('odd');
		
		this._rows[this._rows.length] = row;
		this.createTbody();
		this._tbody.appendChild(row.get());
		return row;
	},
	
	addCells: function(cells, commonAttribs) {
		this.createTbody();
		var row = this.addRow();
		row.addCells(cells, commonAttribs);
	},
	
	hideColumn: function(label) {
		for (var i = 0; i < this._rows.length; i++) {
			var cell = this._rows[i].getCell(label);
			cell.hide();
		}
		this._headers[label].html.style.display = 'none';
		this._headers[label].data.hidden = true;
		if (this._sums[label].elt)
			this._sums[label].elt.style.display = 'none';
		
		if (this._onHideColumn)
			this._onHideColumn(label);
	},
	
	onHideColumn: function(funcName) {
		if (INTRIGO.isFunction(funcName)) {
			this._onHideColumn = funcName;
		}
		return this;
	},
	
	showColumn: function(label) {
		for (var i = 0; i < this._rows.length; i++) {
			var cell = this._rows[i].getCell(label);
			cell.show();
		}
		this._headers[label].html.style.display = '';
		this._headers[label].data.hidden = false;
		if (this._sums[label].elt)
			this._sums[label].elt.style.display = '';
		
		if (this._onShowColumn)
			this._onShowColumn(label);
	},
	
	onShowColumn: function(funcName) {
		if (INTRIGO.isFunction(funcName)) {
			this._onShowColumn = funcName;
		}
		return this;
	},
	
	sortBy: function(label, type) {
		var newSort = [];
		for (var i = 0; i < this._rows.length; i++) {
			if (this._sortLabel && this._sortLabel != label) {
				this._rows[i].getCell(this._sortLabel).sorted(false);
			}
			var cell = this._rows[i].getCell(label);
			cell.sorted(true);
			newSort[i] = {};
			newSort[i].row = this._rows[i];
			if (type == 'date')
				newSort[i].data = Date.parse(cell.getData());
			else newSort[i].data = cell.getData();
		}
		
		if (this._sortLabel == label) {
			if (this._sortDir == 'ASC') {
				if (type == 'number' || type == 'date')
					newSort.sort(this.sortNumAscHelper);
				else newSort.sort(this.sortDescHelper);
				this._sortDir = 'DESC';
			}
			else {
				if (type == 'number' || type == 'date')
					newSort.sort(this.sortNumDescHelper);
				else newSort.sort(this.sortAscHelper);
				this._sortDir = 'ASC';
			}
		}
		else {
			if (type == 'number' || type == 'date')
				newSort.sort(this.sortNumDescHelper);
			else newSort.sort(this.sortAscHelper);
			this._sortLabel = label;
			this._sortDir = 'ASC';
		}
		
		for (var i = 0; i < newSort.length; i++) {
			var row = newSort[i].row;
			this._tbody.appendChild(row.get());
			this._rows[i] = row;
		}

		this.setParity();
	},
	
	sortAscHelper: function(a, b) {
		var x = a.data.toLowerCase();
	    var y = b.data.toLowerCase();
	    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
	},
	
	sortDescHelper: function(a, b) {
		var x = a.data.toLowerCase();
	    var y = b.data.toLowerCase();
	    return ((x > y) ? -1 : ((x < y) ? 1 : 0));
	},
	
	sortNumAscHelper: function(a, b) {
		var x = a.data;
	    var y = b.data;
	    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
	},
	
	sortNumDescHelper: function(a, b) {
		var x = a.data;
	    var y = b.data;
	    return ((x > y) ? -1 : ((x < y) ? 1 : 0));
	},
	
	addFilter: function(value, tagValue) {
		if (tagValue) {
			if (!this._tagFilters[value + tagValue]) {
				this._tagFilters[value + tagValue] = {};
				this._tagFilters[value + tagValue].tag = value;
				this._tagFilters[value + tagValue].value = tagValue;
				this.filterBy('');
			}
		}
		else if (this._filters.indexOf(value) == -1) {
			this._filters += value + ' ';
			this.filterBy('');
		}
	},
	
	filterBy: function(value) {
		value = this._filters + ' ' + value;
		if (this._sumsEnabled)
			this.resetSums();

		for (var i = 0; i < this._rows.length; i++) {
			var row = this._rows[i];

			if (row.search(value, true) && this.filterByTag(row)) {
				row.show();
				if (this._sumsEnabled)
					this.calculateSums(row);
			}
			else row.hide();
		}
		this.setParity();
	},
	
	filterByTag: function(row) {
		var count = 0;
		var found = 0;
		for (var i in this._tagFilters) {
			count++;
			var rowTag = row.getTag(this._tagFilters[i].tag);
			if (typeof(rowTag) == 'object') {
				for (var j = 0; j < rowTag.length; j++) {
					if (rowTag[j] == this._tagFilters[i].value)
						found++;
				}
			}
			else if (rowTag == this._tagFilters[i].value)
				found++;
		}
		if (count == 0)
			return true;
		else if (count == found)
			return true;
		else return false;
	},
	
	removeFilter: function(value, tagValue) {
		if (tagValue)
			delete(this._tagFilters[value + tagValue]);
		else this._filters = this._filters.replace(value + ' ', "");
		this.filterBy('');
	},
	
	removeFilters: function() {
		this._filters = '';
		this._tagFilters = {};
		this.reset();
	},
	
	reset: function() {
		var lastParity = 'odd';
		for (var i = 0; i < this._rows.length; i++) {
			var row = this._rows[i];
			
			row.show();
			
			if (this._sumsEnabled)
				this.calculateSums(row);
				
			if (lastParity == 'even') row.setParity('odd');
				else row.setParity('even');
				lastParity = row.getParity();
		}
	},
	
	setParity: function() {
		var lastParity = 'odd';
		for (var i = 0; i < this._rows.length; i++) {
			var row = this._rows[i];
			if (row.visible()) {
				if (lastParity == 'even') row.setParity('odd');
				else row.setParity('even');
				lastParity = row.getParity();
			}
		}
	},
	
	showRow: function(row) {
		row.show();
	},
	
	hideRow: function(row) {
		row.hide();
	},
	
	showSums: function(attribs) {
		this._sumsEnabled = true;
		this.createTfoot();
		for (var label in this._headers) {
			var cell = document.createElement('td');
			
			if (this._sums[label].enabled) {
				Intrigo.setAttribute(cell, attribs);
				cell.innerHTML = Intrigo.number_format(this._sums[label].total, 2);
				this._sums[label].elt = cell;
			}
			else {
				cell.innerHTML = '&nbsp;';
				this._sums[label].elt = cell;
			}
			if (this._headers[label].data.hidden === true)
				cell.style.display = 'none';
			this._tfootRow.appendChild(cell);
		}
	},
	
	calculateSums: function(row) {
		for (var label in this._sums) {
			this.calculateSum(label, row.getCell(label).getData());
		}
	},
	
	calculateSum: function(label, value) {
		if (this._sums[label].enabled) {
			this._sums[label].total += value;
			if (this._sums[label].elt) {
				this._sums[label].elt.innerHTML = Intrigo.number_format(this._sums[label].total, 2);
			}
		}
	},
	
	resetSums: function(row) {
		for (var label in this._sums) {
			if (this._sums[label].enabled) {
				this._sums[label].total = 0;
				this._sums[label].elt.innerHTML = '0.00';
			}
		}
	}
};

Table.row = function(attribs, tableRef) {
	var row = document.createElement('tr');
		
	Intrigo.setAttribute(row, attribs);
	
	this._row = row;
	this._visibility = 'visible';
	this._cells = {};
	this._tags = {};
	this._tableRef = tableRef;
}
Table.row.prototype = {
	_row:null,
	_cells:null,
	_parity:null,
	_visibility:null,
	_tags:null,
	
	_tableRef:null,
	
	addCell: function(label, data, commonAttribs) {
		if (data.tag)
			this._tags[label] = data.tag;
		
		var cell = new Table.cell(data, commonAttribs);
		
		if (this._tableRef._headers[label].data.hidden)
			cell.hide();
		
		this._cells[label] = cell;
		this._row.appendChild(cell.get());
		
		if (data.type == 'number')
			this._tableRef.calculateSum(label, data.data);
	},

	addCells: function(data, commonAttribs) {
		try {
			for (var label in data) {
				this.addCell(label, data[label], commonAttribs);
			}
		}
		catch (e) {
			alert('Table.row.addCells error: ' + e);
		}
	},
	
	get: function() {
		return this._row;
	},
	
	getCell: function(label) {
		return this._cells[label];
	},
	
	getParity: function() {
		return this._parity;
	},
	
	search: function(value, inclusive) {
		var allValues = '';
		for (var i in this._cells) {
			if (inclusive) 
				allValues += this._cells[i].getData() + ' ';
			else if (Table.search(value, this._cells[i].getData()))
				return true;
		}

		if (inclusive)
			return Table.search(value, allValues);
		else return false;
	},
	
	show: function() {
		this._row.style.display = '';
		this._visibility = 'visible';
	},
	
	hide: function() {
		this._row.style.display = 'none';
		this._visibility = 'hidden';
	},
	
	visible: function() {
		if (this._visibility == 'hidden')
			return false;
		else return true;
	},
	
	setParity: function(value) {
		if (value == 'even'){
			Intrigo.addClassName(this._row, 'even');
			Intrigo.removeClassName(this._row, 'odd');
		}
		else {
			Intrigo.addClassName(this._row, 'odd');
			Intrigo.removeClassName(this._row, 'even');
		}
		this._parity = value;
	},
	
	addTag: function(tag, value) {
		this._tags[tag] = value;
	},
	
	addTags: function(tags) {
		try {
			for (var i in tags) {
				this.addTag(i, tags[i]);
			}
		}
		catch(e) {
			alert('Table.Row.addTags error: ' + e);
		}
	},
	
	getTag: function(tag) {
		if (this._tags[tag])
			return this._tags[tag];
		else return false;
	}
};


Table.cell = function(data, commonAttribs) {
	var cell = document.createElement('td');
	
	if (typeof(data) == 'string') {
		data = {
			display:data,
			data:data
		}
	}
	
	Intrigo.setAttribute(cell, commonAttribs);
	Intrigo.setAttribute(cell, data.attrib);

	if (typeof(data.display) == 'object')
		cell.appendChild(data.display);
	else cell.innerHTML = data.display;
	
	this._cell = cell;
	this._data = data.data;
}
Table.cell.prototype = {
	_cell: null,
	_data: null,
	_sorted: null,
	
	get: function() {
		return this._cell;
	},
	
	getData: function() {
		return this._data;
	},
	
	sorted: function(value) {
		if (value == true) Intrigo.addClassName(this._cell, 'sorted');
		else Intrigo.removeClassName(this._cell, 'sorted');
		this._sorted = value;
	},
	
	hide: function(){
		this._cell.style.display = 'none';
	},
	
	show: function() {
		this._cell.style.display = '';
	}
};

Table.search = function(search, haystack) {
	if (search == null || search == "")
		return false;

	var str = String(search).toLowerCase(); //cast to string incase javascript has 'cleverly' cast our name to a number
	var search_array = str.split(" ");
	var haystack = String(haystack).toLowerCase();

	for (var i = 0; i < search_array.length; i++)
		if ( haystack.indexOf(search_array[i]) == -1)
			return false; //Our work is done here.
	return true; //Only if it contained all of the filter words.
}