/**
 * JavaScript general functions
 *
 * General JavaScript functions.
 *
 * @author	Philip Withnall <drbob@tecnocode.co.uk>
 * @copyright	Philip Withnall 2006
 * @package	General
 * @subpackage	JavaScript
 * @version	1.9.2
 * @license	http://tecnocode.co.uk/links/sourcecode-license.html
 * @filesource
 */

window.onload=function() { window.loaded=true; };

// Make console.* a no-op for non-supportive browsers
if(!console)
{
	var console={
		debug:function(){},
		info:function(){},
		warn:function(){},
		error:function(){},
		assert:function(){},
		dir:function(){},
		dirxml:function(){},
		trace:function(){},
		group:function(){},
		groupEnd:function(){},
		time:function(){},
		timeEnd:function(){},
		profile:function(){},
		profileEnd:function(){},
		count:function(){}
	};
}

// Sort out the Element object for IE
if(!window.Element)
{
	var Element={
		prototype:{
			hasAttribute:function(attribute_name) {
				return (this.getAttribute(attribute_name)!=null);
			}
		}
	};
}

Element.prototype.properties_populated=true;

Element.add_properties=function(our_element)
{
	if(!our_element) return our_element;
	if(!our_element.properties_populated)
	{
		for(property in Element.prototype)
		{
			our_element[property]=Element.prototype[property];
		}
		our_element.properties_populated=true;
	}
	return our_element;
};

function $(element_id)
{
	var our_element=Element.add_properties(document.getElementById(element_id));
	if(our_element && our_element.parentNode) Element.add_properties(our_element.parentNode);
	return our_element;
}

function ce(element_type)
{
	return Element.add_properties(document.createElement(element_type));
}

//document.createElement=createElement;

/*
 * Add onload hook
 *
 * Add a hook to onload so that it will be called when the page is loaded.
 *
 * @param	object		Function/Code
*/
function add_onload_hook(function_name)
{
	if(window.loaded)
	{
		function_name();
		return;
	}

	if(window.attachEvent) window.attachEvent('onload',function_name);
	else window.addEventListener('load',function_name,false);
}

/*
 * Load JS file
 *
 * Dynamically load a JavaScript file.
 *
 * @param	string		Filename
*/
function load_js_file(url)
{
	for(var i=0;i<load_js_file.loaded.length;i++)
	{
		if(load_js_file.loaded[i]==url) return;
	}

	load_js_file.loaded.push(url);

	var script=document.createElement('script');
	script.setAttribute('type','text/javascript');
	script.setAttribute('src','{$BASE_URL;}?media=js&page='+url);
	document.getElementsByTagName('head')[0].appendChild(script);
}

load_js_file.loaded=[];

/*
 * Load CSS file
 *
 * Dynamically load a CSS file.
 *
 * @param	string		Filename
*/
function load_css_file(url)
{
	for(var i=0;i<load_css_file.loaded.length;i++)
	{
		if(load_css_file.loaded[i]==url) return;
	}

	load_css_file.loaded.push(url);

	var link=document.createElement('link');
	link.setAttribute('rel','stylesheet');
	link.setAttribute('type','text/css');
	link.setAttribute('href','{$BASE_URL;}?media=css&page='+url);
	document.getElementsByTagName('head')[0].appendChild(link);
}

load_css_file.loaded=[];

// Shamelessly copied from prototype
Function.prototype.bind=function()
{
	var __method=this;
	var args=[];
	for(var i=0;i<arguments.length;i++) args.push(arguments[i]);
	var object=args.shift();

	return function()
	{
		var _arguments=[];
		for(var x=0;x<arguments.length;x++) _arguments.push(arguments[x]);

		return __method.apply(object,args.concat(_arguments));
	};
};

/*
 * Get elements by class name
 *
 * Get all elements under the specified node by class name.
 *
 * @param	string			Class name
 * @return	array|false		Elements or false
*/
document.getElementsByClassName=function(classname)
{
	var a=[];
	var re=new RegExp('(^| )'+classname+'( |$)');
	var els=this.getElementsByTagName('*');

	for(var i=0,j=els.length;i<j;i++)
	{
		if(re.test(els[i].className)) a.push(els[i]);
	}

	return a;
};

Element.prototype.getElementsByClassName=document.getElementsByClassName;

