var SortTableMT = Class.create( {
	initialize: function ( element ) {
		this.element = $( element );
		this.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
		this.cache = [];
		this.makeSortable();
		return this;
	},
	makeSortable: function () {
		if ( this.element.getElementsByTagName('thead').length == 0 ) {
			var the = document.createElement('thead');
			the.appendChild( this.element.rows[0] );
			table.insertBefore( the, this.element.firstChild );
		}
		if ( this.element.tHead == null ) this.element.tHead = this.element.getElementsByTagName('thead')[0];
		if ( this.element.tHead.rows.length != 1 ) return;
		var sortbottomrows = [];
		for ( var i = 0, n = this.element.rows.length; i < n; i++ ) {
			if ( this.element.rows[i].className.search( /\bsortbottom\b/ ) != -1 ) {
				sortbottomrows[ sortbottomrows.length ] = this.element.rows[i];
			}
		}
		if ( sortbottomrows ) {
			if ( this.element.tFoot == null ) {
				var tfo = document.createElement('tfoot');
				this.element.appendChild( tfo );
			}
			for ( var i = 0, n = sortbottomrows.length; i < n; i++ ) {
				tfo.appendChild( sortbottomrows[i] );
			}
			sortbottomrows = null;
		}
		var headrow = this.element.tHead.rows[0].cells;
		for ( var i = 0, n = headrow.length; i < n; i++ ) {
			if ( !headrow[i].className.match( /\bsorttable_nosort\b/ ) ) {
				var mtch = headrow[i].className.match( /\bsorttable_([a-z0-9]+)\b/ );
				if ( mtch ) var override = mtch[1];
				if ( mtch && typeof SortTableMT[ 'sort_' + override ] == 'function' ) {
					headrow[i].sorttable_sortfunc = SortTableMT[ 'sort_' + override ];
				} else {
					headrow[i].sorttable_sortfunc = this.guessType(i);
				}
				headrow[i].sorttable_columnindex = i;
				headrow[i].sorttable_tbody = this.element.tBodies[0];
				var cf = function () {
					if ( this.className.search( /\bsorttable_sorted\b/ ) != -1 ) {
						SortTableMT.reverse( this.sorttable_tbody );
						this.className = this.className.replace('sorttable_sorted','sorttable_sorted_reverse');
						this.removeChild( $('sorttable_sortfwdind') );
						var sortrevind = document.createElement('span');
						sortrevind.id = 'sorttable_sortrevind';
						sortrevind.innerHTML = '&nbsp▼';
						this.appendChild( sortrevind );
						return;
					}
					if ( this.className.search( /\bsorttable_sorted_reverse\b/ ) != -1 ) {
						SortTableMT.reverse( this.sorttable_tbody );
						this.className = this.className.replace('sorttable_sorted_reverse','sorttable_sorted');
						this.removeChild( $('sorttable_sortrevind') );
						var sortfwdind = document.createElement('span');
						sortfwdind.id = 'sorttable_sortfwdind';
						sortfwdind.innerHTML = '&nbsp▲';
						this.appendChild( sortfwdind );
						return;
					}
					var theadrow = this.parentNode;
					$A( theadrow.childNodes ).each( function ( cell ) {
						if ( cell.nodeType == 1 ) {
							cell.className = cell.className.replace('sorttable_sorted_reverse','');
							cell.className = cell.className.replace('sorttable_sorted','');
						}
					} );
					var sortfwdind = $('sorttable_sortfwdind');
					if ( sortfwdind ) sortfwdind.remove();
					var sortrevind = $('sorttable_sortrevind');
					if ( sortrevind ) sortrevind.remove();
					this.className += ' sorttable_sorted';
					sortfwdind = document.createElement('span');
					sortfwdind.id = 'sorttable_sortfwdind';
					sortfwdind.innerHTML = '&nbsp▲';
					this.appendChild( sortfwdind );
					var row_array = [], col = this.sorttable_columnindex, rows = this.sorttable_tbody.rows;
					for ( var j = 0, m = rows.length; j < m; j++ ) {
						row_array[ row_array.length ] = [ SortTableMT.getInnerText( rows[j].cells[ col ] ), rows[j] ];
					}
					row_array.sort( this.sorttable_sortfunc );
					var tb = this.sorttable_tbody;
					for ( var j = 0, m = row_array.length; j < m; j++ ) {
						tb.appendChild( row_array[j][1] );
					}
					row_array = null;
				}.bind( headrow[i] );
				Event.observe( headrow[i], 'click', cf );
				this.cache[ this.cache.length ] = [ headrow[i], cf ];
			}
		}
	},
	destroy: function () { this.cache.each( function (b) { Event.stopObserving( b[0], 'click', b[1] ); } ); },
	guessType: function ( column ) {
		var sortfn = SortTableMT.sort_alpha;
		for ( var i = 0, n = this.element.tBodies[0].rows.length; i < n; i++ ) {
			var text = SortTableMT.getInnerText( this.element.tBodies[0].rows[i].cells[ column ] );
			if ( text != '' ) {
				if ( text.match( /^-?[・｣$・､]?[\d,.]+%?$/ ) ) return SortTableMT.sort_numeric;
				var possdate = text.match( SortTableMT.DATE_RE )
				if ( possdate ) {
					var first = parseInt( possdate[1] ), second = parseInt( possdate[2] );
					if ( first > 12 ) {
						return SortTableMT.sort_ddmm;
					} else if ( second > 12 ) {
						return SortTableMT.sort_mmdd;
					} else {
						sortfn = SortTableMT.sort_ddmm;
					}
				}
			}
		}
		return sortfn;
	}
} );
Object.extend( SortTableMT, {
	DATE_RE: /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/,
	getInnerText: function ( node ) {
		var hasInputs = ( typeof node.getElementsByTagName == 'function') && node.getElementsByTagName('input').length;
		if ( node.getAttribute('sorttable_customkey') != null ) {
			return node.getAttribute('sorttable_customkey');
		} else if ( typeof node.textContent != 'undefined' && !hasInputs ) {
			return node.textContent.replace( /^\s+|\s+$/g, '' );
		} else if ( typeof node.innerText != 'undefined' && !hasInputs ) {
			return node.innerText.replace( /^\s+|\s+$/g, '' );
		} else if ( typeof node.text != 'undefined' && !hasInputs ) {
			return node.text.replace( /^\s+|\s+$/g, '' );
		} else {
			switch ( node.nodeType ) {
				case 3:
					if ( node.nodeName.toLowerCase() == 'input' ) {
						return node.value.replace( /^\s+|\s+$/g, '' );
					}
				case 4:
					return node.nodeValue.replace( /^\s+|\s+$/g, '' );
					break;
				case 1: case 11:
					var innerText = '';
					for ( var i = 0, n = node.childNodes.length; i < n; i++ ) {
						innerText += SortTableMT.getInnerText( node.childNodes[i] );
					}
					return innerText.replace( /^\s+|\s+$/g, '' );
					break;
				default: return '';
			}
		}
	},
	reverse: function ( tbody ) {
		var newrows = [];
		for (var i = 0, n = tbody.rows.length; i < n; i++ ) {
			newrows[ newrows.length ] = tbody.rows[i];
		}
		for ( var i = newrows.length - 1; i >= 0; i-- ) {
			tbody.appendChild( newrows[i] );
		}
		newrows = null;
	},
	sort_numeric: function (a,b) {
		var aa = parseFloat( a[0].replace( /[^0-9.-]/g, '' ) );
		if ( isNaN(aa) ) aa = 0;
		var bb = parseFloat( b[0].replace( /[^0-9.-]/g, '' ) );
		if ( isNaN(bb) ) bb = 0;
		return aa - bb;
	},
	sort_alpha: function (a,b) {
		if ( a[0] == b[0] ) return 0;
		if ( a[0] < b[0] ) return -1;
		return 1;
	},
	sort_ddmm: function (a,b) {
		var mtch = a[0].match( SortTableMT.DATE_RE ), y = mtch[3], m = mtch[2], d = mtch[1];
		if ( m.length == 1 ) m = '0' + m;
		if ( d.length == 1 ) d = '0' + d;
		var dt1 = y + m + d;
		mtch = b[0].match( SortTableMT.DATE_RE );
		y = mtch[3]; m = mtch[2]; d = mtch[1];
		if ( m.length == 1 ) m = '0' + m;
		if ( d.length == 1 ) d = '0' + d;
		var dt2 = y + m + d;
		if ( dt1 == dt2 ) return 0;
		if ( dt1 < dt2 ) return -1;
		return 1;
	},
	sort_mmdd: function (a,b) {
		var mtch = a[0].match( SortTableMT.DATE_RE ), y = mtch[3], m = mtch[2], d = mtch[1];
		if ( m.length == 1 ) m = '0' + m;
		if ( d.length == 1 ) d = '0' + d;
		var dt1 = y + m + d;
		mtch = b[0].match( SortTableMT.DATE_RE );
		y = mtch[3]; d = mtch[2]; m = mtch[1];
		if ( m.length == 1 ) m = '0' + m;
		if ( d.length == 1 ) d = '0' + d;
		var dt2 = y + m + d;
		if ( dt1 == dt2 ) return 0;
		if ( dt1 < dt2 ) return -1;
		return 1;
	},
	shaker_sort: function ( list, comp_func ) {
		var b = 0, t = list.length - 1, swap = true;
		while ( swap ) {
			swap = false;
			for ( var i = b; i < t; ++i ) {
				if ( comp_func( list[i], list[ i + 1 ] ) > 0 ) {
					var q = list[i];
					list[i] = list[ i + 1 ];
					list[ i + 1 ] = q;
					swap = true;
				}
			}
			t--;
			if ( !swap ) break;
			for ( var i = t; i > b; --i ) {
				if ( comp_func( list[i], list[ i - 1 ] ) < 0 ) {
					var q = list[i];
					list[i] = list[ i - 1 ];
					list[ i - 1 ] = q;
					swap = true;
				}
			}
			b++;
		}
	}
} );
