/* ================================================================================
  START: JavaScript code for city search
================================================================================ */

/* ================================================================================
  Create global objects
  oSelectedZips: an array object to store the selected zip codes
    The format of this object will be:
    {[{"dispname": "", "zipcodes": [], "sortnum": n, "dispall": true|false},
      {etc.}]}
  rZipCodes: an object that will hold an AJAX request for available zip codes
	rNearByCities: an object that will hold an AJAX request for nearby cities
  oLastSearched: an object based off the "cLastSearched" class to store the last
    searched entry
================================================================================ */
var oSelectedZips = new Array();
var rZipCodes     = null; 
var rNearByCities = null;

function cLastSearched(){
	this.city  = "";
	this.state = "";
	this.zip   = "";
}
var oLastSearched = new cLastSearched();

/* ================================================================================
  This function will do a sort a custom sort by for the "oSelectedZips" object.
================================================================================ */
function sortSelectedZips(a, b){
	var x = parseInt(a.sortnum);
	var y = parseInt(b.sortnum);
	var sortOrder = 0;

	if(is_ie) return ((x > y) ? -1 : ((x < y) ? 1 : 0)); // for IE
	else return ((x < y) ? -1 : ((x > y) ? 1 : 0)); // for everything else (or at least FF)
}

/* ================================================================================
  This function will remove spaces and change the casing to all uppercase
================================================================================ */
function changeCase(data){
	return data.replace(/\s/g, "").toUpperCase();
}

/* ================================================================================
  This function will check the value of the search field and default a label within
  the field if it is blank.
================================================================================ */
function checkSearchBox(){
	var fSearch = document.getElementById("f_search");

	if(fSearch.value == ""){
		fSearch.style.color = "#999999";
		fSearch.value = "Search by City & State or ZIP";
	} else if(fSearch.value == "Search by City & State or ZIP"){
		fSearch.style.color = "#000000";
		fSearch.value = "";
	}
}

/* ================================================================================
  This function will prevent the entire form from being submitted if the user hits
  the "enter" key while in the search field. Instead it will run the "runSearch()"
  function.
================================================================================ */
function checkKeyPress(e){
	if(window.event) keynum = e.keyCode; // for IE
	else if(e.which) keynum = e.which; // Netscape/Firefox/Opera

	if(keynum == 13) runSearch();
	return (keynum != 13);

}

/* ================================================================================
  This function is to reload the search field and selected zips fields in the event
  that the page reloads due to a submission error.
================================================================================ */
function checkExistingForm(){
	var fSelZipsObj = unescape(document.getElementById("selZipsObj").value);
	var fCityObj    = unescape(document.getElementById("cityObj").value);
	var fSearchBox  = document.getElementById("f_search");

	if(fSelZipsObj.length) oSelectedZips = JSON.parse(fSelZipsObj);
	if(fCityObj.length){
		oLastSearched = JSON.parse(fCityObj);
		if(oLastSearched.zip.length) fSearchBox.value = oLastSearched.zip;
		else fSearchBox.value = oLastSearched.city + ", " + oLastSearched.state;
		runSearch();
	}
	displaySelectedZips();
}

/* ================================================================================
  This function kicks the whole process off.
================================================================================ */
function runSearch(){
	var bWarningMsg = document.getElementById("b_warning_msg");
	var fWarningMsg = document.getElementById("f_warning_msg");
	var bAltCities  = document.getElementById("b_alt_cities");
	var bZipGrid    = document.getElementById("b_zip_grid");
	var lZipGrid    = document.getElementById("l_zip_grid");
	var searchValue = document.getElementById("f_search").value;
	var reZipCode   = /\d{5}/i; // matches a 5 digit zip code
	var searchedZip = reZipCode.test(searchValue);
	var geocoder    = new google.maps.ClientGeocoder();
	geocoder.setBaseCountryCode("us");

	// hide warning message, alternate cities, and zip code grid areas
	bWarningMsg.style.display = "none";
	bAltCities.style.display  = "none";
	lZipGrid.style.display    = "none";
	bZipGrid.style.display    = "none";

	// checks for a value in the search box and calls the geocoding service
	if(searchValue == "" || searchValue == "Search by City & State or ZIP"){
		bWarningMsg.style.display = "block";
		fWarningMsg.innerHTML = "Please enter city, state or ZIP code and try again.";
	} else {
		// if searching on zip code use Google GeoCoder
		if(searchedZip) geocoder.getLocations(stripSpecialChars(searchValue), geocodeLookup);
		else {
			// starts an AJAX call to HG's system for a list of city and states
			rCityStates = makeAjaxRequest();
			if(rCityStates == null) alert("Unable to create request.");
			else {
				// generate url string
				var rUrl = "/client/ae_parse_csz_get_city_and_states?address=" + escape(searchValue);
				rUrl += "&ts=" + escape(Date());
				rCityStates.onreadystatechange = getHGCityAndStates;
				rCityStates.open("GET", rUrl, true);
				rCityStates.send(null);
			}
		}
	}
}