/*
 * Get label by input
 *
 * Get a label for the specified form input.
 *
 * @param	object		Form
 * @param	object		Input
 * @return	string		Label value
*/
function getLabelByFormField(form,form_field)
{
	var labels=form.getElementsByTagName('label');

	for(var i=0;i<labels.length;i++)
	{
		if(labels[i].htmlFor==form_field.getAttribute('id')) return Element.add_properties(labels[i]).getTextContent();
	}

	return '(unknown)';
}

/*
 * Get legend by input
 *
 * Get a legend for the specified form input.
 *
 * @param	object		Form
 * @param	object		Input
 * @return	object|false	Legend or false
*/
function getLegendByFormField(form,form_field)
{
	var legends=form.getElementsByTagName('legend');

	for(var i=0;i<legends.length;i++)
	{
		if(legends[i].parentNode==form_field.parentNode.parentNode) return Element.add_properties(legends[i]);
	}

	return false;
}

/*
 * Get fieldset by input
 *
 * Get a fieldset for the specified form input.
 *
 * @param	object		Form
 * @param	object		Input
 * @param	object|false	Fieldset or false
*/
function getFieldsetByFormField(form,form_field)
{
	while(!form_field.isTag('fieldset'))
	{
		form_field=form_field.parentNode;
		if(form_field.isTag('body')) return false;
	}

	return Element.add_properties(form_field);
}

/*
 * Get form by input
 *
 * Get a form for the specified form input.
 *
 * @param	object		Input
 * @param	object|false	Form or false
*/
function getFormByFormField(form_field)
{
	while(form_field.isTag('form'))
	{
		form_field=form_field.parentNode;
		if(form_field.isTag('body')) return false;
	}

	return Element.add_properties(form_field);
}

/*
 * Remove children
 *
 * Remove all the children from the specified element.
 *
 * @param	object		Element
*/
function removeAllChildren(node)
{
	for(var i=0;i<node.childNodes.length;i++) node.removeChild(node.childNodes[i]);
}

/*
 * Leap year?
 *
 * Is the date's year a leap year?
 *
 * @return	boolean		Leap year?
 */
Date.prototype.isLeapYear=function()
{
	var current_year=this.getFullYear();
	return (((Math.round(current_year/4)==current_year/4) && (Math.round(current_year/100)!=current_year/100)) || ((Math.round(current_year/100)==current_year/100) && (Math.round(current_year/400)==current_year/400)));
};

Date.prototype.getMonthLengths=function()
{
	if(this.isLeapYear()) return new Array(31,29,31,30,31,30,31,31,30,31,30,31);
	else return new Array(31,28,31,30,31,30,31,31,30,31,30,31);
};

Date.prototype.getMonthLength=function(month_index)
{
	var month_lengths=this.getMonthLengths();
	return month_lengths[month_index];
};

Date.prototype.getCurrentMonthLength=function()
{
	return this.getMonthLength(this.getMonth());
}

Date.prototype.getDateZero=function()
{
	return this.getDate()-1;
};

Date.prototype.getDayZero=function()
{
	var day=this.getDay()-1;
	if(day<0) day=6;
	return day;
};

Date.prototype.decrementMonth=function()
{
	this.setMonth(-1);
};

Date.prototype.incrementMonth=function()
{
	this.setMonth(this.getMonth()+1);
};

Date.prototype.monthNamesTiny=new Array('J','F','M','A','M','J','J','A','S','O','N','D');
Date.prototype.monthNamesShort=new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
Date.prototype.monthNames=new Array('January','February','March','April','May','June','July','August','September','October','November','December');

Date.prototype.weekDaysTiny=new Array('M','T','W','T','F','S','S');
Date.prototype.weekDaysShort=new Array('Mon','Tue','Wed','Thu','Fri','Sat','Sun');
Date.prototype.weekDays=new Array('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday');

/*
 * Insert into input
 *
 * Insert text into the specified input, replacing what's currently selected, or at the current caret point.
 *
 * @param	object		Input
 * @param	string		Text
 * @return	boolean		Inverse success?
*/
function insert_into_input(form_field,text)
{
	var element=$(form_field);

	if (document.selection)
	{
		var sel=document.selection;
		var our_range=sel.createRange();
		our_range.text=our_range.text+text;
		return false;
	}
	if (element.selectionEnd)
	{
		var from=element.selectionStart;
		var to=element.selectionEnd;

		var start=element.value.substring(0,from);
		var end=element.value.substring(to,element.value.length);

		element.value=start+element.value.substring(from,to)+text+end;
		return false;
	}

	element.value+=text;

	return false;
}

