
//
// Utils
//

//
// Extensions of $().is :
// $().all : return true iff all elements match the selector
$.fn.all = function (sel) { return this.filter(sel).length == this.length; }
// $().none : return true iff no elements match the selector
$.fn.none = function (sel) { return this.not(sel).length == this.length; }

// Shortcuts for ID and name selectors
function hasName(name) { return '[name="' + name + '"]'; }
function hasId(id) { return "#" + id; }

function makeInteger(str) { return + ( str.replace(/[^0-9]/g,'') ); }

function mainForm() { return $(hasName('MainForm')); }
function $formElement (name) { return $( 'input' + hasName(name) + ', select' + hasName(name) ); }
function formElement (name) { return $formElement(name).get(0); }

function isChecked(name) { return (elem = formElement(name) ) && elem.checked; }
function formValue(name) {
	$elem = $formElement(name);
	
	if($elem.length == 1) {
		if($elem.is("[type=checkbox]")) {
			return $elem[0].checked ? $elem.val() : null;
		} else {
			return $elem.val();
		}
	} else if( $elem.all("[type=radio]") )
		return $elem.filter(":checked").val();
	else 
		return null;
}

//
// Form verification
//
function verifyFields(list) { // [[ field name, predicate, error string ], ...]
	$.each(list, function(i, v) {
		   if(! v[1]( formValue(v[0]) ) ) throw ({ err: v[2], fd: formElement( v[0] ) });
		   });
}

function handleVerifyError(e) {
	if(e.hasOwnProperty('err') && e.err) { alert(e.err); }
	if(e.hasOwnProperty('fd') && e.fd) { e.fd.focus(); }
}

// Some predicates for verification
function isEmptyString(str) { return !(str && typeof(str) == 'string' && str.trim()); }
function isNotEmptyString(str) { return !isEmptyString(str); }
function isEmptyArray(arr) { return !($.isArray(arr) && arr.length); }
function isNotEmptyArray(arr) { return $.isArray(arr) && arr.length }
function isPositive(num) { return num > 0; }


//
// Ensure reciprocal focusing between related checkboxes / radio buttons & text fields
// Should usually be called on ready event, i.e. $(reciprocalFocus);
//
// The "rel" attribute should be on the checkbox, and give the ID of the text field, etc.
// that the checkbox controls
//

function reciprocalFocus() {
	$("input[type=checkbox], input[type=radio]")
	.click(function(e) {
		   // Install click handler on the checkbox to focus the associated field
		   rel = e.target.getAttribute('rel');
		   relfield = document.getElementById(rel) || formElement(rel);
		   if( e.target.checked && relfield ) { relfield.focus(); }
		   } )
	
	.each(function() {
		  // Install change handlers for the associated field to enable the checkbox
		  rel = this.getAttribute('rel');
		  relfield = document.getElementById(rel) || formElement(rel);

		  if( relfield ) {
			  eventname = (relfield.tagName == 'INPUT') ? 'click' : 'change';
			  var that = this;
			  $(relfield).bind(eventname, function(e) { that.checked = true; })
		  }
		  });
}

//
// Given an object representing values for form fields (e.g. from a previous
// CGI request), make the state of the displayed form reflect them
//

function displayPreviousChoices(cgi) {
	var field, value, $formFields, descent;
	
	for(field in cgi) {
		value = cgi[field];

		$formFields = $formElement( field );
		if(! $formFields.length ) $formFields = $formElement( field + '[]' );

		switch( $formFields.length ) {
				
			case 0:
				// There are no fields named either 'field' or 'field[]'. In this case, we'll try
				// looking for fields named with explicit indices like 'field[a]' 
				if( $.isArray(value) || $.isPlainObject(value) ) {
					descent = {};
					$.each(value, function ( key, val ) {
						   descent[ field + '[' + key + ']' ] = val;
						   });
					displayPreviousChoices( descent );
				}
				
				break;
				
			case 1:
				// Just use jQuery's val() to set the value of the form element, and check if radio/checkbox
				$formFields.val(value);
				
				if( $formFields.is('[type=checkbox],[type=radio]') )
					$formFields[0].checked = true;
				
				break;
				
			default: 
				// There are multiple items. In this case, we loop over and either check/uncheck
				// or use jQuery's val() to set the value
				if(! $.isArray(value) ) value = [value];
				
				$formFields.each( function ( i ) {
								 
								 if( $(this).is('[type=checkbox],[type=radio]') )
									 this.checked = ( value.indexOf(this.value) != -1 );
								 else 
									 this.value = value[i];
								 
								 } );
				
				break;
		}
		
	}
	
}
