/**
* NoRecruitmentAgencies.com Custom JS
* @version 1.0
* @author NoRecruitmentAgencies.com - http://www.norecruitmentagencies.com
* @requires jQuery Core 1.3+ - http://www.jquery.com/
*/
/*jslint bitwise: true, eqeqeq: true, passfail: false, nomen: false, plusplus: false, undef: true, evil: true */
/*global window, document,  jQuery, NRA, DI, self */


/**
* @namespace Root namespace for holding all objects created for NRA.
*/
var NRA = window.NRA || {};


/**
* @namespace CSS3 'retro fit' enhancements for target browsers that do not support CSS3.
*/
NRA.retroFit = {
	browserIdentity : false,
	browserVersions	: {
		ff2	: '1.8',
		ff3 : '1.9'
	},
	panelTypeASelector : '.panelTypeA',
	panelTypeBSelector : '.panelTypeB',
	panelTypeCSelector : '.panelTypeC',
	panelTypeAWrappingElements : '<div class="panelTypeA-t"><div class="panelTypeA-r"><div class="panelTypeA-b"><div class="panelTypeA-l"><div class="panelTypeA-tl"><div class="panelTypeA-tr"><div class="panelTypeA-br"><div class="panelTypeA-bl"></div></div></div></div></div></div></div></div>',
	panelTypeBWrappingElements : '<div class="panelTypeB-tl"><div class="panelTypeB-tr"><div class="panelTypeB-br"><div class="panelTypeB-bl"></div></div></div></div>',
	panelTypeCWrappingElements : '<div class="panelTypeC-tl"><div class="panelTypeC-tr"><div class="panelTypeC-br"><div class="panelTypeC-bl"></div></div></div></div>',
	
	init: function () {
		var currentBrowserVersion = jQuery.browser.version;
		var currentBrowserVersionDetails = NRA.utilities.parseVersionString(currentBrowserVersion);
		
		// Identify browser version from known browsers with sub-optimal CSS3 support
		if (jQuery.browser.mozilla === true) {
			// Firefox versions
			var ff2BrowserVersionDetails = NRA.utilities.parseVersionString(this.browserVersions.ff2);
			var ff3BrowserVersionDetails = NRA.utilities.parseVersionString(this.browserVersions.ff3);
			// Identify Firefox versions 2/3
			if (currentBrowserVersionDetails.major === ff2BrowserVersionDetails.major && currentBrowserVersionDetails.minor <= ff2BrowserVersionDetails.minor) {
				this.browserIdentity = 'ff2';
			} else if (currentBrowserVersionDetails.major === ff3BrowserVersionDetails.major && currentBrowserVersionDetails.minor >= ff3BrowserVersionDetails.minor) {
				this.browserIdentity = 'ff3';
			}
		}
		else if (jQuery.browser.msie === true && currentBrowserVersionDetails.major >= 6) {
			// IE 6+ only
			this.browserIdentity = 'ie';
		}

		// Setup retro-fit markup
		if (this.browserIdentity !== false) {
			// Apply visual styling on sub-panel elements where border-radius only is not available
			if (this.browserIdentity === 'ff2' || this.browserIdentity === 'ie') {
				jQuery(this.panelTypeASelector).wrap(this.panelTypeAWrappingElements);
				jQuery(this.panelTypeBSelector).wrap(this.panelTypeBWrappingElements);
				jQuery(this.panelTypeCSelector).wrap(this.panelTypeCWrappingElements);
			}
		}
	}
};


/**
 * @namespace Calendar popup behaviour.
 * @requires jQuery UI datepicker plugin
 * <p>The following values must be present in the Data Island object DI.lang.datePicker:
 * <ul>
 * <li>DI.lang.datePicker.minDay</li>
 * <li>DI.lang.datePicker.minMonth</li>
 * <li>DI.lang.datePicker.minYear</li>
 * <li>DI.lang.datePicker.maxDay</li>
 * <li>DI.lang.datePicker.maxMonth</li>
 * <li>DI.lang.datePicker.maxYear</li>
 * <li>DI.lang.datePicker.prevText</li>
 * <li>DI.lang.datePicker.nextText</li>
 * <li>DI.lang.datePicker.closeText</li>
 * <li>DI.lang.datePicker.buttonText</li>
 * <li>DI.lang.datePicker.buttonImage</li>
 * <li>DI.lang.datePicker.closeImage</li>
 * <li>DI.lang.datePicker.prevImage</li>
 * <li>DI.lang.datePicker.nextImage</li>
 * <li>DI.lang.datePicker.dayNamesLong</li>
 * <li>DI.lang.datePicker.dayNamesMin</li>
 * <li>DI.lang.datePicker.monthNames</li>
 * </ul>
 */
