//travPack.js
//helpArray has the help comments that are displayed in editPackage. A help number is present on each item with help, and the number corresponds to the index in this array 
var helpArray = ['This is the email address that users will be taken to, if they click the Enquiry Now button on this package',
    'This is the resort that the package is available for the user to travel to. Enter a few letters of the resort name and the rest will be auto filled. Type "Enter" or "Tab" or click elsewhere when the correct resort is showing',
    'This is the base price that you will be charging for this package, based on the first date option, the first travel option and the first accommodation option that you enter below',
    'These are sets of dates between which people may book this package, each of which may have a different price. The first one will assume the base price is charged for the package. Any range with a blank starting date will be ignored',
    'Enter different travel options here, for instance with different carriers, or different modes of travel, such as plane or bus. The first one will assume the base price is charged for the package. Any options with no text in the carrier text box will be ignored',
    'Enter the type of travel here, for example air or train or via a city. This is a text field and may be used for other text if you wish, or may be left blank',
    'Enter the carrier name here. This text field must have some text in it to be included in the package. If you do not want to use one of the travel options leave this field blank. This is a text field and may be used for other text if you wish',
    'Enter the price variation from base price here. This indicates to the user how much price variation will result from selecting this option',
    'This field indicates whether a variation in price will be an increase in price or a decrease',
    'Enter different accommodation options here, for instance with different hotels. The first one will assume the base price is charged for the package. Any options with no text in the accommodation text box will be ignored. If you do not want to use one of the accommodation options leave this field blank',
    'Enter the hotel here. This is a text field and may be used for other text if you wish',
    'Enter further information about the accommodation here, such as ski on/ski off or child care available. This is a text field and may be used for other text if you wish',
    'Select a period of stay here. If there is not a suitable stay period, select "Other" and you will be able to enter your own. If you do not want to use a variation you have created, set this to "Select"',
    'Enter the price variation from base price here. This indicates to the user how much price variation will result from selecting this accommodation option',
    'This field indicates whether a variation in price will be an increase in price or a decrease',
    'Click the "Variation" button to add another stay period to this accommodation option. The price variation chosen for the different stay period will be the variation on base price for the package, not the accommodation option. Rows with an empty period or a period set to "Select" will be ignored',
    'Enter extra data about the package here. If you want to have a heading use this section, or for text without a heading use the section below. For more items with headings click "More Items", or for more text on the same heading click "More Text"',
    'Enter extra data about the package here. If you want text without a heading use this section, or for text with a heading use the previous section',
	'Enter a name for the package here. This must be at least 2 non-space characters',
    'The introduction text will be prominently displayed on your package. This must be at least 2 non-space characters and has a maximum of 500 characters',
	'Add the number of free nights included.'];
