var map;
var homeMarker;
var centerPosition;
var homeHref;
var params;
var sortLinks;
var url = '/update';

var minimumDistance;
var maximumDistance;
var minimumPrice;
var maximumPrice;

var markers = new Hash ();
var htmls = new Hash ();

var allowUpdate = true;
var hasUpdated = false;

Event.observe 
(
 	window,
	'load',
	function ()
	{
		params = new Hash ();
		sortLinks = new Hash ();
		
		map = new GMap2 ($ ('search-results-map'));
		map.addControl (new GLargeMapControl ());
		map.addControl (new GMapTypeControl ());
	
		GEvent.addListener
		(
			map,
			'dragend',
			function ()
			{
				if (allowUpdate)
				{
					resetParams ();
					updateResults ();
				}
			}
		);
		
		GEvent.addListener
		(
			map.getInfoWindow (),
			'closeclick',
			function ()
			{
				allowUpdate = true;
				map.panTo (centerPosition);
			}
		);
		
		drawMarkers ();
		updateAjaxableLinks ();
		updateMarkerOpeners ()
		setupMetaSearch ();
		setupHints ();
		
		Lat49App.init (map);
	}
);

Event.observe 
(
 	window,
	'unload',
	function ()
	{
 		GUnload ();
	}
);

function setupMetaSearch ()
{
	setupWalkingDistance ();
	setupPrice ();
	setupCovered ();
	setupDatePickerPane ();
	setupType ();	
}

function resetParams ()
{
	params.unset ('distanceFrom');
	params.unset ('distanceTo');
	params.unset ('priceFrom');
	params.unset ('priceTo');
	params.unset ('covered');
	
	var types = $$ ('.type');
	
	types.each
	(
	 	function (item)
		{
			params.unset ('type[' + item.id + ']');
		}
	);
	
	params.unset ('type');
	
	params.unset ('arrival');
	params.unset ('departure');
	params.unset ('type[hourly]');
	
	params.set ('resetMeta', true);
}

function updateAjaxableLinks ()
{
	var ajaxableLinks = $$ ('.ajaxable');
	
	ajaxableLinks.each 
	(
		function (link)
		{
			link.onclick = function ()
			{
				var sortType = sortLinks.get (link.rel);
				
				if (link.rel == 'offset')
				{
					params.set ('offset', link.title);
				}
				else
				{
					if (! sortType)
					{
						sortType = 'DESC';
					}
					else if (sortType == 'DESC')
					{
						sortType = 'ASC';
					}
					else if (sortType == 'ASC')
					{
						sortType = 'DESC';
					}
					
					sortLinks.set (link.rel, sortType);
					
					params.set ('sortBy', link.rel);
					params.set ('sortType', sortType);
				}
				
				updateResults ();
				
				return false;
			}
			
		}
	);
}

function updateMarkerOpeners ()
{
	var markerOpeners = $$ ('.marker-opener');
	
	markerOpeners.each 
	(
		function (link)
		{
			link.onclick = function ()
			{
				var marker = markers.get (link.rel);
				
				var details = document.createElement ('div');
				
				details.innerHTML = htmls.get (link.rel);
				
				var streetView = document.createElement ('div');
				
				streetView.style.width = '500px';
				streetView.style.height = '350px';
				
				var myPano = new GStreetviewPanorama (streetView);
				
				myPano.setLocationAndPOV (marker.getLatLng ());
				
				var infoWindow = document.createElement ('div');
				
				infoWindow.appendChild (details);
				infoWindow.appendChild (streetView);
	
				marker.openInfoWindowHtml (infoWindow);
				
				allowUpdate = false;

				return false;
			}
			
		}
	);
}

