/*
Classes for handling google maps throughout the public site.
Requires:
	Mootools 1.1 core
	GoogleMapsAPI
	Mercurytide.Google

For clustering version it requires:
	ClusterMarker 1.3.2

BaseGoogleMap should be subclassed for required usage, overriding the get_marker_list
method allows you define alternative marker sources.

*/
var SGFIcons = {};
/*Define the icon types here*/
Mercurytide.GoogleMaps.whenLoaded(function(){
	SFGIcons = {
		newsIcon: new GIcon({image:'/media/img/icons/news_map.png',
					iconSize: new GSize(48, 29),
					iconAnchor: new GPoint(20, 29),
					infoWindowAnchor: new GPoint(20, 29),
					infoShadowAnchor: new GPoint(18, 25)}
					),
		eventIcon: new GIcon({image:'/media/img/icons/event_map.png',
					iconSize: new GSize(48, 29),
					iconAnchor: new GPoint(20, 29),
					infoWindowAnchor: new GPoint(20, 29),
					infoShadowAnchor: new GPoint(18, 25)}
					),
		multiCommunityIcon : new GIcon({image:'/media/img/icons/multiple_communities_icon_balloon.png',
					shadow: 'media/img/icons/multiple_communities_icon_shadow.png',
					iconSize: new GSize(58, 43),
					shadowSize: new GSize(58, 43),
					iconAnchor: new GPoint(13, 42),
					infoWindowAnchor: new GPoint(20, 29),
					infoShadowAnchor: new GPoint(18, 25)}
					),
		communityIcon : new GIcon({image:'/media/img/icons/community_icon_balloon.png',
					shadow:'/media/img/icons/community_icon_shadow.png',
					iconSize: new GSize(31, 24),
					shadowSize: new GSize(31, 24),
					iconAnchor: new GPoint(7, 23),
					infoWindowAnchor: new GPoint(20, 29),
					infoShadowAnchor: new GPoint(18, 25)}
					),
		POIIcon : new GIcon({image:'/media/img/icons/poi_small_icon.png',
					shadow:'/media/img/icons/POI_business_small_shadow.png',
					iconSize: new GSize(37, 23),
					shadowSize: new GSize(37, 23),
					iconAnchor: new GPoint(24, 22),
					infoWindowAnchor: new GPoint(23, 8),
					infoShadowAnchor: new GPoint(23, 8)}
					),
		POISelectedIcon : new GIcon({image:'/media/img/icons/poi_large_icon.png',
					shadow:'/media/img/icons/POI_business_large_shadow.png',
					iconSize: new GSize(44, 33),
					shadowSize: new GSize(44, 33),
					iconAnchor: new GPoint(27, 30),
					infoWindowAnchor: new GPoint(25, 11),
					infoShadowAnchor: new GPoint(25, 11)}
					),
		BusinessIcon : new GIcon({image:'/media/img/icons/business_small_icon.png',
					shadow:'/media/img/icons/POI_business_small_shadow.png',
					iconSize: new GSize(37, 23),
					shadowSize: new GSize(37, 23),
					iconAnchor: new GPoint(24, 22),
					infoWindowAnchor: new GPoint(23, 8),
					infoShadowAnchor: new GPoint(23, 8)}
					),
		BusinessSelectedIcon : new GIcon({image:'/media/img/icons/business_large_icon.png',
					shadow:'/media/img/icons/POI_business_large_shadow.png',
					iconSize: new GSize(44, 33),
					shadowSize: new GSize(44, 33),
					iconAnchor: new GPoint(27, 30),
					infoWindowAnchor: new GPoint(25, 11),
					infoShadowAnchor: new GPoint(25, 11)}
					),
		RouteIcon : new GIcon({image:'/media/img/icons/route_small_icon.png',
					shadow:'/media/img/icons/route_small_shadow_icon.png',
					iconSize: new GSize(66, 25),
					shadowSize: new GSize(66, 25),
					iconAnchor: new GPoint(38, 23),
					infoWindowAnchor: new GPoint(38, 7),
					infoShadowAnchor: new GPoint(38, 23)}
					),
		RouteSelectedIcon : new GIcon({image:'/media/img/icons/route_large_icon.png',
					shadow:'/media/img/icons/route_large_shadow.png',
					iconSize: new GSize(110, 41),
					shadowSize: new GSize(110, 41),
					iconAnchor: new GPoint(64, 40),
					infoWindowAnchor: new GPoint(64, 13),
					infoShadowAnchor: new GPoint(64, 40)}
					)
	};
});

/*Define the  google control styles here, they augment the built in default_style method */
var GoogleControlStyles = {
	Business: {
		'background':'#1B468A url(/media/img/icons/button_add_business.png) center right no-repeat',
		'color':'#fff',
		'font-weight': 'bold',
		'padding': '2px 25px 2px 5px'
	},
	Poi: {
		'background':'#0D812E url(/media/img/icons/button_add_poi.png) center right no-repeat',
		'color':'#fff',
		'font-weight':'bold',
		'padding': '2px 25px 2px 5px'
	},
	Clear: {
		'background':'#A60004 url(/media/img/icons/button_clear.png) center right repeat-x',
		'color': '#fff',
		'font-weight': 'bold',
		'width': '60px'
	},
	Edit: {
		'background':'#BB730D url(/media/img/icons/button_edit.png) center right repeat-x',
		'color': '#fff',
		'font-weight': 'bold',
		'width': '60px'
	},
	Search: {
		'background':'#426463 url(/media/img/icons/button_search.png) center right repeat-x',
		'color': '#fff',
		'font-weight': 'bold',
		'width': '60px'
	},
	SearchBusinessInput: {
		'border': '1px solid #1B468A',
		'color': '#1B468A'
	},
	SearchPoiInput: {
		'border': '1px solid #0D812E',
		'color': '#0D812E'
	},
	SearchInput: {
		'border': '1px solid black'
	}
};

var APIUrls = {
	'communities': '/api/communities/',
	'listings_search': '/routes/api/api_listings_in_area/',
	'listing_lookup': '/routes/api/api_currently_selected_listings/',
	'poi_search': '/routes/api/api_pois_in_area/',
	'edit_poi_lookup': '/routes/api/edit_currently_selected_pois/',
	'display_poi_lookup': '/routes/api/display_currently_selected_pois/'
};

