/***************************************************************************************************************\
	Requires jQuery
	
	Usage:
		Given HTML similar to this:
		
				<div class="radios">
					<input type="hidden" value="" />
					<a class="radio" href="#" value="1">1</a>
					<a class="radio" href="#" value="2">2</a>
					<a class="radio" href="#" value="3">3</a>
					<a class="radio" href="#" value="4">4</a>
					<a class="radio" href="#" value="5">5</a>
				</div>
		
		Or, if labels are needed, each "radio" button should be done like so:
		
				...
				<div class="radiolabel">
					<a class="radio" href="#" value="1">&raquo;</a>
					<a class="label">Lorem Ipsum</a>
				</div>
				...
		
		Script it like so:
			- 	Simply include this file.  If new groups are added after the DOM ready event, run the 
				radios_init() function to initialize them.  New radio buttons may be added to or removed
				from an existing group without running this function.
			-	The hidden form field's "change" event is fired whenever its value is set.
				
	HTML notes:
		-	The widths of the a.radio elements will be set to the widest one of the group's width by default.
			If this behaviour is not desired, simply add the class "noresize" to the group's parent(.radios)
			element.
		-	The examples use "div" elements, these may be anything appropriate (spans, tables, table rows,
			table cells, list elements, whatever).
			The only required element types are the anchors ("radio" button and, if used, the "label").
		-	Unrelated HTML elements may be present within a "radios" button group's structure, so long
			as there is a parent element wrapping the entire group with the class "radios" and, if used,
			each "radio" button and its corresponding "label" share a parent element with the "radiolabel"
			class.
		-	Only one each a.radio and a.label may existing within each .radiolabel element.
		-	Each group must be within its own .radios element.
			
	Pre-populated forms:
		-	Simply set the value of the hidden field and the corresponding "radio" button will be selected.
			This also works for "remembering" the selection if the page is refreshed (on F5 but
			not Ctrl+F5 -- just like the real thing).
			
	Notes:
		-	Should work with a form reset button (reverting to original label text and hidden field value).
		-	If entire div.radios radio groups are added after DOM ready, radios_init() must be run again.
			This will only initialize new .radios groups.
		-	"Radio" buttons may be added or removed to an existing group without rerunning the init function.
		-	Keyboard navigation should be similar to that of an HTML radio group.

\***************************************************************************************************************/
jQuery(function(){
	radios_init();
});
function radios_init(){
	var $ = jQuery;
	//set up each radio group
	$('div.radios:not(.ready)').each(function(){
		var $group = $(this), $field = radios_field($group), val = $field.val(), $radios = $group.find('a.radio'), $labels = $group.find('a.label');
		$group.addClass('ready'); //allows new .radios to be initialized wihout interfering with existing ones
		$labels.attr('tabindex','-1'); //exlude a.label links from tab order
		if(!$group.hasClass('noresize')) radios_equalize_widths($,$radios);
		$group.find('a.radio[value="' + val + '"]:first').addClass('selected'); //set pre-populated selection
		//events
			//  delegation allows options to be changed without needing to reset event listeners
			//	provided the parent .radios element has been initialized
		//hover
			$group.delegate('a', 'mouseover', radios_mouseover);
			$group.delegate('a', 'mouseout', radios_mouseout);
		//focus/blur
			$group.delegate('.radio', 'focus', radios_focus);
			$group.delegate('.radio', 'blur', radios_blur);
		//click
			$group.delegate('.radio', 'click', radios_click);
			$group.delegate('.label', 'click', radios_click);
		//keydown
			$group.delegate('.radio', 'keydown', radios_keydown);
	});
}
/* events */
function radios_mouseover() {
	var $ = jQuery, $this = $(this), $group = radios_group($this);
	$group.find('.hover').removeClass('hover');
	$this.closest('.radiolabel', $group).addClass('hover');
}
function radios_mouseout() {
	var $ = jQuery, $this = $(this), $group = radios_group($this);
	$this.closest('.radiolabel', $group).removeClass('hover');
}
function radios_focus() {
	var $ = jQuery, $this = $(this), $group = radios_group($this);
	$this.addClass('focus');
	radios_mouseover($this, $group);
}
function radios_blur() {
	var $ = jQuery, $this = $(this), $group = radios_group($this);
	$this.removeClass('focus');
	radios_mouseout($this, $group);
}
function radios_click(e) {
	e.preventDefault();
	var $ = jQuery, $this = $(this), $group = radios_group($this), $field = radios_field($group);
	if($this.hasClass('label')) {
		$this.blur();
		$this = $this.closest('.radiolabel', $group).find('.radio');
		$this.focus();
	}
	if($this.hasClass('selected')) return;
	$group.find('.selected').removeClass('selected');
	$this.addClass('selected');
	$field.val($this.attr('value'));
	$field.change();
}
function radios_focus_previous($this) {
	var $group = radios_group($this), $radios = $group.find('.radio');
	var i = $radios.index($this) - 1;
	if(i >= 0) $radios.get(i).focus();
}
function radios_focus_next($this) {
	var $group = radios_group($this), $radios = $group.find('.radio');
	var i = $radios.index($this) + 1;
	if(i < $radios.length) $radios.get(i).focus();
}
function radios_keydown(e){
	var k = e.keyCode, $this = jQuery(this);
	if(jQuery.inArray(k,[13,32,37,38,39,40]) > -1) {
		e.preventDefault();
		e.stopPropagation();
		if(k == 13 || k == 32) $this.click(); //enter or space
		else if(k == 37 || k == 38) radios_focus_previous($this); //left or up arrow
		else if(k == 39 || k == 40) radios_focus_next($this); //right or down arrow
		return;
	}
}
/* utilities */
function radios_group($this) { //return parent group
	return $this.closest('.radios');
}
function radios_field($group) { //return group's hidden input field
	return $group.find('input[type="hidden"]:first');
}
function radios_equalize_widths($,$radios){
	//sets all radio buttons in a group to the same width (that of the widest of the group)
	var w = 0;
	$radios.each(function(){
		var tw = $(this).width();
		if(tw > w) w = tw;
	});
	$radios.width(w);
}
