var DynamicTable = new Class({

    initialize: function (table, rowHtml)
    {
        this.table   = table;
        this.rowHtml = rowHtml;
    },

    addRow: function()
    {

        var tbody = this.table.getElementsByTagName("tbody")[0];
        
        var row = document.createElement("TR");
        $(row).set('html', this.rowHtml);
     
        tbody.appendChild(row);
     
    }   
    
});

/**
 * This class is used to create a label inside an input element which disappears when the 
 * user enters something in the input.
 */
var InnerLabel = new Class({

    initialize: function (input, label)
    {
        
        this.inputId = input.id;
        this.label   = label;
        this.labeled = false;
        this.type    = input.getAttribute("type");

		// Detect Konqueror and Safari which don't have unique objects, since this crashes
		// Konqueror 3.4 and Safari 1.0
        
		var ua = navigator.userAgent.toLowerCase();
		
		if (!((ua.indexOf('konqueror')!=-1) && /khtml\/3\.[0-4]/.test(ua)) && 
			!(((ua.indexOf('safari')!=-1) && !window.print)))
		{
			// Start the label as visible.
			this._blur();
			this._assignEventHandlers(input);
		}
        
        // We also need to add an event to clear the input of our label when the parent form is submit.
        
        var form = $(input).getParent("form");
		
		if (form != undefined)
		{
			var self = this;
			form.addEvent( 'submit', function () { self._submit(); } );
		}

    },
    
    _blur: function ()
    {
	
		if (this.hasFocus) return;

        var input = $(this.inputId);

        if (input.value == '')
        {
            // Add the label.
            input.addClass("labeled");
            
			if (this.type == 'password')
			{
				input = this._changeInputType(input, 'text', this.label, false, true);
			}
			else
			{
				input.value = this.label;
			}
			
            this.labeled = true;
        }
        
    },
    
    _focus: function ()
    {

		if (this.hasFocus) return;
		
		if (this.labeled)
        {
            
			// Clear out the label.
            
			var input = $(this.inputId);
			
			if (this.type == 'password')
			{
				input = this._changeInputType(input, 'password', '', true, false);
			}
			else
			{
				input.value = '';
			}
			
            input.removeClass("labeled");
            this.labeled = false;
			
        }
    },
    
    _submit : function ()
    {
        // Remove the label so we don't submit it.
        if (this.labeled)
        {
            var input = $(this.inputId);
            input.value = '';
        }
    },
	
	_assignEventHandlers : function (input)
	{
		// Needed to capture this for the closure.
		var self = this;
		$(input).addEvent( 'blur',  function () { self._blur(); } );
		$(input).addEvent( 'focus', function () { self._focus(); } );
	},

	_changeInputType : function ( oldElm, iType, iValue, blankValue, noFocus)
	{ 
		// Adapted from:
		// http://www.dynamicsitesolutions.com/javascript/change-input-type-dynamically/
	
		if (!oldElm || !oldElm.parentNode || (iType.length<4) || 
			!document.getElementById || !document.createElement) return;

		var isMSIE=/*@cc_on!@*/false; //http://dean.edwards.name/weblog/2007/03/sniff/
		if(!isMSIE){
			var newElm=document.createElement('input');
			newElm.type=iType;
		} else {
			var newElm=document.createElement('span');
			newElm.innerHTML='<input type="'+iType+'" name="'+oldElm.name+'">';
			newElm=newElm.firstChild;
		}
		
		var props=['name','id','className','size','tabIndex','accessKey'];
		
		for (var i=0,l=props.length;i<l;i++)
		{
			if (oldElm[props[i]]) newElm[props[i]]=oldElm[props[i]];
		}
	  
		this._assignEventHandlers(newElm);

		// hasFocus is to prevent a loop where onfocus is triggered over and over again
		this.hasFocus=false;
		// some browsers need the value set before the element is added to the page
		// while others need it set after
		if(!blankValue) newElm.value=iValue;
		oldElm.parentNode.replaceChild(newElm,oldElm);
		if(!isMSIE && !blankValue) newElm.value=iValue;
		if(!noFocus || typeof(noFocus)=='undefined')
		{
			window.tempElm=newElm;
			setTimeout("tempElm.hasFocus=true;tempElm.focus();",1);
		}
		return newElm;
	}
	
});

function tableHeadingOnClick(table, col)
{

	function Cell() {}

	var sortOrder = 1;
	
	if (table.sortColumn == col + 1)
	{
		sortOrder = -1;
	}
	
	function sortColumn(a, b)
	{
		if (a.value < b.value) {
			return sortOrder;
		} else if (a.value > b.value) {
			return -sortOrder;
		}
		return 0;
	}
	
	// Gather the table data.
	
	var body = table.getElementsByTagName("tbody")[0];
	var rows = table.getElementsByTagName("tr");
	
	// Convert from the object colelct
	
	var cols = new Array(rows.length - 1);
		
	for (var i = 1; i < rows.length; ++i)
	{

		var cells = rows[i].getElementsByTagName("td");
		cols[i - 1] = new Cell;
		
		// Make our sorting case insensitive.
		var text = cells[col].textContent.toLowerCase();
		
		// Check if the colum has a number in it.
		if (text.match(/^\d+$/))
		{
			// Pad out the number with 0s so we can do string comparison on it. If the number is
			// more than 32 digits this won't work, but that's a pretty big number,
			while (text.length < 32)
			{
				text = '0' + text;
			}
		}
		
		cols[i - 1].value = text;
		cols[i - 1].row   = rows[i];
	}
		
	// Sort the rows.
	cols.sort(sortColumn);

	// Remove the rows except the heading from the table (must be done in reverse order).
	for (var i = rows.length - 1; i > 0; --i)
	{
		body.removeChild(rows[i]);
	}

	// Add the rows back in the new sorted order.
	for (var i = 0; i < cols.length; ++i)
	{
		body.appendChild(cols[i].row);
	}
	
	// Save some info in the table on how it's sorted.
	table.sortColumn = (col + 1) * sortOrder;
	
}

function tableGetOnClickHandler(table, col)
{
	return function() { tableHeadingOnClick(table, col); };
}

function tableMakeSortable(id)
{

	// Make all of the headers clickable.

	var table = document.getElementById(id);
	var headings = table.getElementsByTagName("th");
	
	for (var i = 0; i < headings.length; ++i)
	{
		headings[i].onclick = tableGetOnClickHandler(table, i);
	}

}