/* Classes for allowing the specification of GMap controls for inclusion in GMap instances */
var GenericGoogleControl = new Class({
	initialize: function(map, opts) {
		this.map = map;
		this.children = new Hash();
		this.discardable_overlays = [];
		this.permanent_overlays = [];
		this.overlays_to_store = {};
		this.container =  null;
		this.position = [G_ANCHOR_TOP_RIGHT, new GSize(7, 7)];
		$extend(this, opts); /*Extend the contoller with the attributes we assign in on init*/
		this.attach_container_if_needed();
		this.build_control();
		this.enabled = false;

		/*Listen for activity from other controls and hide our junk when it happens*/
		GEvent.addListener(this.map, 'hideControlElements', function(){
			this.reset();
		}.bind(this));
	},

	reset: function(){
		/* Clear any child elements */
		this.children.each(function(v){
			this.map.removeControl(v);
		}.bind(this));
		this.discardable_overlays.each(function(v){
			this.map.removeOverlay(v)
		}.bind(this));
	},

	click: function(){
		/*Trigger the map hide element event, then do what we want*/
		GEvent.trigger(this.map, 'hideControlElements');
	},
	enable: function(){
		this.enabled = true;
	},
	disable: function(){
		this.enabled = false;
	},
	attach_container_if_needed: function(){
		/* If we're provided a container, spit in that otherwise create on and adopt it for our needs*/
		if(!this.container){
			this.container = new Element('div', {'id':'control_generated'});
			this.map.getContainer().adopt(this.container);
		}
	},

	additional_style: function(elem, name){
		elem.setStyles(GoogleControlStyles[name]);
	},

	default_style: function(elem){
		elem.setStyles({
			'background':'#fff',
			'text-decoration':'none',
			'color':'#0000cc',
			'font-family':'Arial',
			'font-size':'11px',
			'padding':'2px',
			'margin-left':'3px',
			'margin-bottom':'3px',
			'text-align':'center',
			'width':'auto',
			'cursor':'pointer',
			'float':'left'
		});
	},

	get_control: function() {
		this.control = new this._control();
		return this.control;
	}
});

/* MarkerLookupControl extends GenericGoogleControl to add the ability to show a search box that performs an ajax search for points to
  be plotted on the map */
