var map;
var allMarkers = new Array();
var destinationMarker = false;
var geocoder = new google.maps.Geocoder();
var infowindow = new google.maps.InfoWindow({});
var inPlaceSearchLatLng;

function initializeMap() { //TODO: specify map options and controls (logged in/out states)
    var latlng = new google.maps.LatLng(40.77269, -73.949431);
    var myOptions = {
      zoom: 12,
      center: latlng,
      scrollwheel: false,
      keyboardShortcuts: false,
      disableDefaultUI: true,
      navigationControl:true,
      disableDoubleClickZoom:true,
      navigationControlOptions: google.maps.NavigationControlStyle.SMALL,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
        
    google.maps.event.addListener(map, 'zoom_changed', function() {
    	if (map.getZoom()>12){ //if the user zooms below 12, hide markers...
    		//WORK AROUND FOR GMAP V3
    		//TODO: replace this when clearOverlays becomes available for V3
    		for(var i=0; i<allMarkers.length; i++){
    			allMarkers[i].setMap(null);
    		}
    		if (destinationMarker)
    			destinationMarker.setMap(null);
    		infowindow.close();
    		//WORK AROUND FOR GMAP V3
    	} else if (allMarkers.length>0) { //...else if there are markers to show...
    		if (allMarkers[0].getMap()==null) { //...and the markers aren't currently attached
    			for(var i=0; i<allMarkers.length; i++){
    				allMarkers[i].setMap(map);
    			}
    			if (destinationMarker) {
    				destinationMarker.setMap(map);
    			}
    			//TODO: hide zoom controls when zoomed out?
        		//map.setOptions({navigationControl:false});
    		}
    	}
    });
    google.maps.event.addListener(map, 'rightclick', function(event) {
    	document.inPlaceSearchForm.inPlaceSearchLat.value = event.latLng.lat();
        document.inPlaceSearchForm.inPlaceSearchLng.value = event.latLng.lng();
        inPlaceSearchLatLng = event.latLng;
    });
    
    google.maps.event.addListener(map, 'bounds_changed', function() {
    	closeInPlaceSearch();
    });

  }

function clearOverlays(){
	//WORK AROUND FOR GMAP V3
	//TODO: replace this when clearOverlays becomes available for V3
	for(var i=0; i<allMarkers.length; i++){
		allMarkers[i].setMap(null);
	}
	allMarkers.length = 0;
	if (destinationMarker)
		destinationMarker.setMap(null);
	infowindow.close();
	//WORK AROUND FOR GMAP V3
}
function getSpaces(){

	//WORK AROUND FOR GMAP V3
	//TODO: replace this when clearOverlays becomes available for V3
	clearOverlays();
	//WORK AROUND FOR GMAP V3
	
	allMarkers = []; // reset the array so there won't be old data in it
	document.getElementById('spaceInfoWindowDivs').innerHTML = ''; //clear the old infoWindows
	//TODO: synch validation with backend
	
	var addressString; //initialize address string, set below:
	var criteriaAddress; //used below to show the search criteria
	if (document.search_form.refinedAddress.value!=''){ //if a refinedAddress is present, use it...
		addressString = document.search_form.refinedAddress.value;
		criteriaAddress = addressString;
	} else { // ...otherwise use the user input fields
		criteriaAddress = document.search_form.spaceAddress.value;
		addressString = criteriaAddress + ", " + document.search_form.spaceArea.value + " NY, USA"
		//TODO: make this smarter? what if bad address, do we need USA, etc?
	}
	geocoder.geocode({ address:addressString }, function(results,status){ //get address info from google
		if (status!='OK'){ //if the status code is anything but 200 (successful query) throw an error message
			//TODO: Make this more user-friendly
			alert('Your search returned no results.\nPlease make sure you entered the address correctly. (' + status + ')');
			return false;
		}
		if(results.length>1){ //if more than one address is returned, show a popup that lets the user choose the right one
			//TODO: don't build html popup here
			var tableData = '<table border="0" cellpadding="4" cellspacing="0">\n';
			var linkText = '';
			for (var i=0;i<results.length;i++){ //Each result indicates a possible address
				//linkText = '';
				var addressDetails = results[i].formatted_address; //get the AddressDetails object
				tableData += '<tr><td valign="top"><img src="images/flag_green.png"></td>\n';
				tableData += '<td valign="top">';
				//link for the user to select correct address
				tableData += '<a href="#" class="refineLink" onClick="refineAddress(\'' + addressDetails + '\');return false;">' + addressDetails + '</a></td></tr>\n';
			}
			tableData += '</table>\n';
			document.getElementById('search_messageData').innerHTML = tableData;
			//tell the user we have multiple matching addresses and stop this search
			document.getElementById('search_messageWindow').style.display = 'block';
			return false;
		}
		if (results[0].geometry.location_type=='APPROXIMATE'){ // location_type to indicate exactness of result
			openMsgWin('APPROXIMATE_RESULT');
			return false;
		}
		//if we've gotten here, we can assume we have one unique address
		var latLon = results[0].geometry.location; //locations.Placemark[0].Point.coordinates; //get address coordinates
		document.search_form.latitude.value = latLon.lat(); //update hidden fields, used by SP to find nearby spaces
		document.search_form.longitude.value = latLon.lng();
		//mark our destination and center the map there
		addDestinationMarker(latLon);
		//show the please wait message while the database is searched and points are plotted
		document.getElementById('pleaseWait').style.visibility='visible';
		$('search_form').action.toLowerCase(); //this fixes a safari bug
		var formParams;
		try {
			formParams = $('search_form').serialize(true); //prototype.js code to turn all search_form fields into params
		} catch (err){
			formParams =  '?latitude=' + encodeURI(document.search_form.latitude.value);
			formParams += '&longitude=' + encodeURI(document.search_form.longitude.value);
			formParams += '&spacePlate=' + encodeURI(document.search_form.spacePlate.value);
			formParams += '&spaceAddress=' + encodeURI(document.search_form.spaceAddress.value);
			formParams += '&refinedAddress=' + encodeURI(document.search_form.refinedAddress.value);
			formParams += '&spaceArea=' + encodeURI(document.search_form.spaceArea.value);
			formParams += '&spaceTime=' + encodeURI(document.search_form.spaceTime.value);
			formParams += '&spaceDate=' + encodeURI(document.search_form.spaceDate.value);
			formParams += '&spaceDistance=' + encodeURI(document.search_form.spaceDistance.value);
			formParams += '&spaceWindow=' + encodeURI(document.search_form.spaceWindow.value);
		}
		//send query via prototype.js AJAX request
		new Ajax.Request('execute/FindSpaces',
		  {
		    method:'post',
			parameters: formParams,
			onSuccess: function(transport){ //on success plot the markers and show the results tab
				document.getElementById('pleaseWait').style.visibility='hidden'; //hide the please wait message
				var spacesWrapper = transport.responseText.evalJSON(); //use prototype to access the space data
				var spaces = spacesWrapper.spaces;
				if(!spacesWrapper.success){
					var errors = spacesWrapper.errors;
					var validators  = new Object;
					for (var e=0;e<errors.length;e++){
						validators.name = errors[e].field;
						searchValidation(validators,validators,errors[e].errorCode);
					}
					return false;
				}
				// TODO - are there other error messages?
				if (spaces.length==0){
					openMsgWin('NO_SPACES_FOUND');
					
					//TODO: should there be one function to reset the search/list/results area?
					//clear any existing results from the results tab
					document.getElementById('resultsList').innerHTML = '';
					//show the search form -- this is in case there are zero results (otherwise we'd have a blank results list)
					// if we do have results, they will be written to the results tab
					showForm('searchForm');
					//don't want to show the results tab, in case there are no results
					$('resultsTab').style.visibility = 'hidden';
					
					return false;
				} else {
					for (i=0;i<spaces.length;i++){ //add each space to the global array
						addMarker(spaces[i],spaces.length);
					}
					showSpacesTable(spaces); //build and show the results tab
				}
			},
			//this assumes a failure to retrieve data from the server
			onFailure: function(){
				openMsgWin('SEARCH_ERROR');
				return false;
			}
		});
	});
	//update the criteria on the results page
	document.getElementById('criteriaAddress').innerHTML = criteriaAddress;
	document.getElementById('criteriaTime').innerHTML = document.search_form.spaceTime.options[document.search_form.spaceTime.selectedIndex].text;
	document.getElementById('criteriaDate').innerHTML = document.search_form.spaceDate.value;
	//reset the refinedString field so we don't bypass the user input on subsequent trips
	document.search_form.refinedAddress.value='';
}

function addMarker(space,last){ //add a marker object to the global marker array
	var lat = space.lat;
	var lon = space.lon;
	var owner = space.owner;
	createSpaceInfoNode(space);
	var image = 'images/pin_grey32.png';
	var myLatLng = new google.maps.LatLng(lat,lon);
	var spaceMarker = new google.maps.Marker({
	      position: myLatLng,
	      icon: image,
	      zIndex: 1
	  });
	var windowNode = document.getElementById('spaceInfo' + owner);
	//this binds the content for gmapV3 which no longer has a "bind" method
    google.maps.event.addListener(spaceMarker, 'click', function() {
    	infowindow.setContent(windowNode); 
    	infowindow.open(map,spaceMarker);
    });
 
	allMarkers[allMarkers.length] = spaceMarker; //add the marker to the array
	if (allMarkers.length==last){ //if we are at the end...
		showSpaces(); // ...show the spaces
	}
}

function addDestinationMarker(point){
	var image = 'images/flag_checkered32.png';
	var destination = 'Destination'; //TODO: make this the address
	destinationMarker = new google.maps.Marker({
	      position: point,
	      icon: image,
	      map: map,
	      title: destination,
	      zIndex: 1
	  });
	map.setZoom(12);
	map.panTo(point);
	//TODO: add info window?
}

function createSpaceInfoNode(space){
	var my_div = document.createElement('div');
	my_div.setAttribute('id', 'spaceInfo' + space.owner );
	//TODO: use createElement instead of innerHTML
	var spaceDetails = '<span class="label">Space Details:</span><br>\n';
	spaceDetails += 'Time Available: ' + space.reserveTime + '<br>\n';
	
	if (space.nextDay){
		spaceDetails += 'This spot is good for this day and the next day.<br>\n';
	} else if (space.fullDay){
		spaceDetails += 'This spot is good for the rest of this day.<br>\n';
	} else if (space.metered){
		spaceDetails += 'This spot is metered.<br>\n';
	}
	if (space.notes!=""){
		spaceDetails += 'Notes: ' + space.notes + '<br>\n';
	}
	
	spaceDetails += '<br><b>Would you like to reserve this space?</b><br><br>';
	spaceDetails += '<input type="button" value="YES" onClick="selectSpace(\'' + space.owner + '\',' + space.reserveDateTime + ');">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
	spaceDetails += '<input type="button" value="NO" onClick="infowindow.close();">';
	// insert it in the document
	my_div.innerHTML = spaceDetails;
	document.getElementById('spaceInfoWindowDivs').appendChild(my_div);
}

function showSpaces(){ //look through each space in allMarkers and show them
	for (var i = 0; i < allMarkers.length; i++) {
		allMarkers[i].setMap(map);
	}
}

function refineAddress(refinedString){ //update a hidden field with the refined address
	document.search_form.refinedAddress.value = refinedString;
	document.getElementById('search_messageWindow').style.display = 'none';
	getSpaces(); //TODO - do we really need to search for address again? could we check the geocoder???
}
	
function showSpacesTable(spaces){
	document.getElementById('resultsList').innerHTML = '';
	//create the table
	var myTable = document.createElement('table');
	myTable.setAttribute('id', 'searchResultsTable');
	myTable.setAttribute('border', '0');
	myTable.setAttribute('cellpadding', '0');
	myTable.setAttribute('cellspacing', '0');
	Element.extend(myTable);
	myTable.addClassName('table-autosort table-autostripe table-stripeclass:alternate');
	//add head section
	var myTableHead = document.createElement('thead');
	Element.extend(myTableHead);
	myTable.appendChild(myTableHead);
	//add header row
	var myTableRowHeader = document.createElement('tr');
	myTableHead.appendChild(myTableRowHeader);
	//add header cell
	//var myTableHeaderCell1 = document.createElement('th');
	//myTableHeaderCell1.addClassName('resultsCol1');
	//myTableRowHeader.appendChild(myTableHeaderCell1);
	//add header cell
	var myTableHeaderCell2 = document.createElement('th');
	Element.extend(myTableHeaderCell2);
	myTableHeaderCell2.addClassName('distanceCol table-sortable:numeric');
	myTableHeaderCell2.innerHTML = '<nobr>Distance</nobr>';
	myTableRowHeader.appendChild(myTableHeaderCell2);
	//add header cell
	var myTableHeaderCell3 = document.createElement('th');
	Element.extend(myTableHeaderCell3);
	myTableHeaderCell3.addClassName('timeCol table-sortable:numeric');
	myTableHeaderCell3.innerHTML = '<nobr>Time</nobr>';
	myTableRowHeader.appendChild(myTableHeaderCell3);
	//add header cell
	var myTableHeaderCell3a = document.createElement('th');
	Element.extend(myTableHeaderCell3a);
	myTableHeaderCell3a.addClassName('dateCol table-sortable:numeric');
	myTableHeaderCell3a.innerHTML = '<nobr>Date</nobr>';
	myTableRowHeader.appendChild(myTableHeaderCell3a);
	//add header cell
	var myTableHeaderCell4 = document.createElement('th');
	myTableRowHeader.appendChild(myTableHeaderCell4);
	//add body section
	var myTableBody = document.createElement('tbody');
	Element.extend(myTableBody);
	myTable.appendChild(myTableBody);
	for (var r=0;r<spaces.length;r++){
		//create a row
		var myTableRow = document.createElement('tr');
		myTableRow.setAttribute('id', 'row' + r );
		myTableBody.appendChild(myTableRow);
		//create cell
		//var myTableCell1 = document.createElement('td');
		//myTableRow.appendChild(myTableCell1);
		//create cell
		var myTableCell2 = document.createElement('td');
		Element.extend(myTableCell2);
		myTableCell2.addClassName('distanceCol');
		myTableCell2.innerHTML = '<img id="listIcon' + r + '" align="absmiddle" src="images/pin_grey.png" border="0"/>&nbsp;' + spaces[r].distance;
		myTableRow.appendChild(myTableCell2);
		//create cell
		var myTableCell3 = document.createElement('td');
		Element.extend(myTableCell3);
		myTableCell3.addClassName('timeCol');
		myTableCell3.innerHTML = spaces[r].reserveTime;
		myTableRow.appendChild(myTableCell3);
		//create cell
		var myTableCell3a = document.createElement('td');
		Element.extend(myTableCell3a);
		myTableCell3a.addClassName('dateCol');
		myTableCell3a.innerHTML = spaces[r].date;
		myTableRow.appendChild(myTableCell3a);
		//create cell
		var myTableCell4 = document.createElement('td');
		myTableRow.appendChild(myTableCell4);
	}
	// insert it in the document
	document.getElementById('resultsList').appendChild(myTable);
	document.getElementById('resultsTab').style.visibility = 'visible';
	document.getElementById('resultsLink').style.color='#000000';
	document.getElementById('resultsTab').style.borderBottom='1px solid #EEEEFF';
	document.getElementById('listTab').style.borderBottom='1px solid #000066';
	document.getElementById('searchLink').style.color='#999999';
	document.getElementById('searchTab').style.borderBottom='1px solid #000066';
	document.getElementById('searchResultsDisplay').style.visibility = 'visible';
	//make it sortable
	Table.auto();
	//add highlights
	for (var h=0;h<spaces.length;h++){
		addHighlights(spaces[h].owner,h)
	}
}

//needed to move this out of showSpacesTable to make sure correct values are assigned
function addHighlights(owner,h){
	$('row' + h).observe("mouseover",  function() {
		highlightRow(this,h);
	});
	$('row' + h).observe("mouseout",  function() {
		removeHighlight(this,h);
	});
	$('row' + h).observe("click",  function() {
		showSpace(owner,h);
	});
	//TODO: set pointer - myTableRow.setAttribute('style', 'cursor:pointer');
}

function getSpacesNav(){
	validateSearchForm();
}

function validateSearchForm(){
	var validationErrors = new Array();
	validationErrors[0] = tmt.validator.validateField(document.getElementById('spaceAddress'),'searchValidation');
	validationErrors[1] = tmt.validator.validateField(document.getElementById('spaceArea'),'searchValidation');
	validationErrors[2] = tmt.validator.validateField(document.getElementById('spaceTime'),'searchValidation');
	if (validationErrors.exist(true)){
		return true;
	}
	sendSearchToServerForValidation();
}

function sendSearchToServerForValidation(){
	getSpaces();
}

function searchValidation(formNode, validators, errorCode){
	if (validators){
		//these error codes don't have an associated field so we show a generic error message
		if (validators.name=='latitude' || validators.name=='longitude' || validators.name=='spaceWindow' || validators.name=='spaceDistance' || validators.name=='spaceDate'){
			openMsgWin('SEARCH_ERROR');
		} else {
			document.getElementById(validators.name + 'Label').style.backgroundColor="#FF0000";
			document.getElementById(validators.name + 'Label').style.color="#FFFFFF";
			//document.getElementById(validators.name + 'Help').style.color = "#CC0000";
			//document.getElementById(validators.name + 'Help').innerHTML = getValidationMsg(validators, errorCode);
		}
	} else {
		document.getElementById(formNode.name + 'Label').style.backgroundColor="#FFFFCC";
		document.getElementById(formNode.name + 'Label').style.color="#000000";
		//document.getElementById(formNode.name + 'Help').style.color = "#999999";
		//document.getElementById(formNode.name + 'Help').innerHTML = getValidationMsg(formNode,'inlineHelp');
	}
}




function listASpace(){

	//WORK AROUND FOR GMAP V3
	//TODO: replace this when clearOverlays becomes available for V3
	clearOverlays();
	//WORK AROUND FOR GMAP V3
	
	var addressString; //initialize address string, set below:
	if (document.list_form.refinedAddress.value!=''){ //if a refinedAddress is present, use it...
		addressString = document.list_form.refinedAddress.value;
	} else { // ...otherwise use the user input fields
		addressString = document.list_form.listAddress.value + ", " + document.list_form.listArea.value + " NY, USA";
		//TODO: make this smarter? what if bad address, do we need USA, etc?
	}
	geocoder.geocode({ address:addressString }, function(locations,status){
		if (status!='OK'){ //if that status isn't ok, it means either no results or google error
			//TODO: Make this more user-friendly
			alert('We couldn\'t find that address.\nPlease make sure you entered the address correctly. (' + status + ')');
			return false;
		}
		if(locations.length>1){ //if more than one address is returned, show a popup that lets the user choose the right one
			//TODO: don't build html popup here
			var tableData = '<table border="0" cellpadding="4" cellspacing="0">\n';
			for (var i=0;i<locations.length;i++){ //Each result indicates a possible address
				if(locations[i].geometry.location_type=='ROOFTOP' || locations[i].geometry.location_type=='RANGE_INTERPOLATED'){
					var locationDetails = locations[i].formatted_address; //get the AddressDetails object
					tableData += '<tr><td valign="top"><img src="images/flag_green.png"></td>\n';
					tableData += '<td valign="top">';
					//link for the user to select correct address
					tableData += '<a href="#" class="refineLink" onClick="refineListing(\'' + locationDetails + '\');return false;">' + locationDetails + '</a></td></tr>\n';
				}
			}
			tableData += '</table>\n';
			document.getElementById('search_messageData').innerHTML = tableData;
			//tell the user we have multiple matching addresses and stop this search
			document.getElementById('search_messageWindow').style.display = 'block';
			return false;
		}
		var latLon = locations[0].geometry.location;
		document.list_form.latitude.value = latLon.lat();
		document.list_form.longitude.value = latLon.lng();
		document.getElementById('pleaseWait').style.visibility='visible';
		$('list_form').action.toLowerCase();
		var formParams;
		try {
			formParams = $('list_form').serialize(true); //prototype.js code to turn all list_form fields into params
		} catch (err){
			formParams =  '?latitude=' + encodeURI(document.list_form.latitude.value);
			formParams += '&longitude=' + encodeURI(document.list_form.longitude.value);
			formParams += '&listPlate=' + encodeURI(document.list_form.listPlate.value);
			formParams += '&listAddress=' + encodeURI(document.list_form.listAddress.value);
			formParams += '&refinedAddress=' + encodeURI(document.list_form.refinedAddress.value);
			formParams += '&listArea=' + encodeURI(document.list_form.listArea.value);
			formParams += '&listTime=' + encodeURI(document.list_form.listTime.value);
			formParams += '&listDate=' + encodeURI(document.list_form.listDate.value);
			formParams += '&listWait=' + encodeURI(document.list_form.listWait.value);
			formParams += '&listRules=' + encodeURI(document.list_form.listRules.value);
			formParams += '&listNote=' + encodeURI(document.list_form.listNote.value);
		}
		new Ajax.Request('execute/ListSpace',{
		    method:'post',
			parameters: formParams,
			onSuccess: function(transport){
				var response = transport.responseText.evalJSON();
				if (response.errors) {
					// validation error(s)
					var errors = response.errors;
					var validators  = new Object;
					for (var e=0;e<errors.length;e++){
						validators.name = errors[e].field;
						listValidation(validators,validators,errors[e].errorCode);
					}
				} else if (response.error) {
					// error
					openResponseMsgWin(response);
				} else {
					var listing = response.listing;
					var lat = listing.lat;
					var lon = listing.lon;
					var address = listing.address;
					var borough = listing.borough;
					var date = listing.date;
					var time = listing.time;
					var wait = listing.waitFor;
					$('listingAddress').innerHTML = address;
					$('listingBorough').innerHTML = borough;
					$('listingTime').innerHTML = time;
					$('listingDate').innerHTML = date;
					$('listingWait').innerHTML = wait + ' minutes';
					//successful list, so show info and hide inputs
					$('listInfo').style.display = 'block';
					$('listInput').style.display = 'none';
					
					//TODO: combine into function (same code in login function)
					if (response.listing.taker!=null){
						var headerListing = 'Claimed <b>listing</b>: <a href="#" onClick="showListingDetails(\'' + response.listing.address + '\',\'' + response.listing.borough + '\',\'' + response.listing.time + '\',\'' + response.listing.date + '\',\'' + response.listing.waitFor + '\',\'' + response.listing.lat + '\',\'' + response.listing.lon + '\',true,\'' + response.listing.taker.year + '\',\'' + response.listing.taker.make + '\',\'' + response.listing.taker.model + '\',\'' + response.listing.taker.color + '\',\'' + response.listing.taker.info + '\');return false;">' + response.listing.address + ', ' + response.listing.borough + " at " + response.listing.time + " on " + response.listing.date + '</a><br>';
						showListingDetails(address,borough,time,date,wait,lat,lon,true,listing.taker.year,listing.taker.make,listing.taker.model,listing.taker.color,listing.taker.info);
					} else {
						var headerListing = 'Your <b>listing</b>: <a href="#" onClick="showListingDetails(\'' + response.listing.address + '\',\'' + response.listing.borough + '\',\'' + response.listing.time + '\',\'' + response.listing.date + '\',\'' + response.listing.waitFor + '\',\'' + response.listing.lat + '\',\'' + response.listing.lon + '\',false);return false;">' + response.listing.address + ', ' + response.listing.borough + " at " + response.listing.time + " on " + response.listing.date + '</a><br>';
						showListingDetails(address,borough,time,date,wait,lat,lon,false);
					}
					//TODO: make this better
					//if there's code in the headerReservation field, it's because there's a Reservation
					//and we have to make sure there's a <br> or else add one (to make sure things aren't all on one line)
					var headerResText = $('headerReservation').innerHTML;
					if (headerResText!=''){
						if (headerResText.indexOf('<br>')<0){
							headerListing = '<br>' + headerListing;
						}
					}
					$('headerListing').innerHTML = headerListing;
					$('reservationListing').style.display='block';
				}							
				
				document.getElementById('pleaseWait').style.visibility='hidden';
		    },
			onFailure: function(){
				openMsgWin('ERROR');
				document.getElementById('pleaseWait').style.visibility='hidden';
			}
		});
	});
	//reset the refinedString field so we don't bypass the user input on subsequent trips
	document.list_form.refinedAddress.value='';
}

function refineListing(refinedString){ //update a hidden field with the refined address
	document.list_form.refinedAddress.value = refinedString;
	document.getElementById('search_messageWindow').style.display = 'none';
	listASpace(); //TODO - do we really need to search for address again? could we check the geocoder???
}

function confirmCancel(){
	openConfirmWin('CONFIRM_CANCEL_LISTING');
}

function cancelListing(){
	
	showMapWait();
	clearOverlays();
	new Ajax.Request('execute/CancelListing',
	{
		method:'post',
		onSuccess: function(transport){
			var response = transport.responseText.evalJSON();
			if (response.success) {
				openMsgWin('CANCEL_LISTING_SUCCESS');
				$('listInfo').style.display = 'none';
				$('listInput').style.display = 'block';
				if (response.credits>=0){
					$('welcomeBackCredits').innerHTML = response.credits;
				}
			} else {
				openResponseMsgWin(response);
			}
			$('headerListing').innerHTML = "";
			if ($('headerListing').innerHTML=="" && $('headerReservation').innerHTML==""){
				$('reservationListing').style.display = 'none';
			}
			hideMapWait();
		},
		//this assumes a failure to retrieve data from the server
		//TODO: Make this more user-friendly
		onFailure: function(){
			openMsgWin('ERROR');
			hideMapWait();
		}
	});
}

function listSpaceNav(){
	validateListForm();
}

function validateListForm(){
	var validationErrors = new Array();
	validationErrors[0] = tmt.validator.validateField(document.getElementById('listAddress'),'listValidation');
	validationErrors[1] = tmt.validator.validateField(document.getElementById('listArea'),'listValidation');
	validationErrors[2] = tmt.validator.validateField(document.getElementById('listTime'),'listValidation');
	validationErrors[3] = tmt.validator.validateField(document.getElementById('listWait'),'listValidation');
	if (validationErrors.exist(true)){
		return true;
	}
	sendListToServerForValidation();
}

function sendListToServerForValidation(){
	listASpace();
}

function listValidation(formNode, validators, errorCode){
	if (validators){
		//TODO - change this when logged out error condition is fixed above
		if (errorCode=='LOGGED_OUT'){
			openMsgWin('LOGGED_OUT');
		} else if (errorCode=='ALREADY_LISTED'){
			openMsgWin('ALREADY_LISTED');
		}else if (validators.name=='latitude' || validators.name=='longitude' || validators.name=='listDate'){
			//these error codes don't have an associated field so we show a generic error message
			openMsgWin('LIST_ERROR');
		} else {
			document.getElementById(validators.name + 'Label').style.backgroundColor="#FF0000";
			document.getElementById(validators.name + 'Label').style.color="#FFFFFF";
			//document.getElementById(validators.name + 'Help').style.color = "#CC0000";
			//document.getElementById(validators.name + 'Help').innerHTML = getValidationMsg(validators, errorCode);
		}
	} else {
		document.getElementById(formNode.name + 'Label').style.backgroundColor="#CCFFCC";
		document.getElementById(formNode.name + 'Label').style.color="#000000";
		//document.getElementById(formNode.name + 'Help').style.color = "#999999";
		//document.getElementById(formNode.name + 'Help').innerHTML = getValidationMsg(formNode,'inlineHelp');
	}
}

function showListingDetails(listingAddress,listingBorough,listingTime,listingDate,listingWait,listingLat,listingLon,tkr,tkrYear,tkrMake,tkrModel,tkrColor,tkrAddInfo){
	var listingDetails = '<span class="label">Your Listing Details:</span><br>\n';
	listingDetails += listingAddress + ', ' + listingBorough + '<br>\n';
	listingDetails += listingTime + ', ' + listingDate + '<br>\n';
	listingDetails += 'Wait time: ' + listingWait + ' minutes<br><br>\n'; //show meter, day, next, info?
	if (tkr){
		listingDetails += '<span class="label">Look for this car:</span><br>\n';
		listingDetails += tkrColor + ' ' + tkrYear + ' ' + tkrMake + ' ' + tkrModel + '<br>\n';
		if (tkrAddInfo!=""){
			listingDetails += '(' + tkrAddInfo + ')<br>\n';
		}
	} else {
		listingDetails += '<span class="label">Your spot has not been claimed yet.</span><br>\n';
	}
	listingDetails += '<br><input type="button" value="OK" onClick="clearOverlays();">';
	listingDetails += '<div class="deleteLink" style="position:absolute;right:0px;bottom:0px;"><a href="#" onClick="confirmCancel();return false;">cancel listing</a></div>';
	clearOverlays();
	infowindow.setContent(listingDetails); 
	var latlng = new google.maps.LatLng(listingLat, listingLon);
	var image = 'images/flag_green32.png';
	var listingMarker = new google.maps.Marker({
	      position: latlng,
	      icon: image,
	      zIndex: 1
	  });
	allMarkers.length = 0; //reset the array in case there's anything in there
	allMarkers[0] = listingMarker; //add the marker to the array
	showSpaces(); // ...show the spaces
	infowindow.open(map,listingMarker);
	//TODO: when the infowindow opens, it should be 100% visible, for some reason it's not quite 100% in view
}





function showSpace(owner,h){
	var windowNode = document.getElementById('spaceInfo' + owner);
	infowindow.setContent(windowNode); 
	google.maps.event.trigger(allMarkers[h], 'click');
}

function selectSpace(spaceId,reserveDateTime){
	/* Commented out for the prettier message box that will show 
	   TODO create nice message box without the trip to the server.
	if (!document.search_form.spacePlate.value){
		alert('Please log in');
		return false;
	}
	*/
	document.getElementById('pleaseWait').style.visibility='visible';
	new Ajax.Request('execute/ReserveSpace',
	{
		method:'post',
		//use prototype to serialize the form
		parameters: {relinquisher:spaceId,taker:document.search_form.spacePlate.value,reserveDateTime:reserveDateTime},
		//on success plot the markers and show the results tab
		onSuccess: function(transport){
			document.getElementById('pleaseWait').style.visibility='hidden';
			//alert(transport.responseText);
			var response = transport.responseText.evalJSON();
			if (response.success) {
				//TODO: display reserved confirmation, print directions? details, etc
				openResponseMsgWin(response);
				showReservationDetails(response.reservation.address,response.reservation.borough,response.reservation.reserveTime,response.reservation.date,response.reservation.giver.year,response.reservation.giver.make,response.reservation.giver.model,response.reservation.giver.color,response.reservation.giver.info,response.reservation.lat,response.reservation.lon,response.reservation.metered,response.reservation.fullDay,response.reservation.nextDay,response.reservation.notes);
				//TODO: combine into function (same code in login function)
				var headerReservation = 'Your <b>reservation</b>: <a href="#" onClick="showReservationDetails(\'' + response.reservation.address + '\',\'' + response.reservation.borough + '\',\'' + response.reservation.reserveTime + '\',\'' + response.reservation.date + '\',\'' + response.reservation.giver.year + '\',\'' + response.reservation.giver.make + '\',\'' + response.reservation.giver.model + '\',\'' + response.reservation.giver.color + '\',\'' + response.reservation.giver.info + '\',\'' + response.reservation.lat + '\',\'' + response.reservation.lon + '\',\'' + response.reservation.metered + '\',\'' + response.reservation.fullDay + '\',\'' + response.reservation.nextDay + '\',\'' + response.reservation.notes + '\')">' + response.reservation.address + ', ' + response.reservation.borough + ' at ' + response.reservation.reserveTime + ' on ' + response.reservation.date + '</a>';
				if ($('headerListing').innerHTML!=""){
					headerReservation = headerReservation + "<br/>";
				}
				$('headerReservation').innerHTML = headerReservation;
				$('reservationListing').style.display='block';
				if (response.credits>=0){
					$('welcomeBackCredits').innerHTML = response.credits;
				}
			} else {
				// failure
				openResponseMsgWin(response);
			}
		},
		onFailure: function(){
			document.getElementById('pleaseWait').style.visibility='hidden'; 
			openMsgWin('ERROR');
		},
		asynchronous: false
	});
}

function showReservationDetails(resAddress,resBorough,resTime,resDate,gvrYear,gvrMake,gvrModel,gvrColor,gvrAddInfo,resLat,resLon,resMeter,resDay,resNext,resNotes){
	var reservationDetails = '<span class="label">Your Reservation Details:</span><br>\n';
	reservationDetails += resAddress + ', ' + resBorough + '<br>\n';
	reservationDetails += resTime + ', ' + resDate + '<br><br>\n';
	reservationDetails += '<span class="label">Look for this car:</span><br>\n';
	reservationDetails += gvrColor + ' ' + gvrYear + ' ' + gvrMake + ' ' + gvrModel + '<br>\n';
	if (gvrAddInfo!=""){
		reservationDetails += '(' + gvrAddInfo + ')<br>\n';
	}
	reservationDetails += '<br><span class="label">Additional Information:</span><br>\n';

	//this is a little hacky, it's done to fix problems where JS functions are passing in true/false as a string and JSON as boolean
	//TODO: fix this hack
	if (resNext=="true"){
		resNext = true;
	}
	if (resDay=="true"){
		resDay = true;
	}
	if (resMeter=="true"){
		resMeter = true;
	}
	if (resNext=="false"){
		resNext = false;
	}
	if (resDay=="false"){
		resDay = false;
	}
	if (resMeter=="false"){
		resMeter = false;
	}
	//end hack
	
	if (resNext){
		reservationDetails += 'This spot is good for this day and the next day.<br>\n';
	} else if (resDay){
		reservationDetails += 'This spot is good for the rest of this day.<br>\n';
	} else if (resMeter){
		reservationDetails += 'This spot is metered.<br>\n';
	}
	
	if (resNotes!=""){
		reservationDetails += resNotes + '<br>\n';
	}
	reservationDetails += '<br><input type="button" value="OK" onClick="clearOverlays();">';
	reservationDetails += '<div class="deleteLink" style="position:absolute;right:0px;bottom:0px;"><a href="#" onClick="confirmCancelRes();return false;">cancel reservation</a></div>';
	clearOverlays();
	infowindow.setContent(reservationDetails); 
	var latlng = new google.maps.LatLng(resLat, resLon);
	var image = 'images/flag_checkered32.png';
	var spaceMarker = new google.maps.Marker({
	      position: latlng,
	      icon: image,
	      zIndex: 1
	  });
	allMarkers.length = 0; //reset the array in case there's anything in there
	allMarkers[0] = spaceMarker; //add the marker to the array
	showSpaces(); // ...show the spaces
	infowindow.open(map,spaceMarker);
	//TODO: when the infowindow opens, it should be 100% visible, for some reason it's not quite 100% in view
}


function confirmCancelRes(){
	openConfirmWin('CONFIRM_CANCEL_RESERVATION');
}

function cancelReservation(){
	showMapWait();
	clearOverlays();
	new Ajax.Request('execute/CancelReservation',
	{
		method:'post',
		onSuccess: function(transport){
			var response = transport.responseText.evalJSON();
			if (response.success) {
				openMsgWin('CANCEL_RESERVATION_SUCCESS');
				if (response.credits>=0){
					$('welcomeBackCredits').innerHTML = response.credits;
				}
			} else {
				openResponseMsgWin(response);					
			}
			$('headerReservation').innerHTML = "";
			if ($('headerListing').innerHTML=="" && $('headerReservation').innerHTML==""){
				$('reservationListing').style.display = 'none';
			}
			hideMapWait();
		},
		//this assumes a failure to retrieve data from the server
		onFailure: function(){
			openMsgWin('ERROR');
			hideMapWait();
		}
	});
}

function showMapWait(){
	$('mapWorking').style.display='block';
}

function hideMapWait(){
	$('mapWorking').style.display='none';
}









