/**
 * Javascript for the mid-year tool
 */
$(document).ready(function()
{
	// Create a new Midyear Tool
	var midyearTool = new Tool();
});



/**
 * A Career tab
 *
 * On this tab the user selects a Career they are interested in.
 */
function CareerTab()
{
	var _link = "/ajax/tool/career";
	var _careerId = null;


	/**
	 * Returns the destination URL for the tab
	 *
	 * @return string
	 */
	this.getUrl = function()
	{
		var tabLink = _link;
		var queryString = new Array();

		if( _careerId > 0 )
		{
			queryString[queryString.length] = 'careerId=' + _careerId;
		}

		tabLink += "?" + implode('&', queryString);

		return tabLink;
	}


	/**
	 * Load actions for the tab
	 */
	this.load = function()
	{
		debug.log("Loading Career data...");

		// If a career has been chosen, preselect that career button
		if( _careerId > 0 )
		{
			$('#career-' + _careerId).click();
		}

		// Hide all radios of the Career buttons
		$("#form_career").muRadioButton();
	}


	/**
	 * Save actions for the tab
	 */
	this.save = function()
	{
		debug.log("Saving Career data...");

		// Get the currently selected career id from the radio button selected
		var selectedCareerId = $('input:radio[name=careerId]:checked').val();
		if( parseInt(selectedCareerId) > 0 )
		{
			// A career is selected, so store it.
			_careerId = selectedCareerId;
		}
	}


	/**
	 * Validates the tab
	 *
	 * @return bool
	 */
	this.validate = function()
	{
		debug.log('Validating Career data...');

		if( _careerId == null )
		{
			return false;
		}

		return true;
	}


	/**
	 * Returns the current Career Id
	 */
	this.getCareerId = function()
	{
		return parseInt(_careerId);
	}


	/**
	 * Registers an Omniture tracking request for the tab
	 *
	 * NOTE: This should be called in response to a user clicking the next button on a tab, but only once the tab is valid
	 */
	this.omnitureTrack = function()
	{
		var s=s_gi(s_account);
		s.pageName=s.pageName.replace(new RegExp(/main page|career|course|qualifications|whoareyou|altentry /g),'career');
		s.events='event2';
		s.eVar8= 'Mid Year';
		s.t();

		mboxUpdate('midyear_top','page=career');
	}
}


/**
 * A Course tab
 *
 * This tab appears after the Career Tab and allows a user to select a Course they are interested in.
 *
 * @param CareerTab careerTab
 */