$(document).ready(function() { //This function runs as soon as the document is ready
		$('#travpackEmailForm').validate(); 
		$('#opt').click(function(event) { //This deals with whether the options div shows on the logged in page
			if ($('div#options').length) {
			$('div#options').attr('style', ''); 
			$('div#options').toggleClass('none'); 
			event.preventDefault(); 
			}
		}); 	   
/*
$('.help').qtip({
   content: 'This is an active list element',
   show: 'mouseover',
   hide: 'mouseout'
})
*/
		$('.help').each(function(i){
			$(this).qtip({
   				content: helpArray[this.id.substring(4)],
				tip: true,
   				style: {
					name: 'blue',
      					border: {
         					width: 3,
         					radius: 8,
         					color: '#6699CC'
      					},
					tip: 'bottomLeft'
				 },
   				position: {
      					corner: {
         					target: 'topRight',
         					tooltip: 'bottomLeft'
      					}
   				},
   				show: 'mouseover',
   				hide: 'mouseout'
			});
		});
//The help display function
/*
		$('.help').css({textDecoration: 'underline', position: 'relative'}).hover(function() { //This function runs when the cursor hovers over the element
              $('<div class="helpText"><p style="white-space: normal">' + helpArray [this.id.substring(4)] + '</p></div>').prependTo(this);
		}, function() { //This function runs when the cursor leaves the element	
			$('.helpText').remove();	
		});
*/
//Add availability periods when the more dates button is pressed 
		$('#moreDates').click(function(event) {
            var thisRow = $(this).parents('tr:first'); //Get the first tr in the parent elements
			var dateRows = Number(thisRow.prev().find('td:eq(1)').find('input').attr('id').substring(6)) + 1;
              $("<tr><td></td><td><input type='text' size='12' maxlength='16' id='datFro" + dateRows + "' name='datFro" + dateRows + "' /></td>" +
              "<td><input type='text' size='12' maxlength='10' id='datTo" + dateRows + "' name='datTo" + dateRows + "' /></td>" +
               "<td><input type='text' size='12' maxlength='10' id='datPr" + dateRows + "' name='datPr" + dateRows + "' value='0'/></td>" +
               "<td><select id='datID" + dateRows + "' name='datID" + dateRows + "'><option value='3'>Base Price</option><option value='1' selected>Increase</option><option value='2'>" + "Decrease</option></select></td></tr>"). insertBefore (thisRow) ;
				thisRow.prev().find('td:eq(1)').find('input').focus();
              event.preventDefault(); //This prevents the submit action of the button submitting the form twice, but allows form submission if the user does not have javascript enabled
		});
		
		
//Add travel option rows when the more options button is pressed 
		$('#moreTravel').click(function(event) {
            var thisRow = $(this).parents('tr:first'); //Get the first tr in the parent elements
            var travRows = Number(thisRow.prev().find('td:eq(0)').find('input').attr('id').substring(5)) + 1;
            $("<tr><td><input type='text' size='20' maxlength='32' id='traCa" + travRows + "' name='traCa" + travRows + "' /></td>" +
                "<td><input type='text' size='20' maxlength='32' id='traTy" + travRows + "' name='traTy" + travRows + "' /></td>" +
                "<td><input type='text' size='12' maxlength='16' id='traPr" + travRows + "' name='traPr" + travRows + "' value='0'/></td>" +
                "<td><select id='traID" + travRows + "' name='traID" + travRows + "'><option value='3'>Base Price</option><option value='1' selected>Increase</option>" +
				"<option value='2'>Decrease</option></select></td></tr>").insertBefore(thisRow);
			thisRow.prev().find('td:eq(0)').find('input').focus(); 
			event.preventDefault();
		});
		addAllVariationEvents(); //Sets up the events for when the user clicks variation on an accommodation option
		addAllOtherPeriodEvents(); //Sets up the events for when the user clicks other in the accommodation period

//This function adds accommodation option rows when the more options button is pressed 
		$('#moreAcc').click(function(event) {
            var thisRow = $(this).parents('tr:first'); //Get the first tr in the parent elements
			var prevOptRow = thisRow.prev();
			while (!prevOptRow.hasClass('accOpt')) //Go back to the last option row rather than variation row otherwise there is no td:eq(0) 
				prevOptRow = prevOptRow.prev(); 
				var accomRows = Number(prevOptRow.find('td:eq(0)').find('input').attr('id').substring(5)) + 1;
                $("<tr class='accOpt' ><td><input type='text' size='20' maxlength=' 32 ' id='accTy" + accomRows + "' name='accTy" + accomRows + "' /></td>" +
                    "<td><select id='accQu" + accomRows + "' name='accQu" + accomRows + "'> <option value='*'>*</option><option value='**'>**</option><option value='***'>*** </option>" +
                    "<option value='****'>****</option><option value='*****'>*****</option></select></td>" +
                    "<td><input type='text' size='20' maxlength=' 32' id='accLo" + accomRows + "' name='accLo" + accomRows + "' /></td>" +
                    "<td><select id='accPe" + accomRows + "/0' name='accPe" + accomRows + "/0' class='perSel'>" +
					'<option value="s">Select</option>' +
					'<option value="1">1 night</option>' +
					'<option value="2">2 nights</option>' +
					'<option value="3">3 nights</option>' +
					'<option value="4">4 nights</option>' +
					'<option value="5">5 nights</option>' +
					'<option value="6">6 nights</option>' +
					'<option value="7">7 nights</option>' +
					'<option value="8">8 nights</option>' +
					'<option value="9">9 nights</option>' +
					'<option value="10">10 nights</option>' +
					'<option value="11">11 nights</option>' +
					'<option value="12">12 nights</option>' +
					'<option value="13">13 nights</option>' +
					'<option value="14">14 nights</option>' +
					'<option value="15">15 nights</option>' +
					'<option value="16">16 nights</option>' +
					'<option value="17">17 nights</option>' +
					'<option value="18">18 nights</option>' +
					'<option value="19">19 nights</option>' +
					'<option value="20">20 nights</option>' +
					'<option value="20+">20+ nights</option>' +
					'<option value="ot">Other</option>' +
					"</select></td>" +
					"<td><select id='accFn" + accomRows + "/0' name='accFn" + accomRows + "/0' class='perSel'>" +
					'<option value="0">n/a</option>' +
					'<option value="1">1 night</option>' +
					'<option value="2">2 nights</option>' +
					'<option value="3">3 nights</option>' +
					'<option value="4">4 nights</option>' +
					'<option value="5">5 nights</option>' +
					'<option value="6">6 nights</option>' +
					'<option value="7">7 nights</option>' +
					'<option value="8">8 nights</option>' +
					'<option value="9">9 nights</option>' +
					'<option value="10">10 nights</option>' +
					'<option value="11">11 nights</option>' +
					'<option value="12">12 nights</option>' +
					'<option value="13">13 nights</option>' +
					'<option value="14">14 nights</option>' +
					'<option value="15">15 nights</option>' +
					'<option value="16">16 nights</option>' +
					'<option value="17">17 nights</option>' +
					'<option value="18">18 nights</option>' +
					'<option value="19">19 nights</option>' +
					'<option value="20">20 nights</option>' +
					'<option value="20+">20+ nights</option>' +
					'<option value="ot">Other</option>' +
					"</select></td>" +
                    "<td><input type='text' size='12' maxlength='16' id='accPr" + accomRows + "/0' name='accPr" + accomRows + "/0' class='accPrice' value='0'/></td>" + 
					"<td><select id='accID" + accomRows + "/0' name='accID" + accomRows + 
					"/0'><option value='3'>Base Price</option><option value='1' selected>Increase</option><option value='2'>Decrease</option></select></td>" +
                    "<td><input type='button' value='Variation' class='accVar' id='accVar" + accomRows + 
					"' name='accVar" + accomRows + "' /></td></tr>").insertBefore(thisRow); 
					//The next bit is a hack. The purpose of it is to listen for when the user clicks "Variation" in the new accommodation row and add a variation. If the event is applied to all instances of the variation button (like on page load), the event is applied 
					//twice to the variation buttons that were already there and runs twice (or more depending on how many times a new option has been added). This means the variation button causes more than one row to be added. Therefore it is necessary to add the event to only the button or select being created, not to all on the page. It should be possible to select the element by id, but it doesn't work, hence the selectFormElement function
					selectFormElement('accVar', 'accVar' + accomRows).click(addVariationEvent); 
					//Now use the same hack to put an event onto the "Other" option in the period select
					selectFormElement('perSel', 'accPe' + accomRows + '/0').change(addPeriodEvent);
					thisRow.prev().find('td:eq(0)').find('input').focus();
					event.preventDefault();
		});
        addAllHeadingTextEvents(); 
//This puts an event on the first more text buttons of any heading text sets that are there on page load 
//Add more heading/text sets
		$('#moreHeadText').click(function(event) {
            var thisRow = $(this).parents('tr:first'); //Get the first tr in the parent elements
            var heTextSetsArray = thisRow.prev().find('td:eq(0)').find('input').attr('id').split('/');
			var heTextSets = Number(heTextSetsArray[0].substring(4)) + 1; 
			$("<tr height='15px'><td></td></tr><tr><th nowrap><p>Heading: </p></th>" + "<td><input type='text' size='50' maxlength='128' id='head" + heTextSets + "' name='head" + heTextSets + "' /></td></tr><tr><th nowrap><p>Text: </p></th>" +
							"<td><input type='text' size='50' maxlength='250' id='heTe" + heTextSets +
							"/0' name='heTe" + heTextSets + "/0' /></td>" +
							"<td><input type='button' value='More Text' id='mrHeTe" + heTextSets + "' class='mrHeTe' /></td></tr>").insertBefore(thisRow); 
//Put an event onto the "More Text" button in the new set
            selectFormElement('mrHeTe', 'mrHeTe' + heTextSets).click(addHeadingTextEvent) ;
			thisRow.prev().prev().find('td:eq(0)').find('input').focus(); 
			++heTextSets; 
			event.preventDefault(); 
		});
		
		$('#moreText').click(function(event) { //This function is used to add more text (without heading) rows
            var thisRow = $(this).parents('tr:first'); //Get the first tr in the parent elementsf
			while (thisRow.next().hasClass('textRow'))
                thisRow = thisRow.next(); //Add the new row after the last text only row
				var textRows = Number(thisRow.find('td:eq(0)').find('input').attr ('id').substring(4) ) + 1;
				$("<tr class='textRow'><th nowrap><p>Text :</p></th><td><input type='text' size='50' maxlength=" +
                    "'250' id='text" + textRows + "' name='text" + textRows + "' /></td> </tr>").
			insertAfter(thisRow); thisRow.next().find('td:eq(0)').find('input').focus(); 
			++textRows;
			event.preventDefault(); 
		});
	   
		$('#submitPackage').click(function(event) { 
//This function is used to initiate validation on a package in the edit form and submit the form if validation is ok. 
			var validation = validateForm(); 
			if (validation != '')
				alert(validation); 
			else
				document.mainForm.submit(); 
				event.preventDefault() ; 
		}); 
		
		var focusSet = 0;
		var errorFocusSet = 0;

		$('form input').each(function() { //This function sets the focus of the cursor on page load
			if (focusSet == 0 && $(this).attr('type') == 'text') { //First focus on the first text box
				$(this).focus();
                focusSet = 1; //Don't focus on any more fields with this if statement, but if an error field comes up, focus on it with the next if statement
			}
			if (errorFocusSet == 0 && $(this).hasClass('error')) { //Focus on an error field if there is one
				$(this).focus();
				errorFocusSet = 1; //Don't change the focus again, we want the first error on the page focussed 
				} 
		}); 
//Validate a new value for a number of different places in the system as being numeric
		var numericValidationArray = [['newPerPage', 'changePerPage', 'positive number of results to show per page'],
				['purchaseNum', 'purchaseSlots', 'positive number of slots to purchase'],
				['accountSlotPrice', 'changeSlotPrice', 'positive slot price'],
				['rate', 'setRate', 'positive exchange rate'],
				['allSlotPrice', ' changeAllSlotPrice', 'positive slot price'],
				['allSlotPrice', 'override', 'positive slot price']];
		for (var i = 0; i < numericValidationArray.length; ++i) 
		{
			validateNumericField(numericValidationArray[i][0], numericValidationArray[i][1], numericValidationArray[i][2]); 
		}
	   
//On the private package list we have a form with checkboxes. In order to have Check All buttons, an All link is placed on the page, and this function replaces the link with a button and makes it check the boxes when clicked. The link will do the same for those who do not have javascript enabled
       $('a.checkAll').each(function() { //This is the check all button for make live and take offline
			var linkText = $(this).text() ; 
			$(this).empty();
            var newButton = $("<input type='button' value='" + linkText + "' />").click(function(event) {
				if ($(this).val() == 'All') { 
					$(this).val('Undo');
					$('.checkBoxAll').attr('checked', 'true'); 
				} else {
					$(this).val('All') ;
					$('.checkBoxAll').attr('checked', ''); 
				}
			event.preventDefault(); }).appendTo($(this)); });
			
		$('a.checkDel').each(function() { //This is the check all button for deleting 
			var linkText = $(this).text(); $(this).empty();
              var newButton = $("<input type='button' value='" + linkText + "' />").click(function(event) {
				if ($(this).val() == 'All') { 
					$(this).val('Undo') ;
					$('.checkBoxDel').attr('checked', 'true'); } 
				else {
					$(this).val('All') ;
					$('.checkBoxDel').attr('checked', '' ) ; }
				event.preventDefault(); }).appendTo($(this));}); 
		});
		
