// Initialise global Hc context
var Hc = Hc || {};

// create Map object within Hc context.
Hc.Map = {
	initialised : false,

	// accuracy is from 0 (unknown) to 9 (property level)
	// 0 = unknown
	// 1 = country 
	// 2 = region
	// 3 = subregion
	// 4 = town
	// 5 = postal code
	// 6 = street
	// 7 = intersection
	// 8 = address
	// 9 building name	
	accuracyToZoom: [
		[0,1],
		[1,4],
		[2,7],
		[3,9],
		[4,11],
		[5,13],
		[6,14],
		[7,15],
		[8,16],
		[9,16],
		[10,16]
	],
	map: null,
	points: [],
	centre: {},
	lat: 0,
	lng: 0,
	acc: 0,
	lastMarkerClicked: null,
	mapClicked: function(overlay, point) {
		Hc.Map.map.addOverlay(new GMarker(point));
	},
	zoomToLocation: function(lat, lng, accuracy) {

		var zoom = this.accuracyToZoom[accuracy][1];
		this.map.setCenter(new GLatLng(lat, lng), zoom);
		if(accuracy > 0) {
			this.map.clearOverlays();
			this.map.addOverlay(Hc.Map.infoWindow);
			this.map.addOverlay(this.createMarker(new GLatLng(lat, lng), 0));	
		}
	},	
	createMarker: function(point, number) {
	
		// Create our "tiny" marker icon
		var tinyIcon = new GIcon();
		tinyIcon.image = "http://www.healthandcreativity.com/images/temple.png";
		tinyIcon.shadow = "http://www.healthandcreativity.com/images/templeShadow.png";
		tinyIcon.iconSize = new GSize(22, 18);
		tinyIcon.shadowSize = new GSize(36, 18);
		tinyIcon.iconAnchor = new GPoint(10, 13);
		tinyIcon.infoWindowAnchor = new GPoint(16, 5);

		// Set up our GMarkerOptions object literal
		markerOptions = { icon:tinyIcon };

		var marker = new GMarker(point, markerOptions);
		marker.value = number;
		
		GEvent.addListener(marker, "click", function() {

			/*
			var myHtml = '<a href="#" onclick="Hc.Map.infoWindow.hide();return false;" style="display:block;padding:0;line-height:1em;float:right;border:1px solid red;background-color:red;color:white;">X</a>';
			for(var i=0; i<Hc.Map.aggregatePoints[number].points.length; i++) {
				myHtml += (i+1)+'. <a href="/profile/'+Hc.Map.aggregatePoints[number].points[i].slug+'/">' + Hc.Map.aggregatePoints[number].points[i].name + '</a><br/>';
			}
			
			Hc.Map.infoWindow.point = marker.getPoint();
			Hc.Map.infoWindow.infoDiv.innerHTML = myHtml;
			Hc.Map.infoWindow.visible = true;
			Hc.Map.infoWindow.infoDiv.style.display = "";
			Hc.Map.infoWindow.redraw(true);
			*/
			if(Hc.Map.lastMarkerClicked) {
				Hc.Map.lastMarkerClicked.setImage("http://www.healthandcreativity.com/images/temple.png");
			}
			marker.setImage("http://www.healthandcreativity.com/images/temple_bak.png");
			Hc.Map.lastMarkerClicked = marker;
			
			var myHtml = '';
			for(var i=0; i<Hc.Map.aggregatePoints[number].points.length; i++) {
				var myResult = '<div class="contentView"><div class="header clearfix"><img class="avatarMini" src="'+Hc.Map.points[Hc.Map.aggregatePoints[number].points[i]][6]+'"/><b><a href="/profile/'+Hc.Map.points[Hc.Map.aggregatePoints[number].points[i]][4]+'/">'+Hc.Map.points[Hc.Map.aggregatePoints[number].points[i]][3]+'</a></b><br/>(<a href="/subject/'+Hc.Map.points[Hc.Map.aggregatePoints[number].points[i]][8]+'/">'+Hc.Map.points[Hc.Map.aggregatePoints[number].points[i]][7]+'</a>)<br/></div></div>';
				myHtml += myResult;
				//myHtml += (i+1)+'. <a href="/profile/'+Hc.Map.aggregatePoints[number].points[i].slug+'/">' + Hc.Map.aggregatePoints[number].points[i].name + '</a><br/>';
			}			
			$('#mapSearchResults').html(myHtml);
		});
		return marker;
	},
	onMapScriptLoaded: function() {
		if (GBrowserIsCompatible()) {
			this.map = new GMap2(document.getElementById("map"));
			
			// add controls ...
			// the zoom and pan
			this.map.addControl(new GSmallMapControl());		
			
			// the map type toggle
			this.map.addControl(new GMapTypeControl());	
			
			// the overview
			//this.map.addControl(new GOverviewMapControl());
			
			// set the type
			//this.map.setMapType(G_HYBRID_MAP);
			//this.map.setMapType(G_PHYSICAL_MAP);
			this.map.setMapType(G_NORMAL_MAP);

			// any event listeners..?
			//GEvent.addListener(this.map,"click", this.mapClicked);

			
			// add points
			this.map.setCenter(new GLatLng(0, 0), 0);
			
			
			//Create an empty GLatLngBounds() object.
			var bounds = new GLatLngBounds();
						
			// go through all the points, add them to the map, work out the bounds 
			// and find the accuracy of the least accurate point in the list (smallestAccuracyValue)
			// Give it a completely out of range value to start.
			var smallestAccuracyValue = -1;
			for(var i=0; i<this.points.length; i++) {
				// ignore points that have been given 0 accuracy, they do not have
				// vaild lat/lng
				if(this.points[i][2] > 0) {
					// Each time a point is read, add the point to the map
					// and extend the bounds object to include that point.
					var latlng = new GLatLng(this.points[i][0], this.points[i][1]);
					bounds.extend(latlng);					

					// if this is the smallest accuracy value so far, record it.
					if(	this.points[i][2] < smallestAccuracyValue ||
						smallestAccuracyValue == -1
					) smallestAccuracyValue = this.points[i][2];
				}
			}			
			// if unnasigned, set the value to 0, the least accurate value.
			if(smallestAccuracyValue == -1) smallestAccuracyValue = 0;
			
			// now find the smallest zoom level based on the accuracy value.
			var smallestZoomLevel = this.accuracyToZoom[smallestAccuracyValue][1];
			
			// now find the smallest zoom level based on the bounds of all the points.
			var boundsZoomLevel = this.map.getBoundsZoomLevel(bounds)-1;
			if(boundsZoomLevel <= 0) boundsZoomLevel=1;

			// choose the smallest value of the two.
			var smallestZoomOfBoundsAndAccuracy = (smallestZoomLevel < boundsZoomLevel) ? smallestZoomLevel : boundsZoomLevel;
						
			if(this.acc == 0) {
				// Now we can set the zoom.
				this.map.setZoom(smallestZoomOfBoundsAndAccuracy);
				// ..And the centre can be obtained by using the bounds.getCenter() method
				this.map.setCenter(bounds.getCenter());
			} else {
				this.map.setCenter(new GLatLng(this.lat, this.lng), this.accuracyToZoom[this.acc][1]);
			}
			
			// create the aggregate markers.
			this.getAggregatePoints();
			
			GEvent.addListener(this.map, "zoomend", function() {
				Hc.Map.getAggregatePoints();
				// add back the info window  -since we removed all overlays above!
				Hc.Map.infoWindow.visible = false;
				Hc.Map.map.addOverlay(Hc.Map.infoWindow);
			});

			// create our own info window.
			Hc.Map.InfoWindow = function() {};
			Hc.Map.InfoWindow.prototype = new GOverlay();
			Hc.Map.InfoWindow.prototype.initialize = function(map) {
				this.map = map;
				this.visible = false;
		        this.infoDiv = document.createElement("div");
				this.infoDiv.style.position = "absolute";
				this.infoDiv.style.width = "200px";
				this.infoDiv.style.padding = "3px";
				this.infoDiv.style.backgroundColor = "#ddddee";
				this.infoDiv.style.border = "1px solid #000099";
				this.infoDiv.style.display = "none";
				this.map.getPane(G_MAP_FLOAT_SHADOW_PANE).appendChild(this.infoDiv);
			};
			Hc.Map.InfoWindow.prototype.redraw = function(force) {
		        if (!force) {return;}
		        if (!this.visible) {return;}
		        var p = this.map.fromLatLngToDivPixel(this.point);
				this.infoDiv.style.left = (p.x-100) + "px";
				this.infoDiv.style.bottom = (-p.y+10) + "px";
				//this.infoDiv.style.zIndex = GOverlay.getZIndex(this.point.lat());
				//this.infoDiv.style.display = "block";
			};
			Hc.Map.InfoWindow.prototype.hide = function() {
				Hc.Map.infoWindow.visible = false;
				Hc.Map.infoWindow.infoDiv.style.display = "none";
				return false;
			}
			Hc.Map.InfoWindow.prototype.remove = function() {
				this.infoDiv.parentNode.removeChild(this.infoDiv);
			};
			Hc.Map.InfoWindow.prototype.copy = function() {
				return new Hc.Map.InfoWindow();
			};
			this.infoWindow = new Hc.Map.InfoWindow();
			// add back the info window  -since we removed all overlays above!
			this.map.addOverlay(Hc.Map.infoWindow);
		}
	},
	dhtmlLoadScript: function (url)
	{
		var e = document.createElement("script");
		e.src = url;
		e.type="text/javascript";
		document.body.appendChild(e);
	},
	loadGoogleMapScript: function() {
		// live
		
//		this.dhtmlLoadScript("http://maps.google.com/maps?file=api&v=2.x&key=ABQIAAAA0d95pO91xygMQMHL7RL3MBQODUx2VbI_VgH8Wu_FyFBJp1aaQhTSwlKgc12BruLTvTGLI1OS6S352g&async=2&callback=Hc.Map.onMapScriptLoaded");

		// europropertymap.com
		this.dhtmlLoadScript("http://maps.google.com/maps?file=api&v=2.x&key=ABQIAAAA0d95pO91xygMQMHL7RL3MBTnsSWXAQ6lGXzj0MIS52plAjQc9hQ8yXa8KBBzuy0ChulLivgLYH_yog&async=2&callback=Hc.Map.onMapScriptLoaded");		
//		this.dhtmlLoadScript("http://maps.google.com/maps?file=api&v=2.x&key=ABQIAAAA0d95pO91xygMQMHL7RL3MBTWK2dyIypAGhbcfmzfU0pe1GFRZxRQkn3rquReoIT2Lmtf0dovSHAXGg&async=2&callback=Hc.Map.onMapScriptLoaded");
		// local
		//this.dhtmlLoadScript("http://maps.google.com/maps?file=api&v=2.x&key=ABQIAAAA0d95pO91xygMQMHL7RL3MBQODUx2VbI_VgH8Wu_FyFBJp1aaQhTSwlKgc12BruLTvTGLI1OS6S352g&async=2&callback=Hc.Map.onMapScriptLoaded");
	},
	getAggregatePoints: function() {
		Hc.Map.lastMarkerClicked = null;
		var aggregatePoints = [];
		for(var i=0; i<this.points.length; i++) {
			if(this.points[i][2] == 0) continue;
		
			var lat = this.points[i][0];
			var lng = this.points[i][1];
			var found = false;
			for(var j=0; j<aggregatePoints.length; j++) {
//				if(	lat>aggregatePoints[j].minLat && lat<aggregatePoints[j].maxLat &&
//					lng>aggregatePoints[j].minLng && lng<aggregatePoints[j].maxLng ) {
				if(	aggregatePoints[j].bounds.containsLatLng( new GLatLng(this.points[i][0], this.points[i][1]) ) ) {
					
					/*
					aggregatePoints[j].points[aggregatePoints[j].points.length] = { 
						name: this.points[i][3], 
						slug: this.points[i][4],
						url:  this.points[i][5]
					};
					*/
					aggregatePoints[j].points[aggregatePoints[j].points.length] = i;
					
					found = true;
				}					
			}
			if(!found) {
				var proj = this.map.getCurrentMapType().getProjection();
				var point = proj.fromLatLngToPixel(new GLatLng(this.points[i][0], this.points[i][1]), this.map.getZoom())
				var newAgg = new Object();
				newAgg.lat = this.points[i][0]; // lat
				newAgg.lng = this.points[i][1]; // lng
				
				var topLeft 	= proj.fromPixelToLatLng(new GPoint(point.x-10, point.y-10), this.map.getZoom());
				var bottomRight = proj.fromPixelToLatLng(new GPoint(point.x+10, point.y+10), this.map.getZoom());

				var bounds = new GLatLngBounds();
				bounds.extend(topLeft);
				bounds.extend(bottomRight);
				
				newAgg.bounds = bounds;
/*
				newAgg.minLat = topLeft.lat();
				newAgg.maxLat = bottomRight.lat();
				newAgg.minLng = topLeft.lng();
				newAgg.maxLng = bottomRight.lng();			
*/				
				newAgg.points = new Array();
				newAgg.points[0] = i;
				aggregatePoints[aggregatePoints.length] = newAgg;
			}
		}
		
		this.aggregatePoints = aggregatePoints;
		
		this.map.clearOverlays();
				
		// now add the relevant markers.
		for(var i=0; i<this.aggregatePoints.length; i++) {
			var latlng = new GLatLng(this.aggregatePoints[i].lat, this.aggregatePoints[i].lng);
			this.map.addOverlay(this.createMarker(latlng, i));				
		}
	},
	refresh: function(data) {
		if(data.points) {
			this.points = data.points;			
		}
		if(data.centre) {
			this.lat = data.centre.lat;
			this.lng = data.centre.lng;
			this.acc = data.centre.acc;
		}		
		this.map.clearOverlays();
		this.getAggregatePoints();
		var zoom = this.accuracyToZoom[this.acc][1];
		this.map.setCenter(new GLatLng(this.lat, this.lng), zoom);
	},
	init: function(data) {
	
		if( this.initialised ) return;
		if(data.points) {
			this.points = data.points;			
		}
		if(data.centre) {
			this.lat = data.centre.lat;
			this.lng = data.centre.lng;
			this.acc = data.centre.acc;
		}
		
		this.loadGoogleMapScript();
		
		this.initialised = true;
	},
	deinit: function() {
		GUnload();
	}
};