function CourseTab( careerTab )
{
	var _link = "/ajax/tool/course";
	var _courseId = null;
	var _careerTab = careerTab;

	// When a NEW career is selected ensure the selected course gets reset as it might not
	// be a course that is associated with the new career.
	$('input:radio[name=careerId]').live("click", function()
	{
		if( $('input:radio[name=careerId]:checked').val() != _careerTab.getCareerId() )
		{
			_courseId = null;
		}
	});


	/**
	 * Returns the destination URL for the tab
	 *
	 * @return string
	 */
	this.getUrl = function()
	{
		var tabLink = _link;
		var queryString = new Array();
		var selectedCareerId = _careerTab.getCareerId();

		if( selectedCareerId > 0 )
		{
			queryString[queryString.length] = 'careerId=' + selectedCareerId;
		}

		if( _courseId > 0 )
		{
			queryString[queryString.length] = 'courseId=' + _courseId;
		}

		tabLink += "?" + implode('&', queryString);

		return tabLink;
	}


	/**
	 * Load actions for the tab
	 */
	this.load = function()
	{
		debug.log("Loading Course data...");
	}


	/**
	 * Save actions for the tab
	 */
	this.save = function()
	{
		debug.log("Saving Course data...");

		// Get the currently selected course id from the radio button selected
		var selectedCourseId = $('input:radio[name=courseId]:checked').val();
		if( parseInt(selectedCourseId) > 0 )
		{
			_courseId = selectedCourseId;
		}
	}


	/**
	 * Display actions for the tab
	 */
	this.show = function()
	{
		// If a course has been chosen, preselect that course button
		// NOTE: this should occur before .muRadioButton() is applied.
		if( _courseId > 0 )
		{
			$('#course-' + _courseId).click();
		}

		// Hide all radios of the Course buttons
		$("#form_course").muRadioButton();

		// IMPORTANT NOTE: The next set of operations regarding the jScrollPane must be performed after the .muRadioButton() has been applied.
		// Init the jscrollpane for courses
		try
		{
			$('#courses_scroller').jScrollPane({scrollbarWidth: 24, scrollbarMargin: 0, showArrows : true, dragMinHeight : 24, animateTo: true});
		}
		catch( error )
		{
			// Catch for IE6 as it throws an exception but still the Jscrollpane works.
		}

		// If a 'more info' link is clicked, then launch the Course Info overlay
		$("#courses_scroller li a").mouseup(function()
		{
			var path = this.getAttribute('href');
			$.get(path, function(data)
			{
				$('.jScrollPaneContainer').append(data);

				// If the 'Close Window' button is clicked in the Course Info overlay, then destroy the overlay
				$("#btnCloseWindow").click( function()
				{
					$("#courseInfo").remove();

					return false;
				});
			});
		});

		// If a course is selected, move the scroller to that course
		// NOTE: this should be performed last in the show actions so the correct location on screen is scrolled too.
		if( _courseId > 0 )
		{
			try
			{
				$("#courses_scroller")[0].scrollTo('#li-' + _courseId);
			}
			catch( error )
			{
				// opera web browser is known to be too slow at rendering the tab content and the .scrollTo fails.
			}
		}
	}


	/**
	 * Validates the tab
	 *
	 * @return bool
	 */
	this.validate = function()
	{
		debug.log("Validation Course data...");

		if( _courseId == null )
		{
			return false;
		}

		return true;
	}


	/**
	 * Returns the current Course Id
	 *
	 * @return int/NaN
	 */
	this.getCourseId = function()
	{
		return parseInt(_courseId);
	}


	/**
	 * Registers an Omniture tracking request for the tab
	 *
	 * NOTE: This should be called in response to a user clicking the next button on a tab, but only once the tab is valid
	 */
	this.omnitureTrack = function()
	{
		var s=s_gi(s_account);
		s.pageName=s.pageName.replace(new RegExp(/main page|career|course|qualifications|whoareyou|altentry /g),'course');
		s.events= '';
		s.eVar8= '';
		s.t();

		mboxUpdate('midyear_top','page=course');
	}
}


/**
 * A Qualifications tab
 *
 * This tab appears after the Career and Course tabs. It allows a user to select
 * qualifications they hold.
 *
 * @param CareerTab careerTab
 * @param CourseTab courseTab
 */
