Element.extend({
    ancestors: function () {
        var result = [], el = this;
        while (el = el.getTag() !== 'html' ? el.getParent() : false) result.push(el);
        return $$(result);
    }
});

MAX_ZOOM = 5;
function restrictZoom(oldZoom, newZoom) {
	if (newZoom < MAX_ZOOM) {
		this.setZoom(MAX_ZOOM);
		alert('You cannot zoom out any further.');
	}
}

NE_LIMIT = [61, 0];
SW_LIMIT = [50, -10];
function restrictPan() {
	var c = this.getCenter();
	var lat = c.lat();
	var lng = c.lng();
	if (lat > NE_LIMIT[0] || lat < SW_LIMIT[0] || lng > NE_LIMIT[1] || lng < SW_LIMIT[1]) {
		if (lat > NE_LIMIT[0]) lat = NE_LIMIT[0];
		if (lat < SW_LIMIT[0]) lat = SW_LIMIT[0];
		if (lng > NE_LIMIT[1]) lng = NE_LIMIT[1];
		if (lng < SW_LIMIT[1]) lng = SW_LIMIT[1]; 
		this.setCenter(new GLatLng(lat, lng));
	}
}

function initDefaultFieldValue(element, defaultValue) {
	element = $(element);
	if (element == null) return;
	if (element.value == '') {
		element.value = defaultValue;
		element.addClass('defaultValue');
	}
	element.addEvent('focus', function(defaultValue) {
		if (this.value == defaultValue) {
			this.value = '';
			this.removeClass('defaultValue');
		}
	}.bind(element, defaultValue));
	
	var f = updateDefaultFieldValue.bind(element, defaultValue)
	element.addEvent('blur', f);
	f();
}

function updateDefaultFieldValue(defaultValue) {
	if (this.value == '' || this.value.toLowerCase() == defaultValue.toLowerCase()) {
		this.value = defaultValue;
	}
	if (this.value == defaultValue) {
		this.addClass('defaultValue');
	}
}

function convertMonetaryAmount() {
	var value = this.value;
	value = value.replace(/[\s,]/g, '')
	value = value.replace(/^(\d+)k$/i, function() { return arguments[1] * 1000 })
	value = value.replace(/^(\d+.?\d*)m$/i, function() { return arguments[1] * 1000000 })
	this.value = intcomma(value);	
}

function intcomma(value) {
	value = '' + value;
    var newValue = value.replace(/^(\d+)(\d{3})/, '$1,$2');
    if (value == newValue) {
        return newValue
    } else {
        return intcomma(newValue)
    }
}



function updateWheres() {
	var specifiers = [
		'where_specifier_area_radio',
		'where_specifier_list_radio',
		'where_specifier_map_radio'
		].map($);

	specifiers.remove(null);

	var mode = 0;

	specifiers.every(function(element, index) {
		if (element.checked) {
			mode = index;
			return false;
		} else {
			return true;
		}
	});
	
	for (var i = 0; i < specifiers.length; i++) {
		if (i == mode) { 
			$(specifiers[i].parentNode.parentNode.parentNode).addClass('selected');
		} else {
			$(specifiers[i].parentNode.parentNode.parentNode).removeClass('selected');
		}
	}
	
	var inputs = specifiers.map(function(element) {
		return $ES('.inputs', element.parentNode.parentNode);
	});
	
	for (var i = 0; i < inputs.length; i++) {
		for (var j = 0; j < inputs[i].length; j++) {
			if (!inputs[i][j]) continue;
			if (typeof inputs[i][j].fx == 'undefined') {
				if (i == 0 && j == 0) {
					inputs[i][j].fx = new Fx.Style(inputs[i][j], 'opacity', {duration:500});
					inputs[i][j].appear = inputs[i][j].fx.start.bind(inputs[i][j].fx, 1);
					inputs[i][j].disappear = inputs[i][j].fx.start.bind(inputs[i][j].fx, 0);
				} else if (i == 0 && j == 1) {
					inputs[i][j].fx = {hide: function() { this.setStyle('display', 'none'); }.bind(inputs[i][j]) };
					inputs[i][j].appear = function() { this.setStyle('display', ''); }.bind(inputs[i][j]);
					inputs[i][j].disappear = function() { this.setStyle('display', 'none'); }.bind(inputs[i][j]);
					inputs[i][j].setStyle('clear', 'both');
				} else {
					inputs[i][j].fx = new Fx.Slide(inputs[i][j], {
						duration: 500,
						onStart: function() {
							this.addClass('hidden');
						}.bind(inputs[i][j]),
						onComplete: function() {
							if (this.fx.wrapper.offsetHeight != 0 && this.fx.wrapper.offsetWidth != 0) {
								this.removeClass('hidden');
							}
						}.bind(inputs[i][j])
						});
					inputs[i][j].appear = inputs[i][j].fx.slideIn.bind(inputs[i][j].fx);
					inputs[i][j].disappear = inputs[i][j].fx.slideOut.bind(inputs[i][j].fx);
				}
				if (i == 0 && j == 1) {
					//$(inputs[i][j].parentNode).setStyles('clear', 'both');
				}
				if (i != mode) {
					if (i > 0) inputs[i][j].addClass('hidden');
					inputs[i][j].fx.hide();
				}
			} else {
				if (i == mode) {
					inputs[i][j].appear();
				} else {
					inputs[i][j].disappear();
				}
			}
		}
	}

	
}

function updateRentalAreas() {
	var region = $E('#where_specifier_list #field_region select');
	var areas = $E('#where_specifier_list #field_area');
	
	var current_area = region.options[region.selectedIndex].value;
	var new_areas = area_list[current_area];
	areas.empty();
	
	if (typeof new_areas != 'undefined') {
		new_areas.unshift('All areas in ' + current_area);
		
		var select = new Element('select');
		select.id = 'id_area';
		select.name = 'area';
		for (var i = 0; i < new_areas.length; i++) {
			var option = new Element('option');
			option.innerHTML = new_areas[i];
			option.value = (i == 0 ? '' : new_areas[i]);
			option.injectInside(select);
			if (new_areas[i] == initial_area) select.selectedIndex = i;
		}
		initial_area = '';
		select.injectInside(areas); 
			
		$E('#where_specifier_list #field_area').style.display = "block";
	} else {
		$E('#where_specifier_list #field_area').style.display = "none";
	}
	$E('#where_specifier_list .inputs').parentNode.style.height = "auto";
}

function initStylisedLabels(parent) {
	function toggleClass() {
		var labels = this.ancestors().filterByTag('label');
		if (this.checked) {
			this.addClass('checked');
			$ES('label[for=' + this.id + ']', parent).extend(labels).each(function(e) {
				e.addClass('checked');
			}); 
		} else {
			this.removeClass('checked');
			$ES('label[for=' + this.id + ']', parent).extend(labels).each(function(e) {
				e.removeClass('checked');
			});
		}
	}
	
	$ES('input[type=checkbox]', parent).each(function(element) {
		element.addEvent('click', toggleClass);
		toggleClass.bind(element)();
	});
	
	function toggleRadioClass() {
		$$(this.form[this.name]).each(function(el) {
			toggleClass.bind(el)();
		});
	}
	$ES('input[type=radio]', parent).each(function(element) {
		element.addEvent('click', toggleRadioClass);
		toggleRadioClass.bind(element)();
	});
}


