
// formValidator.js
// @developer : tsiciliani@digitas.com

// The js processing here might appear complex, but this is due do the following:
// First, the js here is capable of processing different forms of different sizes, as
// long as they have the fields named the same, and this is because any operation checks first
// for the existence of the fields that it needs before doing anything. If a field is absent,
// the operation does not take place.
// We will discuss briefly here the requirements for the most complex of the forms processed by
// this file (search_brand.jsp).

// The user has different search options :

//                 SEARCH TYPE      |       FIELDS
//				   ----------------------------------------------------------------------
//					 by Location	|	city, state, zip, country
//					 by Address		|   address, city and state. country = USA(implicit).
//					 by pOfInterest |   point of interest. country = USA(implicit).
//				   ------------------------------------------------------------------------
//

// It appears immediately, that we have two city fields and two state fields that are mutually
// exclusive (only one type of search is allowed). The back-end for its part, expects only one
// city field ('city') and one state ('stateProvince') at submit time.
// To make error checking work, it is necessary to use different names on each type of search :
// 'city1' for Location search, 'city2' for Address search, and same thing for states.
// Another further complication is that we have values coming in when first loading the form.
// For example, the user does a search from the home page, gets search results, and then decides
// to do a more detailed search (=this form) by clicking 'Change Location' for example.
// Then the form must have the Location section pre-populated on start.
// Also, the user might then decide to change his type of search, so he blanks all Location fields
// and starts entering data in the Address section, then clicks on submit, and then might decide
// to click the browser's back button etc...
// For these and other reasons, hidden fields are used.And for 'city' for example, we have not only
// 'city1' and 'city2', but also the hidden fields 'nCity1' and 'nCity2'...and same thing for
// 'stateProvince'...
//

//--------------------------------------------------------------------------------------------
				// I N I T
// -------------------------------------------------------------------------------------------

function init(form)
{

		// load the dates
		loadDates(form);// in dateValidator.js

	    // get # of rooms from hidden fields
		loadIntoListNumber(form.nRooms, form.numberOfRooms);

		// get # of adults/room from hidden fields
		loadIntoListNumber(form.nAdults, form.numberOfAdults);

		// get ratePlanName
		loadIntoListName(form.rPlan, form.ratePlanName);

		// get roomBedCode
		loadIntoListName(form.rBedCode, form.roomBedCode);

		loadWheelChair(form.rWheelChair, form.wheelchairPreference);

		// get city
		loadCities(form);

		//get state
		loadStates(form);

		// get country
		loadCountry(form);

		// pre-check feature check boxes if set up in the hidden fields
     	loadFeatures(form);

		// pre-select any radio button
		//DKersting: COMMENTED OUT 11/06/2003 loadRadio(form.nLocation, form.hotelLocationType );

		// load poi if requested (rpoi)
		loadIntoField(form.rpoi, form.pOI);
		if(form.rpoi != null && form.rpoi.value != '')
			blankLocationFields(form);

		// SPG
		if(form.category != null)
			funcCaller(form, form.category, loadCategories);
}


//--------------------------------------------------------------------------------------------
				// E R R O R    H A N D L I N G
// -------------------------------------------------------------------------------------------

//--------------------------------------------------
// this function is called on submitting the form
// THIS IS THE MAIN FUNCTION THAT CALLS ALL THE ERROR HANDLERS
function ok(form)
{

  		// error handlers
		if( ! okSearchType(form))
     		return false;

   		if( ! okZip(form,form.postalCode,'countryRequired')) // zipValidator.js
    	 	return false;

   		if( ! checkDates(form,'Search')) // dateValidator.js
     		return false;

		 // process all checkboxes : features, categories(SPG), brands(SPG)
		 //alert("okCheckBoxes? " + okCheckBoxes(form))
		 if( ! okCheckBoxes(form))
     		return false;
		//alert("okSherlock? " + okSherlockFormElems(form,'freeNight'))
		if ( ! okSherlockFormElems(form,'freeNight'))
			return false;

		// resolve any discrepancies with the back-end
		setForBackEnd(form);


  	// last but not least, force call the onsubmit evt hdler (Netscape bug) so that
	// generic checks such as illegal chars entered (commonErr.js) take place before submitting..
     return form.onsubmit() ? true : false;
}

//-------------------------------------------------
// different search types
var searchByLocation = false;
var searchByVicinity = false;
var searchByPOI = false;