NRA.datePicker = {
    /**
	* @namespace Constants used by datepicker JavaScript used to identify datepicker components within the corresponding datepicker html markup.
	*/
    constants: {
        datePickerSelector				: '.datePicker',
        parentSelector					: '.inputGroup',
        parentFormFieldSelector			: '.element',
        daySelector						: '.day',
        monthSelector					: '.month',
        yearSelector					: '.year'
    },

    /**
	* @namespace Namespace to contain 'tool' functions used by datepicker JS.
	*/
    tools: {
        /**
		* Converts a string of the form 'yyyy-mm-dd' to a JavaScript Date object.
		*
		* @memberOf NRA.datePicker.tools
		* @param {String} details String of the form 'yyyy-mm-dd'
		* @returns {Object} A JavaScript Date
		*/
        convertDetailsToDate : function (details) {
            details = details.split('-');
            var yyyy = details[0];
            var mm = details[1];
            var dd = details[2];
            return new Date(yyyy, mm - 1, dd);
        },

        /**
		* Transfer the date range restrictions specified in certain validation routines to the datepicker calendar's 'default options' object.
		*
		* @memberOf NRA.datePicker.tools
		* @param {Object} validationRoutineDetails The validation routine details as defined within the classname of the parent form field DOM element of the associated datepicker calendar
		* @param {Object} defaultOptions An object containing the default options for use when creating a new datepicker calendar widget
		* @returns {Object} defaultOptions The updated default options object
		*/
        //If the minDate is specified in the parent formField's validationRoutineDetails and the value of minDate in the default options is not yet set then assign it accordingly
        transferDateRangeRestrictionRulesToDatepicker : function (validationRoutineDetails, defaultOptions) {
            if (validationRoutineDetails.minDate !== undefined) {
                defaultOptions.minDate = NRA.datePicker.tools.convertDetailsToDate(validationRoutineDetails.minDate);
            }
            //Similarly for maxDate
            if (validationRoutineDetails.maxDate !== undefined) {
                defaultOptions.maxDate = NRA.datePicker.tools.convertDetailsToDate(validationRoutineDetails.maxDate);
            }
            return defaultOptions;
        },

        /**
		* Find and return the other datepicker hidden text input element in a datepicker range pair
		*
		* @memberOf NRA.datePicker.tools
		* @param {String} datePickerType A string that indicates what type of datepicker in a datepicker range pair has been selected (ie 'from' or 'to')
		* @param {String} datePickerPairName An string containing the name of the datepicker range pair
		* @returns {Object} otherDatePickerInRangePair The other datepicker hidden text input element in the datepicker range pair
		*/
        findOtherDatePickerInRangePair: function (datePickerType, datePickerPairName) {
            var otherDatePickers, otherDatePickerInRangePair;
            if (datePickerType === 'to') {
                otherDatePickers = jQuery('input:hidden.from');
            }
            else if (datePickerType === 'from') {
                otherDatePickers = jQuery('input:hidden.to');
            }
            for (var i = 0, len = otherDatePickers.length; i < len; i++) {
                if (otherDatePickers[i].datePickerGroupName === datePickerPairName) {
                    otherDatePickerInRangePair = otherDatePickers[i];
                    break;
                }
            }
            return otherDatePickerInRangePair;
        },

        /**
		 * Validate if an input is a well-formed date which is a valid date within the Gregorian calendar.
		 *
		 * @param {Object} $formFieldElement jQuery wrapped element representing the associated form field DOM element which contains the input data to be validated
		 * @returns {Boolean} Returns true if the data inputted passes validation
		 */
        validDate : function ($formFieldElement) {
            var isValid = true;
            var dd = $formFieldElement.find('.day')[0].value;
            if (dd.length === 1) {
                dd = '0' + dd;
            }
            var mm = $formFieldElement.find('.month')[0].value;
            var yyyy = $formFieldElement.find('.year')[0].value;

            var rdy = new RegExp('^(0[1-9]|[12][0-9]|3[01])$');
            var rmo = new RegExp('^(0[1-9]|1[012])$');
            var ryr = new RegExp('^[0-9]{4}$');
            if (!(rdy.test(dd))) {
                isValid = false;
            }
            if (!(rmo.test(mm))) {
                isValid = false;
            }
            if (!(ryr.test(yyyy))) {
                isValid = false;
            }
            if (dd !== '' && mm !== '' && yyyy !== '') {
                if (dd === '31' && (mm === '04' || mm === '06' || mm === '09' || mm === '11')) {
                    isValid = false; // 31st of a month with 30 days
                }
                else if (dd >= '30' && mm === '02') {
                    isValid = false; // February 30th or 31st
                }
                else if (mm === '02' && dd === '29' && !((yyyy % 4 === 0) && (yyyy % 100 !== 0 || yyyy % 400 === 0))) {
                    isValid = false; // February 29th outside a leap year
                }
            }
            return isValid;
        }
    },

    /**
	* @namespace Namespace to contain the 'default options' object as used by the jQuery UI datepicker widget.
	*/
    defaultOptions: {
        showButtonPanel		: true,
        closeText			: ' ',
        buttonText			: DI.lang.datePicker.buttonText,
        buttonImage			: DI.lang.datePicker.buttonImage,
        dayNamesLong		: DI.lang.datePicker.dayNamesLong,
        dayNamesMin			: DI.lang.datePicker.dayNamesMin,
        monthNames			: DI.lang.datePicker.monthNames,
        dateFormat			: 'dd/mm/yy',
        minDate				: null,
        maxDate				: null,

        /**
		* Function to determine which of the days in a datepicker widget should be unselectable based on the validation routine restrictions set in the
		* associated parent form field element.
		*
		* @memberOf NRA.datePicker.defaultOptions
		* @param {Object} date A JavaScript date object
		* @returns {Array} An array containing dates and 'selectable' flag pairs
		*/
        beforeShowDay : function (date) {
            var isValidDateToSelect = true;
            var dayOfMonth = date.getDate();
            var monthOfYear = date.getMonth();
            var year = date.getFullYear();

            var daysOfWeekNames = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
            var dayOfWeekEntered = daysOfWeekNames[date.getDay()];

            var monthsOfYearNames = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];
            var monthOfYearEnteredName = monthsOfYearNames[monthOfYear], j, len;

            var validationRoutineDetails = this.validationRoutines.validateDateRestriction;

            if (validationRoutineDetails !== undefined) {
                if (validationRoutineDetails.invalidDates !== undefined) {
                    if (typeof validationRoutineDetails.invalidDates === 'string') {
                        validationRoutineDetails.invalidDates = [validationRoutineDetails.invalidDates];
                    }
                    for (j = 0, len = validationRoutineDetails.invalidDates.length; j < len; j++) {
                        var validationRoutineDetailsSplit = validationRoutineDetails.invalidDates[j].split('-');
                        if (year === parseInt(validationRoutineDetailsSplit[0], 10) && monthOfYear === parseInt(validationRoutineDetailsSplit[1] - 1, 10) && dayOfMonth === parseInt(validationRoutineDetailsSplit[2], 10)) {
                            isValidDateToSelect = false;
                        }
                    }
                }

                if (validationRoutineDetails.invalidDaysOfWeek !== undefined) {
                    if (typeof validationRoutineDetails.invalidDaysOfWeek === 'string') {
                        validationRoutineDetails.invalidDaysOfWeek = [validationRoutineDetails.invalidDaysOfWeek];
                    }
                    for (j = 0, len = validationRoutineDetails.invalidDaysOfWeek.length; j < len; j++) {
                        if (dayOfWeekEntered === validationRoutineDetails.invalidDaysOfWeek[j]) {
                            isValidDateToSelect = false;
                        }
                    }
                }

                if (validationRoutineDetails.invalidMonthsOfYear !== undefined) {
                    if (typeof validationRoutineDetails.invalidMonthsOfYear === 'string') {
                        validationRoutineDetails.invalidMonthsOfYear = [validationRoutineDetails.invalidMonthsOfYear];
                    }
                    for (j = 0, len = validationRoutineDetails.invalidMonthsOfYear.length; j < len; j++) {
                        if (monthOfYearEnteredName === validationRoutineDetails.invalidMonthsOfYear[j]) {
                            isValidDateToSelect = false;
                        }
                    }
                }
            }

            return [isValidDateToSelect, ''];
        },
        showOn				: 'both',
        hideIfNoPrevNext	: true,
        buttonImageOnly		: true,
        changeMonth			: true,
        changeYear			: true,

        /**
		* Links the three select inputs that represent a date input to the datepicker widget.
		* <p>
		* Reads the input values and passes them to the datepicker before it is shown. If the inputs do not represent a valid date (e.g. no day value),
		* the datepicker will show today's date.
		* @memberOf NRA.datePicker.defaultOptions
		*/
        beforeShow : function () {
            var defaultDate = null;
            var newFromDate = this.originalMinDate;
            var newToDate = this.originalMaxDate;

            if (NRA.datePicker.tools.validDate(this.parentWrapperElement)) {
                var year = parseInt(this.parentWrapperElement.find(NRA.datePicker.constants.yearSelector).val(), 10);
                var month = parseInt(this.parentWrapperElement.find(NRA.datePicker.constants.monthSelector).val(), 10) - 1;
                var day = parseInt(this.parentWrapperElement.find(NRA.datePicker.constants.daySelector).val(), 10);

                this.$hiddenDatePickerTextInput.val(day + '/' + (month + 1) + '/' + year);
                defaultDate = new Date(year, month, day);
            }

            if (this.typeOfDatePicker === 'to' || this.typeOfDatePicker === 'from') {
                var otherDatePickerInRangePair = NRA.datePicker.tools.findOtherDatePickerInRangePair(this.typeOfDatePicker, this.datePickerGroupName);
                if (this.typeOfDatePicker === 'to') {
                    newFromDate = otherDatePickerInRangePair.$hiddenDatePickerTextInput.datepicker('getDate');
                }
                else if (this.typeOfDatePicker === 'from') {
                    newToDate = otherDatePickerInRangePair.$hiddenDatePickerTextInput.datepicker('getDate');
                }
            }

			return {defaultDate : defaultDate,	minDate : newFromDate,	maxDate : newToDate};
        },

        /**
		* Updates the date input and select elements following selection of a date in the datepicker widget.
		* <p>
		* Gets the selected date from the datepicker and sets the date inputs to the selected date,
		* then updates the date range text.  This function also updates the 'other' datepicker in a datepicker range pair
		* by destroying the 'other' datepicker, changing the default options object by reading in validation routine details, and then
		* creating a new datepicker in place of the destroyed one.
		*
		* @param {String} date String representation of the date selected in the datepicker, in dd/mm/yyyy format.
		* @see NRA.searchDateRange.updateRangeText
		*/
        onSelect : function (date) {
            this.parentWrapperElement.find(NRA.datePicker.constants.daySelector).val(date.slice(0, 2));
            this.parentWrapperElement.find(NRA.datePicker.constants.monthSelector).val(date.slice(3, 5));
            this.parentWrapperElement.find(NRA.datePicker.constants.yearSelector).val(date.slice(6, 10));
            this.parentWrapperElement.find(NRA.datePicker.constants.datePickerSelector).blur();
            // update search date range text
            //NRA.searchDateRange.updateRangeText();

            // Logic for controlling validation triggering for single formField with a datepicker
            if (this.typeOfDatePicker === 'single') {
                this.parentWrapperElement.find(NRA.datePicker.constants.daySelector).focus();
                this.parentWrapperElement.find(NRA.datePicker.constants.daySelector).blur();
            }

            // Logic for controlling validation triggering for a range pair of datepickers
            else if (this.typeOfDatePicker === 'to' || this.typeOfDatePicker === 'from') {
                var otherDatePickerInRangePair = NRA.datePicker.tools.findOtherDatePickerInRangePair(this.typeOfDatePicker, this.datePickerGroupName);

                if (otherDatePickerInRangePair.parentWrapperElement.find(NRA.datePicker.constants.daySelector).val() !== '' && this.parentWrapperElement.find(NRA.datePicker.constants.daySelector).val() !== '') {
                    this.parentWrapperElement.find(NRA.datePicker.constants.daySelector).focus();
                    this.parentWrapperElement.find(NRA.datePicker.constants.daySelector).blur();
                }
                // For a range pair of datepickers with a set relative range restriction the other datepicker in the pair must be adjusted each time a date is selected

                otherDatePickerInRangePair.$hiddenDatePickerTextInput.datepicker('destroy');

                var defaultOptions = NRA.datePicker.defaultOptions;
                var newToDate, newFromDate;

                if (this.typeOfDatePicker === 'to') {
                    newToDate = this.$hiddenDatePickerTextInput.datepicker('getDate');
                    newFromDate = otherDatePickerInRangePair.originalMinDate;
                    if (this.maxRangeInMonths !== undefined) {
                        newFromDate = new Date(newToDate);
                        newFromDate.setMonth(parseInt(newFromDate.getMonth(), 10) - parseInt(this.maxRangeInMonths, 10));
                        if (this.originalMinDate !== null && newFromDate < this.originalMinDate) {
                            newFromDate = this.originalMinDate;
                        }
                    }
                }
                else if (this.typeOfDatePicker === 'from') {
                    newFromDate = this.$hiddenDatePickerTextInput.datepicker('getDate');
                    newToDate = otherDatePickerInRangePair.originalMaxDate;
                    if (this.maxRangeInMonths !== undefined) {
                        newToDate = new Date(newFromDate);
                        newToDate.setMonth(parseInt(newToDate.getMonth(), 10) + parseInt(this.maxRangeInMonths, 10));
                        if (this.originalMaxDate !== null && newToDate > this.originalMaxDate) {
                            newToDate = this.originalMaxDate;
                        }
                    }
                }

                defaultOptions.minDate = newFromDate;
                defaultOptions.maxDate = newToDate;

                otherDatePickerInRangePair.$hiddenDatePickerTextInput.datepicker(defaultOptions);
            }
        }
    },

    /**
	* Initialise datepickers in the page.
	* <p>
	* Searches for elements in the DOM with the specified class name, and attaches the jQuery UI datepicker object to the element.
	* @memberOf NRA.datePicker
	*/
    init: function () {
        //Assign datepicker to hidden input.
        jQuery(NRA.datePicker.constants.datePickerSelector).each(function () {
            NRA.datePicker.createDatePicker.call(this, this, NRA.datePicker.defaultOptions);
        });
    },

    /**
	* Create a datepicker widget.
	*
	* @memberOf NRA.datePicker
	* @param {Object} hiddenDatePickerTextInput A hidden text input DOM element that is associated with a datepicker calendar
	* @param {Object} defaultOptions An object containing the default options for use when creating a new datepicker calendar widget
	*/
    createDatePicker: function (hiddenDatePickerTextInput, defaultOptions) {
        //Reference for scope control.
        var that = this;
        //Reference to hidden input used in all datepickers.
        this.$hiddenDatePickerTextInput = jQuery(hiddenDatePickerTextInput);
        //Reference to parent div with class 'inputgroup'.
        this.parentWrapperElement = this.$hiddenDatePickerTextInput.parents(NRA.datePicker.constants.parentSelector + ":first");
        //Reference to parent div with class 'formField'.
        this.parentFormField = this.$hiddenDatePickerTextInput.parents(NRA.datePicker.constants.parentFormFieldSelector + ":first");

        //Set the default type of datepicker to be a single datepicker.
        this.typeOfDatePicker = 'single';

        //The block below is for usage with a date range pair of datepickers:
        // Flag whether this a from or to datepicker.
        if (this.$hiddenDatePickerTextInput.hasClass('to')) {
            this.typeOfDatePicker = 'to';
        }
        else if (this.$hiddenDatePickerTextInput.hasClass('from')) {
            this.typeOfDatePicker = 'from';
        }

        //Get a reference to the datepicker group name, for usage  with multiple datepicker pairs in a page.
        this.datePickerGroupName = NRA.utilities.convertClassDetailsToData(this, 'datePickerGroupName:')[0];

        //Get the validation routines for the datepicker from the formfield:
        this.validationRoutines = NRA.utilities.convertClassDetailsToData(this.parentFormField.get(0), 'validate:');
        //Get the 'formFieldGroup' validation routines for the datepicker from the formfield:
        var formFieldGroupValidationRoutines = NRA.utilities.convertClassDetailsToData(this.parentFormField.get(0), 'formFieldGroup:');
        //Iterate through the validation routines and push them into a validationRoutines associative array.
        for (var i = 0, len = formFieldGroupValidationRoutines.length; i < len; i++) {
            this.validationRoutines.push(formFieldGroupValidationRoutines[i]);
            this.validationRoutines[formFieldGroupValidationRoutines[i]] = formFieldGroupValidationRoutines[formFieldGroupValidationRoutines[i]];
        }

        //Set defaults for max date and min date for overwriting later.
        this.originalMaxDate = null;
        this.originalMinDate = null;

        // Transfer validation routine 'validationRoutineDetails' specific restrictions to associated datepicker:
        for (i = 0, len = this.validationRoutines.length; i < len; i++) {
            //Key of 'validationRoutines' associative array:
            var validationRoutineName = this.validationRoutines[i];
            //Value of 'validationRoutines' associative array:
            var validationRoutineDetails = this.validationRoutines[validationRoutineName];


            //If the 'validateDateTimeRange' validationRoutine is defined then we need to transfer the minDate and maxDate values to the minDate and maxDate
            //attributes of the hidden form input datepicker field (which 'this' references).  These date range limits are then
            //picked up when the datepicker is instantiated.
            if (validationRoutineName === 'validateDateTimeRange' || validationRoutineName === 'specificDateWithRadio') {
                defaultOptions = NRA.datePicker.tools.transferDateRangeRestrictionRulesToDatepicker(validationRoutineDetails, defaultOptions);
                this.originalMinDate = defaultOptions.minDate;
                this.originalMaxDate = defaultOptions.maxDate;
            }
            //We do a similar thing if the 'validateDatesRelativeRange' validation routine is defined.
            if (validationRoutineName === 'validateDatesRelativeRange') {
                this.maxRangeInMonths = validationRoutineDetails.maxRangeInMonths;
            }
        //NB we don't need to trandfer the 'validateDateRestriction' validation routine details to be properties of the datepicker hidden input, as these are
        //utilised by the 'beforeShowDay' function of the 'defualtObject' object.
        }

        // Create datepicker on associated hidden text input element using jQuery UI method 'datepicker()'
        this.$hiddenDatePickerTextInput.datepicker(defaultOptions);

        //Read in the
        var year = parseInt(this.parentWrapperElement.find(NRA.datePicker.constants.yearSelector).val(), 10);
        var month = parseInt(this.parentWrapperElement.find(NRA.datePicker.constants.monthSelector).val(), 10) - 1;
        var day = parseInt(this.parentWrapperElement.find(NRA.datePicker.constants.daySelector).val(), 10);

        this.$hiddenDatePickerTextInput.datepicker('setDate', new Date(year, month, day));
    }
};