initPage = function() {
	var search = $('search');
	if (search && $E('form', search)) {

		// Area groups that are initially shown to the user is settable in the admin. These
		// groups will have a class of initially_shown
		var area_groups = $ES('#where_specifier_list div.search_area_group');
		
		if (area_groups) {
			for (var i = 0; i < area_groups.length; i++) {
				var area_group = area_groups[i];
				if (area_group.hasClass('initially_shown')) {
					continue;
				}
				
				var h3 = $E('h3', area_group);
				h3.appendText(' ');
				var show_hide_link = new Element('a', {'href': '#'}).injectInside(h3);
				var ul = $E('ul', area_group);
				ul.slide = new Fx.Slide(ul);
				// check if we have any checked boxes, if we do, the group needs to be
				// shown by default
				var check_boxes = $ES('input', area_group);
				var something_checked = false;
				if (check_boxes) {
					for (var j = 0; j < check_boxes.length; j++) {
						if (check_boxes[j].checked) {
							something_checked = true;
							break;
						}
					}
				}
				
				if (something_checked) {
					show_hide_link.innerHTML = '(hide)';
				}
				else {
					show_hide_link.innerHTML = '(show)';
					ul.addClass('hide');
					ul.slide.hide();
				}
				
				show_hide_link.addEvent('click', function (e) {
					e = new Event(e);
					$E('#where_specifier_list .inputs').getParent().setStyle('height', 'auto');
					var link = e.target;
					showHideAreas(link);
					e.stop();
				});
			}
			
			function showHideAreas(link) {
				var this_area_group = link.getParent().getParent();
				var ul = $E('ul', this_area_group);
				
				if (ul.hasClass('hide')) {
					// show has been clicked so show the areas
					ul.slide.slideIn();
					link.innerHTML = '(hide)';
					ul.removeClass('hide');
				}
				else {
					// hide has been clicked so hide the areas and 
					// untick the checkboxes
					ul.slide.slideOut();
					var check_boxes = $ES('input', ul);
					for (var i = 0; i < check_boxes.length; i++) {
						var check_box = check_boxes[i]
						check_box.checked = false;
						$(check_box.parentNode).removeClass('checked');
					}
					link.innerHTML = '(show)';
					ul.addClass('hide');
				}
			}
		}

		if ($('id_keywords')) {
			initDefaultFieldValue('id_keywords', 'Separate keywords / phrases with a comma');
		}
	
		if ($('id_min_price')) {
			initDefaultFieldValue('id_min_price', 'Any');
			initDefaultFieldValue('id_max_price', 'Any');
			initDefaultFieldValue('id_location', 'Anywhere');
			[$('id_min_price'), $('id_max_price')].filter(
				function(f) {return f != null}
			).map(
				function (f) {f.addEvent('blur', convertMonetaryAmount)}
			);
			[$('id_min_price'), $('id_max_price')].each(function(element) {
				convertMonetaryAmount.bind(element)();
			});
		}
	
		if (search.hasClass('property_search')) {
			var mapParent = $('where_specifier_map');
			if(mapParent) {
				new MapSearch(mapParent, []);
				$('where_specifier_map_radio').addEvent('click', updateWheres);
			}		
		} else if (search.hasClass('solicitor_search')) {
			initDefaultFieldValue('id_postcode', 'Anywhere');
		}
		
		if ($('where_specifier_area_radio'))
			$('where_specifier_area_radio').addEvent('click', updateWheres);
		if ($('where_specifier_list_radio'))
			$('where_specifier_list_radio').addEvent('click', updateWheres);
		
		var regionSelect = $E('#where_specifier_list #field_region select');
		if (regionSelect) {
			regionSelect.addEvent('change', updateRentalAreas);
			updateRentalAreas();
		}
		
		updateWheres();

	}
	
	if ($('id_reference')) {
		initDefaultFieldValue('id_reference', 'Property ref. number');
	}
	
	// List sorter hover effect
	sorters = $ES('.sorters a').extend($ES('#house_price_search_results thead a'));
	for (var i = 0; i < sorters.length; i++) {
		sorters[i].addEvent('mouseover', function () {
			$(this.parentNode).addClass('light');
			if ($(this.parentNode).hasClass('sorted')) {
				$(this.parentNode).addClass('sorted_light');
			} else if ($(this.parentNode).hasClass('ascending')) {
				$(this.parentNode).addClass('ascending_light');
			}
		});
		sorters[i].addEvent('mouseout', function () {
			$(this.parentNode).removeClass('light');
			$(this.parentNode).removeClass('sorted_light');
		});
	}
	
	$ES('#edit_saved_search_type, #advanced_search_property_type').each(function(element) {
		// For each type in list
		var type_categories = $ES('.type', element);
		for (var i = 0; i < type_categories.length; i++) {
			var type_select = $E('.type_select', type_categories[i]);
			type_select.types = $E('.field_wrapper', type_categories[i]);
			type_select.slide = new Fx.Slide(type_select.types);
			
			// Create "parent" checkbox
			type_select.input = new Element('input', {
				id: type_select.id,
				type: 'checkbox'
			});
			type_select.input.checked = false;
			type_select.input.injectTop(type_select);
			
			// For each input in sub-list
			type_select.inputs = $ES('input', type_select.types);
			for (var j = 0; j < type_select.inputs.length; j++) {
				type_select.inputs[j].type_select = type_select
				
				// Tick parent checkbox depending on if one of it's "child" checkboxes is ticked
				if (type_select.inputs[j].checked) {
					type_select.input.checked = true;
					type_select.addClass('checked');
				}
				
				// Change event that closes the section if all other checkboxes are unticked
				type_select.inputs[j].addEvent('click', function () {
					var checked = false;
					for (var i = 0; i < this.type_select.inputs.length; i++) {
						if (this.type_select.inputs[i].checked) checked = true;
					}
					if (!checked) {
						this.type_select.slide.slideOut();
						this.type_select.input.checked = false;
						this.type_select.removeClass('checked');
					}
				});
			}
			if (!type_select.input.checked) type_select.slide.hide();
			
			type_select.input.addEvent('click', function (e) {
				var type_select = $(this.parentNode);
				type_select.slide.toggle();
				var inputs = $ES('input', type_select.types);
				for (var i = 0; i < inputs.length; i++) {
					if (type_select.slide.open) {
						inputs[i].checked = false;
						inputs[i].parentNode.removeClass('checked');
					} else {
						inputs[i].checked = true;
						inputs[i].parentNode.addClass('checked');
					}
				}
			});
		}
	});

	if ($('advertisements')) {
		var stylesheet = document.styleSheets[0];
		if (stylesheet.addRule) {
			stylesheet.addRule('#gspc', 'margin-left: 0;');
			var gspcCssRule = stylesheet.rules[stylesheet.rules.length-1];
		} else {
			stylesheet = new Element('style').injectInside($E('head'));
			stylesheet = document.styleSheets[document.styleSheets.length-1];
			stylesheet.media.appendMedium('screen');
			stylesheet.media.appendMedium('projection');
			stylesheet.insertRule('#gspc{ margin-left: 0; }', stylesheet.cssRules.length);
			var gspcCssRule = stylesheet.cssRules[stylesheet.cssRules.length-1];
		}
		
		var resizeForAdverts = function() {
			if (document.body.scrollWidth > 775) {
				var d = Math.min(170, document.body.scrollWidth - 775)
				gspcCssRule.style.marginLeft = (-d) + 'px';
				$('advertisements').setStyle('left', (document.body.scrollWidth - d) / 2);
			} else {
				gspcCssRule.style.marginLeft = '0px';
				$('advertisements').setStyle('left', '50%');
			}
		}
		window.addEvent('resize', resizeForAdverts);
		resizeForAdverts();
	}

	// Make all GET forms submit via the fragment, not a query string
	$$('form').each(function(form) {
		if(form.method.toLowerCase() != 'post') {
			form.addEvent('submit', (function(event) {
				event.stop()
				var data = this.toQueryString();
				var qs;
				var w = $('gspc_inner_frame').contentWindow;
				if(w.location.search.indexOf("a=a") != -1)
					qs = '?a=b';
				else
					qs = '?a=a';
				var href = location.protocol + '//' + location.host + location.pathname + qs + '#' + data;
				w.location.href = href;
			}).bindWithEvent(form));
		}
	});


	if ($('property_photos')) {
	
		function showThumbnail(event) {
			event = new Event(event);
			$('main_photo').src = this.href;
			event.stop();
		}
	
		$$('#property_photos a').each(function(element) {
			element.addEvent('click', showThumbnail.bindAsEventListener(element));
		});
	
	}
	
	if ($('search_results_map')) {
		new MapResults('search_results_map');
	}
	
	if ($('valuation_more_info')) {
	
		var radios = $ES('input', 'field_more_information');
		var fx = new Fx.Slide('valuation_more_info');
		
		$($('valuation_more_info').parentNode).setStyle('clear', 'both');
		
		function showHideMoreInformation(fx) {
			if (this.checked) {
				fx.slideIn();
			} else {
				fx.slideOut();
			}
		}
		radios.each(function(radio) {
			$(radio).addEvent('click', showHideMoreInformation.bind(radios[0], fx)); 
		});
		if (!radios[0].checked) {
			fx.hide();
		}
		showHideMoreInformation.bind(radios[0])(fx);
	}
	
	// Find all forms with class "auto_submit" and hide their submit buttons
	// and make them auto-submit when any of their selects are changed. 
	$$('form.auto_submit').each(function(form) {
		$ES('select', form).each(function(select) {
			$(select).addEvent('change', function() {
				this.submit();
			}.bind(form));
		});
		$ES('input[type=submit]', form).each(function(element) {
			$(element).setStyle('display', 'none');
		});
	});
	
	if ($('quick_jump')) {
		var input = $E('input[type=text]', 'quick_jump');
		$('quick_jump').addEvent('submit', function(event) {
			var input = $E('input[type=text]', 'quick_jump');
			input.setStyle('background', '#fff url(' + MEDIA_URL + 'img/checking_reference.gif) no-repeat right');
			var reference = input.value;
			if (reference == '' || reference == 'Property ref. number') {
				alert('Please enter a GSPC reference number');
				new Event(event).stop();
				return;
			}
			var ajax = new Ajax('/property/exists/', {method: 'get', data: $('quick_jump').toQueryString()});
			ajax.addEvent('onSuccess', function(response) {
				input.setStyle('background', '#fff'); 
				var exists = Json.evaluate(response, true);
				if (exists) {
					location.href = $('quick_jump').action + '?' + $('quick_jump').toQueryString();
				} else {
					alert('No live property could be found with reference number "' + reference + '".\n\nPlease check and try again.');
				}
			});
			ajax.request();
			new Event(event).stop();
		});
	}
	

	// REMOVE
	// $ES('#search_results div.result').each(function(result) {
	// 	$ES('li.shortlist input[type=image]', result).each(function(input) {
	// 		var result = this;
	// 		input.addEvent('mouseover', function(result) {
	// 			if (!result.hasClass('shortlisted') && !result.hasClass('updating')) {
	// 				this.src = MEDIA_URL + 'img/add_to_my_shortlist_hover.png';
	// 			}
	// 		}.bind(input, result));
	// 		input.addEvent('mouseout', function(result) {
	// 			if (!result.hasClass('shortlisted') && !result.hasClass('updating')) {
	// 				this.src = MEDIA_URL + 'img/add_to_my_shortlist.png';
	// 			}
	// 		}.bind(input, result));
	// 	}.bind(result));
	// 	
	// 	$ES('li.shortlist a', result).each(function(a) {
	// 		a.addEvent('click', function() {
	// 			$('my_shortlist').addClass('updating');
	// 			setTimeout(function() {
	// 				$('my_shortlist').removeClass('updating');
	// 			}, 2000);
	// 		});
	// 	}.bind(result));
	// });
	// 
	// updateShortlisted();
	// 
	initStylisedLabels();

	// Create maps
	Mercurytide.GoogleMaps.loadIfRequired();
	createInlineMaps();
	
	window.fireEvent('postdomready');

};