//-----------------------------------------------------
// set to only one search type
function setSearchType(isLocation, isVicinity, isPOI)
{
        //ONLY FOR DEBUGGING
        //alert('isVicinity: ' + isVicinity);
	if(isLocation)
		searchByLocation = true;
	else if(isVicinity) {
                //ONLY FOR DEBUGGING
                //alert('in Vicinity block');
		searchByVicinity = true;
                //added for CQ 4891
                //setCountry(document.forms[0].country, document.forms[0].stateProvince2);
        }
	else if(isPOI)
		searchByPOI = true;

	/*debug('Search type --By Location ? ' + searchByLocation +
					  '--By Vicinity ? ' + searchByVicinity +
					  '--By POI ? ' + searchByPOI );*/
}

//--------------------------------------------------

function okSearchType(form)
{
        //ONLY FOR DEBUGGING
        //alert('In okSearchType');
	// all fields must exist, otherwise the check is not needed
   		if(
			f.city1 == null || f.stateProvince1 == null || f.country == null || f.postalCode == null // location
		    || f.propertyStreetAddress1 == null || f.city2 == null || f.stateProvince2 == null // vicinity
			|| f.pOI == null // p of interest
		  ) {
                      //alert('returning false');
					return false;
                }

	// enough info has to be entered
	if( ! okSearchInfo(f) ) {
        //ONLY FOR DEBUGGING
            //alert('okSearchInfo returned false');
			return false;
        }

	// only one type of search allowed
	if( ! okCrossType(form)) {
                                //ONLY FOR DEBUGGING
            //alert('okCrossType returned false');
     		return false;
        }

	// errors in location search
   	if ( ! okLocation(form)) {
                                //ONLY FOR DEBUGGING
            //alert('okLocation returned false');
      		return false;
        }

	// errors in vicinity search
	if( ! okVicinity(form)) {
                                //ONLY FOR DEBUGGING
            //alert('okVicinity returned false');
     		return false;
        }

	// errors in starpoints format
	if( ! okPoints(form)) {
                                //ONLY FOR DEBUGGING
            //alert('okPoints returned false');
     		return false;
        }
	return true;
}

//------------------------------------------------------
// Do we have enough info to start searching
function okSearchInfo(f)
{
                //ONLY FOR DEBUGGING
                //alert('In okSearchInfo');
		var searchOptions = new Array(5);
		var usaSelected = ( f.country.options[f.country.selectedIndex].value == 'US' );

		// first choice : at least one of : city1, state1, zip , country. (SEARCH BY LOCATION)
		searchOptions[0] = ( f.city1.value != ""
		                || f.stateProvince1.options[f.stateProvince1.selectedIndex].value != ""
		                || f.postalCode.value != ""
						|| f.country.options[f.country.selectedIndex].value != "");

	  	// second choice : addr + city2 + state2 (country = US). (SEARCH BY VICINITY)
		searchOptions[1] = (f.propertyStreetAddress1.value != ""
		                || f.city2.value != ""
	                   || f.stateProvince2.options[f.stateProvince2.selectedIndex].value != "");

		// third choice : pt of interest (country = US). (SEARCH BY PT OF INTEREST)
		searchOptions[2] = (f.pOI.value != "");

		// fourth choice : if we have hotel brands (SPG), US-only search should be permitted.
		// okLocation() will catch any error
		searchOptions[3] = ( f.CA != null && usaSelected );

		// same here for categories (SPG)
		searchOptions[4] = ( f.category != null && usaSelected );

		var enoughInfo = false;
		var i=0;
		while(i <searchOptions.length)
		{
			if( searchOptions[i] )
			{
				enoughInfo = true;
                                //ONLY FOR DEBUGGING
				debug('searchChoice' + i + ' is true');
				break;
			}
			++i;
		}

		if( !enoughInfo )
		 {
                                //ONLY FOR DEBUGGING
                                //alert('missing some info');
			 	error('missingSearchInput');
				return false;
		 }

		// set the search vars
		setSearchType( searchOptions[0] || searchOptions[3] || searchOptions[4],
					   searchOptions[1] ,
					   searchOptions[2] )


		return true;
}

