/**
 * DOM Extender
 * 
 * These functions are written to make it more easy to work with DOM/HTML elements in JavaScript.
 * After adding some very useful, but missing, functionalities, working with some elements will be more easy.
 * 
 * To extend an object you need to use one of the following functions to initize them:
 *   select_extend(obj)
 *   table_extend(obj)
 *   input_extend_radio(obj)
 * You can also choose to call dom_extend() in your initialisation-script, so all objects will be extended. 
 * 
 * You may freely use this file, but please leave all comments, including the authors name, in it.
 * 
 * Extra added functionalities (needs initialisation):
 *   select.options.addItem(value, text)    // Easy way to add an item to the pulldown
 *   select.options.clear(except)           // Removes all options from a pulldown
 *   select.options.copyFrom(src_obj)       // Copies all options from another SELECT-element to this one
 *   select.options.search(value)           // Easy way to find the index of a value, returns -1 if not found
 *   select.options.sort()                  // Sorts all items in the pulldown by value
 *   select.textValue()                     // Returns not the value but the text bounded to the value
 *   input.radio.getValue()                 // Returns the value of a checked radio button with the same name
 *   input.radio.setValue(value)            // Checks the radio button with the same name and this value
 *   table.createRow(cells, index, html)    // Creates a new row into the table
 *   table.clearRows(except)                // Removes all rows from a table
 *  
 * Extra added functionalities (don't need initialisation): 
 *   Math.factorial(n)                      // Calculates the factorial of a number (n!)
 *   Number.toPercent()                     // Displays a number as percent value
 *   Number.toRank()                        // Displays a number as rank
 * 
 * @author Stefan Thoolen <stefan@netvlies.nl>
 */

/**
 * Extends all currently available extendable elements
 * @return	boolean			Always returns true 
 */
function dom_extend() {
	select_extend_all();
	table_extend_all();
	input_extend_all();
	return true;
}

/**
 * Extends all currently available SELECT-elements
 * @return	boolean			Always returns true 
 */
function select_extend_all() {
	var that=document.getElementsByTagName('SELECT');
	for(var i=0;i<that.length;i++) select_extend(that[i]);
	return true;
}

/**
 * Extends one specific SELECT-element
 * This function will check if the element is already extended.
 * If so, it will return false.
 * 
 * @param	object	that	SELECT-element that has to be extended (if it's a string, it must be the id of the object)
 * @return	boolean			Returns true if this object is extended, false if not
 */
function select_extend(that) {
	if(typeof that=='string') var that=document.getElementById(that);
	if(that.extended) return false;
	that.extended=true;
	
	/**
	 * Easy way to add an item to the pulldown
	 * @param	string	value	The value of the option
	 * @param	string	text	The displayed text of the option
	 * @return	boolean			Always returns true
	 */
	that.options.addItem=function (value, text) {
		if(!text) var text=value;
		var n=document.createElement("OPTION");
		n.value=value;
		n.text=text;
		that.options.add(n);
		return true;
	}
	
	/**
	 * Removes all options from a pulldown
	 * @param	string	except	If filled, options with except as value will remain
	 * @return	boolean			Always returns true
	 */
	that.options.clear=function (except) {
		for(var i=that.options.length-1;i>=0;i--) if(typeof except == 'undefined' || that.options.item(i).value!=except) that.remove(i);
		return true;
	}
	
	/**
	 * Copies all options from another SELECT-element to this one
	 * @param	object	src_obj	The object from which the options must be copied (if it's a string, it must be the id of the object)
	 * @return	boolean			Always returns true
	 */
	that.options.copyFrom=function (src_obj) {
		if(typeof src_obj=='string') var src_obj=document.getElementById(src_obj);
		that.options.clear();
		for(var i=0;i<src_obj.options.length;i++) that.options.addItem(src_obj.options.item(i).value, src_obj.options.item(i).text);
		return true;
	}
	
	/**
	 * Easy way to find the index of a value, returns -1 if not found
	 * @param	string	value	The value we want to find
	 * @return	int				The option index of the item, or -1
	 */
	that.options.search=function (value) {
		for(var i=0;i<that.options.length;i++) {
			if(that.options.item(i).value==value) return i;
		}
		return -1;
	}
	
	/**
	 * Sorts all items in the pulldown by value
	 * @return	boolean			Always returns true
	 */
	that.options.sort=function () {
		var all_vals=new Array();
		for(var i=0;i<that.options.length;i++) all_vals[all_vals.length]=that.options.item(i).value;
		all_vals=all_vals.sort();
		var new_texts=new Array();
		for(var vi=0;vi<all_vals.length;vi++) {
			new_texts[vi]='';
			for(var oi=0;oi<that.options.length;oi++) if(that.options.item(oi).value==all_vals[vi] && that.options.item(oi).text!='') {
				new_texts[vi]=that.options.item(oi).text;
				that.options.item(oi).text='';
			}
		}
		for(var oi=0;oi<that.options.length;oi++) {
			that.options.item(oi).text=new_texts[oi];
			that.options.item(oi).value=all_vals[oi];
		}
		return true;
	}
	
	/**
	 * Returns not the value but the text bounded to the value
	 * @return	string			The text
	 */
	that.textValue=function () {
		for(var i=0;i<that.options.length;i++) {
			if(that.options.item(i).selected) return that.options.item(i).text;
		}
	}
	return true;
}