/*
 * Clear form inputs
 *
 * Clear all contents of the form inputs for the specified form.
 *
 * @param	object		Form
*/
function clear_form_inputs(form)
{
	var input_elements=form.getElementsByTagName('input');
	var i;

	for(i in input_elements)
	{
		if((typeof(input_elements[i])=='object') && (!input_elements[i].hasAttribute('readonly')) && (input_elements[i].getAttribute('type')!='submit'))
		{
			input_elements[i].value='';
		}
	}

	var textarea_elements=form.getElementsByTagName('textarea');

	for(i in textarea_elements)
	{
		if((typeof(textarea_elements[i])=='object') && (!textarea_elements[i].hasAttribute('readonly')))
		{
			textarea_elements[i].value='';
		}
	}

	var select_elements=form.getElementsByTagName('select');
	var option_elements;
	var a;

	for(i in select_elements)
	{
		if(typeof(select_elements[i])=='object')
		{
			option_elements=select_elements[i].getElementsByTagName('option');

			for(a in option_elements)
			{
				if((typeof(option_elements[a])=='object') && (option_elements[a].hasAttribute('selected')))
				{
					select_elements[i].setAttribute('selectedIndex',a);
				}
			}
		}
	}
}

/*
 * Assign random ID
 *
 * Assign a random ID to the specified element.
 *
 * @return	integer		Random ID
*/
Element.prototype.assignRandomId=function()
{
	if((this.hasAttribute('id')) && (this.getAttribute('id')!='') && (this.getAttribute('id')!=null)) return this.getAttribute('id');

	var id;

	do
	{
		id=Math.floor(Math.random()*10000+Math.random()*1000+Math.random()*100+Math.random()*10);
	}
	while($(id)!=null);

	this.setAttribute('id',id);

	return id;
};

Element.prototype.getTextContent=function()
{
	if(this.textContent) return this.textContent;
	else if(this.innerText) return this.innerText;
	else return false;
}

/*
 * Has class?
 *
 * Determine if an element has a class.
 *
 * @param	string		Class name
 * @return	boolean		Has class?
*/
Element.prototype.hasClass=function(class_name)
{
	var reg_exp=new RegExp('(^| )'+class_name+'( |$)');
	return reg_exp.test(this.getAttribute('class'));
};

/*
 * Add class
 *
 * Add a class to an element.
 *
 * @param	string		Class name
*/
Element.prototype.addClass=function(class_name)
{
	if(this.hasClass(class_name)) return;

	if(this.hasAttribute('class'))
	{
		var current_class=this.getAttribute('class');
		if(current_class.length>0) current_class+=' ';
		this.setAttribute('class',current_class+=class_name);
	}
	else this.setAttribute('class',class_name);
};

/*
 * Remove class
 *
 * Remove a class from an element.
 *
 * @param	string		Class name
*/
Element.prototype.removeClass=function(class_name)
{
	if(this.hasAttribute('class'))
	{
		var reg_exp=new RegExp('(^| )'+class_name+'( |$)');
		this.setAttribute('class',this.getAttribute('class').replace(reg_exp,' '));
	}
};

/*
 * Find previous sibling
 *
 * Find the previous non-text sibling of the element.
 *
 * @return	object		Previous sibling
*/
Element.prototype.findPreviousSibling=function()
{
	var element=this;
	do element=element.previousSibling;
	while((element) && (element.nodeType!=1));
	return element;
};

/*
 * Find next sibling
 *
 * Find the next non-text sibling of the element.
 *
 * @return	object		Next sibling
*/
Element.prototype.findNextSibling=function()
{
	var element=this;
	do element=element.nextSibling;
	while((element) && (element.nodeType!=1));
	return element;
};

/*
 * Tag match?
 *
 * Is this element of the specified (case-insensitive) tag?
 *
 * @param	string		Tag name
 * @return	boolean		Tag match?
*/
Element.prototype.isTag=function(tag_name)
{
	return (this.tagName.toLowerCase()==tag_name.toLowerCase());
};

/*
 * Wait!
 *
 * Wait a specified number of milliseconds.
 *
 * @param	double		Milliseconds
*/
function wait(milliseconds)
{
	var date=new Date();
	var current_date=null;

	do current_date=new Date();
	while(current_date-date<milliseconds);
}

/*
 * IE?
 *
 * Is the client running certified rubbish?
 *
 * @return	boolean		Running IE?
*/
function is_IE()
{
	return (navigator.appName=='Microsoft Internet Explorer'); //SCUM! SCUM! SCUM! SCUM! SCUM! SCUM! SCUM! SCUM! SCUM!
}