/* ================================================================================
  This is the callback function that the "runSearch()" function calls after
  getting a list of city and states.
================================================================================ */
function getHGCityAndStates(){
	if(rCityStates.readyState == 4){
		if(rCityStates.status == 200){
			var listCityStates = JSON.parse(rCityStates.responseText);
			var oPlacemarks    = filterPlacemarks(listCityStates.Placemark);

			// if there is exactly once city found
			if(oPlacemarks.length == 1) doCitySearch(oPlacemarks);
			// if there is more than one city found
			else if(oPlacemarks.length > 1) doDisplayMultipleCities(oPlacemarks);
			// if nothing was found run search against Google
			else {
				runGoogleSearch();
			}
		}
	}
}

/* ================================================================================
  This function runs the Google geocoder.
================================================================================ */
function runGoogleSearch(){
	var bWarningMsg = document.getElementById("b_warning_msg");
	var fWarningMsg = document.getElementById("f_warning_msg");
	var bAltCities  = document.getElementById("b_alt_cities");
	var bZipGrid    = document.getElementById("b_zip_grid");
	var lZipGrid    = document.getElementById("l_zip_grid");
	var searchValue = document.getElementById("f_search").value;
	var reZipCode   = /\d{5}/i; // matches a 5 digit zip code
	var searchedZip = reZipCode.test(searchValue);
	var geocoder    = new google.maps.ClientGeocoder();
	geocoder.setBaseCountryCode("us");

	// hide warning message, alternate cities, and zip code grid areas
	bWarningMsg.style.display = "none";
	bAltCities.style.display  = "none";
	lZipGrid.style.display    = "none";
	bZipGrid.style.display    = "none";

	// checks for a value in the search box, calls the geocoding service, than calls the callback function: geocodeLookup()
	if(searchValue == "" || searchValue == "Search by City & State or ZIP"){
		bWarningMsg.style.display = "block";
		fWarningMsg.innerHTML = "Please enter city, state or ZIP code and try again.";
	} else {
		// add ", usa" if the user is searching for a city
		if(!searchedZip) searchValue += ", USA";
		geocoder.getLocations(stripSpecialChars(searchValue), geocodeLookup);
	}
}

/* ================================================================================
  This is the callback function that the "runGoogleSearch()" function calls after
  geocoding the value of the search field.
================================================================================ */
function geocodeLookup(objAddress){
	var bWarningMsg = document.getElementById("b_warning_msg");
	var fWarningMsg = document.getElementById("f_warning_msg");

	if(objAddress.Status.code == G_GEO_SUCCESS){
		var oPlacemarks = filterPlacemarks(objAddress.Placemark);

		// if there is exactly once city found
		if(oPlacemarks.length == 1) doCitySearch(oPlacemarks);
		// if there is more than one city found
		else if(oPlacemarks.length > 1) doDisplayMultipleCities(oPlacemarks);
		// if nothing was found
		else {
			bWarningMsg.style.display = "block";
			fWarningMsg.innerHTML = "We weren't able to find the location you've entered.";
		}
	} else {
		// if the geocoding does not return anything
		bWarningMsg.style.display = "block";
		fWarningMsg.innerHTML = "We weren't able to find the location you've entered.";
	}
}