function updateResults ()
{
	var datePickerButtonText = null;
	var center = map.getCenter ();
	
	centerPosition = center;
	
	params.set ('lat', center.lat ());
	params.set ('lon', center.lng ());
	
	clearMarkers ();
	
	new Ajax.Request
	(
		url, 
		{
			method: 'get',
			parameters: params,
			onCreate: function ()
			{
				Element.addClassName ($ ('search-result-grid-loader'), 'on');
				Element.addClassName ($ ('search-results-grid'), 'loading');
				
				if ($ ('date-picker-pane'))
				{
					datePickerButtonText = $ ('button-date-picker-update-results').value;
					
					$ ('button-date-picker-update-results').disabled = true;
					$ ('button-date-picker-update-results').value = 'Updating ...';
				}
			},
			onFailure: function ()
			{
				alert ('Error reading data...');
			},
			onSuccess: function (transport)
			{
				hasUpdated = true;
				
				try
				{
					var response = transport.responseText.evalJSON ();
					
					if (response.properties)
					{
						response.properties.each
						(
						 	function (property)
							{
								addInfoMarker (property.propertyID, property.detailsUrl, property.longitude, property.latitude, property.address + ', ' + property.city + ', ' + property.stateAbbrev, property.price, property.distance, property.marker);
							}							
						);
					}
					
					$ ('search-results-grid').innerHTML = response.searchResultGrid;
					
					if (response.datePickerErrorMessage)
					{
						if ($ ('date-picker-pane'))
						{
							$ ('date-picker-error-message').innerHTML = response.datePickerErrorMessage;
						}
						
						Element.addClassName ($ ('date-picker-error-message'), 'on');
					}
					else
					{
						Element.removeClassName ($ ('date-picker-error-message'), 'on');
					}
					
					if (response.metaSearch)
					{
						$ ('meta-search-container').innerHTML = response.metaSearch;

						minimumDistance = response.minimumDistance;
						maximumDistance = response.maximumDistance;
						minimumPrice = response.minimumPrice;
						maximumPrice = response.maximumPrice;
						
						setupMetaSearch ();
						
						params.unset ('resetMeta');
					}

					updateAjaxableLinks ();
					updateMarkerOpeners ();
					
					setupHints ();
					
					Element.removeClassName ($ ('search-result-grid-loader'), 'on');
					Element.removeClassName ($ ('search-results-grid'), 'loading');
					
					if ($ ('date-picker-pane') && datePickerButtonText)
					{
						$ ('button-date-picker-update-results').disabled = false;
						$ ('button-date-picker-update-results').value = datePickerButtonText;
					}
				}
				catch (e)
				{
					if (console)
					{
						console.log (e.toString ());
					}
				}
			}
		}
	);
}

function clearMarkers ()
{
	var i = 0;
	
	markers.each
	(
	    function (marker)
	    {
	    	map.removeOverlay (marker.value);
	    }
	);
	
	markers = new Hash ();
	htmls = new Hash ();
}

function addInfoMarker (id, detailsUrl, longitude, latitude, address, price, distance, letter)
{
	var latLng = new GLatLng (latitude, longitude);
	
	var icon = new GIcon ();
	
	icon.shadow = 'http://www.google.com/mapfiles/shadow50.png';
	icon.iconSize = new GSize (20, 34);
	icon.shadowSize = new GSize (37, 34);
	icon.iconAnchor = new GPoint (9, 34);
	icon.infoWindowAnchor = new GPoint (9, 2);
	icon.infoShadowAnchor = new GPoint (18, 25);
	icon.image = "http://www.google.com/mapfiles/marker" + letter + ".png";
	
	var marker = new GMarker (latLng, icon);
	
	var html = '';
	
	var startAddress = $ ('page-header-search-box-input').value;
	var endAddress = address;
	
	html += '<div id="info-window-details">';
	html += '<p class="info-window-address"><strong>Address</strong>: ' + address + '<br />';
	html += '<strong>Price</strong>: ' + ((price != '') ? price : '<a class="price-hint" href="price-hint">?</a>') + '<br />';
	html += '<strong>Walking Time</strong>: ' + distance + '</p>';
	html += '<p class="info-window-directions"><a href="http://maps.google.com/maps?saddr=' + startAddress + '&daddr=' + endAddress + '&dirflg=w" target="_blank">Get Directions</div>';
	html += '<p class="info-window-contact"><a href="' + homeHref + '/' + detailsUrl + '">Contact Parking Owner</a></p>';
	html += '</div>';
	
	GEvent.addListener
	(
		marker,
		'click',
		function ()
		{
			var details = document.createElement ('div');
			
			details.innerHTML = html;
			
			var streetView = document.createElement ('div');
			
			streetView.style.width = '500px';
			streetView.style.height = '350px';
			
			var myPano = new GStreetviewPanorama (streetView);
			
			myPano.setLocationAndPOV (latLng);
			
			var infoWindow = document.createElement ('div');
			
			infoWindow.appendChild (details);
			infoWindow.appendChild (streetView);

			marker.openInfoWindowHtml (infoWindow);
			
			allowUpdate = false;
		}
	);
	
	markers.set (letter, marker);
	htmls.set (letter, html);

	map.addOverlay (marker);
}