function createInlineMaps() {

	// Automatically replace all <div class="googlemap"> elements with real
	// Google Maps. The div must contain a link to Google Maps that contains
	// the latitude/longitude as part of its query string.
	$$('div.googlemap').each(function(element) {
		var href = $E('a', element).href;
		var matches = href.match(/q=([^&]*),([^&]*)/);
		if (matches) {
			var image = $E('img', element);
			var w = image.offsetWidth;
			var h = image.offsetHeight;
			var anchor = image.alt.split(',');
			var x = parseInt(anchor[0]);
			var y = parseInt(anchor[1]);
			var printImage = anchor[2];
			
			element.innerHTML = '<br /><br />Loading map...<br /><img src="' + MEDIA_URL + 'vanilla/img/loading_map_2.gif" alt="" /><br /><a href="' + href + '" target="_blank">View map in a new window</a>';
			element.setStyle('text-align', 'center');
			
			var args = [matches[1], matches[2], image.src, printImage, w, h, x, y];
			
			Mercurytide.GoogleMaps.whenLoaded(function(lat, lng, image, printImage, imageWidth, imageHeight, anchorX, anchorY) {
				var map = new GMap2(this);
				var point = new GLatLng(lat, lng);
        		map.setCenter(point, 15);
        		map.addControl(new GSmallMapControl());
        		map.addControl(new GMapTypeControl());
        		Mercurytide.GoogleMaps.enableScrollWheelZoom(map);
        		map.enableContinuousZoom();
        		
				var icon = new GIcon();
				icon.image = image;
				icon.iconSize = new GSize(imageWidth, imageHeight);
				icon.iconAnchor = new GPoint(anchorX, anchorY);
				icon.printImage = printImage;
				icon.mozPrintImage = printImage;
				
				GEvent.addListener(map, 'zoomend', restrictZoom.bind(map));
				GEvent.addListener(map, 'move', restrictPan.bind(map));
				
        		map.addOverlay(new GMarker(point, {icon: icon, clickable: false}));
        	}.bind(element, args));
		}
	});
}