/* ================================================================================
  This function starts the process of getting zip codes for a single city.
================================================================================ */
function doCitySearch(oPlacemarks){
	var oLocalityData = getLocalityData(oPlacemarks[0]);
	var cityName      = oLocalityData.city + ", " + oLocalityData.state;
	var searchValue   = document.getElementById("f_search").value;
	var reZipCode     = /\d{5}/i; // matches a 5 digit zip code
	var searchedZip   = reZipCode.test(searchValue);

	if(searchedZip){
		// if the user is searching for a particular zip code, populate the "zip" field in the "oLastSearched" object
		oLastSearched.city  = oLocalityData.city;
		oLastSearched.state = oLocalityData.state;
		oLastSearched.zip   = oLocalityData.zip;
	} else {
		oLastSearched.city  = oLocalityData.city;
		oLastSearched.state = oLocalityData.state;
		oLastSearched.zip   = "";
		// changes the value of the search field to what is retreived from the Google geocoder
		if(oLocalityData.accuracy >= 4) document.getElementById("f_search").value = cityName;
	}
	// starts an AJAX call to HG's system for a list of covered ZIP codes
	rZipCodes = makeAjaxRequest();
	if(rZipCodes == null) alert("Unable to create request.");
	else {
		// generate url string
		var rUrl = "ae_buyer_zip_list?";
		rUrl += "city=";
		// check if there is a valid city
		if(!isUndefinedNull(oLastSearched.city)) rUrl += escape(oLastSearched.city);
		rUrl += "&state=";
		// check if there is a valid state
		if(!isUndefinedNull(oLastSearched.state)) rUrl += escape(oLastSearched.state.toUpperCase());
		rUrl += "&zip=";
		// check if there is a valid zip
		if(!isUndefinedNull(oLastSearched.zip)) rUrl += escape(oLastSearched.zip);
		// adds a timestamp to prevent cacheing
		rUrl += "&ts=" + escape(Date());
		// if the user is searching for a particular zip code
		if(searchedZip) rZipCodes.onreadystatechange = processZipSearch;
		// if the user is searching for a particular city
		else rZipCodes.onreadystatechange = getZipCodes;
		rZipCodes.open("GET", rUrl, true);
		rZipCodes.send(null);
	}
}

/* ================================================================================
  This is one of the callback functions that the "doCitySearch()" function calls
  after getting a list of available zip codes if the user searched by zip code.
================================================================================ */
function processZipSearch(){
	if(rZipCodes.readyState == 4){
		if(rZipCodes.status == 200){
			var searchedZip   = document.getElementById("f_search").value;
			var availableZips = JSON.parse(rZipCodes.responseText);
			var zipCodesList  = availableZips.zipcodes;
			var bZipGrid      = document.getElementById("b_zip_grid");
			var lZipGrid      = document.getElementById("l_zip_grid");
			var bWarningMsg   = document.getElementById("b_warning_msg");
			var fWarningMsg   = document.getElementById("f_warning_msg");
			var tmpCityName   = new Array();
			var selZipNum     = 0;
			var maxZipFlag    = false;
			var coveredZip    = false;

			// checks the number of selected zip codes
			for(i in oSelectedZips){
				selZipNum += oSelectedZips[i].zipcodes.length;
			}
			if(selZipNum >= 8) maxZipFlag = true;

			// checks the number of available zip codes and processes the results
			if(zipCodesList.length <= 0){
				// if there are no available zips
				bWarningMsg.style.display = "block";
				fWarningMsg.innerHTML = "We don't currently have agents in the ZIP code you searched for, but we do have agents nearby who can assist you. Please select one of the nearby cities from the list below.";
				getNearByCities();
			} else {
				// reset the "oLastSearched" to match what HG has
				tmpCityName = availableZips.cityname.split(", ");
				oLastSearched.city  = tmpCityName[0];
				oLastSearched.state = tmpCityName[1];

				// check if zip code entered is covered
				for(i in zipCodesList){
					if(zipCodesList[i] == searchedZip){
						coveredZip = true;
						break;
					}
				}

				if(coveredZip){
					if(maxZipFlag){
						// reset all the previously selected cities to display all of their zip codes
						for(i in oSelectedZips) oSelectedZips[i].dispall = true;
						displayZipCodeGrid(availableZips);
						displaySelectedZips();
					} else {
						// add the zip code to the list of selected zip codes
						addZipCodes({"cityname": availableZips.cityname, "zipcodes": [searchedZip]});

						if(zipCodesList.length <= 8){
							// if there is only one covered zip code, do not show it's city in the nearby cities drop down
							if(zipCodesList.length == 1) oLastSearched.zip = "";
							// if there are 8 or less covered zip codes, show nearby cities drop down
							getNearByCities();
						} else displayZipCodeGrid(availableZips); // if there are 8 or more covered zip codes, show zip code grid for that city
					}
				} else {
					// if there are no available zip codes
					displayZipCodeGrid(availableZips);
					bWarningMsg.style.display = "block";
					fWarningMsg.innerHTML = "We don't currently have agents in the ZIP code you searched for, but we do have agents nearby who can assist you. Please select one of the nearby ZIP codes from the list below.";
				}
			}
		}
	}
}