var MarkerLookupControl = GenericGoogleControl.extend({
	initialize: function(map, opts){
		this.url = APIUrls.listings_search;
		this.init_url = APIUrls.listing_lookup;
		this.callback = function(marker_points){alert(marker_points);};
		this.parent(map, opts);
	},

	data_init: function(){
		var currently_selected = Json.evaluate(this.saveInput.value);
		if(currently_selected){
			this.overlays_to_store = currently_selected;
			var marker_list = [];
			var marker_points = new Json.Remote(this.init_url, {onComplete: function(data){
				data.each(function(e, i){
					if(this.overlayIcon){
						e.icon = SFGIcons[this.selectedOverlayIcon];
					}else{
						e.icon = SFGIcons.newsIcon;
					}
					marker_list[marker_list.length] = e;
				}.bind(this));
				this.reset();
				plot_points(marker_list);
			}.bind(this)}).send({'ids':this.saveInput.value});

			var plot_points = function(marker_list){
				marker_list.each(function(e, i){
					if(e['latitude'] && e['longitude']){
						var point = new GLatLng(e['latitude'], e['longitude']);
						var marker = new GMarker(point, {icon: e['icon']});
						var marker_text = this.marker_text_formatter(e);
						this.create_selection_balloon(marker, marker_text);
						if(e['type'] && e['id']){
							marker._scf_type = e['type'];
							marker._scf_id = e['id'];
						}
						this.map.addOverlay(marker);
						this.permanent_overlays[this.permanent_overlays.length] = marker;
						this.add_marker_listener(marker);
					}
				}.bind(this));
			}.bind(this);
		}
	},

	build_control: function(){
		this._control = function(){};
		this._control.prototype = new GControl();
		this._control.prototype.initialize = function(map){
			var control_item = new Element('div');
			control_item.setText(this.task_name);
			this.default_style(control_item);
			if(this.googleControlStyle) this.additional_style(control_item, this.googleControlStyle);
			this.container.adopt(control_item);
			GEvent.addDomListener(control_item, 'click', function(e){
				var event = new Event(e);
				event.stop();
				this.click();
				if(this.enabled){
					this.create_search();
				}else{
					alert('You must draw your route before adding map markers');
				}
			}.bind(this));
			return this.container;
		}.bind(this);
		this._control.prototype.getDefaultPosition = function() {
			return new GControlPosition(this.position[0], this.position[1]);
		}.bind(this);
	},

	encode_to_input: function(){
		if(this.overlays_to_store){
			this.saveInput.value = Json.toString(this.overlays_to_store);
		}
	},

	create_selection_balloon: function(marker, text){
		marker._scf_text = text;
		marker.text = new Element('div');
		marker.text.adopt(new Element('div').setStyles({'font-size':'90%','text-align':'center','display':'block','width':'200px'}).adopt(text));
		if(marker.getIcon() == SFGIcons['POIIcon'] || marker.getIcon() == SFGIcons['POISelectedIcon']){
			var button_name = "point of interest";
			var styles = "clear:both;margin-top:5px;padding:2px 20px 2px 2px;color:#fff;font-weight:bold;font-size:12px;border:0;background:#0D812E url(/media/img/icons/button_add_poi.png) repeat-x right top;"
		}else if(marker.getIcon() == SFGIcons['BusinessIcon'] || marker.getIcon() == SFGIcons['BusinessSelectedIcon']){
			var button_name = "business";
			var styles = "clear:both;margin-top:5px;padding:2px 20px 2px 2px;color:#fff;font-weight:bold;font-size:12px;border:0;background:#1B468A url(/media/img/icons/button_add_business.png) repeat-x right top;"
		}
		if(marker.getIcon() == SFGIcons[this.selectedOverlayIcon]){
			var input_opts = {'type':'button', 'name':'Remove this ' + button_name, 'value':'Remove this ' + button_name, 'style':styles};
		}else{
			var input_opts = {'type':'button', 'name':'Add this ' + button_name, 'value':'Add this ' + button_name, 'style':styles};
		}
		marker.text.adopt(new Element('br'), {'style':'clear:both;'});
		marker.text.adopt(new Element('input', input_opts).addEvent('click', function(e){
			GEvent.trigger(this, 'is_selected');
		}.bindWithEvent(marker)));
		marker.text.adopt(new Element('br'), {'style':'clear:both;'});
	},

	replicate_marker: function(marker, icon){
		/*Allows us to swap markers for selected versions (google doesn't really support icon swapping) */
		var point = marker.getLatLng();
		var new_marker = new GMarker(point, {icon: icon});
		this.create_selection_balloon(new_marker, marker._scf_text);
		new_marker._scf_id = marker._scf_id;
		new_marker._scf_type = marker._scf_type;
		return new_marker;
	},

	add_marker_listener: function(marker){
		/*Add click events to the marker to either add it or remove it from our "wanted" list */
		GEvent.addListener(marker, 'mouseover', function(m){
			if(this.enabled) m.openInfoWindow(m.text);
		}.bind(this, marker));
		GEvent.addListener(marker, 'is_selected', function(m){
			if(this.discardable_overlays.contains(m)){
				this.overlays_to_store[m._scf_id] = m._scf_id;
				this.discardable_overlays.remove(m);
				if(this.selectedOverlayIcon){
					var icon = SFGIcons[this.selectedOverlayIcon];
				}else{
					var icon = SFGIcons.newsIcon;
				}
				var new_marker = this.replicate_marker(m, icon);
				this.add_marker_listener(new_marker);
				this.map.removeOverlay(m);
				this.map.addOverlay(new_marker);
				this.permanent_overlays[this.permanent_overlays.length] = new_marker;
				this.encode_to_input();
			}else{
				delete this.overlays_to_store[m._scf_id];
				this.permanent_overlays.remove(m);
				if(this.overlayIcon){
					var icon = SFGIcons[this.overlayIcon];
				}else{
					var icon = SFGIcons.newsIcon;
				}
				var new_marker = this.replicate_marker(m, icon);
				this.add_marker_listener(new_marker);
				this.map.removeOverlay(m);
				this.map.addOverlay(new_marker);
				this.discardable_overlays[this.discardable_overlays.length] = new_marker;
				this.encode_to_input();
			}
		}.bind(this, marker));
	},

	marker_text_formatter: function(e){
		var marker_text = new Element('div').setHTML('<strong>' + e['name'] + '</strong>' + '<br />' + '<p style="text-align:left">'+ e['text'] + '</p>');
		if(e['images']){
			for(var j=0; j<e['images'].length && j<5; j++){
				var link = new Element('a', {'style':'border:1px solid #ababab;display:block;float:left;', 'rel':'lightbox', 'title':e['images'][j]['medium'][1], 'href':e['images'][j]['medium'][0] }).adopt(new Element('img', {'src': e['images'][j]['thumbnail'][0], 'style':'margin: 5px 5px 5px 0;'}));
				link.slimbox({
					overlayOpacity: 0.6,
					overlayFadeDuration: 200,
					resizeDuration: 200,
					resizeTransition: Fx.Transitions.Elastic.easeOut,
					previousKeys: [37, 80, 16],
					nextKeys: [39, 78, 17]
				});
				marker_text.adopt(link);
			}
		}
		return marker_text;
	},

	create_search: function(){
		var Search = function(){};
		Search.prototype = new GControl();
		Search.prototype.initialize = function(map){
			if(!this.searchContainer){
				var container = new Element('div');
				this.map.getContainer().adopt(container);
			}else{
				var container = this.searchContainer;
			}
			var search_submit = new Element('div');
			search_submit.setText('Search');
			this.default_style(search_submit);
			this.additional_style(search_submit, 'Search');
			var perform_search = function(){
				marker_list = [];
				search_submit.setText('');
				search_submit.setStyles({
					'background':'url(/media/img/icons/search_loader.gif) no-repeat center top',
					'height':'20px'
				});
				if(search_input.value == this.googleSearchControlText) search_input.value = '';

				var marker_points = new Json.Remote(this.url, {onComplete: function(data){
					data.each(function(e, i){
						if(e.warning || e.error){
							if(e.warning) alert(e.warning);
							if(e.error) alert(e.error);
						}else{
							if(this.overlayIcon){
								e.icon = SFGIcons[this.overlayIcon];
							}else{
								e.icon = SFGIcons.newsIcon;
							}
							marker_list[marker_list.length] = e;
						}
					}.bind(this));
					this.reset();
					plot_points(marker_list);
				}.bind(this)}).send({'q':search_input.value, 'exclude':this.overlays_to_store});
			}.bind(this);

			var plot_points = function(marker_list){
				marker_list.each(function(e, i){
					if(e['latitude'] && e['longitude']){
						var point = new GLatLng(e['latitude'], e['longitude']);
						var marker = new GMarker(point, {icon: e['icon']});
						var marker_text = this.marker_text_formatter(e);
						this.create_selection_balloon(marker, marker_text);
						if(e['type'] && e['id']){
							marker._scf_type = e['type'];
							marker._scf_id = e['id'];
						}
						this.map.addOverlay(marker);
						this.discardable_overlays[this.discardable_overlays.length] = marker;
						this.add_marker_listener(marker);
					}
				}.bind(this));
			}.bind(this);

			var search_input = new Element('input', {'type':'text', 'value': this.googleSearchControlText});
			search_input.addEvent('focus', function(){
				this.value = '';
			}.bind(search_input));

			this.default_style(search_input);
			if(this.googleSearchControlStyle){
				this.additional_style(search_input, this.googleSearchControlStyle);
			}else{
				this.additional_style(search_input, 'SearchInput');
			}
			search_input.setStyles({'text-align':'left', 'width':'15em', 'text-decoration':'none'});
			search_input.addEvent('keydown', function(event) {
				if (event.key == 'enter') {
					perform_search();
					event.preventDefault();
					event.stopPropagation();
				}
			}.bindWithEvent(this));
			container.adopt(search_input);
			container.adopt(search_submit);
			GEvent.addDomListener(search_submit, 'click', perform_search);
			return container;
		}.bind(this);

		Search.prototype.getDefaultPosition = function() {
			return new GControlPosition(this.position[0], new GSize(this.position[1].width, 49));
		}.bind(this);

		var SearchControl = new Search();
		this.children.set('search_control', SearchControl);
		this.map.addControl(SearchControl);
	}
});

var PickListingsControl = MarkerLookupControl.extend({
	initialize: function(map, opts){
		this.parent(map, opts);
		this.url = APIUrls.listings_search;
		this.init_url = APIUrls.listing_lookup;
		this.callback = null;
		this.data_init();
	}
});