//-------------------------------------------------------
// verify cross-location conflicts
// Error : cross categ--location vs addr/landmark
function okCrossType(f)
{

   		cityConflict = ( f.city2.value != "" && f.city1.value != "" );
   		stateConflict = (
		                  f.stateProvince2.options[f.stateProvince2.selectedIndex].value != ""
	       				  && f.stateProvince1.options[f.stateProvince1.selectedIndex].value != ""
		   		         );

		// different cities inputs
	   	if ( cityConflict && ! stateConflict)
	   	{
	      	error('crossSearchType', f.city1, f.city2);
	      	return false;
	   	}
   		// different states inputs
	   	if( stateConflict && ! cityConflict )
	   	{
	      	error('crossSearchType', f.stateProvince1 , f.stateProvince2);
	      	return false;
	   	}
   		// both
       	if ( cityConflict &&  stateConflict )
	   	{
	      	error('crossSearchType', f.city1, f.city2, f.stateProvince1, f.stateProvince2 );
	      	return false;
	   	}
		// if point of interest is filled
   		if(f.pOI != null && f.pOI.value != '' && f.postalCode != null &&
			f.propertyStreetAddress1 != null && f.country != null)
		{
		    // all else location fields should be empty
			locationNotEmpty = (
			                    f.city1.value != '' ||
			                    f.stateProvince1.options[f.stateProvince1.selectedIndex].value != '' ||
								f.country.options[f.country.selectedIndex].value != '' ||
								f.postalCode.value != ''
								);
			addrNotEmpty = (
							f.propertyStreetAddress1.value != '' ||
							f.city2.value != '' ||
							f.stateProvince2.options[f.stateProvince2.selectedIndex].value != ''
							);

			if( locationNotEmpty || addrNotEmpty )
			{
				error('crossSearchType', f.pOI);
				return false;
			}
		}

	 	return true;
}

//--------------------------------------------------
// verify location section
// Error: search on US-only is too broad, unless SPG.
function okLocation(f)
{
	var usaSelected = ( f.country.options[f.country.selectedIndex].value == 'US' );
    var usOnlySearch =  ( usaSelected && f.city1.value == ''
      					 && f.stateProvince1.options[f.stateProvince1.selectedIndex].value == ''
						 && f.postalCode.value == '' );
	var isSPG = (f.CA != null || f.category != null);

	if( ! usOnlySearch )
		return true;

   	if ( ! isSPG )
	{
	   		error('searchUS',f.country);
	   		return false;
	}
	else
	{
			var field = (f.CA == null) ? f.category : f.CA ;
			var func  =	(f.CA == null) ? checkCategUSOnly : checkBrandUSOnly ;

			//debug('US only search. ' + func + ' was called');

			return funcCaller(f,field,func);
	}

	return true;

}


//------------------------------------------------------
// verify vicinity
// Error : need city and state in a vicinity (propertyStreetAddress1) search
// --> need to have all of these input : addr + city + state/landmark.
function okVicinity(f)
{

 		var acity = f.city2.value;
  		var astate = f.stateProvince2.options[f.stateProvince2.selectedIndex].value;

  		if ( f.propertyStreetAddress1.value != "" && (acity == "" || astate == "") )
		{
	   		if(acity == "" && astate == "")
	        		error('vicinitySearch', f.city2, f.stateProvince2);
	  		 else if(acity == "" && astate != "")
	        		error('vicinitySearch', f.city2);
	   		else if( acity != "" && astate == "")
	        		error('vicinitySearch', f.stateProvince2);

	   		return false;
		}

  		return true;
}

//------------------------------------------------------
// verify starpoints
// Error : starpoints need to be number only and without comma.
function okPoints(f)
{
	if (f.starpoints != null) {
 		var ptString = f.starpoints.value;

  		for (i=0; i<=ptString.length-1; i++){

		  var num=parseInt(ptString.substring(i,i+1));
		   if (!((num<=9)||(num>=0))){
			  error('pointsNotRight');
			  return false;
			  break;
		   }
		}
	}
  		return true;
}

//-----------------------------------------------------------
// handle all checkboxes
function okCheckBoxes(f)
{
    var boxesOK = [true,true,true];

	// features
	if(f.feature != null)
		boxesOK[0] = funcCaller(f, f.feature, okFeatures);
	// categories (SPG)
	if(f.category != null)
		boxesOK[1] =  funcCaller(f, f.category, okCategories);
	if(f.categoryCheck != null)
		boxesOK[1] =  funcCaller(f, f.category, okCategories);
	// brands (SPG)
	if(f.CA != null)
		boxesOK[2] =  funcCaller(f, f.CA, okBrands);

	for(var i = 0; i <boxesOK.length ; i++)
		if( ! boxesOK[i])
			return false;

	return true;
}