var Tack = new Class({
	initialize: function(index, point, xRadius, yRadius) {
		this.index = index;
		this.point = point;
		this.xRadius = xRadius || 0.005;
		this.yRadius = yRadius || 0.005;
		
		var icon = new GIcon();
		icon.image = MEDIA_URL + 'img/tack' + ((this.index % 4) + 1) + '.png';
		icon.iconSize = new GSize(31, 38);
		icon.iconAnchor = new GPoint(5, 38);
		icon.shadow = MEDIA_URL + 'img/tack_shadow.png';
		icon.shadowSize = new GSize(31, 38);
		//shadow.iconAnchor = new GPoint(0, 29);
		
		this.marker = new GMarker(this.point, {icon: icon, draggable: true});
		this.tooltip = new TooltipOverlay(new GLatLng(this.point.lat(), this.point.lng()), {
			offsetY: 10,
			text: 'Area Tack ' + (this.index + 1)
		});
		
		this.updateHalo();
	},
	updateTooltip: function() {
		this.point = this.marker.getLatLng();
		this.tooltip.setPoint(this.point);
		this.tooltip.redraw(true);
	},
	updateHalo: function() {
		this.point = this.marker.getLatLng();
		var lat = this.point.lat();
		var lng = this.point.lng();
		var points = [];
		for (var i = 0; i < 360; i += 10) {
			points.push(new GLatLng(
				lat + (this.yRadius * Math.sin(i * Math.PI / 180)),
				lng + (this.xRadius * Math.cos(i * Math.PI / 180))
				));
		}
		points.push(points[0]);
		this.halo = new GPolygon(points, '#8D8C8C', 2, 1, '#ffffff', 0.75);
	},
	toJson: function() {
		return [
			this.point.lat().toFixed(5),
			this.point.lng().toFixed(5),
			this.yRadius.toFixed(5),
			this.xRadius.toFixed(5)
			];
	}
});
Tack.fromJson = function(index, json) {
	return new Tack(index, new GLatLng(parseFloat(json[0]), parseFloat(json[1])), parseFloat(json[3]), parseFloat(json[2]));
}

// The PlaceMarker class is created upon the first call to the constructor. 
var PlaceMarker = function(latlng, options) {

	PlaceMarker = function(latlng, options) {
		this.latlng = latlng;
		this.text = options.text || '';
		GMarker.apply(this, arguments); 
	};
	PlaceMarker.prototype = new GMarker(new GLatLng(0, 0));
	PlaceMarker.prototype.initialize = function(map) {
		GMarker.prototype.initialize.call(this, map);
		this.map = map;
		this.marquee = new Element('div', {
			'styles': {
				'white-space': 'nowrap'
				}
			});
		this.marquee.appendText(this.text);
		this.div = new Element('div', {
			'styles': {
				'font-size': '11px',
				'height': '13px',
				'overflow': 'hidden',
				'position': 'absolute',
				'width': '92px'
				}
			});
		this.marquee.injectInside(this.div);
		map.getPane(G_MAP_MARKER_PANE).appendChild(this.div);
		
		if (this.marquee.offsetWidth > this.div.offsetWidth) {
			this.marqueeDirection = 'left';
			this.timer = setInterval(this.updateMarquee.bind(this), 100);
		}
		
	};
	PlaceMarker.prototype.updateMarquee = function() {
		if (this.marqueeDirection == 'left') {
			var left = this.marquee.getStyle('margin-left').toInt() - 2;
			if (this.marquee.offsetWidth + left <= this.div.offsetWidth) {
				this.marqueeDirection = 'right';
			}
		} else {
			var left = this.marquee.getStyle('margin-left').toInt() + 2;
			if (left >= 0) {
				this.marqueeDirection = 'left';
			}
		}
		this.marquee.setStyle('margin-left', left);
	};
	PlaceMarker.prototype.redraw = function(force) {
		GMarker.prototype.redraw.call(this, force);

		// We only need to do anything if the coordinate system has changed
		if (!force) return;
	
		var p = this.map.fromLatLngToDivPixel(this.latlng);
		var z = GOverlay.getZIndex(this.latlng.lat());
	
		this.div.style.left = (p.x - 42) + "px";
		this.div.style.top = (p.y - 22) + "px";
		this.div.style.zIndex = z + 1; // Directly in front of the marker image
	};
	PlaceMarker.prototype.remove = function() {
		if ($defined(this.timer)) clearInterval(this.timer);
		this.div.parentNode.removeChild(this.div);
		this.div = null;
		this.marquee = null;
		GMarker.prototype.remove.call(this);
	}

	return new PlaceMarker(latlng, options);

}

// The TooltipOverlay class is created upon the first call to the constructor. 
var TooltipOverlay = function(latlng, options) {

	TooltipOverlay = function(latlng, options) {
		this.latlng = latlng;
		this.text = options.text || '';
		this.offsetX = options.offsetX || 0;
		this.offsetY = options.offsetY || 0;
	}
	TooltipOverlay.prototype = new GOverlay();
	TooltipOverlay.prototype.initialize = function(map) {
		this.div = new Element('div', {
			'styles': {
				'background': '#ffc',
				'border': '1px solid #cc9',
				'font-size': '11px',
				'padding': '5px',
				'position': 'absolute',
				'white-space': 'nowrap'
				}
			});
		this.div.innerHTML = this.text;
		map.getPane(G_MAP_MARKER_PANE).appendChild(this.div);
		this.map = map;
	};
	TooltipOverlay.prototype.setPoint = function(latlng) {
		this.latlng = latlng;
	};
	TooltipOverlay.prototype.redraw = function(force) {
		var p = this.map.fromLatLngToDivPixel(this.latlng);
		var left = p.x + this.offsetX - this.div.offsetWidth / 2;
		var top = p.y + this.offsetY;
		
		// Ensure that the tooltip is shown within the map bounds
		var mapBounds = this.map.getBounds();
		var ne = this.map.fromLatLngToDivPixel(mapBounds.getNorthEast());
		var sw = this.map.fromLatLngToDivPixel(mapBounds.getSouthWest());
		if (left < sw.x) {
			left = sw.x;
		} else if (left + this.div.offsetWidth > ne.x) {
			left = ne.x - this.div.offsetWidth;
		}
		if (top + this.div.offsetHeight > sw.y) {
			top = p.y - this.offsetY - this.div.offsetHeight - 35;
		}
	
		this.div.style.left = left + "px";
		this.div.style.top = top + "px";
		this.div.style.zIndex = 99999999;
	};
	TooltipOverlay.prototype.remove = function() {
		this.div.parentNode.removeChild(this.div);
		this.div = null;
	}

	return new TooltipOverlay(latlng, options);

}

var Place = new Class({
	initialize: function(name, lat, lng) {
		this.name = name;
		this.lat = lat;
		this.lng = lng;
	},
	
	getPoint: function() {
		if (!$defined(this.point)) {
			this.point = new GLatLng(this.lat, this.lng);
		}
		return this.point;
	},
	
	getMarker: function() {
		if (!$defined(this.marker)) {
		
			if (PlaceMarker == null) {

			}

			var icon = new GIcon();
			icon.image = MEDIA_URL + 'img/place_marker.png';
			icon.iconSize = new GSize(115, 29);
			icon.iconAnchor = new GPoint(45, 25);

			this.marker = new PlaceMarker(this.getPoint(), {text: this.name, icon: icon});
		}
		return this.marker;
	}
});