var PickPOIControl = MarkerLookupControl.extend({
	initialize: function(map, opts){
		this.parent(map, opts);
		this.url = APIUrls.poi_search;
		this.init_url = APIUrls.edit_poi_lookup;
		this.callback = null;
		this.data_init();
	}
});

var PerformMapTaskControl = GenericGoogleControl.extend({
	initialize: function(map, opts){
		this.task_name = '<TASK NAME>';
		this.task_func = function(){alert('<TASK FUNC>');}
		this.parent(map, opts);
		this.enabled = true;
	},
	build_control: function(){
		this._control = function(){};
		this._control.prototype = new GControl();

		this._control.prototype.initialize = function(map){
			var control_item = new Element('div');
			control_item.setText(this.task_name);
			this.default_style(control_item);
			if(this.googleControlStyle) this.additional_style(control_item, this.googleControlStyle);
			this.container.adopt(control_item);
			GEvent.addDomListener(control_item, 'click', function(){
				this.click();
				this.task_func();
			}.bind(this));
			return this.container;
		}.bind(this);

		this._control.prototype.getDefaultPosition = function() {
			return new GControlPosition(this.position[0], this.position[1]);
		}.bind(this);
	}
});

/*Display loading images before loading the maps*/
var ShowMapLoading = new Class({
	initialize: function(containers){
		containers = $A(containers);
		containers.each(function(e){
			e.setStyles({'display':'block', 'text-align':'center', 'background':'#E7E6E6'});
			e.innerHTML = "<p>Map Loading..</p><img src='" + MEDIA_URL + "img/icons/map_loader.gif' alt='Map Loading...' style='margin: 15px auto' />";
		});
	}
});

/*The most basic GoogleMapConfiguration */
var BaseGoogleMap = new Class({
	elem: null,
	map: null,
	initialize: function(container, height, marker_list, opts) {
		if(typeof(marker_list) == 'undefined') marker_list = [];
		if(typeof(opts) == 'undefined') opts = {};
		$extend(this, opts);
		this.marker_list = marker_list;
		this.elem = container;
		this.elem.empty();
		this.elem.setStyles({'visibility':'visible', 'display':'block', 'height': height, 'overflow':'hidden'});
		this.init_map();
		this.plot_points(this.get_marker_list());
	},

	init_map: function(){
		if (GBrowserIsCompatible()) {
			this.map = new GMap2(this.elem);
			this.map.addControl(new GSmallMapControl());
			this.map.setCenter(new GLatLng(56.2752, -3.1244), 11);
		}
	},

	get_marker_list: function(){
		return this.marker_list;
	},

	plot_points: function(marker_list) {
		var bounds = new GLatLngBounds();
		marker_list.each(function(e, i){
			var point = new GLatLng(e['latitude'], e['longitude']);
			bounds.extend(point);
			var marker = new GMarker(point, {icon: e['icon']});
			if (e['url'] != null) {
				marker.text = new Element('a', {'href':e['url']}).setHTML(e['text']);
			} else {
				marker.text = e['text']
			}
			GEvent.addListener(marker, "click", function() {
				this.openInfoWindow(this.text);
			});
			this.map.addOverlay(marker)
		}.bind(this));

		if (!bounds.isEmpty()) {
			this.map.setCenter(bounds.getCenter(), Math.min(15, this.map.getBoundsZoomLevel(bounds)));
		}
	}
});

/*A map that handles the homepage News and Events plotting*/
var EventsNewsGoogleMap = BaseGoogleMap.extend({
	get_marker_list: function(){
		var events = [];
		$$('.vevent').each(function(e) {
			events[events.length] = this.import_data(e, {
				'icon':SFGIcons.eventIcon
			});
		}.bind(this));

		$$('.vnews').each(function(e) {
			events[events.length] = this.import_data(e, {
				'icon':SFGIcons.newsIcon
			});
		}.bind(this));
		var non_empties = [];
		for(var i = 0; i < events.length; ++i){
			if(events[i].latitude && events[i].longitude){
				non_empties[non_empties.length] = events[i];
			}
		}
		return non_empties;
	},

	import_data: function(e, obj){
		obj.text = null;
		obj.longitude = null;
		obj.latitude = null;
		obj.url = null;
		if(e.getElementsBySelector('.summary')[0] && e.getElementsBySelector('.dtstart')[0]) obj.text = e.getElementsBySelector('.summary')[0].getText() + "<br />" + e.getElementsBySelector('.dtstart')[0].getText();
		if(e.getElementsBySelector('.geo .latitude')[0]) obj.latitude = parseFloat(e.getElementsBySelector('.geo .latitude')[0].getText());
		if(e.getElementsBySelector('.geo .longitude')[0]) obj.longitude = parseFloat(e.getElementsBySelector('.geo .longitude')[0].getText());
		if(e.getElementsBySelector('.url')[0]) obj.url = e.getElementsBySelector('.url')[0].href;

		return obj;
	}
});

/*A clustering Google Map*/
var ClusteringGoogleMap = BaseGoogleMap.extend({
	clusterer: null,
	get_marker_list: function(){
		if(this.marker_list.length){
			return this.cluster_marker_list(this.marker_list);
		}else{
			return this.cluster_marker_list(this.get_clusterable_marker_list());
		}
	},

	get_clusterable_marker_list: function(){
		return [];
	},

	cluster_marker_list: function(marker_list){
		var bounds = new GLatLngBounds();
		var cluster_markers = [];
		marker_list.each(function(e, i){
			var point = new GLatLng(e['latitude'], e['longitude']);
			bounds.extend(point);
			var marker = new GMarker(point, {icon: e['icon']});
			if (e['url'] != null) {
				marker.text = new Element('a', {'href':e['url']}).setHTML(e['text']);
			} else {
				marker.text = new Element('a', {'href':'#'}).setHTML(e['text']);
			}
			GEvent.addListener(marker, 'click', function(){window.location=marker.text.href});
			cluster_markers[i] = marker;
		}.bind(this));

		if (!bounds.isEmpty()) {
			this.map.setCenter(bounds.getCenter(), Math.min(15, this.map.getBoundsZoomLevel(bounds)));
		}
		return cluster_markers;
	},

	plot_points: function(cluster_marker_list){
		 this.clusterer = new ClusterMarker(this.map, {clusterMarkerIcon: SFGIcons.newsIcon});
		 this.clusterer.addMarkers(cluster_marker_list);
	}
});