function addAllOtherPeriodEvents() { //Sets up the event for when the user clicks other in the accommodation period, to put a text box instead of the dropdown. Also removes the "Other" buttons provided by the server for those without javascript and installs the "Other" option in the drop down
	$('select.perSel').each(function() { //Remove the "Other" button and add to select
	//$("<option value='ot'>Other</option>").appendTo($(this));	
	$(this).next().remove();
		});
	$('.perSel').change(addPeriodEvent);
}

function addPeriodEvent() { //This function converts a select box into a text box for the period so the user can enter a custom period
//If the user clicks "Other" for the period of accommodation this function will run.
//It will also run any time the select is used as it is triggered by a change event. If an onclick event is
//used on the particular option required the event does not fire in IE6. Therefore onchange is used with filtration
//to determine if the right option was clicked.
	var selectElement = $(this);
    var elementID = selectElement.attr('id').replace('e', 'c'); //Creates a new id so we can work out if it is a custom period on the server. Format is: accPcl/0
	if (selectElement.val() == ' ot') {
        var newTextBox = $('<input type="text" size="13" maxlength="20" id="' + elementID + '" name="' + elementID + '" class="perSel" />');
        selectElement.parent().empty().append(newTextBox); 
		//The next bit applies focus to the newly added text box. Uses the hack selectFormElement()
        var newTextBox = selectFormElement('perSel', elementID).change(addPeriodEvent);
		for (var i = 0; i < 10; i++)
            newTextBox.focus(); //Yet another devastating hack! For some reason IE seems to have trouble focussing the element immediately after adding it, so focusing it 10 times seems to do it
    } 
}
	   