/**
 * @namespace Generic show/hide element behaviour.
 */
NRA.showHide = {

	toggleSelector			: '.showHide',
	triggerSelector			: '.trigger',
	triggerContent 			: '<span class="toggle"></span>',
	paneSelector			: '.pane',
	tempIDPrefix			: 'show',
	closedClass				: 'closed',

	/**
	 * Toggle visibility of show/hide content.
	 * <p>
	 * Element identified by its sibling trigger.
	 *
	 * @param {Object} trigger
	 * @see NRA.showHide.init
	 */
	toggleDisplay: function (trigger) {
		$(trigger).parent().toggleClass(NRA.showHide.closedClass);
		$(trigger).siblings(NRA.showHide.paneSelector).slideToggle("slow", this.toggleCallBack);
	},
	/**
	 * Setup all show/hide elements currently in page.
	 */
	init: function () {
		$(this.toggleSelector).find(this.triggerSelector).each(function (i, trigger) {
			// Identify the content to show/hide
			var thePane = $(trigger).siblings(NRA.showHide.paneSelector)[0];
			// Add icon span
			$(trigger).append(NRA.showHide.triggerContent);
			// Add/use IDs for linking
			var tmpID	= NRA.showHide.tempIDPrefix + i;
			if (thePane.id) {
				tmpID = thePane.id;
			} else {
				thePane.id = tmpID;
			}
			$(trigger).wrapInner('<a href="#' + tmpID + '"></a>');
			
			if(($(trigger).parent().next().hasClass("clearer")) === false) {
				$(trigger).parent().after('<div class="clearer"></div>');
			}

			// Hide if already closed
			if ($(trigger).parent().hasClass(NRA.showHide.closedClass)) {
				$(thePane).hide();
			}
			//Attach an onClick event to the toggle link
			$(trigger).find("a").click(function () {
				NRA.showHide.toggleDisplay($(trigger)[0]);
				return false;
    		});
		});
	}
};