/*The Main communities map*/
var CommunityGoogleMap = ClusteringGoogleMap.extend({
	hideTimer: null,
	get_marker_list: function(){
		var marker_points = new Json.Remote(APIUrls.communities, {onComplete: function(data){
			data.each(function(e){
			   e.icon = SFGIcons.communityIcon;
			});
			cluster_marker_list = this.cluster_marker_list(data);
			this.clusterer = new ClusterMarker(this.map, {clusterMarkerIcon: SFGIcons.multiCommunityIcon});
			this.clusterer.clusterMarkerTitle = '';
			this.clusterer.addMarkers(cluster_marker_list);
			this.clusterer.fitMapToMarkers();
			GEvent.addListener(this.map, 'movestart', function(){this.clear_existing_counts();this.clear_existing_info();}.bind(this));
			GEvent.addListener(this.map, 'zoomstart', function(){this.clear_existing_counts();this.clear_existing_info();}.bind(this));
			GEvent.addListener(this.map, 'zoomend', this.update_cluster_points.bind(this));
			GEvent.addListener(this.map, 'moveend', this.update_cluster_points.bind(this));
			this.update_cluster_points();
		}.bind(this)}).send({'restrict_area_id':this.area_list.value});
	},

	initialize: function(container, height, marker_list, extra){
		this.area_list = $('id_area');
		this.area_list.addEvent('change', function(){
			this.clusterer.removeMarkers();
			this.get_marker_list();
		}.bind(this));
		this.parent(container, height, marker_list, extra);
		this.map_type = this.map.getCurrentMapType();
		this.projection = this.map_type.getProjection();
	},

	clear_existing_counts: function(){
		$$('.scf_count_overlay').each(function(e){
			e.remove();
		});
	},

	clear_existing_info: function(){
		$$('.scf_info_overlay').each(function(e){
			e.remove();
		});
	},

	update_cluster_points: function() {
		this.clear_existing_counts();
		this.clear_existing_info();
		$A(this.clusterer._clusterMarkers).each(function(m) {
			var count = m._childIndexes.length;
			var point = this.map.fromLatLngToContainerPixel(m.getLatLng());
			if(!m.isHidden()) this.create_count(count, point, m);
		}.bind(this));
		$A(this.clusterer._mapMarkers).each(function(m) {
			if(!m.isHidden() && m._isVisible){
				var point = this.map.fromLatLngToContainerPixel(m.getLatLng());
				this.create_count(' ', point,  m);
			}
		}.bind(this));
	},

	create_count: function(count_value, point, marker){
		if(!marker) return;
		var count = new Element('div').setText(count_value);
		var relative_position_x = point.x - marker.getIcon().iconAnchor.x;
		var relative_position_y = point.y - marker.getIcon().iconAnchor.y;
		var absolute_position_x = relative_position_x + this.elem.getPosition().x;
		var absolute_position_y = relative_position_y + this.elem.getPosition().y;
		count.setStyles({
			'display':'block',
			'background': 'url(/media/img/icons/transparent.gif) top left',
			'color':'#fff',
			'position':'absolute',
			'padding': '10px 0px',
			'text-align': 'center',
			'text-indent': '-10px',
			'height': (marker.getIcon().iconSize.height - 20) + 'px',
			'width': marker.getIcon().iconSize.width + 'px',
			'cursor': 'pointer',
			'top': relative_position_y + 'px',
			'left':relative_position_x + 'px',
			'z-index': 100
		});
		count.addClass('scf_count_overlay');
		count.addEvent('click', function(marker){
			GEvent.trigger(marker, 'click');
		}.bind(this, marker));
		count.addEvent('mouseover', function(event, count){
			$clear(this.hideTimeout);
			this.clear_existing_info();
			var info = new Element('div');
			var arrow = new Element('img', {'src':'/media/img/icons/info_arrow.png'});
			arrow.setStyles({'position':'absolute','visibility':'hidden'});
			info.setStyles({
				'visibility':'hidden',
				'display':'block',
				'background': '#fff',
				'border': '2px solid #B1B1B1',
				'position':'absolute',
				'padding':'10px',
				'min-width': '200px',
				'max-width': '300px',
				'max-height': '200px',
				'overflow': 'auto',
				'left': (absolute_position_x + marker.getIcon().iconSize.width + 5) + 'px'
			});
			if(window.ie6) info.setStyles({'width':'200px'});
			info.addClass('scf_info_overlay');
			arrow.addClass('scf_info_overlay');
			if(count._cluster){
				$A(count._cluster).each(function(e){
					var elem = $(this.clusterer._mapMarkers[e].text).clone();
					if(elem.getText()){
						elem.setHTML('- ' + elem.innerHTML);
						info.adopt(elem);
					}
					info.adopt(new Element('br'));
				}.bind(this));
			}else{
				var elem = $(marker.text).clone();
				info.adopt(elem);
			}
			info.addEvent('mouseover', function() {
				$clear(this.hideTimeout);
			}.bind(this));
			info.addEvent('mouseout', function(){
				$clear(this.hideTimeout);
				this.hideTimeout = this.clear_existing_info.delay(100);
			}.bind(this));
			info.injectInside($('body'));
			arrow.injectInside($('body'));
			if(window.ie6){
				info.setStyles({
					'top': absolute_position_y + 'px',
					'visibility':'visible'
				});
			}else{
			   info.setStyles({
				   'top': absolute_position_y - (info.getSize().size.y/2) + (marker.getIcon().iconSize.height/2) + 'px',
					'visibility':'visible'
				});
			}
			arrow.setStyles({
				'top': absolute_position_y - 7 + (marker.getIcon().iconSize.height/2) + 'px',
				'left': info.getPosition().x - 7 + 'px',
				'z-index': 10,
				'visibility':'visible'
			});
		}.bindWithEvent(this, count));
		count.addEvent('mouseout', function(count){
			$clear(this.hideTimeout);
			this.hideTimeout = this.clear_existing_info.delay(100);
		}.bind(this, count));
		if(marker._childIndexes) count._cluster = marker._childIndexes;
		count.injectInside(this.elem);
	},

	plot_points: function(){
		/*Override this because we're using an ajax view*/
	}
});