function addAllVariationEvents () {
       $('.accVar').click(addVariationEvent); 
}

function addVariationEvent(event) 
{ 
//This function adds accommodation variation rows when the variation button is pressed
    var thisRow = $(this).parents('tr:first'); 
	//Get the first tr in the parent elements which gives us the row (the tr) that has the variation button that has been pressed on it
	var optionNumber = $(this).attr('id').substring(6);
    var nextOption = thisRow.next(); 
	//Gives us the next child with the same parent as thisRow
//Now give us the next accommodation option row (the tr) or the more options button row, before which the variation will be inserted
	while (nextOption.attr('className') != 'accOpt') nextOption = nextOption.next(); //Now work out the variation number, for this accommodation option, of the variation we are adding
	var lastVariationRow = thisRow; 
	var variationNumber = 1;
	while (lastVariationRow.next().attr('className') == 'variation') { 
		lastVariationRow = lastVariationRow.next(); 
		++variationNumber; 
	} //This gets us past any already added variations
    $("<tr class='variation'><td colspan=' 3' ></td><td><select id='accPe" +  optionNumber +  "/"   + variationNumber  + "' name='accPe" + optionNumber + '/' + variationNumber +
            "' class='perSel'>" +
			'<option value="s">Select</option>' +
			'<option value="1">1 night</option>' +
			'<option value="2">2 nights</option>' +
			'<option value="3">3 nights</option>' +
			'<option value="4">4 nights</option>' +
			'<option value="5">5 nights</option>' +
			'<option value="6">6 nights</option>' +
			'<option value="7">7 nights</option>' +
			'<option value="8">8 nights</option>' +
			'<option value="9">9 nights</option>' +
			'<option value="10">10 nights</option>' +
			'<option value="11">11 nights</option>' +
			'<option value="12">12 nights</option>' +
			'<option value="13">13 nights</option>' +
			'<option value="14">14 nights</option>' +
			'<option value="15">15 nights</option>' +
			'<option value="16">16 nights</option>' +
			'<option value="17">17 nights</option>' +
			'<option value="18">18 nights</option>' +
			'<option value="19">19 nights</option>' +
			'<option value="20">20 nights</option>' +
			'<option value="20+">20+ nights</option>' +
			'<option value="ot">Other</option></select></td>' +
			"<td><select id='accFn" +  optionNumber +  "/"   + variationNumber  + "' name='accFn" + optionNumber + '/' + variationNumber +
            "' class='perSel'>" +
			'<option value="0">n/a</option>' +
			'<option value="1">1 night</option>' +
			'<option value="2">2 nights</option>' +
			'<option value="3">3 nights</option>' +
			'<option value="4">4 nights</option>' +
			'<option value="5">5 nights</option>' +
			'<option value="6">6 nights</option>' +
			'<option value="7">7 nights</option>' +
			'<option value="8">8 nights</option>' +
			'<option value="9">9 nights</option>' +
			'<option value="10">10 nights</option>' +
			'<option value="11">11 nights</option>' +
			'<option value="12">12 nights</option>' +
			'<option value="13">13 nights</option>' +
			'<option value="14">14 nights</option>' +
			'<option value="15">15 nights</option>' +
			'<option value="16">16 nights</option>' +
			'<option value="17">17 nights</option>' +
			'<option value="18">18 nights</option>' +
			'<option value="19">19 nights</option>' +
			'<option value="20">20 nights</option>' +
			'<option value="20+">20+ nights</option>' +
			'<option value="ot">Other</option></select></td>' +
            "<td><input type='text' size='12' maxlength='16' id='accPr" + optionNumber + "/" + variationNumber + "' name='accPr" + optionNumber + '/' + variationNumber + "' class='accPrice' value='0'/></td>" +
            "<td><select id='accID" + optionNumber + "/" + variationNumber + "' name='accID" + optionNumber + "/" + variationNumber + "'><option value='3'>Base Price</option><option value='1' selected>Increase </option>" +
			"<option value='2' >Decrease</option></select></td></tr>").insertBefore(nextOption);
    nextOption.prev().find('td:eq(2)').find('input').focus(); //Now use the hack to put an event onto the select box in the new variation for if the user wants a custom period
    selectFormElement('perSel', 'accPe' + optionNumber + '/' + variationNumber).change(addPeriodEvent);
    event.preventDefault(); }
	   