function QualificationsTab( careerTab, courseTab )
{
	var _link = "/ajax/tool/qualifications";
	var _qualifications = null;
	var _careerTab = careerTab;
	var _courseTab = courseTab;


	/**
	 * Returns the destination URL of the tab
	 */
	this.getUrl = function()
	{
		var tabLink = _link;
		var queryString = new Array();
		var selectedCareerId = _careerTab.getCareerId();
		var selectedCourseId = _courseTab.getCourseId();

		if( selectedCareerId > 0 )
		{
			queryString[queryString.length] = 'careerId=' + selectedCareerId;
		}

		if( selectedCourseId > 0 )
		{
			queryString[queryString.length] = 'courseId=' + selectedCourseId;
		}

		tabLink += "?" + implode('&', queryString);

		return tabLink;
	}


	/**
	 * Load actions for the tab
	 */
	this.load = function()
	{
		debug.log("Loading Qualification data...");

		// Ensure that if the qualification selected is "I don't have any of these qualifications" that
		// all other qualifications are deselected.
		// NOTE: "I don't have any of these qualifications" checkbox has the name and id of 'qualification-0'.
		$("input:checkbox[name='qualification-0']").click( function()
		{
			$("input:checkbox[name!='qualification-0']:checked").each(function()
			{
				$("label[for='" + $(this).attr('name') + "']").unsetCheckBox();
			});
		});

		// Ensure that if a qualification other than "I don't have any of these qualifications" is selected, then
		// the "I don't have any of these qualifications" checkbox gets deselected.
		// NOTE: "I don't have any of these qualifications" checkbox has the name and id of 'qualification-0'.
		$("input:checkbox[name!='qualification-0']").click( function()
		{
			$("label[for='qualification-0']").unsetCheckBox();
		});
	}


	/**
	 * Save actions for the tab
	 */
	this.save = function()
	{
		debug.log("Saving Qualification data...");

		// Save the qualifications selected (resetting previously saved ones first)
		_qualifications = null;

		$("input:checkbox[name^='qualification-']:checked").each(function()
		{
			if( _qualifications == null )
			{
				_qualifications = new Array();
			}

			// Save this qualification
			_qualifications[_qualifications.length] = $(this).val();
		});
	}


	/**
	 * Validation for the tab
	 *
	 * @return bool
	 */
	this.validate = function()
	{
		debug.log("Validating Qualification data...");

		if( _qualifications == null )
		{
			// No qualifications selected
			return false;
		}

		return true;
	}


	/**
	 * Display actions for the tab
	 */
	this.show = function()
	{
		// If one or more qualifications have been chosen, preselect those checkboxes
		if( _qualifications != null )
		{
			for( var index in _qualifications )
			{
				$("input:checkbox[name='qualification-" + _qualifications[index] + "']").click();
			}
		}

		// Hide all checkboxes of the Qualifications
		$("#form_qualifications").muCheckbox();
	}


	/**
	 * Returns the current qualifications
	 *
	 * @return object/null
	 */
	this.getQualifications = function()
	{
		return _qualifications;
	}


	/**
	 * Returns whether the current selection of qualifications equates to
	 * being qualified or not
	 *
	 * @return bool
	 */
	this.isQualified = function()
	{
		if( (_qualifications == null) || (_qualifications.length == 1 && _qualifications[0] == 0) )
		{
			// Either no qualifications exist or the qualification '0' (no qualification) is set
			return false;
		}

		return true;
	}


	/**
	 * Registers an Omniture tracking request for the tab
	 *
	 * NOTE: This should be called in response to a user clicking the next button on a tab, but only once the tab is valid
	 */
	this.omnitureTrack = function()
	{
		var s=s_gi(s_account);
		s.pageName=s.pageName.replace(new RegExp(/main page|career|course|qualifications|whoareyou|altentry /g),'qualifications');
		s.events= '';
		s.eVar8= '';
		s.t();

		mboxUpdate('midyear_top','page=qualifications');
	}
}

/**
 * A Results tab.
 *
 * Displays the results of the tool plus a form where the user enters their details.
 * The content of this tab varies depending on whether the user has selected any
 * qualifications on the 'Your qualifications' tab.
 *
 * @param CareerTab careerTab
 * @param CourseTab courseTab
 * @param QualificationsTab qualificationsTab
 * @return void
 */