/* ================================================================================
  This is one of the callback functions that the "doCitySearch()" function calls
  after getting a list of available zip codes if searched by city and state.
================================================================================ */
function getZipCodes(){
	if(rZipCodes.readyState == 4){
		if(rZipCodes.status == 200){
			var availableZips = JSON.parse(rZipCodes.responseText);
			var zipCodesList  = availableZips.zipcodes;
			var bWarningMsg   = document.getElementById("b_warning_msg");
			var fWarningMsg   = document.getElementById("f_warning_msg");
			var dispNameOnly  = false;
			var numZipsSel    = 0;

			// checks the number of available zip codes and processes the results
			if(zipCodesList.length <= 0){
				// if there are no available zips
				bWarningMsg.style.display = "block";
				fWarningMsg.innerHTML = "We don't currently have agents in the city you searched for, but we do have agents nearby who can assist you. Please select one of the nearby cities from the list below.";
				getNearByCities();
			} else if(!oSelectedZips.length){ // if there are no previously selected zips
				if(zipCodesList.length < 8) getNearByCities();
				if(zipCodesList.length <= 8) addZipCodes(availableZips, false);
				else displayZipCodeGrid(availableZips);
			} else { // if there are previously selected zips
				for(i in oSelectedZips){
					// checks if we are only displaying the city name per scenario 1 & 2
					if(!oSelectedZips[i].dispall) dispNameOnly = true;
					numZipsSel += oSelectedZips[i].zipcodes.length;
				}
				if(numZipsSel < 8){
					// if there less than 8 previously selected zips
					if(dispNameOnly) fillInZips(availableZips);
					else if(availableZips.zipcodes.length == 1) addZipCodes(availableZips);
					else displayZipCodeGrid(availableZips);
				} else {
					// if there are 8 or more selected zips
					if(dispNameOnly){
						// reset all the previously selected cities to display all of their zip codes
						for(i in oSelectedZips) oSelectedZips[i].dispall = true;
						displaySelectedZips();
					}
					displayZipCodeGrid(availableZips);
				}
			}
		}
	}
}

/* ================================================================================
  This function starts the process of getting alternate cities.
================================================================================ */
function getNearByCities(){
	// starts an AJAX call to HG's system for a list of nearby cities
	rNearByCities = makeAjaxRequest();
	if(rNearByCities == null) alert("Unable to create request.");
	else {
		// generate url string
		var rUrl = "ae_buyer_city_list?";
		rUrl += "city=";
		// check if there is a valid city
		if(!isUndefinedNull(oLastSearched.city)) rUrl += escape(oLastSearched.city);
		rUrl += "&state=";
		// check if there is a valid state
		if(!isUndefinedNull(oLastSearched.state)) rUrl += escape(oLastSearched.state.toUpperCase());
		rUrl += "&zip=";
		// check if there is a valid zip
		if(!isUndefinedNull(oLastSearched.zip)) rUrl += escape(oLastSearched.zip);
		// adds a timestamp to prevent cacheing
		rUrl += "&ts=" + escape(Date());
		rNearByCities.onreadystatechange = displayNearByCities;
		rNearByCities.open("GET", rUrl, true);
		rNearByCities.send(null);
	}
}