var MapSearch = new Class({
	mapLoaded: false,
	initialize: function(parent, places) {
	
		var div = new Element('div', {'class': 'container'});
		div.injectInside(parent);
		
		var field = new Element('div');
		field.className = 'field';
		field.injectInside(div);
		
		if (navigator.userAgent.indexOf('MSIE') != -1) {
			var radio = $(document.createElement('<input type="radio" id="where_specifier_map_radio" name="where_specifier" value="map" />'));
		} else {
			var radio = new Element('input');
			radio.type = 'radio';
			radio.id = 'where_specifier_map_radio';
			radio.name = 'where_specifier';
			radio.value = 'map';
		}
		radio.injectInside(field);
		
		if (selectedWhereSpecifier == 'map') {
			radio.checked = true;
		}
		
		field.appendChild(document.createTextNode(' '));
		
		var label = new Element('label', {
			'for': 'where_specifier_map_radio'
		});
		label.innerHTML = 'Pick on a map&hellip;';
		label.injectInside(field);
		
		var inputs = new Element('div');
		inputs.className = 'inputs';
		inputs.injectInside(div);
		
		this.element = new Element('div');
		this.element.id = 'mapsearch';
		this.element.style.width = '497px';
		this.element.injectInside(inputs);

		this.element.innerHTML = 'Loading map...<br /><img src="' + MEDIA_URL + 'vanilla/img/loading_map_2.gif" alt="" />'
		this.element.setStyles({
			'height': '400px',
			'text-align': 'center'
			});
		
		this.maxTacks = 10;
		this.tacks = [];
		this.tackIndex = 0;
		
		this.places = places;
		
		// Only load the Google Map if required
		if (radio.checked) {
			this.loadMap();
		} else {
			radio.addEvent('click', this.loadMap.bind(this));
		}		

	},
	loadMap: function() {
		if (this.mapLoaded) return;
		this.mapLoaded = true;
		// Wait until the panel has expanded 
		setTimeout(function() {
			Mercurytide.GoogleMaps.whenLoaded(this.initMap.bind(this));
		}.bind(this), 500);
	},
	initMap: function() {
		this.element.innerHTML = '';
		this.element.setStyles({
			'height': 'auto',
			'position': 'relative',
			'text-align': ''
			});
	
		this.tackList = new Element('div');
		this.tackList.id = 'tack_list';
		this.element.appendChild(this.tackList);
		
	
		var w = Math.max(100, this.element.offsetWidth - 237);
	
		this.mapContainer = new Element('div');
		this.mapContainer.setStyles({
			'border': '1px solid #a7a7a7',
			'height': '400px',
			'width': w
			});
		this.element.appendChild(this.mapContainer);
		

	
		this.map = new GMap2(this.mapContainer);
		var p = new GLatLng(MAP_CENTRE_LATITUDE, MAP_CENTRE_LONGITUDE);
        this.map.setCenter(p, 8);
        
        this.map.addControl(new GLargeMapControl());
		Mercurytide.GoogleMaps.enableScrollWheelZoom(this.map);
		this.map.enableContinuousZoom();
        
		this.setHalo();
        this.halo.hide();
        
        GEvent.addListener(this.map, 'mousemove', function(point) {
        	if (this.tacks.length < this.maxTacks) {
	        	this.halo.setLatLng(point);
	        	this.halo.show();
	        } else {
	        	this.halo.hide();
	        }
        }.bind(this));
        
        var hideHalo = this.halo.hide.bind(this.halo);
        var showHalo = this.halo.show.bind(this.halo);
        
        GEvent.addListener(this.map, 'mouseout', hideHalo);
        GEvent.addListener(this.map, 'move', hideHalo);
        GEvent.addListener(this.map, 'zoomend', hideHalo);
        
        GEvent.addListener(this.map, 'drag', showHalo);
       
        GEvent.addListener(this.map, 'click', function(overlay, point) {
        	if (overlay != null) return;

			if (this.tacks.length >= this.maxTacks) {
				alert('Only ' + this.maxTacks + ' area tacks may be selected at once.');
				return;
			}

			// The Earth's curvature means that pixels don't map to lat/lng
			// linearly. We therefore need to calculate two radii, for the x
			// and y axes when drawing the circle using lat/lng.
        	var projection = this.map.getCurrentMapType().getProjection();
        	var zoom = this.map.getZoom();
        	var pixelPoint = projection.fromLatLngToPixel(point, zoom);
        	var northwestPixel = new GPoint(pixelPoint.x - 55, pixelPoint.y - 55);
        	var northwestLatLng = projection.fromPixelToLatLng(northwestPixel, zoom);
        	var xRadius = Math.abs(northwestLatLng.lng() - point.lng());
        	var yRadius = Math.abs(northwestLatLng.lat() - point.lat());
        	
        	var tack = new Tack(this.tackIndex, point, xRadius, yRadius);
        	this.addTack(tack);
        }.bind(this));

		GEvent.addListener(this.map, 'zoomend', restrictZoom.bind(this.map));
		GEvent.addListener(this.map, 'move', restrictPan.bind(this.map));

		var existingMapPointsData = $('id_map_points').value;
		if (existingMapPointsData) {
			var points = Json.evaluate(existingMapPointsData, true);
			if (points.length > 0) {
				for (var i = 0; i < points.length; i++) {
		        	var tack = Tack.fromJson(this.tackIndex, points[i]);
		        	this.addTack(tack);
				}
				// Ensure existing tacks are visible
				var bounds = null;
				for (var i = 0; i < this.tacks.length; i++) {
					if (bounds == null) {
						bounds = this.tacks[i].halo.getBounds();
					} else {
						var tackBounds = this.tacks[i].halo.getBounds();
						bounds.extend(tackBounds.getNorthEast());
						bounds.extend(tackBounds.getSouthWest());
					}
				}
				var zoom = this.map.getBoundsZoomLevel(bounds);
				if (zoom >= MAX_ZOOM) {
					this.map.setCenter(bounds.getCenter(), zoom);
				} else {
					this.map.setCenter(this.tacks[0].point, MAX_ZOOM);
				}
			}
		}
		this.updateTackList();
		
		var ul = new Element('div');
		for (var i = 0; i < this.places.length; i++) {

			var checked = $defined(selectedPopularPlaces[this.places[i].name]);
			if (navigator.userAgent.indexOf('MSIE') != -1) {
				var input = $(document.createElement('<input type="checkbox" id="popular_area_' + i + '" name="map_places" value="' + this.places[i].name + '"' + (checked ? ' checked="checked"' : '') + ' />'));
			} else {
				var input = new Element('input', {
					id: 'popular_area_' + i,
					'type': 'checkbox',
					'name': 'map_places',
					'value': this.places[i].name,
					'checked': checked
				});
			}
			
			if (checked) {
				this.showPlace(this.places[i]);
			}
			
			var label = new Element('label', {'for': 'popular_area_' + i});
			label.appendText(' ' + this.places[i].name);
			
			var li = new Element('li');
			li.appendChild(input);
			li.appendChild(label);

			input.addEvent('click', function(checkbox, place) {
				if (checkbox.checked) {
					this.showPlace(place);
					this.map.panTo(place.getPoint());
				} else {
					this.hidePlace(place);
				}
			}.bind(this, [input, this.places[i]]));
			ul.appendChild(li);
		}
		initStylisedLabels(ul);
		// this.popularPlaces.appendChild(ul);
        
	},
	
	setHalo: function(size) {
		if ($defined(this.halo)) {
			this.map.removeOverlay(this.halo);
		}
	
		size = size || 110;
		
		var icon = new GIcon();
		icon.image = MEDIA_URL + 'img/circle.png';
		icon.iconSize = new GSize(size, size);
		icon.iconAnchor = new GPoint(size/2, size/2);
		this.halo = new GMarker(new GLatLng(0, 0), {
			icon: icon,
			clickable: false,
			draggable: false
			});
        this.map.addOverlay(this.halo);
	},
	
	addTack: function(tack) {
		this.map.addOverlay(tack.marker);
		this.map.addOverlay(tack.halo);
		
		GEvent.addListener(tack.marker, 'mouseover', function(tack) {
			this.map.removeOverlay(tack.tooltip);
			this.map.addOverlay(tack.tooltip);
		}.bind(this, tack));
		GEvent.addListener(tack.marker, 'mouseout', function(tack) {
			this.map.removeOverlay(tack.tooltip);
		}.bind(this, tack));
			
        GEvent.addListener(tack.marker, 'dragstart', function(tack) {
        	this.map.removeOverlay(tack.halo);
        	
        	var projection = this.map.getCurrentMapType().getProjection();
        	var zoom = this.map.getZoom();
        	var point = this.halo.getLatLng();
        	var pixelPoint = projection.fromLatLngToPixel(point, zoom);
			var northwestLatLng = new GLatLng(point.lat() - tack.yRadius, point.lng() - tack.xRadius);
			var northwestPixel = projection.fromLatLngToPixel(northwestLatLng, zoom);
			var radius = Math.abs(northwestPixel.x - pixelPoint.x);
			
        	this.setHalo(radius * 2);
        	
        }.bind(this, tack));
        GEvent.addListener(tack.marker, 'dragend', function(tack) {
        	this.setHalo();
       		tack.updateHalo();
       		tack.updateTooltip();
       		this.map.addOverlay(tack.halo);
        }.bind(this, tack));
        GEvent.addListener(tack.marker, 'drag', function(tack) {
        	tack.updateTooltip();
        }.bind(this, tack));
        
		this.tacks.push(tack);
		this.tackIndex++;
		
		this.updateTackList();
	},
	
	deleteTack: function(tack) {
		this.map.removeOverlay(tack.marker);
		this.map.removeOverlay(tack.halo);
		this.tacks.remove(tack);
		this.updateTackList();
	},
	
	redrawTacks: function() {
		var zoom = this.map.getZoom();
		document.title = [zoom, 1118 / zoom];
		var newTacks = [];
		for (var i = 0; i < this.tacks.length; i++) {
			var icon = new GIcon();
			icon.image = MEDIA_URL + 'img/selected_circle.png';
			var size = 1118 / zoom;
			icon.iconSize = new GSize(size, size)
			icon.iconAnchor = new GPoint(size / 2, size / 2);
			var tack = new GMarker(this.tacks[i].getLatLng(), {icon: icon, draggable: true});
			this.map.removeOverlay(this.tacks[i]);
			this.map.addOverlay(tack);
			newTacks.push(tack);
		}
		this.tacks = newTacks;
	},
	
	updateTackList: function() {
		this.tackList.innerHTML = '<h3>My areas</h3>'; // TODO FIXME -- this could be nicer
		
		if (mapSearchHelp) {
			var helpIcon = new Element('a', {'class': "help", title: 'Help'});
			helpIcon.addEvent('click', (function(event) {
				doc = '<html>'
				    + '<head>'
				    + '<title>Help</title>'
				    + '<link href="' + MEDIA_URL + 'css/vi_core.css" media="screen,projection" rel="stylesheet" type="text/css" />'
				    + '</head>'
				    + '<body style="background: #E7EEF4; padding: 10px;"><div class="cms">'
				    + mapSearchHelp
				    + '<hr /><p>Copyright &copy; ' + new Date().getFullYear() + ' Glasgow Solicitors Property Centre Ltd</p>';
				    + '</div></body></html>';
				var helpWin = window.open('about:blank', 'help', 'width=450,height=400,scrollbars=1,resizable=1');
				helpWin.document.open();
				helpWin.document.write(doc);
				helpWin.document.close();
				event.stop();
			}).bindWithEvent());
			this.tackList.appendChild(helpIcon);
		}
		
		var div = new Element('div');
		this.tackList.appendChild(div);
		
		
		var hiddenValue = [];
		for (var i = 0; i < this.tacks.length; i++) {
			hiddenValue.push(this.tacks[i].toJson()); 
		}
		$('id_map_points').value = Json.toString(hiddenValue);
				
		if (this.tacks.length == 0) {
			var p = new Element('p');
			p.appendText('Click on the map to select zones to search. Zoom in to select more specific areas.');
			div.appendChild(p);
		} else {
			var ul = new Element('ul');
			div.appendChild(ul);
			for (var i = 0; i < this.tacks.length; i++) {
				var li = new Element('li');
				
				var a = new Element('a');
				a.addClass('delete');
				a.href = '#';
				a.title = 'Delete this tack';
				a.addEvent('click', function(event, tack) {
					this.deleteTack(tack);
					event.stop()
				}.bindWithEvent(this, this.tacks[i]));
				li.appendChild(a);
						
				var a = new Element('a');
				a.href = '#';
				a.addEvent('click', function(event, tack) {
					event = new Event(event);
					this.map.panTo(tack.point);
					event.stop();
				}.bindAsEventListener(this, this.tacks[i]));
				a.addEvent('mouseover', function(event, tack) {
					this.map.removeOverlay(tack.tooltip);
					this.map.addOverlay(tack.tooltip);
				}.bindAsEventListener(this, this.tacks[i]));
				a.addEvent('mouseout', function(event, tack) {
					this.map.removeOverlay(tack.tooltip);
				}.bindAsEventListener(this, this.tacks[i]));
				
				img = new Element('img');
				img.src = MEDIA_URL + 'img/tack' + ((this.tacks[i].index % 4) + 1) + '_small.png';
				img.setStyles({'padding-right': '5px', 'vertical-align': 'middle'});
	
				a.appendChild(img);
				a.appendText('Area Tack ' + (this.tacks[i].index + 1));
				li.appendChild(a);
				ul.appendChild(li);
			}
		}
	},
	
	showPlace: function(place) {
		this.map.addOverlay(place.getMarker());
	},

	hidePlace: function(place) {
		this.map.removeOverlay(place.getMarker());
	}
	
});