/**
 * Extends all currently available TABLE-elements
 * @return	boolean			Always returns true 
 */
function table_extend_all() {
	var that=document.getElementsByTagName('TABLE');
	for(var i=0;i<that.length;i++) table_extend(that[i]);
	return true;
}

/**
 * Extends one specific TABLE-element
 * This function will check if the element is already extended.
 * If so, it will return false.
 * 
 * @param	object	that	TABLE-element that has to be extended (if it's a string, it must be the id of the object)
 * @return	boolean			Returns true if this object is extended, false if not
 */
function table_extend(that) {
	if(typeof that=='string') var that=document.getElementById(that);
	if(that.extended) return false;
	that.extended=true;
	
	/**
	 * Creates a new row into the table
	 * @param	array	cells	An array with all cells that must be in the table row
	 * @param	int		index	The position where the row must be placed (default at the end)
	 * @param	boolean	html	Values may contain HTML-code, default: false
	 * @return	object			Returns the TR-element
	 */
	that.createRow=function (cells, index, html) {
		if(typeof cells=='string') var cells=new Array(cells);
		if(typeof index=='undefined') var index=-1;
		if(typeof html=='undefined') var html=false;
		var row=that.insertRow(index);
		for(var i=0;i<cells.length;i++) {
			var cell=row.insertCell(-1);
			cells[i]=new String(cells[i]); // A table cell can only contain strings
			// Fixes some entity bugs (not all, only the ones causing direct troubles)
			if(!html) cells[i]=cells[i].replace(/&/gm,'&amp;').replace(/\</gm,'&lt;').replace(/\>/gm,'&gt;').replace(/\n/gm,'<br />');
			cell.innerHTML=cells[i];
		}
		return row;
	}
	
	/**
	 * Removes all rows from a table (except the first one(s) if except is filled)
	 * @param	int	except		The number of top rows that shouldn't be removed
	 * @return	boolean			Always returns true
	 */
	that.clearRows=function (except) {
		if(!except) var except=0;
		for(var i=that.rows.length-1;i>=except;i--) that.deleteRow(i);
		return true;
	}
}

/**
 * Extends all currently available INPUT-elements
 * @return	boolean			Always returns true 
 */
function input_extend_all() {
	var that=document.getElementsByTagName('INPUT');
	for(var i=0;i<that.length;i++) {
		if(that[i].type=='radio') input_extend_radio(that[i]);
	}
	return true;
}

/**
 * Extends one specific INPUT TYPE=radio-element
 * This function will check if the element is already extended.
 * If so, it will return false.
 * 
 * @param	object	that	TABLE-element that has to be extended (if it's a string, it must be the id of the object)
 * @return	boolean			Returns true if this object is extended, false if not
 */
function input_extend_radio(that) {
	if(that.extended) return false;
	that.extended=true;
	
	/**
	 * Returns the checked value of all radio buttons with the same name
	 * @return	string		The checked value, or false when nothing's checked
	 */
	that.getValue=function () {
		var options=document.getElementsByTagName('INPUT');
		for(var i=0;i<options.length;i++) if(options[i].type=='radio' && options[i].name==that.name && options[i].checked) return options[i].value;
		return false;
	}
	/**
	 * Checks a radio button by its value
	 * @return	boolean		True on success, false on failure (when the value does not exist)
	 */
	that.setValue=function (val) {
		var options=document.getElementsByTagName('INPUT');
		for(var i=0;i<options.length;i++) if(options[i].type=='radio' && options[i].name==that.name && options[i].value==val) { options[i].checked=true; return true; }
		return false;
	}
}

/**
 * Calculates the factorial of a number (n!)
 * In case of 4, the reply will be 1x2x3x4=24
 * @param	int		n		The number of which you want the factorial
 * @return	int				The factorial
 */
Math.factorial=function (n) {
	var ret=1; for(var i=2;i<=n;i++) ret=ret*i;
	return ret;
}

/**
 * Displays a number as percent value
 * Will return 2% for value 0.02
 * @param	int		digits	The max. number of digits that should be displayed after .
 * @return	string			The number in percents
 */
Number.prototype.toPercent=function (digits) {
	if(!digits) var digits=2;
	var round_digits=1; for(var i=0;i<digits;i++) round_digits=round_digits*10;
	var p=Math.round(this*100*round_digits)/round_digits;
	return new String(p)+'%';
}

/**
 * Displays a number as rank
 * Will return 1st 2nd 3rd 4th 5th 6th etc.
 * @return	string			The number as rank
 */
Number.prototype.toRank=function () {
	if(this==1) return '1st';
	if(this==2) return '2nd';
	if(this==3) return '3rd';
	return this.toString()+'th';
}