/* ================================================================================
  This is the callback function that the "getNearByCities()" function calls
  after getting a list of alternate cities.
================================================================================ */
function displayNearByCities(){
	if(rNearByCities.readyState == 4){
		if(rNearByCities.status == 200){
			var nearByCities  = JSON.parse(rNearByCities.responseText);
			var bWarningMsg   = document.getElementById("b_warning_msg");
			var fWarningMsg   = document.getElementById("f_warning_msg");
			var bNearByCities = document.getElementById("b_alt_cities");
			var lNearByCities = document.getElementById("l_alt_cities");
			var fNearByCities = document.getElementById("f_alt_cities");
			var arrayCities   = new Array();
			var addCity       = true;
			var cityCovered   = false;
			var lenCityName   = 15;
			var nextOption    = 1;

			if(nearByCities.nearbys.length){
				// display nearby cities label and drop down
				lNearByCities.style.display = "block";
				lNearByCities.innerHTML     = "If you would like to add a nearby city, select from the list of cities we have agents in below:";
				bNearByCities.style.display = "block";

				// puts all nearby cities into an array
				for(i in nearByCities.nearbys){
					addCity = true;
					// do not display the city being searched in the nearby cities drop down
					if(changeCase(nearByCities.nearbys[i]) == changeCase(oLastSearched.city + "," + oLastSearched.state)){
						cityCovered = true;
						addCity = false;
					} else {
						for(x in oSelectedZips){
							// do not display a city that has already been selected
							if(changeCase(nearByCities.nearbys[i]) == changeCase(oSelectedZips[x].dispname)){
								addCity = false;
								break;
							}
						}
					}
					if(addCity){
						// gets the length of the longest city name
						if(lenCityName < nearByCities.nearbys[i].length) lenCityName = nearByCities.nearbys[i].length;
						arrayCities.push(nearByCities.nearbys[i]);
					}
				}
				if(arrayCities.length){
					// sort and populates the alternate cities drop down
					arrayCities.sort();
					fNearByCities.style.width = (lenCityName * 10) + "px";
					fNearByCities.options.length = arrayCities.length;
					fNearByCities.options[0] = new Option("Please select", "__none__");
					if(oLastSearched.zip.length && cityCovered){
						// if the user searched for a particular zip code, add the city of that zip code as the first city in the nearby cities drop down
						fNearByCities.options.length++;
						fNearByCities.options[1] = new Option(oLastSearched.city + ", " + oLastSearched.state, escape(oLastSearched.city + ", " + oLastSearched.state));
						nextOption++;
					}
					for(i in arrayCities){
						fNearByCities.options[nextOption] = new Option(arrayCities[i], escape(arrayCities[i]));
						nextOption++;
					}
				} else {
					lNearByCities.style.display = "none";
					lNearByCities.innerHTML     = "";
					bNearByCities.style.display = "none";
					if(bWarningMsg.style.display == "block") fWarningMsg.innerHTML = "We don't currently have agents in the area you searched for. Please enter another location you're interested in.";
				}
			} else {
				bWarningMsg.style.display = "block";
				fWarningMsg.innerHTML = "We don't currently have agents in the area you searched for. Please enter another location you're interested in.";
			}
		}
	}
}

/* ================================================================================
  This function adds zip codes to the "oSelectedZips" object.
================================================================================ */
function addZipCodes(selectedZips, dispAll){
	var dispName    = selectedZips.cityname;
	var zipCodes    = selectedZips.zipcodes;
	var newSelArray = new Array();
	var tmpSelArray = new Array();
	var newZipArray = new Array();
	var tmpZipCode  = "";
	var selZipList  = "";
	var nextSortNum = 0;
	var dupCityFlag = false;

	// defaults the "dispall" field to "true" if nothing was specified
	if(isUndefinedNull(dispAll)) dispAll = true;

	if(oSelectedZips.length){
		while(oSelectedZips.length){
			tmpSelArray = oSelectedZips.pop();

			// gets the next highest sort number
			if(parseInt(tmpSelArray.sortnum) >= nextSortNum) nextSortNum = (parseInt(tmpSelArray.sortnum) + 1);

			// checks for duplicate city name
			if(tmpSelArray.dispname == dispName){
				dupCityFlag = true;
				newZipArray = tmpSelArray.zipcodes;
				selZipList  = tmpSelArray.zipcodes.join(',');

				while(zipCodes.length){
					tmpZipCode = zipCodes.pop();
					// checks for duplicate zip code
					if(selZipList.indexOf(tmpZipCode) < 0) newZipArray.push(tmpZipCode);
				}

				newSelArray.push({"dispname": tmpSelArray.dispname, "zipcodes": newZipArray, "sortnum": parseInt(tmpSelArray.sortnum), "dispall": dispAll});
				continue;
			} else newSelArray.push(tmpSelArray);
		}

		if(!dupCityFlag) newSelArray.push({"dispname": dispName, "zipcodes": zipCodes, "sortnum": parseInt(nextSortNum), "dispall": dispAll});

		oSelectedZips = newSelArray;
	} else if(zipCodes.length){
		oSelectedZips.push({"dispname": dispName, "zipcodes": zipCodes, "sortnum": 0, "dispall": dispAll});
	}
	displaySelectedZips();
}