function addAllHeadingTextEvents () {
    $('.mrHeTe').click(addHeadingTextEvent); 
}

function addHeadingTextEvent(event) { 
//This function is used to add more text rows within a heading/text set
    var nextRow = $(this).parents('tr:first').next(); //Get the first tr in the parent elements, then the next row
	var textRowNum = 1;
	while (nextRow.hasClass('heTextRow')) {
        nextRow = nextRow.next(); //This moves next row so that it will be the row after the last text box row
        ++textRowNum; //This gets the number of the next text box row for the current heading/text set
	}
	var heTextCurr = $(this).attr('id').substring(6);
	$('<tr  class="heTextRow"><th  nowrap><p>Text: </p></th> '   +
	'<td><input  type="text"   size="50"  maxlength="256"   id="heTe' + heTextCurr + '/' + textRowNum  +   '"   name="heTe' + heTextCurr + '/' + textRowNum + '"   /> </td>' +
	'</tr>').insertBefore(nextRow);
	nextRow.prev().find('td:eq(0)').find('input').focus();
      event.preventDefault(); }
	   
function validateForm() {
    $('.error').removeClass('error'); 
	//Removes red back ground from error fields so that they can be re-checked 
	//Check there is a package name
	if (shortStringInvalid($('#name').val())) { 
		$('#name').addClass('error').focus();
		return 'Please enter a package name that is at least 2 non-space characters'; 
	} 
	//Check that the base price is numeric and not empty 
	if (notNumeric($('#baseP').val())) {
	$('#baseP').addClass('error').focus();
    return 'Please enter a valid, positive, numeric base price'; } 
	//Check the student base price. This can be empty
	if ($('#studentP').val().length && notNumeric($('#studentP').val())) { 
		$('#studentP').addClass('error').focus();
        return 'Please enter a valid, positive, numeric student price or make sure there is no text in the student price box';
	} 
	//Check there is an introduction
	if (shortStringInvalid($('#introduction').val())) { 
		$('#introduction').addClass('error').focus();
        return 'Please enter an introduction that is at least 2 non-space characters' ;
    } 
	//Check all date from fields for valid dates. The date not valid function needs to be done properly. Hopefully there is a date validation
	//jquery plugin that can be used. Otherwise a rudimentary one could be written to test for three numeric values in range, and the server
	//date validation could be relied on for an actual valid date, ie, not the 30th of Feb or something like that.
    var errorMessage = ''; 
	//Any time this errorMessage is not an empty string, stop validating and return the error message
    $('input[@id^="datFro"]').each(function(index) { 
		//Uses an xpath selector to select all input elements with an id that begins with 'datFro'. This will get all the date range rows for validation
        if (errorMessage == '') { //If errorMessage was set on a previous row, don't do any more validation
			if (index == 0) { //The first date range must exist, so validate the whole row no matter what
                if (notValidDate($(this).val())) { //This is the date from field on the first row, which is compulsory
					$(this).addClass('error').focus();
                    errorMessage = 'Please enter a valid date from for the first date range. Other date ranges are optional';
					}
                    if (errorMessage == '' && notValidDate($('#datTo' + index).val ())) { //This is the date to field on the first row, which is compulsory
						$('#datTo' + index).addClass('error').focus(); 
						errorMessage = 'Please enter a valid date to for the first date range. Other date ranges are optional';
					} 
			} else { //Check subsequent rows
				if ($(this).val() != '') { //Only validate date ranges where the from date is set
					if (errorMessage == '' && notValidDate($(this).val()))
					{ //The from date
						(this).addClass('error').focus();
                        errorMessage = 'Please enter a valid date from for the date range on row ' + (index + 1);
					} 
					if (errorMessage == '' && notValidDate($('#datTo' + index).val())) { //The to date
						$('#datTo' + index).addClass('error').focus(); errorMessage = 'Please enter a valid date to for the date range on row ' + (index + 1);
					}
                    if (errorMessage == '' && notNumeric($('#datPr' + index).val())) { //The price variation
						$('#datPr' + index).addClass('error').focus(); 
						errorMessage = 'Please enter a valid price variation for the date range on row ' + (index +1) + '. For no variation enter 0';
					} 
				} 
			} 
		} 
	}); 
	if (errorMessage != '')
       return errorMessage; 
	var travOrAccomSet = false; //A package must have a travel or an accomodation option but not necessarily both. This variable will remain false until one is set
    $('input[@id^="traCa"]').each(function(index) { //Uses an xpath selector to select all input elements with an id that begins with 'traCa'. This will get all the travel option rows for validation, and particularly the carrier name text box, as this is the one that must have data for the option to be used
        if (errorMessage == '') { //If errorMessage was set on a previous row, don't do any more validation
            if ($(this).val() != '') { //Only validate date ranges where the carrier text box is set (not an empty string)
                if (shortStringInvalid($(this).val())) { //Check the carrier is at least 2 non space characters
					$(this).addClass('error').focus();
                    errorMessage = 'Please enter a carrier that is at least 2 non space characters on row ' + (index + 1) + ' or make sure there is no text in the carrier text box';
				}
                if (errorMessage == '' && index > 0 && notNumeric($('#traPr' + index).val())) { //The price variation
					$('#traPr' + index).addClass('error').focus(); 
					errorMessage = 'Please enter a valid, positive, numeric price variation for the travel option on row ' + (index +1) + '. For no variation enter 0';
				}
				if (errorMessage == '')
					travOrAccomSet = true; 
			} 
		} 
	}); 
	if (errorMessage != '')
       return errorMessage; 
   
	$('input[@id^="accTy"]').each(function(index) { //Uses an xpath selector to select all input elements with an id that begins with 'accTy'. This will get all the accommodation option rows for validation
        if (errorMessage == '') { //If errorMessage was set on a previous row, don't do any more validation
            if ($(this).val() != '') { //Only validate accommodation options where the accommodation text box is set (not an empty string)
                if (shortStringInvalid($(this).val())) { //Check the accommodation is at least 2 non space characters if it is set at all
					$(this).addClass('error').focus();
                    errorMessage = 'Please enter an accommodation name that is at least 2 non space characters on option ' + (index + 1);
				} 
				var oneValidPeriod = false; //There must be one valid period for each accommodation option used
                if (errorMessage == '') { //Now check each period variation for the current accommodation option.
                    $('.perSel').each(function(lowerlndex) { //Gets all selects and textboxes for period
                    if (index == $(this).attr('id').split('/')[0].substring(5)) { //Only do those variation rows that are within the accommodation row specified by index
						var variationNumber = $(this).attr('id').split('/')[1];
						var periodBox = $(this); //This may be a select or a text box
                        var periodVal = validatePeriod(periodBox); //If it is a text box and less than two whitespace chars and not empty, we get an error message back
                        if (!(periodVal == 'emptyText' || (periodVal == '' && periodBox.val() == 's'))) { //If periodVal equals 'emptyText', it is an empty text box so we don't validate, or if periodVal is an empty string, it is a select because validatePeriod() says so, and so if it also has a value of 's', it is set to nothing and we don't validate the row
							//We are validating the row, so check for an error message. At this point we can only have periodVal of either 'input', meaning a valid input box with something in it, and therefore we validate, or an empty string, meaning we have a select box that is not set to 's' so we validate the rest of the row, or an error message, in which case we report the message and abort
                            if (!(periodVal == 'input' || periodVal =='')) { //In this case there is an error message so we report and abort
                                selectFormElement('perSel' , 'accPc' + index + '/' + variationNumber).addClass('error').focus();
                                errorMessage = periodVal + (index + 1) + ', variation ' + (Number(variationNumber) +1) + '. If you want the variation to be ignored, make sure there are no characters in the period box';
							}							
                            if ((!(index == 0 && lowerlndex == 0)) && errorMessage == '' && notNumeric(selectFormElement('accPrice', 'accPr' + index + '/' + variationNumber).val())) { 
								//If there was no error on period, validate price variation. Don't do it if both index and lowerlndex equal zero, as this is the base price option and price does not exist
                                selectFormElement('accPrice', 'accPr' + index + '/' + variationNumber).addClass('error').focus();
							errorMessage = 'Please enter a valid, positive, numeric price variation for travel option ' + (index +1) + ', variation ' + (Number(variationNumber) +1) + '. For no variation enter 0';
							}
                            oneValidPeriod = true; //The period may not actually be valid here, but an invalid period error takes precedence over a oneValidPeriod error
						} 
					} 
					}); 
				}
				if (errorMessage == '' && !oneValidPeriod) {
                    errorMessage = 'You must set at least one valid period for each accommodation option (option ' + (index +1) + '). To ignore an accommodation option, make sure there are no characters in the accommodation box for that option';
					if (selectFormElement('perSel', 'accPe' + index + '/0')) 
						selectFormElement('perSel', 'accPe' + index + '/0').addClass('error').focus();
                    else if (selectFormElement('perSel', 'accPc' + index + '/0'))	
						selectFormElement('perSel', 'accPc' + index + '/0').addClass('error').focus();
				} 
				if (errorMessage == '')
					travOrAccomSet = true; 
			} 
		}
	});
	if (errorMessage != '')
       return errorMessage; 
	if (!travOrAccomSet)
        return 'You must have at least one travel option or one accommodation option set' ;
	return '';
}

