	function EKClientMap() {};

	/**
	 * @description 	Sets up all the initial objectsa and variables
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		String - ID of "you searched for box"
	 * @parameter 		String - ID of search form
	 * @parameter 		String - ID of place name field
	 * @parameter 		String - ID of message div
	 * @date      		2007-05-22
	 */
    EKClientMap.prototype._load = function(sMapSearchedForId, sFormId, sPlaceNameId, sPostcodeId, sMessageId) {
		if (GBrowserIsCompatible()) {
			var _self = this;
			this.map = new GMap2(document.getElementById("mapResult"));
			this.aMarkers = [];
			this.oActiveMarker;
			this.aActiveBounds = [];
			this.map.addControl(new GLargeMapControl());
			this.map.addControl(new GMapTypeControl());
			this.map.setCenter(new GLatLng(54.622978,-2.592773), 5, G_NORMAL_MAP);
			this.sMapSearchedForId = sMapSearchedForId;
			this.sFormId = sFormId;
			this.sPlaceNameId = sPlaceNameId;
			this.sPostcodeId = sPostcodeId;
			this.sMessageId = sMessageId;
			this.iListCount = 0;
			this.submitButton = 0;

			//Redraw if the maps moves (panning), is loaded or on at end of zoom
			_self.redraw();

	  	    GEvent.addListener(_self.map, "infowindowclose", function() {
				var aCoords = [];
				aCoords["lat"] = _self.aActiveBounds["maxLat"] - ((_self.aActiveBounds["maxLat"] - _self.aActiveBounds["minLat"]) / 2);
				aCoords["lng"] = _self.aActiveBounds["maxLng"] - ((_self.aActiveBounds["maxLng"] - _self.aActiveBounds["minLng"]) / 2);
				_self.aActiveBounds = [];
				_self.centerOnMap(aCoords, _self);
			});

			GEvent.addListener(_self.map, "moveend", function() {
				if(!_self.aActiveBounds.length) {
					_self.redraw();
				};
			});
			GEvent.addListener(_self.map, "zoomend", function() {
				_self.aActiveBounds = [];
				_self.redraw();
			});

			document.getElementById(this.sPlaceNameId).onfocus = function() {
				_self.value = "";
			};
		};
    };

	/**
	 * @description 	Ajax request to get locations based on user specified data
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		String - Placename
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.getPointsFromPlacename = function(sPlacename) {
		Ajax.request({
			uri:"/prec-includes/map/_request.address.php?q=" + sPlacename + "&country=GB",
			callback:this.parseAddress,
			scope:this
		});
	};

	EKClientMap.prototype.getPointsFromPostcode = function(postcode, callback, context) {
		var _self = this;
		var oLocalSearch = new GlocalSearch();
		var sPostcode = this.getValue(this.sPostcodeId);
		var oMapSearchedFor = document.getElementById(this.sMapSearchedForId);
		oMapSearchedFor.innerHTML = "<p class=\"notify\">You're looking at all posts in the postcode \"" + sPostcode  + "\"</p>";
		oLocalSearch.setSearchCompleteCallback(null,
		function() {
			if(oLocalSearch.results.length) {
				var nLat = oLocalSearch.results[0].lat;
				var nLng = oLocalSearch.results[0].lng;
				var oPoint = new GLatLng(nLat, nLng);
				var oGMessage = document.getElementById('mapSearchResults');
				if(oGMessage){
					while(oGMessage.childNodes[0]) {
					    oGMessage.removeChild(oGMessage.childNodes[0]);
					}
				}
				callback(_self.getPointAsArray(oPoint), context, 13);

			};
		});
		oLocalSearch.execute(postcode + ", UK");
	};

	/**
	 * @description 	Parse results from Ajax request
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		DOM - XML response object
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.parseAddress = function(oXML) {
		if(!oXML.responseText.length) {
			return false;
		};
		var oDoc = XMLDocument.create(oXML.responseText);
		var oGeonames = oDoc.getElementsByTagName("geoname");
		var oGMessage = this.createMessage("mapSearchResults", this.sMessageId);

		//Going to address so remove existing results
		XMLDocument.removeChildren(oGMessage);

		//If results have been returned
		if(oGeonames.length) {
			this.iListCount = 0;
			var oGList = document.createElement("ol");
			oGMessage.appendChild(oGList);
			var aNodes = this.sortResults(oGeonames);
			for(var i = 0; i < aNodes.length; i++) {
				this.createLocationLink(oGList, "location" + i, aNodes[i]);
			};
			if(oGeonames.length == 1) {
				this.centerOnMap(aNodes[0], this, 13);
			};
		} else {
			oGMessage.innerHTML = "<p class=\"notify\">Your search for \"" + this.getValue(this.sPlaceNameId) + "\" doesn't match any location. Check your spelling and try again.</p>";
		};
		oDoc = null;
	};

	EKClientMap.prototype.parseCountry = function(sValue) {
		var aCountries = ["England","Scotland","Wales"];
		for(var i = 0; i < aCountries.length; i++) {
			if(sValue.toLowerCase().indexOf(aCountries[i].toLowerCase()) != -1) {
				return aCountries[i];
			};
		};
		return "UK";
	};

	/**
	 * @description 	Sort node list into array
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		DOM node - List of results nodes
	 * @return	 		Array - array of values based on node list
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.sortResults = function(oNodes) {
		var aNodes = [];
		for(var i = 0; i < oNodes.length; i++) {
			aNodes[i] = [];
			aNodes[i]["name"] = XMLDocument.getText(oNodes[i].getElementsByTagName("name")[0].childNodes[0]);
			aNodes[i]["lng"] = XMLDocument.getText(oNodes[i].getElementsByTagName("lng")[0].childNodes[0]);
			aNodes[i]["lat"] = XMLDocument.getText(oNodes[i].getElementsByTagName("lat")[0].childNodes[0]);
			var oAlternateNames = oNodes[i].getElementsByTagName("alternateNames");
			if(oAlternateNames.length) {
				if(oAlternateNames[0].childNodes.length) {
					aNodes[i]["alternateNames"] = XMLDocument.getText(oAlternateNames[0].childNodes[0]);
					aNodes[i]["country"] = this.parseCountry(aNodes[i]["alternateNames"]);
				};
			};
			var oAdminName1 = oNodes[i].getElementsByTagName("adminName1");
			if(oAdminName1.length) {
				if(oAdminName1[0].childNodes.length) {
					aNodes[i]["adminName1"] = XMLDocument.getText(oAdminName1[0].childNodes[0]);
				};
			};
		};
		return aNodes;
	};

	/**
	 * @description 	Create a link based on results from search
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		DOM node - Parent list node
	 * @parameter 		String - ID for new object
	 * @parameter 		Array - Values for results
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.createLocationLink = function(oGList, sId, aNode) {
		this.iListCount += 1;
		var oGListItem = document.createElement("li");
		if(this.iListCount%2==0){
			oGListItem.className = 'even';
		}
		var oGHeading = document.createElement("h3");
		var oGLink = document.createElement("a");
		oGLink.setAttribute("id", sId);
		oGLink.appendChild(document.createTextNode(aNode["name"]));
		oGListItem.appendChild(oGHeading);
		var oGParagraph = document.createElement("p");
		var sContents = String("");
		if(aNode["country"]){
			sContents += aNode["country"];
			if(aNode["adminName1"]) {
				sContents += ", " + aNode["adminName1"];
			} else {
				sContents = sContents.replace(/,\s$/gi, "");
			};
		}else if(aNode["adminName1"]) {
			sContents += aNode["adminName1"];
		}
		oGParagraph.appendChild(document.createTextNode(sContents));
		oGListItem.appendChild(oGParagraph);
		oGHeading.appendChild(oGLink);
		oGList.appendChild(oGListItem);
		this.addGoToPoint(oGLink, aNode);
	};

	/**
	 * @description 	Calls function of object based on method string
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		String - Containing div id
	 * @parameter 		String - Mapping message div
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.createMessage = function(sContainerId, sId) {
		var oContainer = document.getElementById(sContainerId);
		var oGMessage = document.getElementById(sId);
		if(oContainer && !oGMessage) {
			oGMessage = document.createElement("div");
			oGMessage.setAttribute("id", sId);

			var oGHeading = document.createElement("h2");
			oGHeading.setAttribute("id", "GHeading");
			oGHeading.appendChild(document.createTextNode("Search Results"));

			//oBox = previousObject(previousObject(oContainer.lastChild));
			//oContainer.insertBefore(oGHeading, oBox);
			//oContainer.insertBefore(oGMessage, oBox);
			oContainer.appendChild(oGHeading);
			oContainer.appendChild(oGMessage);
		};
		return oGMessage;
	};


	/**
	 * @description 	Centers location on map and calls redraw function
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		Array - Coordinates
	 * @parameter 		Object - Context / "this"
	 * @parameter 		Int - Zoom level
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.centerOnMap = function(aCoords, context, nZoom) {
		var oPoint = new GLatLng(aCoords["lat"], aCoords["lng"]);
		if(!nZoom) {
			context.map.panTo(oPoint);
		} else {
			context.map.setCenter(oPoint, nZoom);
		};
		context.redraw();
	};

	/**
	 * @description 	Ajax request to get markers and calls function to draw markers
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.redraw = function() {
		this.removeMarkersFromArray(this.aMarkers);
		var aBounds = this.getBounds();
		var json = "json=" + encodeURI("{ \"placename\" : \"" + this.getValue(this.sPlaceNameId) + "\", \"maxLng\" : \"" + aBounds["maxLng"] + "\", \"minLng\" : \"" + aBounds["minLng"] + "\", \"maxLat\" : \"" + aBounds["maxLat"] + "\", \"minLat\" : \"" + aBounds["minLat"] + "\" }");
		Ajax.request({
			uri:"/prec-includes/map/_request.markers.php",
			callback:this.parseXMLMarkers,
			scope:this,
			post:json
		});
	};

	/**
	 * @description 	Callback function for xml generated by markers Ajax request
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		DOM - XML (response object)
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.parseXMLMarkers = function(oXML) {
		if(!oXML.responseText.length) {
			return false;
		};
		var oDoc = XMLDocument.create(oXML.responseText);
		var oGroup = oDoc.getElementsByTagName("group");
		var oMapSearchedFor = document.getElementById(this.sMapSearchedForId);
		if(oGroup.length || assocLength(this.aActiveBounds)) {
			if(oMapSearchedFor) {
				var sPlacename = "";
				var sPostcode = "";
				if(this.submitButton==1){
					sPlacename = this.getValue(this.sPlaceNameId);
				}else if(this.submitButton==2){
					sPostcode = this.getValue(this.sPostcodeId);
				}
				if(sPlacename) {
					oMapSearchedFor.innerHTML = "<p class=\"notify\">You're looking at all posts matching the phrase \"" + sPlacename  + "\"</p>";
				} else if(sPostcode) {
					oMapSearchedFor.innerHTML = "<p class=\"notify\">You're looking at all posts in the postcode \"" + sPostcode  + "\"</p>";
				} else {
					oMapSearchedFor.innerHTML = "<p class=\"notify\">You're looking at all posts in the \"UK\"</p>";
				};
			};
			for(var i = 0; i < oGroup.length; i++) {
				var sLat = oGroup[i].getAttribute("lat");
				var sLng = oGroup[i].getAttribute("lng");
				var oResults = oGroup[i].getElementsByTagName("result");
				if(oResults.length) {
					var aTabs = [];
					for(var j = 0; j < oResults.length; j++) {
						var sType = XMLDocument.getText(oResults[j].getElementsByTagName("type")[0].childNodes[0]);
						var sFile = XMLDocument.getText(oResults[j].getElementsByTagName("file")[0].childNodes[0]);
						var aFile = sFile.replace("_","x").split("x");
						var sMarker = "<div class=\"overlayTab\" style=\"background:#fff; " + (j == 0 && oResults.length > 2 ? " width:" + (oResults.length * 88) + "px;" : " width:254px;") + "\"><h3 style=\"margin-bottom:10px;\"><a href=\"/home/mycommunity/files/file/?fId=" + oResults[j].getAttribute("id") + "\" style=\"color:#fff;\">" + XMLDocument.getText(oResults[j].getElementsByTagName("title")[0].childNodes[0]) + "</a></h3><p style=\"css-float:left; width:230px;\"><img style=\"css-float:left; margin-right:10px; margin-bottom:5px;\" src=\"/wp-content/uploads/map/" + sType  + "/" + (sType == "video" ? "107x81_video_icon.png" : sFile) + "\" width=\"107\" height=\"" + ((107 / parseInt(aFile[0])) * parseInt(aFile[1])) + "\" alt=\"thumbnail\"/>" + XMLDocument.getText(oResults[j].getElementsByTagName("description")[0].childNodes[0]).substring(0, 150) + "......</p></div>";
			          	aTabs[j] = new GInfoWindowTab(XMLDocument.getText(oResults[j].getElementsByTagName("title")[0].childNodes[0]), sMarker);
					};
					this.addMarker(new GLatLng(sLat, sLng), aTabs);
				};
			};
		} else {
			if(oMapSearchedFor && !assocLength(this.aActiveBounds)) {
				oMapSearchedFor.innerHTML = "<p class=\"notify\">No-one has posted anything about your community yet.</p>"
			};
		};
		oDoc = null;
	};

	/**
	 * @description 	Centers location on map and calls redraw function
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		GPoint - Google map point
	 * @parameter 		Array - Tabs
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.addMarker = function(oPoint, aTabs) {
		var _self = this;
		var oMarker = new GMarker(oPoint);
  	    GEvent.addListener(oMarker, "click", function() {
  	    	_self.setActiveMarker(oMarker);
			_self.lat = oMarker;
			_self.aActiveBounds = _self.getBounds();
	        oMarker.openInfoWindowTabsHtml(aTabs);
		});
		this.aMarkers[this.aMarkers.length] = oMarker;
		this.map.addOverlay(this.aMarkers[this.aMarkers.length - 1]);
	};

	/**
	 * @description 	Set active marker
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		GMarker - Google marker
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.setActiveMarker = function(oMarker) {
		this.oActiveMarker = oMarker;
	};

	/**
	 * @description 	Gets bounds of map
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @return 			Array - Coordinates
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.getBounds = function() {
		var bounds = this.map.getBounds();
		var southWest = bounds.getSouthWest();
		var northEast = bounds.getNorthEast();
		var aBounds = [];
		aBounds["maxLng"] = northEast.lng();
		aBounds["minLng"] = southWest.lng();
		aBounds["maxLat"] = northEast.lat();
		aBounds["minLat"] = southWest.lat();
		return aBounds;
	};

	/**
	 * @description 	Checks if marker is in the bounds of the map
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		GMarker - Google marker
	 * @return	 		Boolean
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.isBoundedMarker = function(oMarker) {
		var aCoords = this.getPointAsArray(oMarker.getPoint());
		var aBounds = this.getBounds();
		if(aCoords["lng"] <= aBounds["maxLng"] && aCoords["lng"] >= aBounds["minLng"] && aCoords["lat"] <= aBounds["maxLat"] && aCoords["lat"] >= aBounds["minLat"]) {
			return true;
		};
		return false;
	};

	/**
	 * @description 	Remove specified markers from map
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		Array - Cached markers array
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.removeMarkersFromArray = function(aMarkers) {
		if(this.oActiveMarker) {
			if(!this.isBoundedMarker(this.oActiveMarker)) {
				this.map.closeInfoWindow();
			};
		};
		for(i = 0; i < aMarkers.length; i++) {
			if(aMarkers[i]!=this.oActiveMarker){
				this.map.removeOverlay(aMarkers[i]);
			}
		};
	};

	/**
	 * @description 	Returns points as array
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		GPoint - Google map point
	 * @return			Array - Coordinates
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.getPointAsArray = function(oPoint) {
		var aCoords = [];
		aCoords["lat"] = oPoint.lat();
		aCoords["lng"] = oPoint.lng();
		return aCoords;
	};

	/**
	 * @description 	Get DOM node value by id
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		String - ID
	 * @return			String - value
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.getValue = function(sId) {
		var oElement = document.getElementById(sId);
		if(oElement) {
			return oElement.value;
		};
		return "";
	};

	/**
	 * @description 	Set DOM node value by id
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		String - ID
	 * @parameter		String - value
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.setValue = function(sId, sValue) {
		var oElement = document.getElementById(sId);
		if(oElement) {
			oElement.value = sValue;
		};
	};

	/**
	 * @description 	For actions on submit
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @return			Boolean - hijacks request
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.addFormAction = function() {
		var _self = this;
		/* Track the Enter key for postcode search */
		document.getElementById('fMapPostcode').onkeydown = function(e){
			if(e){
				e = e
			} else {
				e = window.event
			}
			if(e.which){
				var keycode = e.which
			} else {
				var keycode = e.keyCode
			}

			if(keycode == 13) {
				document.getElementById('fPostcodeSubmit').click();
			}
		}
		/**/
		document.getElementById('fPlacenameSubmit').onclick = function(){
			_self.submitButton = 1;
		}
		document.getElementById('fPostcodeSubmit').onclick = function(){
			_self.submitButton = 2;
		}
		document.getElementById(this.sFormId).onsubmit = function() {

			var sPlacename = _self.getValue(_self.sPlaceNameId);
			if(_self.submitButton == 1){
				if(sPlacename != "") {
					_self.getPointsFromPlacename(sPlacename, _self.centerOnMap, _self);
				}
			}
			var sPostcode = _self.getValue(_self.sPostcodeId);
			if(_self.submitButton == 2){
				if(sPostcode != "") {
					_self.getPointsFromPostcode(sPostcode, _self.centerOnMap, _self);
				}
			}
			return false;
		};
	};

	/**
	 * @description 	Associates go to point with object event
	 * @author    		Peter Hammans - peter.hammans@precedent.co.uk
	 * @parameter 		DOM node - Link
	 * @parameter		Array - contains searched for data
	 * @date      		2007-05-22
	 */
	EKClientMap.prototype.addGoToPoint = function(oLink, aNode) {
		var _self = this;
		oLink.onmousedown = function() {
			_self.setValue(_self.sPlaceNameId, aNode["name"]);
			_self.centerOnMap(aNode, _self, 13);
		};
	};

	function isArray(oArray) {
		if(oArray.constructor.toString().indexOf("Array") == -1) {
			return false;
		} else {
			return true;
		};
	};


	//Start mapping!!
	var oEKClientMap = new EKClientMap();
	addWindowEvent(
		function() {
			oEKClientMap._load("mapSearchedFor", "fFormMapSearch", "fMapPlacename", "fMapPostcode", "GMessage");
			oEKClientMap.addFormAction();
		}
	);