function drawHomeMarker (longitude, latitude)
{
    if (homeMarker)
    {
        map.removeOverlay (homeMarker);
    }

	var icon = new GIcon ();
	
	icon.iconSize = new GSize (32,32);
	icon.shadowSize = new GSize (56,32);
	icon.iconAnchor = new GPoint (16,32);
	icon.infoWindowAnchor = new GPoint (16,0);
	
	icon.image = 'http://maps.google.com/mapfiles/kml/pal5/icon6.png';	
	
	var homeMarkerPosition = new GLatLng (latitude, longitude);
	
	homeMarker = new GMarker (homeMarkerPosition, icon);
	
	GEvent.addListener
	(
		homeMarker,
		'click',
		function ()
		{
			if (hasUpdated)
			{
				map.panTo (homeMarkerPosition);
				map.setCenter (homeMarkerPosition, mapZoom);
				resetParams ();
				updateResults ();
			}
		}
	);

	map.addOverlay (homeMarker);
}

/**
 * Search
 */
function setupDatePickerPane ()
{
	if ($ ('date-picker-pane'))
	{
		Event.observe 
		(
			$ ('date-picker-pane-handle'),
			'click',
			function ()
			{
				onDatePickerHandleClicked ();
			}
		);
		
		Event.observe 
		(
			$ ('button-date-picker-update-results'),
			'click',
			function ()
			{
				if ($ ('arrive-date').value == '' || $ ('depart-date').value == '')
				{
					$ ('date-picker-error-message').innerHTML = 'Dates cannot be empty';
					
					Element.addClassName ($ ('date-picker-error-message'), 'on');
				}
				else
				{
					var arrival = $ ('arrive-date').value + ' ' + $ ('arrive-time-hour').value + ':' + $ ('arrive-time-minutes').value;
					
					if ($ ('arrive-time-meridian-am').checked)
					{
						arrival += ' AM';
					}
					else
					{
						arrival += ' PM';
					}
					
					var departure = $ ('depart-date').value + ' ' + $ ('depart-time-hour').value + ':' + $ ('depart-time-minutes').value;
				
					if ($ ('depart-time-meridian-am').checked)
					{
						departure += ' AM';
					}
					else
					{
						departure += ' PM';
					}
				
					params.unset ('offset');
					
					params.set ('type[hourly]', $ ('date-picker-pane-handle').value);
					
					params.set ('arrival', arrival);
					params.set ('departure', departure);
					
					updateResults ();
				}
			}
		);
		
		Calendar.setup
		({
			dateField: 'arrive-date',
			triggerElement: 'arrive-date-handle',
			dateFormat: '%m/%d/%Y'
		});
		
		Calendar.setup
		({
			dateField: 'depart-date',
			triggerElement: 'depart-date-handle',
			dateFormat: '%m/%d/%Y'
		});
	}
}
function toggleDatePickerPageHandle ()
{
	if ($ ('date-picker-pane-handle').checked)
	{
		$ ('date-picker-pane-handle').checked = false;
	}
	else
	{
		$ ('date-picker-pane-handle').checked = true;
	}
}

function onDatePickerHandleClicked ()
{
	if ($ ('date-picker-pane-handle').checked)
	{
		Effect.BlindDown
		(
			 'date-picker-pane',
			 {
				duration: 0.5,
				afterFinish: function ()
				{
					$ ('arrive-date').focus ();
				}
			 }
		 );
	}
	else
	{
		Effect.BlindUp ('date-picker-pane', { duration: 0.5 });
		
		if (params.get ('type[hourly]'))
		{
			params.unset ('arrival');
			params.unset ('departure');
			params.unset ('type[hourly]');
		
			updateResults ();
		}
	}
}