function simpleInitialize(data) {
	if ($chk(data)) {
		for (key in data) {
			if ($defined(this[key]) && $type(this[key]) != 'function') {
				this[key] = data[key];
			}
		}
	}
}

var Property = new Class({
	title: '',
	postcode: '',
	price: 0,
	offerType: 'Offers over',
	description: '',
	reference: '',
	latitude: 0,
	longitude: 0,
	isNew: false,
	url: '#',
	target: '',
	source: '',
	image: '#',

	initialize: simpleInitialize
});

var Cluster = new Class({
	title: '',
	latitude: 0,
	longitude: 0,
	minLatitude: 0,
	minLongitude: 0,
	maxLatitude: 0,
	maxLongitude: 0,

	initialize: simpleInitialize
});

function getLastRemoteQueryString() {
	var w = $('gspc_inner_frame').contentWindow;
	var hash = w.location.hash || "";
	if(hash.indexOf('#') == 0)
		hash = hash.substr(1);
	return hash;
}

var MapResults = new Class({
	initialize: function(element) {
		this.element = $(element);
		
		this.markers = [];
		
		this.element.innerHTML = 'Loading map...<br /><img src="' + MEDIA_URL + 'vanilla/img/loading_map_2.gif" alt="" />'
		this.element.setStyles({
			height: 235,
			paddingTop: 200,
			position: 'relative',
			textAlign: 'center'
			});
				
		Mercurytide.GoogleMaps.whenLoaded(this.initMap.bind(this));
		
	},
	initMap: function() {
	
		this.element.setStyles({
			clear: 'both',
			height: 435,
			paddingTop: 0,
			textAlign: 'left'
			});
	
		this.initIcons();
		
		this.map = new GMap2(this.element);
		
		this.updatingPane = new Element('div', {
			styles: {
				background: '#fff',
				display: 'block',
				fontWeight: 'bold',
				left: 0,
				height: 235,
				opacity: 0.8,
				paddingTop: 200,
				position: 'absolute',
				textAlign: 'center',
				top: 0,
				width: '100%',
				zIndex: 99999
				}
			});
		this.updatingPane.innerHTML = 'Updating map...<br /><img src="' + MEDIA_URL + 'img/loading_map_2.gif" alt="" />';
		this.updatingPane.injectInside(this.element)
		
        this.refreshPointsListener = GEvent.addListener(this.map, 'moveend', this.refreshPoints.bind(this));

        this.map.addControl(new GLargeMapControl());
		Mercurytide.GoogleMaps.enableScrollWheelZoom(this.map);
		this.map.enableContinuousZoom();
		this.setExtents(function() {
			this.map.savePosition(); // Ensure the reset button works
			
	        var savedPosition = this.getSavedPosition();
	        if (savedPosition) {
	        	this.map.setCenter(new GLatLng(savedPosition.lat, savedPosition.lng), savedPosition.zoom);
	        }
	        
	        this.infoWindowOpen = false;
	        this.showingPropertyInfo = false;
	        
	        GEvent.addListener(this.map, 'zoomend', this.map.clearOverlays);
	        GEvent.addListener(this.map, 'zoomend', restrictZoom.bind(this.map));
	        GEvent.addListener(this.map, 'move', restrictPan.bind(this.map));
	        
	        GEvent.addListener(this.map, 'moveend', this.savePosition.bind(this));
	        
			GEvent.addListener(this.map, 'click', function() {
				if (this.showingPropertyInfo) {
					this.showingPropertyInfo = false;
				} else {
					if (this.infoWindowOpen) {
						this.refreshPoints();
					}
					this.infoWindowOpen = false;
				}
			}.bind(this));
		}.bind(this));
        
	},
	initIcons: function() {
		this.NEW_PROPERTY_ICON = new GIcon();
		this.NEW_PROPERTY_ICON.image = MEDIA_URL + 'img/marker_new_property.png';
		this.NEW_PROPERTY_ICON.iconSize = new GSize(35, 35);
		this.NEW_PROPERTY_ICON.iconAnchor = new GPoint(10, 32);
	
		this.PROPERTY_ICON = new GIcon();
		this.PROPERTY_ICON.image = MEDIA_URL + 'img/marker_property.png';
		this.PROPERTY_ICON.iconSize = new GSize(35, 35);
		this.PROPERTY_ICON.iconAnchor = new GPoint(10, 32);
		
		this.PROPERTIES_ICON = new GIcon();
		this.PROPERTIES_ICON.image = MEDIA_URL + 'img/marker_properties.png';
		this.PROPERTIES_ICON.iconSize = new GSize(35, 35);
		this.PROPERTIES_ICON.iconAnchor = new GPoint(10, 32);

		this.MULTIPLE_PROPERTIES_ICON = new GIcon();
		this.MULTIPLE_PROPERTIES_ICON.image = MEDIA_URL + 'img/marker_multiple_properties.png';
		this.MULTIPLE_PROPERTIES_ICON.iconSize = new GSize(35, 35);
		this.MULTIPLE_PROPERTIES_ICON.iconAnchor = new GPoint(13, 13);
	},
	getSavedPositions: function() {
		var savedPositions = Cookie.get(MAP_COOKIE_KEY);
		if (savedPositions) {
			savedPositions = Json.evaluate(savedPositions, true);
		} else {
			savedPositions = {};
		}
		return savedPositions;
	},
	getSavedPosition: function() {
		return $pick(this.getSavedPositions()[location.search], null);
	},
	savePosition: function() {
		var savedPositions = this.getSavedPositions();
		var mapCenter = this.map.getCenter();
		savedPositions[location.search] = {
			lat: mapCenter.lat(),
			lng: mapCenter.lng(),
			zoom: this.map.getZoom()
			};
		// TODO -- ensure savedPositions can't get too big 
		Cookie.set(MAP_COOKIE_KEY, Json.toString(savedPositions), {
			path: '/'
			});
	},
	setExtents: function(callback) {
		// TODO
		updateMapExtents = (function(json) {
			json = Json.evaluate(json);
			var extents = json;
			
			var total = parseInt(extents.total); 
			if (total == 0) {
				this.map.setCenter(new GLatLng(MAP_CENTRE_LATITUDE, MAP_CENTRE_LONGITUDE), 10);
			} else {
				var top = parseFloat(extents.top);
				var right = parseFloat(extents.right);
				var bottom = parseFloat(extents.bottom);
				var left = parseFloat(extents.left);
		
				var ne = new GLatLng(top, right);
				var sw = new GLatLng(bottom, left);
				var mid = new GLatLng(bottom + (top - bottom) / 2, left + (right - left) / 2);
				
				var bounds = new GLatLngBounds(sw, ne);
				var zoom = this.map.getBoundsZoomLevel(bounds);
				
				this.map.setCenter(mid, zoom);
			}
			callback();
		}).bind(this);
		var qs = getLastRemoteQueryString();
		var advanced = (qs.indexOf("property/advanced/") != -1);
		if(advanced)
			var path = '/vanilla/property/advanced/map/extents/';
		else
			var path = '/vanilla/property/map/extents/';
        new Asset.javascript(BASE_URL + path + '?' + qs);
	},
	
	refreshPoints: function() {

		// Don't refresh if there's an InfoWindow open
		if (!this.map.getInfoWindow().isHidden()) return;

        var bounds = this.map.getBounds();
        
        var ne = bounds.getNorthEast();
        var sw = bounds.getSouthWest();
        var w = sw.lng() - ne.lng();
        var h = sw.lat() - ne.lat();
        
		var qs = getLastRemoteQueryString();
        var ajaxData = qs + '&' + Object.toQueryString({
			'top': ne.lat(),
			'right': ne.lng(),
			'bottom': sw.lat(),
			'left': sw.lng(),
			'_': new Date().getTime()
			}); 
        
		// TODO
		updateMapData = (function(json) {
			json = Json.evaluate(json);
			
			this.map.clearOverlays();
			this.propertiesByPostcode = {};
			
			var visibleCount = 0;
			
			var clusters = json.clusters;
			for (var i = 0; i < clusters.length; i++) {
				var count = parseInt(clusters[i].count)
	        	this.addCluster(new Cluster({
	        		title: '<strong>' + intcomma(count) + ' properties in this area.</strong><br />Click to zoom.',
	        		latitude: clusters[i].latitude,
	        		longitude: clusters[i].longitude,
	        		minLatitude: clusters[i].top,
	        		minLongitude: clusters[i].left,
	        		maxLatitude: clusters[i].bottom,
	        		maxLongitude: clusters[i].right
	        	}));
	        	visibleCount += count;
			}
			var properties = json.properties;
			visibleCount += properties.length;
			for (var i = 0; i < properties.length; i++) {
				var price = properties[i].asking_price;
				this.addProperty(new Property({
	        		title: properties[i].street,
	        		postcode: properties[i].postcode,
	        		latitude: properties[i].latitude, 
	        		longitude: properties[i].longitude,
	        		description: properties[i].description,
	        		image: properties[i].image,
	        		price: (price == '' ? null : parseInt(price)),
	        		reference: properties[i].reference,
	        		isNew: !!parseInt(properties[i].is_new),
	        		target: properties[i].target,
	        		url: properties[i].url,
	        		source: properties[i].source
	        	}));
	        }
	        
			var total = parseInt(json.total);
			$E('#search_results_heading h2').setText(intcomma(total) + ' results (' + intcomma(visibleCount) + ' visible on map)');
	        this.updatingPane.setStyle('display', 'none');
		}).bind(this);
		this.updatingPane.setStyle('display', 'block');
		var advanced = (qs.indexOf("property/advanced/") != -1);
		if(advanced)
			var path = '/vanilla/property/advanced/map/data/';
		else
			var path = '/vanilla/property/map/data/';
        new Asset.javascript(BASE_URL + path + '?' + ajaxData);
	
	},
	addProperty: function(property) {
		
		var postcodeProperties = this.propertiesByPostcode[property.postcode];
		if (postcodeProperties) {
			this.map.removeOverlay(postcodeProperties[postcodeProperties.length - 1].marker);
			postcodeProperties.push(property);
			var icon = this.PROPERTIES_ICON;
			var title = postcodeProperties.length + ' properties at this postcode';
		} else {
			this.propertiesByPostcode[property.postcode] = [property];
			var icon = property.isNew ? this.NEW_PROPERTY_ICON : this.PROPERTY_ICON;
			var title = property.title;
		}
		
		var marker = new GMarker(new GLatLng(property.latitude, property.longitude), {
			icon: icon
		});
		GEvent.addListener(marker, 'click', this.showPropertyInfo.bind(this, property.postcode));
		
		var tooltip = new TooltipOverlay(new GLatLng(property.latitude, property.longitude), {
			offsetY: 10,
			text: '<strong>' + title + '</strong><br />Click for details.'
		});
		GEvent.addListener(marker, 'mouseover', function(tooltip) {
			this.map.addOverlay(tooltip);
		}.bind(this, tooltip));
		GEvent.addListener(marker, 'mouseout', function( tooltip) {
			this.map.removeOverlay(tooltip);
		}.bind(this, tooltip));
		
		property.marker = marker;
		this.map.addOverlay(marker);
	},
	addCluster: function(cluster) {
		var marker = new GMarker(new GLatLng(cluster.latitude, cluster.longitude), {
			icon: this.MULTIPLE_PROPERTIES_ICON
		});
		var tooltip = new TooltipOverlay(new GLatLng(cluster.latitude, cluster.longitude), {
			offsetY: 20,
			text: cluster.title
		});
		var sw = new GLatLng(cluster.minLatitude, cluster.minLongitude); 
		var ne = new GLatLng(cluster.maxLatitude, cluster.maxLongitude);  
		var points = [
			sw,
			new GLatLng(cluster.minLatitude, cluster.maxLongitude),
			ne,
			new GLatLng(cluster.maxLatitude, cluster.minLongitude)
			];
		points.push(points[0]);
		var polygon = new GPolyline(points);
		var bounds = new GLatLngBounds(sw, ne);
		GEvent.addListener(marker, 'mouseover', function(polygon, tooltip) {
			this.map.addOverlay(tooltip);
			this.map.addOverlay(polygon);
		}.bind(this, [polygon, tooltip]));
		GEvent.addListener(marker, 'mouseout', function(polygon, tooltip) {
			this.map.removeOverlay(tooltip);
			this.map.removeOverlay(polygon);
		}.bind(this, [polygon, tooltip]));
		GEvent.addListener(marker, 'click', function(marker, bounds) {
			this.map.removeOverlay(tooltip);
			this.map.removeOverlay(polygon);
			var zoom = this.map.getBoundsZoomLevel(bounds);
			this.map.setCenter(marker.getLatLng(), zoom);
		}.bind(this, [marker, bounds])); 
		this.map.addOverlay(marker);
	},
	showPropertyInfo: function(postcode) {

		this.showingPropertyInfo = true;

		var tabs = [];

		for (var i = 0; i < this.propertiesByPostcode[postcode].length; i++) {
			var property = this.propertiesByPostcode[postcode][i];

			var div = new Element('div', {'class': 'map_window'});
			div.setStyles({
				'float': 'left',
				paddingBottom: '10px',
				width: '310px'
				});
			var info = new Element('div', {'class': 'info', 'styles': {
				'float': 'left',
				'width': '120px'
			}});
			info.injectInside(div);
			
			var image_a = new Element('a', {href: property.url, target: property.target});
			image_a.injectInside(info);
			
			if (property.image != '') {
				var image = new Element('img', {'src': property.image, 'width': 120, 'height': 90});
			} else {
				var image = new Element('img', {'src': MEDIA_URL + 'img/no_image_small.png', 'width': 120, 'height': 90});
			}
			image.injectInside(image_a);
			
			var priceInfo = new Element('div', {'class': 'price_info'});
			priceInfo.injectInside(info);
			
			var offerType = new Element('div', {'class': 'offer_type'});
			offerType.injectInside(priceInfo);
			offerType.innerHTML = property.offerType;

			var price = new Element('div', {'class': 'price'});
			price.injectInside(priceInfo);
			price.innerHTML = '&pound;' + intcomma(property.price);
			
			var reference = new Element('div', {'class': 'reference'});
			reference.injectInside(info);
			reference.innerHTML = 'Ref: ' + property.reference;
			
			var details = new Element('div', {'class': 'details', 'styles': {
				fontSize: '90%', 
				marginLeft: '135px'
			}});
			details.injectInside(div);
			
			var h3 = new Element('h3');
			h3.injectInside(details);
			
			var a = new Element('a', {href: property.url, target: property.target});
			a.injectInside(h3);
			a.innerHTML = property.title;
			
			var p = new Element('p', {styles: {
				margin: '1em 0'
			}});
			p.injectInside(details);
			p.innerHTML = property.description;
			
			var viewDetails = new Element('div', {'class': 'view_details'});
			viewDetails.injectInside(details);
			a = new Element('a', {href: property.url, target: property.target, styles:{
				display: 'block',
				lineHeight: '20px',
				padding: '0 8px'
			}});
			a.injectInside(viewDetails);
			a.innerHTML = 'View property details';
			
			tabs.push(new GInfoWindowTab('Property ' + (tabs.length + 1), div));
			
			var latLng = new GLatLng(property.latitude, property.longitude);
		
		}

		if (tabs.length == 1) {				
			this.map.openInfoWindow(latLng, div, {maxWidth: 300});
		} else {
			this.map.openInfoWindowTabs(latLng, tabs, {maxWidth: 300});
		}
		
		this.infoWindowOpen = true;
		
		GEvent.addListener(this.map, 'closeclick', function() {
			this.infoWindowOpen = false;
		}.bind(this));
		
	}
	
});