function ResultsTab( careerTab, courseTab, qualificationsTab )
{
	var _link = "/ajax/tool/results_qualified";
	var _circumstances = null;
	var _careerTab = careerTab;
	var _courseTab = courseTab;
	var _qualificationsTab = qualificationsTab;
	var _formData = null;

	/**
	 * Returns the destination URL for the tab
	 *
	 * @return string
	 */
	this.getUrl = function()
	{
		// The tab source changes depending on whether the user has any qualifications.
		if( qualificationsTab.isQualified() == false )
		{
			// User has no qualifications
			var tabLink = "/ajax/tool/results_unqualified";
		}
		else
		{
			// User has qualifications so defualt to the standard link
			var tabLink = _link;
		}

		var queryString = new Array();
		var selectedCareerId = _careerTab.getCareerId();
		var selectedCourseId = _courseTab.getCourseId();

		if( selectedCareerId > 0 )
		{
			queryString[queryString.length] = 'careerId=' + selectedCareerId;
		}

		if( selectedCourseId > 0 )
		{
			queryString[queryString.length] = 'courseId=' + selectedCourseId;
		}

		tabLink += "?" + implode('&', queryString);

		return tabLink;
	}


	/**
	 * Load actions for the tab
	 */
	this.load = function()
	{
		debug.log("Loading Results data...");

		// Load the Results form
		_initForm();
	}


	/**
	 * Display actions for the tab
	 */
	this.show = function()
	{
		// If there is existing form data, then prefill the form fields
		if( _formData != null )
		{
			for( var fieldName in _formData )
			{
				switch( fieldName )
				{
					case 'gender':
						if( typeof _formData[fieldName] != 'undefined' )
						{
							$("input[name='gender'][value='" + _formData[fieldName] +"']").attr("checked", "checked");
						}
						break;
					case 'optin':
						if( _formData[fieldName] == true )
						{
							$("input[name='optin']").attr("checked", "checked");
						}
						break;
					default:
						$("input[name='" + fieldName + "']").val(_formData[fieldName]);
						break;
				}
			}
		}

		// If one or more circunstances have been chosen, preselect those checkboxes
		if( _circumstances != null )
		{
			for( var index in _circumstances )
			{
				$("input:checkbox[name='circumstance-" + _circumstances[index] + "']").click();
			}
		}

		// Hide all checkboxes of the Circumstances (if they exist)
		if( $("#circumstances").length > 0 )
		{
			$("#circumstances").muCheckbox();
		}
	}


	/**
	 * Save actions for the tab
	 */
	this.save = function()
	{
		debug.log("Saving Results data...");

		// Save the data entered into the form
		// NOTE: The keys used here should match the names of the HTML input fields
		_formData =
		{
			'first_name'	: $("input[name='first_name']").val(),
			'last_name' 	: $("input[name='last_name']").val(),
			'email_address' : $("input[name='email_address']").val(),
			'gender' 		: $("input[name='gender']:checked").val(),
			'optin'			: $("input[name='optin']").attr("checked")
		}

		// Telephone is only displayed on the unqualified form so may not always be present.
		if( $("input[name='telephone']").length > 0 )
		{
			_formData['telephone'] = $("input[name='telephone']").val();
		}

		// Save the circumstances selected (resetting previously saved ones first)
		// NOTE: Circumstances will only exist if showing the 'unqualified' results content
		_circumstances = null;

		$("input:checkbox[name^='circumstance-']:checked").each(function()
		{
			if( _circumstances == null )
			{
				_circumstances = new Array();
			}

			// Save this circumstance
			_circumstances[_circumstances.length] = $(this).val();
		});



	}


	/**
	 * Validates the tab
	 *
	 * @return bool
	 */
	this.validate = function()
	{
		debug.log("Validating Results data...");

		// Validate the form on the page
		return $("#form_results").validate().form();
	}


	/**
	 * Returns the current circumstances
	 *
	 * @return object/null
	 */
	this.getCircumstances = function()
	{
		return _circumstances;
	}


	/**
	 * Initialises the Results tab form
	 *
	 * @return void
	 */
	function _initForm()
	{
		//
		// Init the form
		//

		$("#form_results").validate(
		{
			errorElement : 	"div",
			errorPlacement: function(error, element)
			{
				if( element.attr("name") == "gender" || element.attr("name") == "circumstancesValidationCheck" )
				{
					error.insertAfter(element.parent());
				}
				else
				{
					error.insertAfter(element);
				}
			}
			//submitHandler: functionName
		});


		//
		// Create some custom validation functions
		//
		jQuery.validator.addMethod("validTelephone", function(telephoneNumber, element)
		{
			telephoneNumber = telephoneNumber.replace(/\D+/g, "");

			return (this.optional(element)) || (telephoneNumber.length >= 8) && (telephoneNumber.match(/(^(1300)\d{6}$)|(^(1800|1900|1902)\d{6}$)|(^(612|613|617|618)?0?[2|3|7|8]{1}[0-9]{8}$)|(^(612|613|617|618)?[1-9]{1}[0-9]{7}$)|(^(04|614)\d{2,3}\d{6}$)/));
		}, "Please enter a valid telephone number");


		//
		// Add the validation rules to the various fields
		//

		$("#first_name").rules("add",
		{
			required: true,
			messages:
			{
				required: 	'Please enter your first name'
			}
		});

		$("#last_name").rules("add",
		{
			required: true,
			messages:
			{
				required: 	'Please enter your last name'
			}
		});

		$("#email_address").rules("add",
		{
			required: 	true,
			email: 		true,
			messages:
			{
				required: 	'Please enter your email address',
				email: 		'Please enter a valid email address'
			}
		});

		$("#email_address_confirm").rules("add",
		{
			required: 	true,
			email: 		true,
			equalTo: 	"input[name=email_address]",
			messages:
			{
				required: 	'Please confirm your email address',
				email: 		'Please enter a valid email address',
				equalTo: 	'The email addresses do not match'
			}
		});

		if( $("#telephone").length > 0 )
		{
			$("#telephone").rules("add",
			{
				required: 		false,
				validTelephone: true,
				messages:
				{
					required: 	'Please enter a valid telephone number'
				}
			});
		}

		$("input[name='gender']").rules("add",
		{
			required: true,
			messages:
			{
				required: 	'Please select your gender'
			}
		});

		if( $("#circumstancesValidationCheck").length > 0 )
		{
			$("#circumstancesValidationCheck").rules("add",
			{
				required: function(element)
				{
					return ($("input:checkbox[name^='circumstance-']:checked").length == 0);
			    },
			    messages:
			    {
			    	required:	'Please select a circumstance'
			    }
			});
		}
	}


	/**
	 * Returns the stored form data
	 *
	 * @return object/null
	 */
	this.getFormData = function()
	{
		return _formData;
	}


	/**
	 * Sets the content of _formData
	 */
	this.setFormData = function(data)
	{
		debug.log('Setting default applicant details...');

		// If the required elements exist, then prefil the form data.
		if( (data.first_name != undefined) && (data.last_name != undefined) && (data.email_address != undefined) && (data.gender != undefined) && (data.optin != undefined) )
		{
			// NOTE: The keys used here should match the names of the HTML input fields
			_formData =
			{
				'first_name'	: data.first_name,
				'last_name' 	: data.last_name,
				'email_address' : data.email_address,
				'gender' 		: data.gender,
				'optin'			: data.optin
			}

			if( data.telephone != undefined )
			{
				_formData['telephone'] = data.telephone;
			}
		}
	}


	/**
	 * Registers an Omniture tracking request for the tab
	 *
	 * NOTE: This should be called in response to a user clicking the next button on a tab, but only once the tab is valid
	 */
	this.omnitureTrack = function()
	{
		if( qualificationsTab.isQualified() == true )
		{
			// Qualified tracking code
			var s=s_gi(s_account);
			s.pageName=s.pageName.replace(new RegExp(/main page|career|course|qualifications|whoareyou|altentry /g),'whoareyou');
			s.events='event3,event24';
			s.eVar8= 'Mid Year';
			s.t();

			mboxUpdate('midyear_top','page=whoareyou');
		}
		else
		{
			// Unqualified tracking code
			var s=s_gi(s_account);
			s.pageName=s.pageName.replace(new RegExp(/main page|career|course|qualifications|whoareyou|altentry /g),'altentry');
			s.events='event3,event25';
			s.eVar8= 'Mid Year';
			s.t();

			mboxUpdate('midyear_top','page=altentry');
		}
	}
}