/*Draw a route ona google map */
var RouteEditGoogleMap = BaseGoogleMap.extend({
	initialize: function(container, height, markers, opts){
		this.parent(container, height, markers, opts);
		this.map.addMapType(G_PHYSICAL_MAP);
		var map_type_control = new GMapTypeControl(true);
		var map_tpe_control_pos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(50, 7))
		this.map.addControl(map_type_control, map_tpe_control_pos);
		this.add_route();
		this.add_controls();
	},

	add_controls: function(){
		this.control_container = new Element('div');
		this.second_control_container = new Element('div');
		this.search_container = new Element('div');

		this.elem.appendChild(this.control_container);
		this.elem.appendChild(this.second_control_container);
		this.elem.appendChild(this.search_container);

		var pickPOIs = new PickPOIControl(this.map, {
			'container':this.control_container,
			'position':[G_ANCHOR_TOP_RIGHT, new GSize(7, 7)],
			'task_name':'Link points of interest',
			'googleControlStyle': 'Poi',
			'googleSearchControlStyle':'SearchPoiInput',
			'googleSearchControlText': 'Enter point of interest name.',
			'overlayIcon': 'POIIcon',
			'selectedOverlayIcon': 'POISelectedIcon',
			'saveInput': this.poi_input
		});
		var editRoute = new PerformMapTaskControl(this.map, {
			'container':this.control_container,
			'position':[G_ANCHOR_TOP_RIGHT, new GSize(7, 7)],
			'task_name':'Edit',
			'task_func':function(){this.edit_route();}.bind(this),
			'googleControlStyle':'Edit'
		});
		var pickListings = new PickListingsControl(this.map, {
			'container':this.second_control_container,
			'position':[G_ANCHOR_TOP_RIGHT, new GSize(7, 28)],
			'task_name':'Link businesses',
			'googleControlStyle':'Business',
			'googleSearchControlStyle':'SearchBusinessInput',
			'googleSearchControlText': 'Enter directory listing name.',
			'overlayIcon': 'BusinessIcon',
			'selectedOverlayIcon': 'BusinessSelectedIcon',
			'saveInput': this.business_input
		});
		var clearRoute = new PerformMapTaskControl(this.map, {
			'container':this.second_control_container,
			'position':[G_ANCHOR_TOP_RIGHT, new GSize(7, 28)],
			'task_name':'Clear',
			'task_func': function(){
				var confirmed = confirm("Are you sure you wish to erase the current route?");
				if(confirmed){this.clear_route();}}.bind(this),
			'googleControlStyle':'Clear'
		});
		/*Add the map controls */
		this._controls = Array(
			pickPOIs,
			editRoute,
			pickListings,
			clearRoute
		);
		this.map.addControl(pickPOIs.get_control());
		this.map.addControl(editRoute.get_control());
		this.map.addControl(pickListings.get_control());
		this.map.addControl(clearRoute.get_control());
	},

	load_route: function(json_points){
		var latlng_list = Json.evaluate(json_points);
		glatlngs = []
		latlng_list.each(function(e, i){
			glatlngs[i] = new GLatLng(e[0], e[1]);
		});
		this.clear_route();
		this.polyline = new GPolyline(glatlngs,'#4C083B', 4, 0.9);
		bounds = this.polyline.getBounds();
		zoom = this.map.getBoundsZoomLevel(bounds);
		this.map.setCenter(bounds.getCenter(), zoom);
		this.map.addOverlay(this.polyline);
		this.edit_route();
		if(typeof(this.route_load_callback)!='undefined'){
			this.route_load_callback();
		}
	},

	ready: function(){
		/*report ready state when there's nothing to load*/
		if(typeof(this.route_load_callback)!='undefined'){
			this.route_load_callback();
		}
	},

	add_route: function(){
		GEvent.addListener(this.map, 'click', function(overlay, latlng){
			if(!this.polyline){
				this.polyline = new GPolyline([latlng],'#4C083B', 4, 0.9);
				this.map.addOverlay(this.polyline);
				this.polyline.enableDrawing();
				GEvent.addListener(this.polyline, 'endline', function(){
					this.encode_route_to_input();
					this._controls.each(function(e){ e.enable(); });
				}.bind(this));
			}
		}.bind(this));
	},

	edit_route: function(){
		if(this.polyline){
			this.polyline.enableEditing();
			this._controls.each(function(e){ e.enable(); });
			this.encode_route_to_input();
			GEvent.addListener(this.polyline, 'lineupdated', function(){
				this.encode_route_to_input();
			}.bind(this))
		}
	},

	clear_route: function(){
		if(this.polyline){
			this.polyline.disableEditing();
			this.map.removeOverlay(this.polyline);
		}
		this._controls.each(function(e){ e.disable(); });
		this.polyline = false;
		this.save_to_input.value = '';
		this.distance_input.value = '';
		this.longitude_input.value = '';
		this.latitude_input.value = '';
	},

	encode_route_to_input: function(){
		if(this.polyline){
			line_points = [];
			for(i=0; i<this.polyline.getVertexCount(); i++){
				vertex = this.polyline.getVertex(i);
				line_points[i] = [vertex.lat(), vertex.lng()];
			}
			this.encoded_polyline = Json.toString(line_points);
			this.save_to_input.value = this.encoded_polyline;
			this.distance_input.value = this.polyline.getLength();
			if(this.polyline.getVertexCount()){
				this.latitude_input.value = line_points[0][0];
				this.longitude_input.value = line_points[0][1];
			}
		}
	}
});

/*Tiny map for displaying the route overviews*/
var MiniRouteGoogleMap = BaseGoogleMap.extend({
	init_map: function(){
		if (GBrowserIsCompatible()) {
			this.map = new GMap2(this.elem);
			this.map.setCenter(new GLatLng(56.2752, -3.1244), 11);
			if(this.click_url){
				GEvent.addListener(this.map, 'click', function(){
					window.location = this.click_url;
				}.bind(this));
			}
		}
	},
	load_route: function(json_points){
		var latlng_list = Json.evaluate(json_points);
		glatlngs = []
		latlng_list.each(function(e, i){
			glatlngs[i] = new GLatLng(e[0], e[1]);
		});
		this.polyline = new GPolyline(glatlngs,'#4C083B', 4, 0.9);
		bounds = this.polyline.getBounds();
		zoom = this.map.getBoundsZoomLevel(bounds);
		this.map.setCenter(bounds.getCenter(), zoom);
		this.map.addOverlay(this.polyline);
	}
});