//------------------------------------------------------------
// calls a function specified as arg
function funcCaller(form, field, func )
{
	if(func == null)
	{
		//debug( func + ' is undefined');
		return true;
	}

	return func(form);

}

//------------------------------------------------------------
// check the features
// Error : too many features selected (more than 3 checkboxes)
function okFeatures(f)
{
   		// if there are no feature check boxes in the form, don't bother
   		if(f.feature == null)
      		return true;

   		// shortcut var
  	    var boxes = f.feature;

   		var count = 0;
   		selection = new Array(3);
		// initialize array to get rid of possible 'undefined' value which will be a problem
		// for the back-end..
		selection = ['','',''];
   		for(var n = 0; n <boxes.length ; n++)
   		{
	    		var isChecked = boxes[n].checked;
				//debug("Box :" + boxes[n] + " selected? " + isChecked );
	    		if ( isChecked == true )
				{
		  				++count;
						//debug("count: " +count);
	    				if ( count > 3 )
	    				{
	        					error('tooManyFeatures');
	        					return false;
	    				}
						else
						{
		   						selection[count-1] = boxes[n].value;
						}
				}
    	}


		// checks are done ,boxes array has no more than 3 selections
		// --> copy into feature hidden fields
    	f.amenityType1.value = selection[0];
		f.amenityType2.value = selection[1];
		f.amenityType3.value = selection[2];

		/*debug("Feature fields going out: ");
		debug("---------------");
		debug("amenityType1= " + f.amenityType1.value);
		debug("amenityType2= " + f.amenityType2.value);
		debug("amenityType3= " + f.amenityType3.value);
		debug("---------------");*/

  	    return true;
}


//--------------------------------------------------------
// set data for the back- end.
// For example, the back-end expects just one param named 'city', not 'city1' and 'city2'
function setForBackEnd(f)
{
         // all fields must exist, otherwise the op is not needed
   		if( f.city1 == null || f.stateProvince1 == null || f.stateProvince == null
                      	   || f.city2 == null || f.stateProvince2 == null || f.city == null)
			return;

   		// all checks have passed. At submit time, the back-end expects only one city and one state:
		// f.city and  f.stateProvince
		f.city.value = ( ( f.city1.value == '' ) ? f.city2.value : f.city1.value );

		// use shortcut vars
		state1 = f.stateProvince1.options[f.stateProvince1.selectedIndex].value;
		state2 = f.stateProvince2.options[f.stateProvince2.selectedIndex].value;

		f.stateProvince.value = ( ( state2 == '' ) ? state1 : state2 );

		/*debug( "For back-end, city= " + f.city.value + ", state= "
		            + f.stateProvince.value );*/

		// also, update city1-2& state1-2 hidden fields so the page can be filled in again
		// on the way back
		f.nCity1.value = f.city1.value;
		f.nCity2.value = f.city2.value;
		f.nState1.value = state1;
		f.nState2.value = state2;


		/*debug( "Updated nCity1= " + f.nCity1.value + " nCity2= " + f.nCity2.value
		       + " nState1= " + f.nState1.value + " nState2= " + f.nState2.value );*/

		// case of vicinity search  : set the country to US on exit, since the back-end
		// cannot handle it...
		if(searchByVicinity)
		{
			// see commonErr.js
			if(  isIn(state2, us_states) ) // double-check
			{
				setCountryValue(f.country,'US');
			}
		}

		if( f.rpoi != null && ! searchByPOI )
		{
			f.rpoi.value = '';
			//debug('rpoi blanked');
		}
}

//---------------------------------------------------------------------------------------


 // UTILITY FUNCTIONS : LOADERS


//---------------------------------------------------------------------------------------

// set city to city1 if both city1 and city2 are empty
function loadCities(form)
{
		if(form.nCity1 != null && form.nCity2 != null)
		{
			if(form.nCity1.value == '' && form.nCity2.value == '')
				loadIntoField(form.city, form.city1);
			else
			{
				loadIntoField(form.nCity1, form.city1);
				loadIntoField(form.nCity2, form.city2);
			}
		}
}

//-----------------------------------------------

function loadStates(form)
{
	if(form.nState1 != null && form.nState2 != null)
		{
			if(form.nState1.value == '' && form.nState2.value == '')
			{
				if( form.stateProvince2 != null )
			     (form.stateProvince2.selectedIndex == 0)?
					loadIntoListName(form.stateProvince, form.stateProvince1)
						:loadIntoListName(form.stateProvince, form.stateProvince2);
			}
			else
			{
				loadIntoListName(form.nState1, form.stateProvince1);
				loadIntoListName(form.nState2, form.stateProvince2);
			}
		}
}
//--------------------------------------------------