function Tool()
{
	debug = new Debug();

	var _tabSet = $("#tabs");
	var _shouldValidate = false;
	var _shouldOmnitureTrack = false;
	var _urlSave = '/ajax/tool/save.php';
	var _urlError = '/error.php';
	var _urlThankyouQualified = '/thankyou_qualify.php';
	var _urlThankyouUnqualified = '/thankyou_unqualified.php';

	var _careerTab = new CareerTab();
	var _courseTab = new CourseTab(_careerTab);
	var _qualificationsTab = new QualificationsTab(_careerTab, _courseTab);
	var _resultsTab = new ResultsTab(_careerTab, _courseTab, _qualificationsTab);

	var _tabData = new Array
	(
		_careerTab,
		_courseTab,
		_qualificationsTab,
		_resultsTab
	)


	/**
	 * Sets the appropriate events that occur when a tab is selected
	 */
	function _setTabSelectEvents()
	{
		// Set the actions that occur when a new tab is selected.
		_tabSet.bind('tabsselect', function(event, ui)
		{
			// Save data from currently selected tab
			var selectedIndex = _getSelectedTabIndex();
			_tabData[selectedIndex].save();

			// Does the current tab content need validating first?
			if( _shouldValidate )
			{
				// ... yes, so validate current tab content.
				_shouldValidate = false;

				// If validation fails, then return false so the tab switching fails
				if( !_tabData[selectedIndex].validate() )
				{
					// Disable the tab that was being switched to.
					_tabSet.tabs('disable', ui.index);

					// Reset the shouldOmnitureTrack flag
					_shouldOmnitureTrack = false;

					// Return failure of switching
					return false;
				}
			}

			// Does a tracking request need to be sent to Omniture (usually as a result of clicking 'next')?
			if( _shouldOmnitureTrack )
			{
				// ... yes, so send an Omniture tracking request
				_tabData[selectedIndex].omnitureTrack();

				_shouldOmnitureTrack = false;
			}

			// Change the url of the new tab that's being loaded
			_tabSet.tabs('url', ui.index, _tabData[ui.index].getUrl());

			// ... switch to the new tab.

		});
	}


	/**
	 * Sets the appropriate events that occur when a tab is loaded
	 */
	function _setTabLoadEvents(_careerTab)
	{
		// Set the actions that occur when a new tab is loaded.
		_tabSet.bind('tabsload', function(event, ui)
		{
			// Load data for new tab
			_tabData[ui.index].load();
		});

		// Set the actions that occur when a new tab is displayed.
		_tabSet.bind('tabsshow', function(event, ui)
		{
			if( _tabData[ui.index].show )
			{
				_tabData[ui.index].show();
			}

			// Register the common events for a tab
			_registerCommonTabEvents(_careerTab);
		});
	}


	/**
	 * Handles the events that occur when a 'Next' button is clicked
	 */
	function _setBtnNextEvents()
	{
		$(".btnNext").click( function()
		{
			// Ensure that an Omniture tracking request is sent prior to moving to the next tab
			_shouldOmnitureTrack = true;

			// Ensure the current tab is valid before moving to next tab
			_shouldValidate = true;

			// Temporarily enable the tab being switched to so the tab 'select' event
			// can be run. If the current tab is not valid, the tab being switched to
			// will be disabled again.
			_tabSet.tabs('enable', (_getSelectedTabIndex()+1));

			// Advance to the next tab.
			// This will cause save() and validate() to be called (in that order)
			$("#tabs").tabs('select', (_getSelectedTabIndex()+1));

			// Stop the clicking of the button from submitting any forms.
			return false;
		});
	}


	/**
	 * Handles the events that occur when a 'Back' button is clicked
	 */
	function _setBtnBackEvents()
	{
		$(".btnBack").click( function()
		{
			// Move back to the previous tab (if not on the first tab [0]).
			// This will cause save() to be called.
			selectedTabIndex = _getSelectedTabIndex();
			if( selectedTabIndex > 0 )
			{
				$("#tabs").tabs('select', (_getSelectedTabIndex()-1));
			}

			// Stop the clicking of the button from submitting any forms.
			return false;
		});
	}


	/**
	 * Handles the events that occur when a 'End' button is clicked
	 */
	function _setBtnEndEvents()
	{
		$(".btnEnd").click( function()
		{
			// Save data from currently selected tab
			var selectedIndex = _getSelectedTabIndex();
			_tabData[selectedIndex].save();

			// Validate the tab content.
			// If validation fails, then return false so moving to the next page fails
			if( !_tabData[selectedIndex].validate() )
			{
				return false;
			}

			// Send an Omniture tracking request to register the click
			_tabData[selectedIndex].omnitureTrack();
			_shouldOmnitureTrack = false;

			// Store the data
			// If successful, the tool will redirect to the approriate thankyou page.
			// If unsuccessful, the tool will redirect to an error page.
			_storeToolData();

			// Stop the clicking of the button from submitting any forms.
			return false;
		});
	}


	/**
	 * Registers the common events that can occur on a tab
	 *
	 * @param careerTab _careerTab
	 * @return void
	 */
	function _registerCommonTabEvents(_careerTab)
	{
		var careerTab = _careerTab;

		// Set the events for the 'Next', 'Back' and 'Finish/End' buttons
		_setBtnNextEvents();
		_setBtnBackEvents();
		_setBtnEndEvents();


		// When a NEW career is selected ensure all other tabs get disabled.
		$('input:radio[name=careerId]').click( function()
		{
			if( $('input:radio[name=careerId]:checked').val() != careerTab.getCareerId() )
			{
				_tabSet.data('disabled.tabs', [1, 2, 3]);
			}
		});


		// When a 'Change' career/area link is clicked, go back to the Career tab
		$('.linkChangeCareer').click( function()
		{
			_tabSet.tabs('select', 0);
		    return false;
		});


		// When a 'Change' course link is clicked, go back to the Course tab
		$('.linkChangeCourse').click( function()
		{
			_tabSet.tabs('select', 1);
		    return false;
		});
	}


	/**
	 * Handles a successful request of the storing of tool data
	 *
	 * @param mixed data
	 * @param string textStatus
	 */
	function _storeToolDataRequestSuccess( data, textStatus )
	{
		debug.log('Request to store tool data succeeded...');

		// 'data' should be an object in the format { success : 1/0, errorMsg : '', applicantId : '', qualifies : true/false }

		// If the tool data was stored successfully, or an error was caught, data.success should be defined.
		// If data.success is not defined then an uncaught error occurred.
		if( data.success == undefined )
		{
			window.location = _urlError + '?errorMsg=' + Url.encode('Returned error status: ' + textStatus);
		}

		if( data.success == 1 )
		{
			// Redirect to the appropriate thankyou page.
			if( data.qualifies == 1 )
			{
				// Qualified applicant thankyou page
				window.location = _urlThankyouQualified + '?id=' + data.applicantId;
			}
			else
			{
				// Unqualified applicant thankyou page
				window.location = _urlThankyouUnqualified + '?id=' + data.applicantId;
			}
		}
		else
		{
			// Redirect to the error page displaying the error that occurred
			window.location = _urlError + '?errorMsg=' + Url.encode(data.errorMsg);
		}
	}


	/**
	 * Handles a failed request of the storing of tool data
	 *
	 * NOTE: typically only one of textStatus or errorThrown will have info
	 *
	 * @param object XMLHttpRequest
	 * @param string textStatus null/"timeout"/"error"/"notmodified"/"parsererror"
	 * @param Exception errorThrown
	 */
	function _storeToolDataFailure( XMLHttpRequest, textStatus, errorThrown )
	{
		debug.log('Request to store tool data failed...');

		// An uncaught error occurred making the request to store the tool data so redirect to an error page.
		window.location = _urlError + '?errorMsg=' + Url.encode('Returned error status: ' + textStatus);
	}


	/**
	 * Stores the data submitted in the Midyear tool
	 *
	 * @return void
	 */
	function _storeToolData()
	{
		debug.log('Saving tool data to database...');

		var selectedCourseId = _courseTab.getCourseId();
		var selectedQualifications = _qualificationsTab.getQualifications();
		var selectedCircumstances = _resultsTab.getCircumstances();
		var isQualified = _qualificationsTab.isQualified();
		var formData = _resultsTab.getFormData();

		var postData =
		{
			'courseId'	: selectedCourseId,
			'qualifies'	: isQualified
		}

		// Add in the submitted form data
		if( formData != null )
		{
			postData = $.extend(postData, formData);
		}

		if( isQualified == true )
		{
			postData['qualifications'] = implode('-', selectedQualifications);
		}
		else
		{
			postData['circumstances'] = implode('-', selectedCircumstances);
		}

		// Store the data in the database
		$.ajax(
		{
			   type		: "POST",
			   url		: _urlSave,
			   data		: postData,
			   dataType	: "json",
			   success	: _storeToolDataRequestSuccess,
			   error	: _storeToolDataFailure
		});
	}


	/**
	 * If a valid maths::int_encode() applicant id exists on the query string, this function
	 * retrieves the applicant's personal data and stores it in the _formData variable of the
	 * Results tab so that personal data will appear prefilled in the Results Tab form when it
	 * is loaded.
	 *
	 * @param ResultsTab _resultsTab
	 * @return void
	 */
	function _setDefaultApplicantData(_resultsTab)
	{
		var resultsTab = _resultsTab;

		// If an encoded applicant id is set in the query string, then try and use that
		// to store the default form data for an applicant.
		var encodedApplicantId = $.query.get('id').toString();

		if( encodedApplicantId.length > 0 )
		{
			var urlApplicantData = '/ajax/tool/applicant_data.php?id=' + encodedApplicantId;

			$.post( urlApplicantData, { id: encodedApplicantId }, function(data)
			{
				// Store the prefilled data if it was obtained
				if( data.success == 1 )
				{
					resultsTab.setFormData(data.applicant);
				}
			},
			"json");
		}
	}


	/**
	 * Gets the index of the currently selected tab.
	 *
	 * @return int
	 */
	function _getSelectedTabIndex()
	{
		var selectedIndex = -1;
		$("#tabs li").each(function( index, element )
		{
			if( $(element).hasClass("ui-tabs-selected") )
			{
				selectedIndex = index;
			}
		});

		return selectedIndex;
	}


	/**
	 * Initialise the object
	 */
	// Reveal the tabs
	_tabSet.show();

	// By default, all tabs except the first one ('Choose a Career') are disabled.
	_tabSet.tabs({ disabled: [1,2,3] });

	// Set the functions that handle tab events
	_setTabSelectEvents();
	_setTabLoadEvents(_careerTab);

	// Set default applicant data displayed on the Results tab if an applicant id has been passed
	_setDefaultApplicantData(_resultsTab);

}