/*Tiny map for displaying the route overviews*/
var MiniPoiGoogleMap = BaseGoogleMap.extend({
	init_map: function(){
		if (GBrowserIsCompatible()) {
			this.map = new GMap2(this.elem);
			this.map.setCenter(new GLatLng(56.2752, -3.1244), 11);
			if(this.click_url){
				GEvent.addListener(this.map, 'click', function(){
					window.location = this.click_url;
				}.bind(this));
			}
		}
	},
	load_route: function(json_points, poi_point, point_type){
		var latlng_list = Json.evaluate(json_points);
		glatlngs = []
		latlng_list.each(function(e, i){
			glatlngs[i] = new GLatLng(e[0], e[1]);
		});
		this.polyline = new GPolyline(glatlngs,'#4C083B', 4, 0.9);
		zoom=11;
		this.map.addOverlay(this.polyline);
		poi_latlng = new GLatLng(poi_point['latitude'], poi_point['longitude']);
		this.map.addOverlay(new GMarker(poi_latlng, {icon: SFGIcons[point_type]}));
		this.map.setCenter(poi_latlng, zoom);
	}
});


/*Draw a route on a google map - used for viewing and for plotting search results */
var RouteGoogleMap = BaseGoogleMap.extend({
	initialize: function(container, height, markers, opts){
		this.parent(container, height, markers, opts);
		this.routeMarkers = [];
		this.poiMarkers = [];
		this.businessMarkers = [];
		this.distanceMarkers = [];
		this.map.addMapType(G_PHYSICAL_MAP);
		var map_type_control = new GMapTypeControl();
		this.map.addControl(map_type_control);
	},

	_clear_selected_markers: function(markers){
		markers.each(function(e){
			this.map.removeOverlay(e);
			if(e._extra_overlay) e._extra_overlay.remove();
		}.bind(this));
		markers = [];
	},

	clear_poi_markers: function(){
		this._clear_selected_markers(this.poiMarkers);
	},

	clear_distance_markers: function(){
		this._clear_selected_markers(this.distanceMarkers);
	},

	clear_business_markers: function(){
		this._clear_selected_markers(this.businessMarkers);
	},

	clear_route_markers: function(){
		this._clear_selected_markers(this.routeMarkers);
	},

	load_route: function(json_points, freeze){
		if(this.polyline) this.map.removeOverlay(this.polyline);
		var latlng_list = Json.evaluate(json_points);
		glatlngs = []
		latlng_list.each(function(e, i){
			glatlngs[i] = new GLatLng(e[0], e[1]);
		});
		this.polyline = new GPolyline(glatlngs,'#4C083B', 4, 0.9);
		if(!freeze) {
			bounds = this.polyline.getBounds();
			zoom = this.map.getBoundsZoomLevel(bounds);
			this.map.setCenter(bounds.getCenter(), zoom);
		}
		this.map.addOverlay(this.polyline);
	},

	add_distance_update: function(marker){
		GEvent.addListener(this.map, 'movestart', function(marker){
			marker._extra_overlay.setStyle('visibility', 'hidden');
		}.bind(this, marker));
		GEvent.addListener(this.map, 'moveend', function(marker){
			var point = this.map.fromLatLngToContainerPixel(marker.getLatLng());
			marker._extra_overlay.setStyles({
				'visibility': 'visible',
				'color': '#fff',
				'padding': '2px 0',
				'position': 'absolute',
				'top': point.y - marker.getIcon().iconAnchor.y + 'px',
				'left': point.x - marker.getIcon().iconAnchor.y + 'px',
				'width': '66px'
			});
		}.bind(this, marker));
		GEvent.addListener(this.map, 'zoomstart', function(marker){
			marker._extra_overlay.setStyle('visibility', 'hidden');
		}.bind(this, marker));
		GEvent.addListener(this.map, 'zoomend', function(marker){
			var point = this.map.fromLatLngToContainerPixel(marker.getLatLng());
			marker._extra_overlay.setStyles({
				'visibility': 'visible',
				'color': '#fff',
				'padding': '2px 0',
				'position': 'absolute',
				'top': point.y - marker.getIcon().iconAnchor.y + 'px',
				'left': point.x - marker.getIcon().iconAnchor.y + 'px',
				'width': '66px'
			});
		}.bind(this, marker));
		marker._extra_overlay.addEvent('click', function(marker){
			GEvent.trigger(marker, 'click');
		}.bind(this, marker));

	},

	show_distance: function(distance){
		if(this.polyline){
			var start = this.polyline.getVertex(0);
			var new_marker = new GMarker(start, {icon: SFGIcons['RouteIcon']});
			this.map.addOverlay(new_marker);
			var dist = new Element('div').setText(distance + ' mi');
			new_marker._extra_overlay = dist;
			var point = this.map.fromLatLngToContainerPixel(start);
			dist.setStyles({
				'color': '#fff',
				'padding': '2px 0',
				'position': 'absolute',
				'top': point.y - new_marker.getIcon().iconAnchor.y + 'px',
				'left': point.x - new_marker.getIcon().iconAnchor.y + 'px',
				'width': '66px'
			});
			this.elem.adopt(dist);
			this.add_distance_update(new_marker);
			this.distanceMarkers[this.distanceMarkers.length] = new_marker;
		}
	},

	replicate_marker: function(marker, icon){
		/*Allows us to swap markers for selected versions (google doesn't really support icon swapping) */
		var point = marker.getLatLng();
		var new_marker = new GMarker(point, {icon: icon});
		new_marker._scf_id = marker._scf_id;
		new_marker.text = marker.text;
		new_marker._extra_overlay = marker._extra_overlay;
		new_marker._extra_overlay.removeEvents();
		var point = this.map.fromLatLngToContainerPixel(marker.getLatLng());
		new_marker._extra_overlay.setStyles({
			'color': '#fff',
			'padding': '2px 0',
			'position': 'absolute',
			'cursor':'pointer',
			'top': point.y - new_marker.getIcon().iconAnchor.y + 'px',
			'left': point.x - new_marker.getIcon().iconAnchor.x + 'px',
			'width': '66px'
		});
		this.add_distance_update(new_marker);
		return new_marker;
	},

	RouteIcon_text:function(desc){
		var text = new Element('div').setStyles({'width':'200px'});
		text.adopt(new Element('a', {'href': desc['url'], 'target':'_blank', 'style':'font-size: 2em'}).setHTML(desc['name']));
		text.adopt(new Element('br'));
		text.adopt(new Element('div').setHTML('<strong>Type:</strong> ' + desc['route_type'].replace(/\n/, '<br />')));
		text.adopt(new Element('div').setHTML('<strong>Suitability:</strong> ' + desc['route_suitability'].replace(/\n/, '<br />')));
		return text;
	},

	BusinessIcon_text: function(desc){
		var text = new Element('div').setStyles({'width':'200px'});;
		text.adopt(new Element('a', {'href': desc['url'], 'target':'_blank', 'style':'font-size: 1.2em'}).setHTML(desc['name']));
		text.adopt(new Element('br'));
		text.adopt(new Element('div').setHTML(desc['text']));
		return text;
	},

	POIIcon_text: function(desc){
		var text = new Element('div').setStyles({'width':'200px'});;
		text.adopt(new Element('a', {'href': desc['url'], 'target':'_blank', 'style':'font-size: 1.2em'}).setHTML(desc['name']));
		text.adopt(new Element('br'));
		text.adopt(new Element('div').setHTML(desc['text']));
		for(var i=0; i<desc['images'].length && i<5; i++){
			var link = new Element('a', {'rel':'lightbox', 'title':desc['images'][i]['medium'][1], 'href':desc['images'][i]['medium'][0] }).adopt(new Element('img', {'src': desc['images'][i]['thumbnail'][0], 'style':'margin: 0 5px 5px 0;'}));
			link.slimbox({
				overlayOpacity: 0.6,
				overlayFadeDuration: 200,
				resizeDuration: 200,
				resizeTransition: Fx.Transitions.Elastic.easeOut,
				previousKeys: [37, 80, 16],
				nextKeys: [39, 78, 17]
			});
			text.adopt(link);
		}
		return text;
	},

	_create_marker_from_description: function(desc, marker_text_func){
		marker_text_func = marker_text_func + '_text';
		var point = new GLatLng(desc['latitude'], desc['longitude']);
		var marker = new GMarker(point, {icon: desc['icon']});
		marker._scf_id = desc['_scf_id'];
		marker.text = this[marker_text_func](desc);
		GEvent.addListener(marker, "click", function() {
			this.openInfoWindow(this.text);
		});
		return marker;
	},

	_show_api_markers: function(json_ids, url, icon, marker_list){
		var currently_selected = Json.evaluate(json_ids);
		if(currently_selected){
			var marker_points = new Json.Remote(url, {onComplete: function(data){
				data.each(function(e, i){
					e.icon = SFGIcons[icon];
					var marker = this._create_marker_from_description(e, icon);
					marker_list[marker_list.length] = marker;
					this.map.addOverlay(marker);
				}.bind(this));
			}.bind(this)}).send({'ids':json_ids});
		}
	},

	_create_bubble_text: function(){

	},

	_show_json_markers: function(json_descriptions, icon, marker_list){
		this.currently_selected = null;
		var bounds = new GLatLngBounds();
		var marker_points = (typeof json_descriptions == 'string' ? Json.evaluate(json_descriptions) : json_descriptions);
		marker_points.each(function(e, i){
			e.icon = SFGIcons[icon];
			var marker = this._create_marker_from_description(e, icon);
			marker_list[marker_list.length] = marker;
			bounds.extend(marker.getLatLng());
			this.map.addOverlay(marker);
			if(e.distance){
				var dist = new Element('div').setText(e.distance + ' mi');
				marker._extra_overlay = dist;
				var point = this.map.fromLatLngToContainerPixel(marker.getLatLng());
				dist.setStyles({
					'color': '#fff',
					'padding': '2px 0',
					'position': 'absolute',
					'cursor':'pointer',
					'top': point.y - marker.getIcon().iconAnchor.y + 'px',
					'left': point.x - marker.getIcon().iconAnchor.y + 'px',
					'width': '66px'
				});
				this.elem.adopt(dist);
				this.add_distance_update(marker);

				GEvent.addListener(marker,'click', function(marker){
					this._clear_previous_selected_state(marker);
					this._show_selected_state(marker);
				}.bind(this, marker));
			}
		}.bind(this));
		if (!bounds.isEmpty()) {
			this.map.setCenter(bounds.getCenter(), Math.min(15, this.map.getBoundsZoomLevel(bounds)));
		}
	},

	_clear_previous_selected_state: function(marker){
		if(this.currently_selected && this.currently_selected != marker ){
			var new_marker = this.replicate_marker(this.currently_selected, SFGIcons.RouteIcon);
			this.map.removeOverlay(this.currently_selected);
			this.map.addOverlay(new_marker);
			GEvent.addListener(new_marker, 'click', function(new_marker){
				this._clear_previous_selected_state(new_marker);
				this._show_selected_state(new_marker);
			}.bind(this, new_marker));

		}
	},

	_show_selected_state: function(marker){
		var new_marker = this.replicate_marker(marker, SFGIcons.RouteSelectedIcon);
		this.map.removeOverlay(marker);
		this.map.addOverlay(new_marker);
		this.currently_selected = new_marker;
		if(this.available_routes[new_marker._scf_id]){
			this.load_route(this.available_routes[new_marker._scf_id], true);
			bounds = this.polyline.getBounds();
			bounds.extend(new_marker.getLatLng());
			zoom = this.map.getBoundsZoomLevel(bounds);
			zoom = zoom-1;
			this.map.setCenter(bounds.getCenter(), zoom);
		}
		new_marker.openInfoWindow(new_marker.text);
		GEvent.addListener(new_marker, 'click', function(){
			this.openInfoWindow(this.text);
		});
	},

	show_poi_markers: function(json_ids){
		this._show_api_markers(json_ids, APIUrls.display_poi_lookup, 'POIIcon', this.poiMarkers);
	},

	show_business_markers: function(json_ids){
		this._show_api_markers(json_ids, APIUrls.listing_lookup, 'BusinessIcon', this.businessMarkers);
	},

	show_route_markers: function(json_descriptions){
		this._show_json_markers(json_descriptions, 'RouteIcon', this.routeMarkers);
	},

	set_available_routes: function(route_json){
		this.available_routes = (typeof route_json == 'string' ? Json.evaluate(route_json) : route_json);
	}
});