function validateNumericField(fieldID, eventClass, errorMessage) { //This is a generic function that that can be used to put javascript validation on any field that needs to be numeric. It is called from a for loop near the bottom of the document ready function 
	$('.' + eventClass).click(function(event) {
		$(this).parents('tr:first').find('input').each(function() 
		{ 
			var b = $(this).attr('id');
			if ($(this).attr('id') == fieldID && notNumeric($(this).val())) {
				$(this).addClass('error').focus(); 
				alert('Please enter a numeric, ' + errorMessage); event.preventDefault(); 
			}
		}); 
	});
} 

function notNumeric(testValue) {
	testValue = testValue.replace(' ', '').replace(',', '');
	var numericExp = /^\d*(\.\d*)?$/;
	if (numericExp.test(testValue) && testValue != '')
       return false; 
	else
       return true; 
}

function notValidDate(testValue) { 
//This function needs to be reworked maybe using a jquery plugin if available
	if (testValue.length < 4)
       return true; 
	else
        return false; 
}

function shortStringInvalid(testValue) { //This function tests a string to make sure it has at least 2 non space characters.
	var len = testValue.replace(' ','').length; 
	if (len > 1)
		return false; 
	else
        return true; 
} 

function validatePeriod(periodBox) {
	if (periodBox.attr('tagName').toUpperCase() == 'INPUT') { 
		if (periodBox.val() == '')
			return 'emptyText'; 
		if (shortStringlnvalid(periodBox.val()))
			return 'Please enter a period that is at least 2 non space characters on accommodation option '; 
		return 'input'; 
	}
    return ''; 
}

function selectFormElement(classString, idString) { //This function is to deal with the problem that form elements seem to be resistant to being selected by id. This receives a class name and finds the element of that class name that has the id sent to it. This is the hack referred to in some sections above 
	var returnObject = 0; 
	$('.' + classString).each(function() {
		if ($(this).attr('id') == idString) returnObject = $(this); });
    return returnObject; 
}