function loadCountry(form)
{
	if(form.nCountry != null)
		{
			if(form.stateProvince2 != null && form.stateProvince2.selectedIndex != 0)
				form.nCountry.value = '';

			if(form.stateProvince1 != null && form.stateProvince1.selectedIndex != 0)
				setCountry( form.nCountry, form.stateProvince1 );

			//debug('On init, nCountry is ' + form.nCountry.value);

			loadIntoListName(form.nCountry, form.country, 'blank');
		}
}

//-----------------------------------------------
// blank all Location search fields
function blankLocationFields(f)
{
   if(f.city1 != null) f.city1.value = '';
   if(f.stateProvince1 != null) f.stateProvince1.selectedIndex = 0;
   if(f.country != null) f.country.selectedIndex =0;
   if(f.postalCode != null) f.postalCode.value = '';
}

//------------------------------------------------
//set wheel chair box checked
function loadWheelChair(fromField, toField)
{
	if(fromField == null || toField == null)
		return;
	else{
		if(fromField.value == '1')
		{
		   toField.checked = true;
		   //return;
		}
	}
}

//------------------------------------------------
// check features on load if any is set up in the 3 feature hidden fields
function loadFeatures(fo)
{
   		// check if fields are present in the form
   		if(fo.feature == null || fo.amenityType1 == null || fo.amenityType2 == null
		                      || fo.amenityType3 == null)
      		return;

		// if all hidden fields are empty , there is nothing to be done
		if(fo.amenityType1.value == '' && fo.amenityType2.value == ''
		   && fo.amenityType3.value == '')
		{
		    //get rid of 'undefined' and replace it by '' for the back-end
		   // fo.amenityType1.value = fo.amenityType2.value = fo.amenityType3.value = '';
			return;
		}

		/*debug("Feature fields coming in: ");
		debug("---------------");
		debug("amenityType1= " + fo.amenityType1.value);
		debug("amenityType2= " + fo.amenityType2.value);
		debug("amenityType3= " + fo.amenityType3.value);
		debug("---------------");*/

   		// shortcut var
   		var boxes = fo.feature;
   		for(var n = 0; n <boxes.length ; n++)
   		{
      		if(
	      		(fo.amenityType1.value != '' && fo.amenityType1.value == boxes[n].value) ||
		  		(fo.amenityType2.value != '' && fo.amenityType2.value == boxes[n].value) ||
		  		(fo.amenityType3.value != '' && fo.amenityType3.value == boxes[n].value)
			  )
			  {
	    		boxes[n].checked = true;
				//debug( boxes[n].value + " checked" );
			  }
   		}
}
//-------------------------------------------------
// load a val into a txt field
function loadIntoField(fromVal, toField)
{
    if(toField == null || fromVal == null || fromVal.value == '')
  			return;

	toField.value = unescape(fromVal.value);
	//debug(toField.name + " field coming in: " + fromVal.value);
}
//--------------------------------------------------
// load a val into drop down
function loadIntoListNumber(fromVal, toField)
{
    	if(toField == null || fromVal == null || fromVal.value == '')
  			return;

		var ix = eval(fromVal.value);
		toField.options[ ix-1 ].selected = true;

		//debug(toField.name + " field coming in: " + fromVal.value);
}
//--------------------------------------------------
// load a val into drop down after finding its index
function loadIntoListName(fromVal, toField)
{
    	if(toField == null || fromVal == null)
  			return;
	    if(arguments[2] == null && fromVal.value == '')
			return;

	   for( var i =0; i <toField.options.length ; i++)
	  		 if( toField.options[i].value == fromVal.value )
			 {
			 		toField.selectedIndex = i;
					break;
			 }

	   //debug(toField.name + " field coming in: " + fromVal.value);
}
//----------------------------------------------------
// pre-select radio button from hidden field
function loadRadio(fromVal, toField)
{
   	   if(toField == null || fromVal == null || fromVal.value == '')
  			return;

	   for( var i =0; i <toField.length ; i++)
	  		 if( toField[i].value == fromVal.value )
			 {
			 		toField[i].checked = true;
					break;
			 }

	  // debug(toField[0].name + " field coming in: " + fromVal.value);
}