/* 
	Sorter from Prototype and script.aculo.us: You Never Knew JavaScript Could Do This!
	Modified by Yannick Van Avermaet
	v1.9 25/02/2010 00:10:11
	All rights reserved © 2009 - 2010
*/
Element.addMethods({
	collectTextNodes: function(element){
		return $A($(element).childNodes).collect(function(node){
			return (node.nodeType == 3 ? node.nodeValue : (node.hasChildNodes()? Element.collectTextNodes(node) : ''));
		}).flatten().join('');
	}
});

var cSorter = Class.create({
	initialize: function(element, options){
		this.first = false;
		this.element = $(element);
		this.options = options || {};
		this.noOrder = this.options.noOrder || new Array();
		this.sortIndex = this.options.startSort-1 || -1;
		this.sortOrder = this.options.sortOrder && ['asc','desc'].indexOf(this.options.sortOrder) > -1 ? this.options.sortOrder : 'asc';
		this.sortOnStart = this.options.sortOnStart || false;
		this.headerRow = this.options.headerRow-1 || 0;
		
		this.initDOMReferences();
		this.initEventHandlers();
		
		if(this.sortOnStart && this.sortIndex >= 0){
			this.first = true;
			this.sort(this.sortIndex);	
		}
	},
	
	initDOMReferences: function(){
		var thead = this.element.down('thead');
		var tbody = this.element.down('tbody');
		if(!thead || !tbody){
			throw 'Table must have a head and a body to be sortable';
		}
		
		this.headers = thead.down('tr', this.headerRow).childElements();
		this.headers.each(function(e,i){
			if(this.noOrder.indexOf(i+1) == -1)
				e._colIndex = i;
		}.bind(this));
		this.bodies = tbody.childElements(); // get all tr descendants
		this.bodies.each(function(e,i){
			e._rowIndex = i;
		});
		this.tbody = tbody;
	},
	
	initEventHandlers: function(){
		this.handler = this.handleHeaderClick.bind(this);
		this.element.observe('click',this.handler, false);
	},
	
	handleHeaderClick: function(e){
		var element = e.element();
		if(!('_colIndex' in element)){
			element = element.ancestors().find(function(elt){
				return '_colIndex' in elt;
			});
			
			if(!((element) && '_colIndex' in element))
				return;
		}
		e.stop();
		this.sort(element._colIndex);
	},
	
	adjustSortMarkers: function(index){
		if(this.sortIndex != -1){
			this.headers[this.sortIndex].removeClassName('sort-'+this.sortOrder);
		}
		
		if(this.sortIndex != index){
			this.sortOrder = 'asc';
			this.sortIndex = index;
		}
		else{
			if(this.first)
				this.first = false;
			else
				this.sortOrder = ('asc' == this.sortOrder ? 'desc' : 'asc');
		}
		
		if(this.headers[index]){
			this.headers[index].addClassName('sort-'+this.sortOrder);
		}
	},
	
	sort: function(index){
		this.adjustSortMarkers(index);
		var rows = this.tbody.childElements();
		
		var length = 0;
		rows.each(function(row){
			var elm = row.childElements()[this.sortIndex];
			value = elm.collectTextNodes().replace(/^\s+|\s+$/g, '');
			if(!isNaN(value) && length < value.length)
				length = value.length;
		}.bind(this));
		
		rows = rows.sortBy(function(row){
			var elm = row.childElements()[this.sortIndex];
			value = elm.collectTextNodes().replace(/^\s+|\s+$/g, '').toLowerCase();
			
			var regexDate = /^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/;
			if(value.replace(/\s/g,'') === ''){
				return '   '+elm.up()._rowIndex;
			}
			else if(!isNaN(value)){
				if(value == 0){
					return ' '+elm.up()._rowIndex+value;
				}
					
				for(var i = 0; i < (length-(value.length-i)); i++)
					value = '0'+value;
			}
			else if(regexDate.test(value)){
				var year = RegExp.$3;
				var month = ((RegExp.$2.length == 1) ? '0' : '') + RegExp.$2;
				var day = ((RegExp.$1.length == 1) ? '0' : '') + RegExp.$1;
				return '  '+year+'/'+month+'/'+day;
			}
			
			return value+elm.up()._rowIndex;
		}.bind(this));
		
		if('desc' != this.sortOrder)
			rows = rows.reverse();

		rows.each(function(row,index){
			if(row.getAttribute('style') == null || (row.getAttribute('style') != null && row.getAttribute('style').toString().indexOf('display') == -1)){
				row[(1 == index % 2 ? 'add': 'remove')+ 'ClassName']('alternate');
			}
			var tmp = index-1;
			if(tmp < 0) tmp = 0;
			this.tbody.insertBefore(row,rows[tmp]);
		}.bind(this));
	}
});