/* ================================================================================
  This function removes items to the "oSelectedZips" object.
================================================================================ */
function removeZipCodes(removeThis){
	var tmpSelArray = new Array();
	var newSelArray = new Array();
	var tmpZipArray = new Array();
	var newZipArray = new Array();
	var tmpZipCode  = "";

	if(oSelectedZips.length){
		while(oSelectedZips.length){
			tmpSelArray = oSelectedZips.pop();

			if(tmpSelArray.dispname == removeThis) continue;
			else {
				tmpZipArray = tmpSelArray.zipcodes;
				newZipArray = new Array();

				while(tmpZipArray.length){
					tmpZipCode = tmpZipArray.pop();
					if(tmpZipCode == removeThis) continue;
					else newZipArray.push(tmpZipCode);
				}

				if(newZipArray.length) newSelArray.push({"dispname": tmpSelArray.dispname, "zipcodes": newZipArray, "sortnum": tmpSelArray.sortnum, "dispall": tmpSelArray.dispall});
			}
		}
		oSelectedZips = newSelArray;
	}
	displaySelectedZips();
}

/* ================================================================================
  This function displays the selected zip codes.
================================================================================ */
function displaySelectedZips(){
	var bSelZips    = document.getElementById("b_selected_zips");
	var fSelZips    = document.getElementById("f_selected_zips");
	var fSelZipsObj = "";
	var fCityObj    = "";
	var selZipsHtml = "";
	var selZipCode  = "";
	var zipCodeList = new Array();

	// sort the "oSelectedZips" object by "sortnum"
	oSelectedZips.sort(sortSelectedZips);
	if(!isUndefinedNull(oSelectedZips)){
		// if there are any zip codes to display, show the "Currently selected area"
		if(oSelectedZips.length) bSelZips.style.display = "block";
		else bSelZips.style.display = "none";

		// sort and display the selected areas
		oSelectedZips = oSelectedZips.sort();
		for(i in oSelectedZips){
			if(parseInt(i)) selZipsHtml += "; ";
			// display city name
			selZipsHtml += "<nobr>";
			selZipsHtml += oSelectedZips[i].dispname;
			selZipsHtml += " <a href=\"javascript:removeZipCodes('";
			selZipsHtml += escape(oSelectedZips[i].dispname);
			selZipsHtml += "');\" id=\"tt_remove_ico\"><img src=\"";
			selZipsHtml += "http://images.homegain.com/i/c/small_red_x_ico.gif";
			selZipsHtml += "\" align=\"bottom\"/></a>";
			if(oSelectedZips[i].dispall)selZipsHtml += ":";
			selZipsHtml += "</nobr> ";

			// display selected zip codes for the city
			for(x in oSelectedZips[i].zipcodes){
				zipCodeList.push(oSelectedZips[i].zipcodes[x]);
				if(oSelectedZips[i].dispall){
					if(parseInt(x)) selZipsHtml += ", ";
					selZipsHtml += "<nobr>";
					selZipsHtml += oSelectedZips[i].zipcodes[x];
					selZipsHtml += " <a href=\"javascript:removeZipCodes('";
					selZipsHtml += escape(oSelectedZips[i].zipcodes[x]);
					selZipsHtml += "');\" id=\"tt_remove_ico\"><img src=\"";
					selZipsHtml += "http://images.homegain.com/i/c/small_red_x_ico.gif";
					selZipsHtml += "\" align=\"bottom\"/></a></nobr>";
				}
			}
		}
		fSelZips.innerHTML = selZipsHtml;

		// add tooltip popup for removing area link
		if(zipCodeList.length){
			var tt_remove = new Spry.Widget.Tooltip("tt_remove", "#tt_remove_ico", {hideDelay:0, offsetX:"15px", offsetY:"-20px"});
		} else document.getElementById('tt_remove').style.display = "none";

		//populate the zip codes
		for(i = 0; i < 8; i++){
			selZipCode = "";
			if(i < zipCodeList.length) selZipCode = zipCodeList[i];
			document.getElementById("zips" + i).value = selZipCode;
		}
	}

	// update hidden fields
	fSelZipsObj = JSON.stringify(oSelectedZips);
	fCityObj    = JSON.stringify(oLastSearched);
	document.getElementById("selZipsObj").value = escape(fSelZipsObj);
	document.getElementById("cityObj").value    = escape(fCityObj);

	// checks for number of zip codes already selected
	checkSelectedZips();
}