/**
 * @namespace Contextual help (tooltips) behaviour.
 * @requires
 * <p>The following values must be present in the Data Island object DI.lang.help:
 * <ul>
 * <li>DI.lang.help.closeHTMLTitle</li>
 * </ul>
 */
NRA.help = {

	triggerSelector			: '.tooltipHelp',
	wrapperSelector			: '.tooltipWrapper',
	tooltipHTML				: '<div class="tooltipWrapper"><div class="tooltip"></div></div>',
	pointerHTML				: '<div class="pointer"></div>',
	closeHTML				: '<p class="close"><a href="#">x</a></p>',
	closeTitle				: 'Close help',
	activeClass				: 'active',
	helpWidth				: 320,

	/**
	 * Identify and hide all help blocks in the page.
	 * <p>
	 * Add tooltip behaviour to all trigger links in the page where a valid help block reference exists.
	 * If the help tooltip would overflow outside the viewport, or is in the right-hand sidebar, it will display to the left of the trigger link.
	 */
	init: function () {
		// Add event delegation to trigger links
		jQuery(NRA.help.triggerSelector + ' a.tooltipTrigger').live('click', function () {
			var helpLink = this;
			// If help block reference is valid setup behaviour
			if (NRA.utilities.urlGetAnchor(helpLink)) {
				if (jQuery(helpLink).hasClass(NRA.help.activeClass)) {
					// If this help is already open close on (second) click
					NRA.help.closeHelp();
				} else {
					// Close existing help
					NRA.help.closeHelp();

					// Calculate whether to display tooltip to the left or right of the link
					var viewPortWidth = self.innerWidth || (document.documentElement && document.documentElement.clientWidth) || document.body.clientWidth;
					var hasArea = viewPortWidth - NRA.utilities.getAbsoluteLeft(helpLink);
					var tooltipHTML = jQuery(NRA.help.tooltipHTML);

					if ((hasArea < NRA.help.helpWidth) || (jQuery(helpLink).parents('.secondary').length > 0)) {
						// if help tooltip would overflow outside the viewport, or is in the rhs, display to the left
						tooltipHTML.find('.tooltip').addClass('left');
					}

					// Clone and insert help block
					var helpContent = jQuery('#' + NRA.utilities.urlGetAnchor(helpLink)).clone(true);
					helpContent.id = '';
					helpContent.appendTo(jQuery(helpLink).parent()[0]);
					helpContent.wrap(tooltipHTML);
					// Add close link
					var closeHelpLink = jQuery(NRA.help.closeHTML);
					closeHelpLink.find('a').attr('title', NRA.help.closeTitle).click(function () {
						NRA.help.closeHelp();
						return false;
					});
					helpContent.after(closeHelpLink);
					helpContent.after(NRA.help.pointerHTML);
					helpContent.attr('tabindex', -1);
					helpContent.focus();

					// Show help
					jQuery(helpLink).addClass(NRA.help.activeClass);
				}
			}
			return false;
		});
	},
	/**
	 * Close currently visible help.
	 *
	 * @see NRA.help.init
	 */
	closeHelp: function () {
		jQuery(NRA.help.triggerSelector + ' .' + NRA.help.activeClass).removeClass(NRA.help.activeClass);
		jQuery(NRA.help.wrapperSelector).remove();
	}
};