/**
 * Join array elements with a glue string.
 *
 * @param string glue
 * @param array pieces
 * @return string
 */
function implode( glue, pieces )
{
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Waldo Malqui Silva
    // *     example 1: implode(' ', ['Kevin', 'van', 'Zonneveld']);
    // *     returns 1: 'Kevin van Zonneveld'

    return ( ( pieces instanceof Array ) ? pieces.join( glue ) : pieces );
}


/**
 * Creates a new Console object.
 *
 * This class can be utilised in order to allow overriding the
 * console.log() function which is only supported by FireFox's
 * FireBug plugin.
 *
 * All other browsers can handle a call to console.log() by using
 * a locally defined instance of this Console object instantiated
 * in the following manner:
 *
 * 	if( typeof console == "undefined" )
 *	{
 *		console = new Console();
 *	}
 */
function Console()
{
	/**
	 * Log a message to the console.
	 */
	this.log = function(msg)
	{
		//alert(msg);
	}
}


/**
 * Creates a new Debug object.
 *
 * This class can be utilised in order to provide useful tools for debugging.
 *
 * @return void
 * @uses Console
 */
function Debug()
{
	/**
	 * Outputs a message to the currently defined console using console.log()
	 *
	 * @param msg
	 * @param restrictToDev whether to just restrict the success of this function to development sites
	 * @uses Console
	 */
	this.log = function(msg, restrictToDev)
	{
		// By default, the success of this function should be restricted to the development environment
		if( typeof restrictToDev != Boolean )
		{
			restrictToDev = true;
		}

		// Get the components of the url to determine what environment is being used
		//	- Development: 	the last component of the domain will be .dev
		var urlComponents = document.location.host.split('.');

		if( (restrictToDev == true) && (urlComponents[urlComponents.length-1] != 'dev') )
		{
			// Dev site restriction in place and site is not a development site
			return;
		}

		// Some browsers (including IE) do not natively implement the console object
		// In that case, implement a dummy Console object to take its place.
		if( typeof console == "undefined" )
		{
			console = new Console();
		}

		// Log the message to the defined console.
		console.log(msg);
	}
}