/* ================================================================================
  This function fills in zip codes from an alternate city until the total zips
  selected equal 8.
================================================================================ */
function fillInZips(availableZips){
	var newZipArray = new Array();
	var numSelZips  = 0;
	var numNewZips  = 0;

	// get the number of already selected zip codes
	for(i in oSelectedZips){
		numSelZips += oSelectedZips[i].zipcodes.length;
	}

	// fill in the rest of the zips from the selected city
	for(i = numSelZips; i < 8; i++){
		if(availableZips.zipcodes.length){
			newZipArray.push(availableZips.zipcodes.shift());
			numNewZips++;
		}
	}
	addZipCodes({"cityname": availableZips.cityname, "zipcodes": newZipArray}, false);
	if((numSelZips + numNewZips) < 8) getNearByCities();
}

/* ================================================================================
  This function processes the available zip codes and displays them in a grid.
================================================================================ */
function displayZipCodeGrid(availableZips){
	var bZipGridLabel  = document.getElementById("l_zip_grid");
	var pZipGridPrompt = document.getElementById("p_zip_grid");
	var bZipGrid       = document.getElementById("b_zip_grid");
	var zipCodesList   = availableZips.zipcodes;
	var zipCodesHtml   = "";

	// checks the total number of zip codes and decides the size of the grid area
	if(zipCodesList.length){
		// display the zip code grid label
		bZipGridLabel.style.display = "block";
		if(oSelectedZips.length) pZipGridPrompt.innerHTML = "If you would like to add nearby ZIP code(s), please select from the list below:";
		else pZipGridPrompt.innerHTML = "<b><u>Next Step:</u></b> Please select the ZIP codes you're most interested in from the list below:";

		// display the zip code grid
		bZipGrid.style.display = "block";
		if(zipCodesList.length <= 7){
			bZipGrid.style.height = "15px";
			bZipGrid.style.overflow = "hidden";
		} else if(zipCodesList.length <= 14){
			bZipGrid.style.height = "35px";
			bZipGrid.style.overflow = "hidden";
		} else {
			bZipGrid.style.height = "55px";
			bZipGrid.style.overflow = "auto";
		}

		// loops through each available zip codes and creates a "cell" for each
		for(i in zipCodesList){
			zipCodesHtml += "\n<div class=\"zip_cell\">";
			zipCodesHtml += "<input type=\"checkbox\"";
			zipCodesHtml += " name=\"f_zipcodes\"";
			zipCodesHtml += " id=\"c_zip_" + zipCodesList[i] + "\"";
			zipCodesHtml += " class=\"zip_checkbox\"";
			zipCodesHtml += " value=\"" + zipCodesList[i] + "\"";
			zipCodesHtml += " onclick=\"processZipFromGrid('" + zipCodesList[i] + "');\">";
			zipCodesHtml += "<span id=\"l_zip_" + zipCodesList[i] + "\">";
			zipCodesHtml += zipCodesList[i];
			zipCodesHtml += "</span>";
			zipCodesHtml += "</div>";
		}
		bZipGrid.innerHTML = zipCodesHtml;
	}
	checkSelectedZips();
}

/* ================================================================================
  This function checks all the selected zips and modifies the display as needed.
================================================================================ */
function checkSelectedZips(){
	var bZipGrid        = document.getElementById("b_zip_grid");
	var lZipGrid        = document.getElementById("l_zip_grid");
	var bWarningMsg     = document.getElementById("b_warning_msg");
	var fWarningMsg     = document.getElementById("f_warning_msg");
	var zipGridElements = document.getElementsByName("f_zipcodes");
	var tmpZipArray     = new Array();
	var dispNameOnly    = false;
	var maxZipFlag      = false;

	// put all selected zip codes into a temporary array
	for(i in oSelectedZips){
		// checks if we are only displaying the city name per scenario 1 & 2
		if(!oSelectedZips[i].dispall) dispNameOnly = true;
		// get all the selected zip codes		
		for(x in oSelectedZips[i].zipcodes){
			tmpZipArray.push(oSelectedZips[i].zipcodes[x]);
		}
	}

	// checks if the maximum allowed zip codes has already been selected
	if(tmpZipArray.length >= 8){
		maxZipFlag = true;
		if(!dispNameOnly){
			bWarningMsg.style.display = "block";
			fWarningMsg.innerHTML = "You have reached the maximum number of ZIP codes that can be selected. If you would like to add another area, please deselect one of your currently selected areas.";
		}
		if(bZipGrid.style.display == "block") lZipGrid.style.display = "none";
	} else {
		maxZipFlag = false;
		bWarningMsg.style.display = "none";
		fWarningMsg.innerHTML = "";
		if(bZipGrid.style.display == "block") lZipGrid.style.display = "block";
	}

	// update checked items in the zip code grid if it is being displayed
	if(bZipGrid.style.display == "block"){
		// clear all zip code check boxes
		for(i = 0; i < zipGridElements.length; i++){
			zipGridElements[i].checked = false;
			if(maxZipFlag){
				zipGridElements[i].disabled = true;
				document.getElementById("l_zip_" + zipGridElements[i].value).style.color = "#999999";
			} else {
				zipGridElements[i].disabled = false;
				document.getElementById("l_zip_" + zipGridElements[i].value).style.color = "#000000";
			}
		}

		// check all selected zip code check boxes
		for(i in tmpZipArray){
			var fZipCheck = document.getElementById("c_zip_" + tmpZipArray[i]);
			var lZipCheck = document.getElementById("l_zip_" + tmpZipArray[i]);
			if(!isUndefinedNull(fZipCheck)){
				fZipCheck.checked = true;
				fZipCheck.disabled = false;
				lZipCheck.style.color = "#000000";
			}
		}
	}
}