/**
 * @namespace Enhancements to the search-jobs page.
 */
NRA.searchJobsEnhancements = {
	enhanceResultsPerPageDropDown: function () {
		var $resultsPerPageDropDown = jQuery('select#slctResultsPerPage');
		
		if ($resultsPerPageDropDown.length > 0) {
			$resultsPerPageDropDown.bind('change', function (event) {
				$resultsPerPageDropDown.parents('form').submit();
			});
		}
	},
	
	
	init: function () {
		NRA.searchJobsEnhancements.enhanceResultsPerPageDropDown();
	}
};


/**
 * @namespace Utility functions re-used in other JS functions
 */
NRA.utilities = {
	/**
	* Utility clone function for prototypal inheritance pattern
	*/
	clone : function (object) {
		// class creation
		var F = function () {}; 
		// assign argument prototypal object to prototype of new function
		F.prototype = object;
		// object instantiation
		return new F ();  
	},
	
	
	/** 
	* Converts a CSS class name to data.
	* <p>By use of a pre-defined syntax a classname may be used to store data.  This function reads in the particular class name and converts it into an array for use in JavaScript.
	*
	* @memberOf NRA.Forms.Validation.Tools
	* @param {Object} element The DOM element containing the classname to be converted to JavaScript parseable data.
	* @param {String} classNameToInterrogate The CSS class name containing validation data
	* @returns {Array} An array of validation data objects
	* @example 
	* &lt;div id="example" class="validate:(required_minLength[6]_maxLength[10])"&gt; &lt;/div&gt;
	* convertClassDetailsToData(document.getElementByID('example'), 'validate:');
	*/
	convertClassDetailsToData: function (element, classNameToInterrogate) {
		var data = [];
		var className = element.className;
		if (className.indexOf(classNameToInterrogate) !== -1) {
			var classNames = className.split(' ');
			for (var i = 0, len1 = classNames.length; i < len1; i++) {
				className = classNames[i];
				if (className.indexOf(classNameToInterrogate) !== -1) {
					var primaryDetails = className.slice(className.indexOf('(') + 1, className.indexOf(/\)\b/)).replace(/^_+/, '').split(/_/g);
					for (var j = 0, len2 = primaryDetails.length; j < len2; j++) {
						var primaryDetail = primaryDetails[j].split('[')[0];
						data.push(primaryDetail);
						data[primaryDetail] = {};
						if (primaryDetails[j].indexOf('[') !== -1) {
							var secondaryDetails = primaryDetails[j].slice(primaryDetails[j].indexOf('[') + 1, primaryDetails[j].indexOf(/\]\b/)).split(/,/g);
							for (var k = 0, len3 = secondaryDetails.length; k < len3; k++) {
								var secondaryDetail = secondaryDetails[k].split(/:/g);
								if (secondaryDetail[1].indexOf('|') === -1) {
									data[primaryDetail][secondaryDetail[0]] = secondaryDetail[1];
								}
								else {
									data[primaryDetail][secondaryDetail[0]] = secondaryDetail[1].split(/\|/g);
								}
							}
						}
					}
				}
			}
		}
		return data;
	},
	
	
	/**
	 * Strip out and return local page anchor from URL.
	 * 
	 * @param {Object} anchor
	 * @return Return the anchor portion of the URL (or false if no anchor)
	 */
	urlGetAnchor: function(anchor) {
		if (anchor.href.indexOf('#') >= 0) { //Check for anchorness
			anchor.destination = anchor.href.slice(anchor.href.indexOf("#")+1);
			return anchor.destination;
		} else {
			return false;
		}
	},
	
	
	/**
	 * Get the left position for an object relative to the upper left viewport corner.
	 * 
	 * @param {Object} element The DOM element
	 * @returns {Number} Number of pixels across from the upper left viewport corner.
	 */
	getAbsoluteLeft: function(element) {
		var oLeft, oParent;
		// Get left position from the parent object
		oLeft = element.offsetLeft;
		// Parse the parent hierarchy up to the document element   
		while (element.offsetParent !== null) {
			// Get parent object reference
			oParent = element.offsetParent;  
			// Add parent left position
			oLeft += oParent.offsetLeft;
			element = oParent;
		}
		return oLeft;
	},
	
	
	/**
	 * Parse version string.
	 * <p>
	 * Parse the version strings with a simple function and return them as objects with appropriate properties whose values are integers. 
	 * Once in this form, we can compare them with simple mathematics.
	 * 
	 * @param 	{String}	browserVersionString
	 * @return 	{Object}	Return the major, minor and patch numbers
	 */
	parseVersionString: function (browserVersionString) {
	    var returnVal;
		if (typeof(browserVersionString) !== 'string') { 
			returnVal = false; 
		}
	    var browserVersionStringParts = browserVersionString.split('.');
	    // parse from string or default to 0 if can't parse
	    var majorVersion = parseInt(browserVersionStringParts[0], 10) || 0;
	    var minorversion = parseInt(browserVersionStringParts[1], 10) || 0;
	    var patchVersion = parseInt(browserVersionStringParts[2], 10) || 0;
	    
		returnVal = {
	        major: majorVersion,
	        minor: minorversion,
	        patch: patchVersion
	    };
		
		return returnVal;
	}
};


/**
* @namespace JobG8 integration enhancements.
*/
NRA.jobG8 = {
	init : function () {
		NRA.jobG8.resizeIframe();
	},
	
	
	/**
	* Resize JobG8 IFrame.
	*/
	resizeIframe : function () {
		jQuery('iframe').one('load', function() {
			this.style.height =	this.contentWindow.document.body.offsetHeight + 20 + 'px';
		});
	}
};


/*
 * SETUP DOM READY AND LOAD EVENTS HERE
*/
jQuery(document).ready(function () {
	NRA.retroFit.init();
	NRA.datePicker.init();
	NRA.showHide.init();
	NRA.help.init();
	NRA.searchJobsEnhancements.init();
});