function setupWalkingDistance ()
{
	if ($ ('slider-walking-distance'))
	{
		var initalValues = [minimumDistance, maximumDistance];
		var handles = ['slider-walking-distance-min', 'slider-walking-distance-max'];
		
		var slider = new Control.Slider
		(
			handles,
			'slider-walking-distance',
			{
				range: $R (minimumDistance, maximumDistance),
				values: $R (minimumDistance, maximumDistance),
				sliderValue: initalValues,
				restricted: true
			}
		);
		
		updateDistanceValue (initalValues);
		
		slider.options.onSlide = function (values)
		{
			updateDistanceValue (values);
		};
		
		slider.options.onChange = function (values)
		{
			params.unset ('offset');
			
			params.set ('distanceFrom', values[0]);
			params.set ('distanceTo', values[1]);
			
			updateResults ();
		};
	}
}

function setupPrice ()
{
	if ($ ('slider-price'))
	{
		var initalValues = [minimumPrice, maximumPrice];
		var handles = ['slider-price-min', 'slider-price-max'];
		
		var slider = new Control.Slider
		(
			handles,
			'slider-price',
			{
				range: $R (minimumPrice, maximumPrice),
				values: $R (minimumPrice, maximumPrice),
				sliderValue: initalValues,
				restricted: true
			}
		);
		
		updatepriceValue (initalValues);
		
		slider.options.onSlide = function (values)
		{
			updatepriceValue (values);
		};
		
		slider.options.onChange = function (values)
		{
			params.unset ('offset');
			
			params.set ('priceFrom', values[0]);
			params.set ('priceTo', values[1]);
			
			updateResults ();
		};
	}
}

function setupCovered ()
{
	var covered = $$ ('.covered');
	
	if (covered[0])
	{
		covered = covered[0];
		
		Event.observe 
		(
			covered,
			'click',
			function ()
			{
				params.unset ('offset');
			
				if (covered.checked)
				{
					params.set ('covered', covered.value);
				}
				else
				{
					params.unset ('covered');
				}
				
				updateResults ();
			}
		);
	}
}

function setupType ()
{
	var type = $$ ('.type');
	
	type.each
	(
	 	function (item)
		{
			Event.observe 
			(
				item,
				'click',
				function ()
				{
					if (item.id != 'date-picker-pane-handle')
					{
						params.unset ('offset');
			
						if (item.checked)
						{
							params.set ('type[' + item.id + ']', item.value);
						}
						else
						{
							params.unset ('type[' + item.id + ']');
						}
											
						updateResults ();
					}
				}
			);	
		}
	);
}

function updateDistanceValue (values)
{
	var startValue = values[0];
	var endValue = values[1];
	
	$ ('slider-walking-distance-value').innerHTML = startValue + ' minute' + ((startValue == 1) ? '' : 's') + ' - ' + endValue + ' minute' + ((endValue == 1) ? '' : 's');
}

function updatepriceValue (values)
{
	var startValue = values[0];
	var endValue = values[1];
	
	$ ('slider-price-value').innerHTML = '$' + startValue + ' - ' + '$' + endValue;
}

function setupHints ()
{
	$$ ('td.price').each
	(
		function (cell)
		{
			var childs = Element.childElements (cell);

			var priceHintTrigger;
			var priceHint;

			childs.each
			(
				function (element)
				{
					if (Element.hasClassName (element, 'price-hint-trigger'))
					{
						priceHintTrigger = element;
					}
					else if (Element.hasClassName (element, 'price-hint'))
					{
						priceHint = element;
					}
				}
			);
			
			if (priceHintTrigger && priceHint)
			{
				priceHintTrigger.onclick = function ()
				{
					return false;
				}
				
				Event.observe 
				(
					priceHintTrigger,
					'mouseover',
					function ()
					{
						Element.setStyle
						(
							priceHint,
							{
								visibility: 'visible'
							}
						);
					}
				);
				
				Event.observe 
				(
					priceHintTrigger,
					'mouseout',
					function ()
					{
						Element.setStyle
						(
							priceHint,
							{
								visibility: 'hidden'
							}
						);
					}
				);
				
				Event.observe 
				(
					priceHintTrigger,
					'click',
					function ()
					{
						toggleDatePickerPageHandle ();
						onDatePickerHandleClicked ();
					}
				);
				
				priceHint.style.top = priceHint.offsetTop - Element.getHeight (priceHint) + Element.getHeight (priceHintTrigger) + 'px';
			}
		}
	);
}