/* ================================================================================
  This function adds/removes the zip code selected from the grid to the
  "oSelectedZips" object.
================================================================================ */
function processZipFromGrid(zipcode){
	var cityName     = oLastSearched.city + ", " + oLastSearched.state;
	var selZipObj    = {"cityname": cityName, "zipcodes": [zipcode]};
	var selZipStatus = document.getElementById("c_zip_" + zipcode).checked;

	// check the status of the checkbox and either add/remove zip code from oSelectedZips
	if(selZipStatus) addZipCodes(selZipObj, true);
	else removeZipCodes(zipcode);
}

/* ================================================================================
  This function displays a drop down of alternative city names if an exact match
  could not be found from the Google geocoder.
================================================================================ */
function doDisplayMultipleCities(oPlacemarks){
	var oLocalityData  = new Object(); // Properties will be dynamically set; no object definition exists.
	var bWarningMsg    = document.getElementById("b_warning_msg");
	var fWarningMsg    = document.getElementById("f_warning_msg");
	var bAltCities     = document.getElementById("b_alt_cities");
	var lAltCities     = document.getElementById("l_alt_cities");
	var fAltCities     = document.getElementById("f_alt_cities");
	var arrayAltCities = new Array();
	var altCityName    = "";
	var lenAltCityName = 15;

	// display warning message area
	bWarningMsg.style.display = "block";
	fWarningMsg.innerHTML = "We weren't able to find the location you've entered.";

	// display alternate cities area and label
	lAltCities.style.display = "block";
	lAltCities.innerHTML     = "Please select from similar locations below:";
	bAltCities.style.display = "block";

	// puts all alternate cities into an array
	for(i in oPlacemarks){
		oLocalityData = getLocalityData(oPlacemarks[i]);
		// checks to make sure there is a city and state
		if(!isUndefinedNull(oLocalityData.city) && !isUndefinedNull(oLocalityData.state)){
			altCityName = oLocalityData.city + ", " + oLocalityData.state;
			if(lenAltCityName < altCityName.length) lenAltCityName = altCityName.length;
			arrayAltCities.push(altCityName);
		}
	}

	// sorts and populates the alternate cities drop down
	arrayAltCities.sort();
	fAltCities.style.width = (lenAltCityName * 10) + "px";
	fAltCities.options.length = arrayAltCities.length;
	fAltCities.options[0] = new Option("Please select", "__none__");
	for(i in arrayAltCities){
		fAltCities.options[(parseInt(i) + 1)] = new Option(arrayAltCities[i], escape(arrayAltCities[i]));
	}
}

/* ================================================================================
  This function takes a selected alternate city and runs a search for available
  zip codes.
================================================================================ */
function selectCity(){
	var fSearch        = document.getElementById("f_search");
	var fAltCities     = document.getElementById("f_alt_cities");
	var altCitiesIndex = fAltCities.selectedIndex;

	if(altCitiesIndex){
		fSearch.value = unescape(fAltCities[altCitiesIndex].value);
		runSearch();
	}
}

/* ================================================================================
  This function opens a new browser window displaying the city being searched in
  google maps.
================================================================================ */
function showMap(){
	var mapUrl = "http://maps.google.com/maps?z=12&q=" + escape(oLastSearched.city + ", " + oLastSearched.state);
	window.open(mapUrl);
}

/* ================================================================================
  END: JavaScript code for city search
================================================================================ */