/*
	TableSort revisited v2.9 by frequency-decoder.com
	Released under a creative commons Attribution-ShareAlike 2.5 license (http://creativecommons.org/licenses/by-sa/2.5/)
	Please credit frequency decoder in any derivative work - thanks
	You are free:
	* to copy, distribute, display, and perform the work
	* to make derivative works
	* to make commercial use of the work
	Under the following conditions:
		by Attribution.
		--------------
		You must attribute the work in the manner specified by the author or licensor.
		sa
		--
		Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one.
	* For any reuse or distribution, you must make clear to others the license terms of this work.
	* Any of these conditions can be waived if you get permission from the copyright holder.
*/

var fdTableSort = {

	regExp_Currency:        /^[£$€¥¤]/,
	regExp_Number:          /^(\-)?[0-9]+(\.[0-9]*)?$/,
	pos:                    -1,
	uniqueHash:             1,
	thNode:                 null,
	tableCache:             {},
	tableId:                null,

	//Todo: change to moo method
	addEvent: function(obj, type, fn) {
		if( obj.attachEvent ) {
			obj["e"+type+fn] = fn;
			obj[type+fn] = function(){obj["e"+type+fn]( window.event );}
			obj.attachEvent( "on"+type, obj[type+fn] );
		} else {
			obj.addEventListener( type, fn, false );
		}
	},

	//Todo: change to moo method
	stopEvent: function(e) {
		e = e || window.event;

		if(e.stopPropagation) {
			e.stopPropagation();
			e.preventDefault();
		}
		/*@cc_on@*/
		/*@if(@_win32)
		e.cancelBubble = true;
		e.returnValue = false;
		/*@end@*/
		return false;
	},

	init: function() {
		if (!document.getElementsByTagName) return;

		var tables = document.getElementsByTagName('table');
		var sortable, headers, thtext, aclone, a, span, columnNum, noArrow, reverseSortOnInit, CustomProcess;

		//*this DOM node is re-used by way of cloneNode()
		a               = document.createElement("a");
		a.href          = "#";
		a.onkeypress    = fdTableSort.keyWrapper;
		span            = document.createElement("span");

		for(var t = 0, tbl; tbl = tables[t]; t++) {
			//*returns <th> from last <tr> of <thead>
			headers = fdTableSort.getTableHeaders(tbl);
			
			//*set variables based upon <table> classes
			sortable  = false;
			columnNum = tbl.className.search(/sortable-onload-([0-9]+)/) != -1 ? parseInt(tbl.className.match(/sortable-onload-([0-9]+)/)[1]) - 1 : -1;
			showArrow = tbl.className.search(/no-arrow/) == -1;
			reverse   = tbl.className.search(/sortable-onload-([0-9]+)-reverse/) != -1;
			CustomProcess = tbl.className.search(/Ethical/) != -1;

			
			// Remove any old dataObj for this table (tables created from an ajax callback require this)
			if(tbl.id && tbl.id in fdTableSort.tableCache) delete fdTableSort.tableCache[tbl.id];

			var colCnt = -1;
			
			//*operate on <th>'s returned by getTableHeaders()
			for (var z=0, th; th = headers[z]; z++) {
				colCnt += th.getAttribute("colspan") ? Number(th.getAttribute("colspan")) : 1;
				
				if(th.className && th.className.match('sortable') && (!th.getAttribute("colspan") || th.getAttribute("colspan") == 1)) {

					// Remove previously applied classes for the ajaxers also
					th.className = th.className.replace(/forwardSort|reverseSort/, "");

					if(colCnt == columnNum) sortable = th;
					thtext = fdTableSort.getInnerText(th);

					//*Remove all children of <th> and put in a link instead
					while(th.firstChild) th.removeChild(th.firstChild);

					//*call custom function to add tooltips
					if (CustomProcess) {
						fdTableSort.customThProcess(th, thtext);
					}

					// Create the link
					aclone = a.cloneNode(true);
					aclone.appendChild(document.createTextNode(thtext));
					//aclone.title = "Sort on " + thtext;
					a.onclick = th.onclick = fdTableSort.clickWrapper;
					th.appendChild(aclone);

					// Add the span if needs be
					if(showArrow) th.appendChild(span.cloneNode(false));

					var cn = "fd-column-" + colCnt;
					th.className = th.className.replace(/fd-identical|fd-not-identical/, "").replace(/fd-column-([0-9]+)/, "") + " " + cn;
					fdTableSort.disableSelection(th);
				};
			};

			if (sortable) {
				fdTableSort.thNode = sortable;
				fdTableSort.initSort();
				if (reverse) {
					fdTableSort.thNode = sortable;
					fdTableSort.initSort();
				};
			};
		};
	},

	//Omit lender name somehow
	customThProcess: function(th, thtext) {
		var d = document.createElement("div");
		var dd = new Image();
		dd.src = "/home-values/images/RatesQuestionMark.gif";
		d.appendChild(dd)
		th.appendChild(d);
		if (thtext.length <= 6 || th.id == "LenderName") {
			var b = document.createElement("br");
			th.appendChild(b);
		}
		//Todo: add tooltip
	},
	
	disableSelection: function(element) {
		element.onselectstart = function() {
			return false;
		};
		element.unselectable = "on";
		element.style.MozUserSelect = "none";
	},
	
	getTableHeaders: function(tbl) {
		var headers;
		var thead = tbl.getElementsByTagName('thead');

		if (thead && thead.length) {
			thead = thead[0];
			headers = thead.getElementsByTagName('tr');
			headers = headers[headers.length - 1].getElementsByTagName('th');
		} else {
			headers = tbl.getElementsByTagName('th');
		}
		return headers;
	},
	
	countColumns: function(thList) {
		var colCnt = 0;
		for (var i = 0, th; th = thList[i]; i++) {
			colCnt += th.getAttribute("colspan") ? Number(th.getAttribute("colspan")) : 1;
		};

		return colCnt;
	},
	
	getTH: function(thList, pos) {
		//var thList = fdTableSort.thNode.parentNode.getElementsByTagName("th");

		var re = new RegExp("fd-column-"+pos);
		for (i in thList) {
			if (thList[i].className && thList[i].className.match(re)) {
				return thList[i];
			}
		}
		/*
		for (var i = 0, th; th = thList[i]; i++) {
			//var re = new RegExp( "(fd-column-" + pos + ")([^0-9]+)" );
			if (th.className.match(re)) {
				return th;
			}
		};
		*/
	},
	
	clickWrapper: function(e) {
		e = e || window.event;
		if (fdTableSort.thNode == null) {
			fdTableSort.thNode = this;
			fdTableSort.addSortActiveClass();
			setTimeout("fdTableSort.initSort()",5);
		};
		return fdTableSort.stopEvent(e);
	},

	keyWrapper: function(e) {
		e = e || window.event;
		var kc = e.keyCode != null ? e.keyCode : e.charCode;
		if(kc == 13) {
			var targ = this;
			while(targ.tagName.toLowerCase() != "th") targ = targ.parentNode;

			fdTableSort.thNode = targ;
			fdTableSort.addSortActiveClass();
			setTimeout("fdTableSort.initSort()",5);

			return fdTableSort.stopEvent(e);
		};
		return true;
	},

	jsWrapper: function(tableid, colNum) {
		var table = $(tableid);
		fdTableSort.thNode = fdTableSort.getTH(table.tHead.rows[0].cells, colNum);
		if(!fdTableSort.thNode || fdTableSort.thNode.className.search(/fd-column/) == -1) return false;
		fdTableSort.addSortActiveClass();
		fdTableSort.initSort();
	},

	addSortActiveClass: function() {
		if (fdTableSort.thNode == null) return;
		fdTableSort.addClass(fdTableSort.thNode, "sort-active");
		fdTableSort.addClass(document.getElementsByTagName('body')[0], "sort-active");
		if ("sortInitiatedCallback" in window) {
			var tableElem   = fdTableSort.thNode;
			while (tableElem.tagName.toLowerCase() != 'table' && tableElem.parentNode) {
				tableElem = tableElem.parentNode;
			}
			sortInitiatedCallback(tableElem.id);
		};
	},

	removeSortActiveClass: function() {
		fdTableSort.removeClass(fdTableSort.thNode, "sort-active");
		fdTableSort.removeClass(document.getElementsByTagName('body')[0], "sort-active");
		if("sortCompleteCallback" in window) {
			var tableElem   = fdTableSort.thNode;
			while(tableElem.tagName.toLowerCase() != 'table' && tableElem.parentNode) {
				tableElem = tableElem.parentNode;
			};
			sortCompleteCallback(tableElem.id);
		};
	},

	addClass: function(e,c) {
		if(new RegExp("(^|\\s)" + c + "(\\s|$)").test(e.className)) return;
		e.className += ( e.className ? " " : "" ) + c;
	},

	removeClass: function(e,c) {
		e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s*\\b[^-])"+c+"($|\\b(?=[^-]))", "g"), "");
	},

	prepareTableData: function(table) {
		// Create a table id if needs be
		if(!table.id) table.id = "fd-table-" + fdTableSort.uniqueHash++;

		var data = [];
		var tbody0 = $('tbody0');
		table.removeChild($('tbody0'));
		if($('tbody1')) var tbody1 = $('tbody1');
		if($('tbody2')) var tbody2 = $('tbody2');
		if(tbody1 && tbody2){
			
			var trs2 = tbody2.getElementsByTagName('tr');
			while(trs2.length){
				tbody1.appendChild(trs2[0]);
			}
		}
		$('tbody1').removeClass('featuredListings');
		
		var start = table.getElementsByTagName('tbody');
		start =start.length ? start[0] : table;

		var trs = start.getElementsByTagName('tr');
		var ths = fdTableSort.getTableHeaders(table);

		var numberOfRows = trs.length;
		var numberOfCols = fdTableSort.countColumns(ths);

		var data = [];
		var identical = new Array(numberOfCols);
		var identVal  = new Array(numberOfCols);

		var tr, td, th, txt, tds, col, row;

		var rowCnt = 0;

		// Start to create the 2D matrix of data
		for(row = 0; row < numberOfRows; row++) {

			tr              = trs[row];

			// Have we any th tags or are we in a tfoot ?
			if(tr.getElementsByTagName('th').length > 0 || (tr.parentNode && tr.parentNode.tagName.toLowerCase() == "tfoot")) continue;

			data[rowCnt]    = [];
			tds             = tr.getElementsByTagName('td');
			col             = -1;

			for(var tmp = 0, th; th = ths[tmp]; tmp++) {

				col += th.getAttribute("colspan") ? Number(th.getAttribute("colspan")) : 1;

				if(th.className.search(/sortable/) == -1 || (th.getAttribute("colspan") && Number(th.getAttribute("colspan")) > 1)) continue;

				td  = tds[col];

				txt = fdTableSort.getInnerText(td) + " ";

				txt = txt.replace(/^\s+/,'').replace(/\s+$/,'');

				if(th.className.search(/sortable-date/) != -1) {
					txt = fdTableSort.dateFormat(txt, th.className.search(/sortable-date-dmy/) != -1);
				} else if(th.className.search(/sortable-numeric|sortable-currency/) != -1) {
					txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));
					if(isNaN(txt)) txt = "";
				} else if(th.className.search(/sortable-text/) != -1) {
					txt = txt.toLowerCase();
				} else if(th.className.search(/sortable-([a-zA-Z\_]+)/) != -1) {
					if((th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData") in window) {
						txt = window[th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData"](td, txt);
					};
				} else {
					if(txt != "") {
						fdTableSort.removeClass(th, "sortable");
						if(fdTableSort.dateFormat(txt) != 0) {
							fdTableSort.addClass(th, "sortable-date");
							txt = fdTableSort.dateFormat(txt);
						} else if(txt.search(fdTableSort.regExp_Number) != -1 || txt.search(fdTableSort.regExp_Currency) != -1) {
							fdTableSort.addClass(th, "sortable-numeric");
							txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));
							if(isNaN(txt)) txt = "";
						} else {
							fdTableSort.addClass(th, "sortable-text");
							txt = txt.toLowerCase();
						};
					};
				};

				if(rowCnt > 0 && identVal[col] != txt) {
					identical[col] = false;
				};

				identVal[col]     = txt;
				data[rowCnt][col] = txt;
			};

			// Add the tr for this row
			data[rowCnt][numberOfCols] = tr;

			// Increment the row count
			rowCnt++;
		}

		// Get the row and column styles
		var colStyle = table.className.search(/colstyle-([\S]+)/) != -1 ? table.className.match(/colstyle-([\S]+)/)[1] : false;
		var rowStyle = table.className.search(/rowstyle-([\S]+)/) != -1 ? table.className.match(/rowstyle-([\S]+)/)[1] : false;

		// Cache the data object for this table
		fdTableSort.tableCache[table.id] = { data:data, pos:-1, identical:identical, colStyle:colStyle, rowStyle:rowStyle, noArrow:table.className.search(/no-arrow/) != -1 };
	},

	initSort: function() {

		var span;
		var thNode      = fdTableSort.thNode;

		// Get the table
		var tableElem   = fdTableSort.thNode;
		while(tableElem.tagName.toLowerCase() != 'table' && tableElem.parentNode) {
			tableElem = tableElem.parentNode;
		};

		// If this is the first time that this table has been sorted, create the data object
		if(!tableElem.id || !(tableElem.id in fdTableSort.tableCache)) {
			fdTableSort.prepareTableData(tableElem);
		};

		// Cache the table id
		fdTableSort.tableId = tableElem.id;

		// Get the column position using the className added earlier
		fdTableSort.pos = thNode.className.match(/fd-column-([0-9]+)/)[1];

		// Grab the data object for this table
		var dataObj     = fdTableSort.tableCache[tableElem.id];

		// Get the position of the last column that was sorted
		var lastPos     = dataObj.pos;

		// Get the stored data object for this table
		var data        = dataObj.data;
		var colStyle    = dataObj.colStyle;
		var rowStyle    = dataObj.rowStyle;
		var len1        = data.length;
		var len2        = data[0].length - 1;
		var identical   = dataObj.identical[fdTableSort.pos] == false ? false : true;
		var noArrow     = dataObj.noArrow;

		if(lastPos != fdTableSort.pos && lastPos != -1) {
			var th = fdTableSort.getTH(thNode.parentNode.getElementsByTagName('th'), lastPos);

			fdTableSort.removeClass(th, "forwardSort");
			fdTableSort.removeClass(th, "reverseSort");
			if(!noArrow) {
				// Remove arrow
				span = th.getElementsByTagName('span')[0];
				while(span.firstChild) span.removeChild(span.firstChild);
			};
		};

		// If the same column is being sorted then just reverse the data object contents.
		var classToAdd = "forwardSort";

		if(lastPos == fdTableSort.pos && !identical) {
			data.reverse();
			classToAdd = thNode.className.search(/reverseSort/) != -1 ? "forwardSort" : "reverseSort";
		} else {
			fdTableSort.tableCache[tableElem.id].pos = fdTableSort.pos;
			if(!identical) {
				if(thNode.className.match(/sortable-numeric|sortable-currency|sortable-date/)) {
					data.sort(fdTableSort.sortNumeric);
				} else if(thNode.className.match('sortable-text')) {
					data.sort(fdTableSort.sortText);
				} else if(thNode.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {
					data.sort(window[thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1]]);
				};
			};
		};

		fdTableSort.removeClass(thNode, "forwardSort");
		fdTableSort.removeClass(thNode, "reverseSort");
		fdTableSort.addClass(thNode, classToAdd);

		if(!noArrow) {
			var arrow = thNode.className.search(/forwardSort/) != -1 ? " \u2193" : " \u2191";
			span = thNode.getElementsByTagName('span')[0];
			while(span.firstChild) span.removeChild(span.firstChild);
			span.appendChild(document.createTextNode(arrow));
		};

		if(!rowStyle && !colStyle && identical) {
			fdTableSort.removeSortActiveClass();
			fdTableSort.thNode = null;
			return;
		}

		var hook = tableElem.getElementsByTagName('tbody');
		hook = hook.length ? hook[0] : tableElem;

		var td, tr;

		for(var i = 0; i < len1; i++) {
			tr = data[i][len2];
			if(colStyle) {
				if(lastPos != -1) {
					fdTableSort.removeClass(tr.getElementsByTagName('td')[lastPos], colStyle);
				}
				fdTableSort.addClass(tr.getElementsByTagName('td')[fdTableSort.pos], colStyle);
			};
			if(!identical) {

				if(rowStyle) {
					if(i % 2) fdTableSort.addClass(tr, rowStyle);
					else fdTableSort.removeClass(tr, rowStyle);
				};

				hook.removeChild(tr); /* Netscape 8.1.2 requires the removeChild call */
				hook.appendChild(tr);
			};
		};
		fdTableSort.removeSortActiveClass();
		fdTableSort.thNode = null;
	},

	getInnerText: function(el) {
		if (typeof el == "string" || typeof el == "undefined") return el;
		if(el.innerText) return el.innerText;

		var txt = '', i;
		for (i = el.firstChild; i; i = i.nextSibling) {
			if (i.nodeType == 3)            txt += i.nodeValue;
			else if (i.nodeType == 1)       txt += fdTableSort.getInnerText(i);
		};

		return txt.replace(/^[ \t\n]+/, "");
	},
	
	dateFormat: function(dateIn, favourDMY) {
		var dateTest = [
			{ regExp:/^(0[1-9]|1[012])([- \/.])(0[1-9]|[12][0-9]|3[01])([- \/.])(\d\d?\d\d)$/, d:3, m:1, y:5 },  // mdy
			{ regExp:/^(0[1-9]|[12][0-9]|3[01])([- \/.])(0[1-9]|1[012])([- \/.])(\d\d?\d\d)$/, d:1, m:3, y:5 },  // dmy
			{ regExp:/^(\d\d?\d\d)([- \/.])(0[1-9]|1[012])([- \/.])(0[1-9]|[12][0-9]|3[01])$/, d:5, m:3, y:1 }   // ymd
			];

		var start;
		var cnt = 0;

		while(cnt < 3) {
			start = (cnt + (favourDMY ? 4 : 3)) % 3;

			if(dateIn.match(dateTest[start].regExp)) {
				res = dateIn.match(dateTest[start].regExp);
				y = res[dateTest[start].y];
				m = res[dateTest[start].m];
				d = res[dateTest[start].d];
				if(m.length == 1) m = "0" + m;
				if(d.length == 1) d = "0" + d;
				if(y.length != 4) y = (parseInt(y) < 50) ? '20' + y : '19' + y;

				return y+m+d;
			}

			cnt++;
		}

		return 0;
	},

	sortDate: function(a,b) {
		var aa = a[fdTableSort.pos];
		var bb = b[fdTableSort.pos];

		return aa - bb;
	},

	sortNumeric:function (a,b) {
		var aa = a[fdTableSort.pos];
		var bb = b[fdTableSort.pos];

		if(aa === "" && !isNaN(bb)) return -1;
		else if(bb === "" && !isNaN(aa)) return 1;
		else if(aa == bb) return 0;

		return aa - bb;
	},

	sortText:function (a,b) {
		var aa = a[fdTableSort.pos];
		var bb = b[fdTableSort.pos];

		if(aa == bb) return 0;
		if(aa < bb)  return -1;

		return 1;
	}
};

//fdTableSort.addEvent(window, "load", fdTableSort.init);