/*
 * Trim whitespace
 *
 * Trim whitespace from the left and right of a string.
 *
 * @param	string		String to trim
 * @return	string		Trimmed string
*/
function trim(the_string)
{
	while(the_string.substring(0,1)==' ') the_string=the_string.substring(1,the_string.length);
	while(the_string.substring(the_string.length-1,the_string.length)==' ') the_string=the_string.substring(0,the_string.length-1);

	return the_string;
}

// Functions to get the absolute position of an element
// Taken from http://www.quirksmode.org/js/findpos.html
function find_x_position(obj)
{
	var curleft=0;
	if(obj.offsetParent)
	{
		while(obj.offsetParent)
		{
			curleft+=obj.offsetLeft;
			obj=obj.offsetParent;
		}
	}
	else if(obj.x) curleft+=obj.x;
	return curleft;
}

function find_y_position(obj)
{
	var curtop=0;
	if(obj.offsetParent)
	{
		while(obj.offsetParent)
		{
			curtop+=obj.offsetTop;
			obj=obj.offsetParent;
		}
	}
	else if(obj.y) curtop+=obj.y;
	return curtop;
}

function find_width(obj)
{
	if(obj.offsetWidth) return obj.offsetWidth;
	else if(obj.clientWidth) return obj.clientWidth;
}

// Function to find the CSS width of an object (no padding, margin, or border included)
function find_css_width(obj,original_width)
{
	var width=0;
	var css_width=0;
	var object=obj;
	if(!original_width) original_width=find_width(obj);
	obj.style.width=original_width+'px';
	if(obj.offsetParent)
	{
		while(obj.offsetParent)
		{
			width+=obj.offsetWidth;
			obj=obj.offsetParent;
		}
	}
	else if(obj.clientWidth) width+=obj.clientWidth;
	css_width=original_width-(width-original_width);
	object.style.width=css_width+'px';
	return css_width;
}

function find_height(obj)
{
	if(obj.offsetHeight) return obj.offsetHeight;
	else if(obj.clientHeight) return obj.clientHeight;
}

// Function to find the CSS height of an object (no padding, margin, or border included)
function find_css_height(obj,original_height)
{
	var height=0;
	var css_height=0;
	var object=obj;
	if(!original_height) original_height=find_height(obj);
	obj.style.height=original_height+'px';
	if(obj.offsetParent)
	{
		while(obj.offsetParent)
		{
			height+=obj.offsetHeight;
			obj=obj.offsetParent;
		}
	}
	else if(obj.clientHeight) height+=obj.clientHeight;
	css_height=original_height-(height-original_height);
	object.style.height=css_height+'px';
	return css_height;
}

function get_window_width()
{
	if (typeof(window.innerWidth)=='number') return window.innerWidth;
	else if (document.documentElement && document.documentElement.clientWidth) return document.documentElement.clientWidth;
	else if (document.body && document.body.clientWidth) return document.body.clientWidth;
	return null;
}

function get_window_height()
{
	if (typeof(window.innerHeight)=='number') return window.innerHeight;
	else if (document.documentElement && document.documentElement.clientHeight) return document.documentElement.clientHeight;
	else if (document.body && document.body.clientHeight) return document.body.clientHeight;
	return null;
}

function get_x_scroll()
{
	if (typeof(window.pageXOffset)=='number') return window.pageXOffset;
	else if (document.body && document.body.scrollLeft) return document.body.scrollLeft;
	else if (document.documentElement && document.documentElement.scrollLeft) return document.documentElement.scrollLeft;
	return 0;
}

function get_y_scroll()
{
	if (typeof(window.pageYOffset) == 'number') return window.pageYOffset;
	else if (document.body && document.body.scrollTop) return document.body.scrollTop;
	else if (document.documentElement && document.documentElement.scrollTop) return document.documentElement.scrollTop;
	return 0;
}

// From http://hartshorne.ca/2006/01/23/javascript_cursor_position/
function get_cursor_position(e)
{
	e=e||window.event;
	var cursor={x:0,y:0};
	if(e.pageX||e.pageY)
	{
		cursor.x=e.pageX;
		cursor.y=e.pageY;
	} 
	else
	{
		var de=document.documentElement;
		var b=document.body;
		cursor.x=e.clientX+(de.scrollLeft||b.scrollLeft)-(de.clientLeft||0);
		cursor.y=e.clientY+(de.scrollTop||b.scrollTop)-(de.clientTop||0);
	}
	return cursor;
}

function scroll_to_object(scroll_element)
{
	window.scroll(get_x_scroll(),find_y_position(scroll_element));
}

