/*
 * 
 *
 * Tabbable Google Controls
 *
 * www.psycle.com
 * author-Lee Davies
 */
//http://dean.edwards.name/weblog/2006/06/again/

/*
Configuration information
*/


 var Defined={
	PERCENT_OF_WIDTH: 0.75,
	IMAGE_PATH : 'http://open2.net/open2static/google_maps/images/', //Path to image folder
	CONTROL_CLASSNAME:'control',//Class name for google map controls
	MAP_WIDTH: 650,
	NAMED_PIN_PREFIX: "pin",
	MAP_HEIGHT: 450
 };


/*
	ClusterMarker Version 1.3.0
	
	A marker manager for the Google Maps API
	http://googlemapsapi.martinpearman.co.uk/clustermarker
	
	Copyright Martin Pearman 2008
	Last updated 5th March 2008

	This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along with this program.  If not, see <http://www.gnu.org/licenses/>.
	
*/

function ClusterMarker($map, $options){
	this._map=$map;
	this._mapMarkers=[];
	this._iconBounds=[];
	this._clusterMarkers=[];
	this._eventListeners=[];
	this.handle=[];

	if(typeof($options)==='undefined'){
		$options={};
	}
	this.borderPadding=($options.borderPadding)?$options.borderPadding:256;
	this.clusteringEnabled=($options.clusteringEnabled===false)?false:true;
	if($options.clusterMarkerClick){
		this.clusterMarkerClick=$options.clusterMarkerClick;
	}
	if($options.clusterMarkerIcon){
		this.clusterMarkerIcon=$options.clusterMarkerIcon;
	}else{
		this.clusterMarkerIcon=new GIcon();
		this.clusterMarkerIcon.image='http://open2.net/open2static/google_maps/images/icons/aggregate.png';
		this.clusterMarkerIcon.iconSize=new GSize(39, 34);
		this.clusterMarkerIcon.iconAnchor=new GPoint(19, 34);
		this.clusterMarkerIcon.infoWindowAnchor=new GPoint(19, 34);
	}
	this.clusterMarkerTitle=($options.clusterMarkerTitle)?$options.clusterMarkerTitle:'Click to zoom in and see %count markers';
	if($options.fitMapMaxZoom){
		this.fitMapMaxZoom=$options.fitMapMaxZoom;
	}
	this.intersectPadding=($options.intersectPadding)?$options.intersectPadding:0;
	if($options.markers){
		this.addMarkers($options.markers);
	}
	this.handle.push(GEvent.bind(this._map, 'moveend', this, this._moveEnd));
	this.handle.push(GEvent.bind(this._map, 'zoomend', this, this._zoomEnd));
	this.handle.push(GEvent.bind(this._map, 'maptypechanged', this, this._mapTypeChanged));
}

ClusterMarker.prototype.addMarkers=function($markers){
	var i;
	if(!$markers[0]){
		//	assume $markers is an associative array and convert to a numerically indexed array
		var $numArray=[];
		for(i in $markers){
			$numArray.push($markers[i]);
		}
		$markers=$numArray;
	}
	for(i=$markers.length-1; i>=0; i--){
		$markers[i]._isVisible=false;
		$markers[i]._isActive=false;
		$markers[i]._makeVisible=false;
	}
	this._mapMarkers=this._mapMarkers.concat($markers);
};

ClusterMarker.prototype._clusterMarker=function($clusterGroupIndexes){
	function $newClusterMarker($location, $icon, $title){
		return new GMarker($location, {icon:$icon, title:$title});
	}
	var $clusterGroupBounds=new GLatLngBounds(), i, $clusterMarker, $clusteredMarkers=[], $marker, $this=this;
	for(i=$clusterGroupIndexes.length-1; i>=0; i--){
		$marker=this._mapMarkers[$clusterGroupIndexes[i]];
		$marker.index=$clusterGroupIndexes[i];
		$clusterGroupBounds.extend($marker.getLatLng());
		$clusteredMarkers.push($marker);
	}
	$clusterMarker=$newClusterMarker($clusterGroupBounds.getCenter(), this.clusterMarkerIcon, this.clusterMarkerTitle.replace(/%count/gi, $clusterGroupIndexes.length));
	$clusterMarker.clusterGroupBounds=$clusterGroupBounds;	//	only req'd for default cluster marker click action
	this._eventListeners.push(GEvent.addListener($clusterMarker, 'click', function(){
		$this.clusterMarkerClick({clusterMarker:$clusterMarker, clusteredMarkers:$clusteredMarkers });
	}));
	return $clusterMarker;
};

ClusterMarker.prototype.clusterMarkerClick=function($args){
	this._map.setCenter($args.clusterMarker.getLatLng(), this._map.getBoundsZoomLevel($args.clusterMarker.clusterGroupBounds));
};

ClusterMarker.prototype.removeEvents=function(){
	for (var i = 0; i < this.handle.length; i++) {
		GEvent.removeListener(this.handle[i]);
	}
};

ClusterMarker.prototype._filterActiveMapMarkers=function(){
	var $borderPadding=this.borderPadding, $mapZoomLevel=this._map.getZoom(), $mapProjection=this._map.getCurrentMapType().getProjection(), $mapPointSw, $activeAreaPointSw, $activeAreaLatLngSw, $mapPointNe, $activeAreaPointNe, $activeAreaLatLngNe, $activeAreaBounds=this._map.getBounds(), i, $marker, $uncachedIconBoundsIndexes=[], $oldState;
	if($borderPadding){
		$mapPointSw=$mapProjection.fromLatLngToPixel($activeAreaBounds.getSouthWest(), $mapZoomLevel);
		$activeAreaPointSw=new GPoint($mapPointSw.x-$borderPadding, $mapPointSw.y+$borderPadding);
		$activeAreaLatLngSw=$mapProjection.fromPixelToLatLng($activeAreaPointSw, $mapZoomLevel);
		$mapPointNe=$mapProjection.fromLatLngToPixel($activeAreaBounds.getNorthEast(), $mapZoomLevel);
		$activeAreaPointNe=new GPoint($mapPointNe.x+$borderPadding, $mapPointNe.y-$borderPadding);
		$activeAreaLatLngNe=$mapProjection.fromPixelToLatLng($activeAreaPointNe, $mapZoomLevel);
		$activeAreaBounds.extend($activeAreaLatLngSw);
		$activeAreaBounds.extend($activeAreaLatLngNe);
	}
	this._activeMarkersChanged=false;
	if(typeof(this._iconBounds[$mapZoomLevel])==='undefined'){
		//	no iconBounds cached for this zoom level
		//	no need to check for existence of individual iconBounds elements
		this._iconBounds[$mapZoomLevel]=[];
		this._activeMarkersChanged=true;	//	force refresh(true) as zoomed to uncached zoom level
		for(i=this._mapMarkers.length-1; i>=0; i--){
			$marker=this._mapMarkers[i];
			$marker._isActive=$activeAreaBounds.containsLatLng($marker.getLatLng())?true:false;
			$marker._makeVisible=$marker._isActive;
			if($marker._isActive){
				$uncachedIconBoundsIndexes.push(i);
			}
		}
	}else{
		//	icondBounds array exists for this zoom level
		//	check for existence of individual iconBounds elements
		for(i=this._mapMarkers.length-1; i>=0; i--){
			$marker=this._mapMarkers[i];
			$oldState=$marker._isActive;
			$marker._isActive=$activeAreaBounds.containsLatLng($marker.getLatLng())?true:false;
			$marker._makeVisible=$marker._isActive;
			if(!this._activeMarkersChanged && $oldState!==$marker._isActive){
				this._activeMarkersChanged=true;
			}
			if($marker._isActive && typeof(this._iconBounds[$mapZoomLevel][i])==='undefined'){
				$uncachedIconBoundsIndexes.push(i);
			}
		}
	}
	return $uncachedIconBoundsIndexes;
};

ClusterMarker.prototype._filterIntersectingMapMarkers=function(){
	var $clusterGroup, i, j, $mapZoomLevel=this._map.getZoom();
	for(i=this._mapMarkers.length-1; i>0; i--)
	{
		if(this._mapMarkers[i]._makeVisible){
			$clusterGroup=[];
			for(j=i-1; j>=0; j--){
				if(this._mapMarkers[j]._makeVisible && this._iconBounds[$mapZoomLevel][i].intersects(this._iconBounds[$mapZoomLevel][j])){
					$clusterGroup.push(j);
				}
			}
			if($clusterGroup.length!==0){
				$clusterGroup.push(i);
				for(j=$clusterGroup.length-1; j>=0; j--){
					this._mapMarkers[$clusterGroup[j]]._makeVisible=false;
				}
				this._clusterMarkers.push(this._clusterMarker($clusterGroup));
			}
		}
	}
};

ClusterMarker.prototype.fitMapToMarkers=function(){
	var $markers=this._mapMarkers, $markersBounds=new GLatLngBounds(), i;
	for(i=$markers.length-1; i>=0; i--){
		$markersBounds.extend($markers[i].getLatLng());
	}
	var $fitMapToMarkersZoom=this._map.getBoundsZoomLevel($markersBounds);
		
	if(this.fitMapMaxZoom && $fitMapToMarkersZoom>this.fitMapMaxZoom){
		$fitMapToMarkersZoom=this.fitMapMaxZoom;
	}
	this._map.setCenter($markersBounds.getCenter(), $fitMapToMarkersZoom);
	this.refresh();
};

ClusterMarker.prototype._mapTypeChanged=function(){
	this.refresh(true);
};

ClusterMarker.prototype._moveEnd=function(){
	if(!this._cancelMoveEnd){
		this.refresh();
	}else{
		this._cancelMoveEnd=false;
	}
};

ClusterMarker.prototype._preCacheIconBounds=function($indexes){
	var $mapProjection=this._map.getCurrentMapType().getProjection(), $mapZoomLevel=this._map.getZoom(), i, $marker, $iconSize, $iconAnchorPoint, $iconAnchorPointOffset, $iconBoundsPointSw, $iconBoundsPointNe, $iconBoundsLatLngSw, $iconBoundsLatLngNe, $intersectPadding=this.intersectPadding;
	for(i=$indexes.length-1; i>=0; i--){
		$marker=this._mapMarkers[$indexes[i]];
		$iconSize=$marker.getIcon().iconSize;
		$iconAnchorPoint=$mapProjection.fromLatLngToPixel($marker.getLatLng(), $mapZoomLevel);
		$iconAnchorPointOffset=$marker.getIcon().iconAnchor;
		$iconBoundsPointSw=new GPoint($iconAnchorPoint.x-$iconAnchorPointOffset.x-$intersectPadding, $iconAnchorPoint.y-$iconAnchorPointOffset.y+$iconSize.height+$intersectPadding);
		$iconBoundsPointNe=new GPoint($iconAnchorPoint.x-$iconAnchorPointOffset.x+$iconSize.width+$intersectPadding, $iconAnchorPoint.y-$iconAnchorPointOffset.y-$intersectPadding);
		$iconBoundsLatLngSw=$mapProjection.fromPixelToLatLng($iconBoundsPointSw, $mapZoomLevel);
		$iconBoundsLatLngNe=$mapProjection.fromPixelToLatLng($iconBoundsPointNe, $mapZoomLevel);
		this._iconBounds[$mapZoomLevel][$indexes[i]]=new GLatLngBounds($iconBoundsLatLngSw, $iconBoundsLatLngNe);
	}
};

ClusterMarker.prototype.refresh=function($forceFullRefresh){
	var i,$marker, $uncachedIconBoundsIndexes=this._filterActiveMapMarkers();
	if(this._activeMarkersChanged || $forceFullRefresh){
		this._removeClusterMarkers();
		if(this.clusteringEnabled && this._map.getZoom()<this._map.getCurrentMapType().getMaximumResolution()){
			if($uncachedIconBoundsIndexes.length>0){
				this._preCacheIconBounds($uncachedIconBoundsIndexes);
			}
			this._filterIntersectingMapMarkers();
		}
		for(i=this._clusterMarkers.length-1; i>=0; i--){
			this._map.addOverlay(this._clusterMarkers[i]);
		}
		for(i=this._mapMarkers.length-1; i>=0; i--){
			$marker=this._mapMarkers[i];
			if(!$marker._isVisible && $marker._makeVisible){
				this._map.addOverlay($marker);
				$marker._isVisible=true;
			}
			if($marker._isVisible && !$marker._makeVisible){
				this._map.removeOverlay($marker);
				$marker._isVisible=false;
			}
		}
	}
};

ClusterMarker.prototype._removeClusterMarkers=function(){
	for(var i=this._clusterMarkers.length-1; i>=0; i--){
		this._map.removeOverlay(this._clusterMarkers[i]);
	}
	for(i=this._eventListeners.length-1; i>=0; i--){
		GEvent.removeListener(this._eventListeners[i]);
	}
	this._clusterMarkers=[];
	this._eventListeners=[];
};

ClusterMarker.prototype.removeMarkers=function(){
	for(var i=this._mapMarkers.length-1; i>=0; i--){
		if(this._mapMarkers[i]. _isVisible){
			this._map.removeOverlay(this._mapMarkers[i]);
		}
		delete this._mapMarkers[i]._isVisible;
		delete this._mapMarkers[i]._isActive;
		delete this._mapMarkers[i]._makeVisible;
	}
	this._removeClusterMarkers();
	this._mapMarkers=[];
	this._iconBounds=[];
};


ClusterMarker.prototype.triggerClick=function($index){
	var $marker=this._mapMarkers[$index];
	if($marker._isVisible){
		//	$marker is visible
		GEvent.trigger($marker, 'click');
	}
	else if($marker._isActive){
		//	$marker is clustered
		this._map.setCenter($marker.getLatLng());
		this._map.zoomIn();
		this.triggerClick($index);
	}else{
		// $marker is not within active area (map bounds + border padding)
		this._map.setCenter($marker.getLatLng());
		this.triggerClick($index);
	}
};

ClusterMarker.prototype._zoomEnd=function(){
	this._cancelMoveEnd=true;
	this.refresh(true);
};



/**
 * Psycle Tabbable areas
 * 
 * The following code injects links into the google map controls so they are tabbable
 */

function TabbableControl(element){
	this.map=element;
	this.items;
	this.noElements=7;
	this.panPercentage=0.5;

}
TabbableControl.prototype={
	register:function(element,type,func) {
		if (element.addEventListener) 
			element.addEventListener(type, func, false);
		else 
			element.attachEvent('on' + type, func)	;
	},
	attachEvents:function(items){
		//Make links clickable. When clicked the parent catches event
		for(var i=0;i<items.length;i++){
			register(items[i],"click",function(){});
		}
	},
	insertImages:function(items){
		var img=new Array("transUp.gif","transLeft.gif","transRight.gif","transDown.gif","transReset.gif","transZoomIn.gif","transZoomOut.gif");
		
		for(var i=0;i<img.length;i++){
				items[i].firstChild.firstChild.src=Defined.IMAGE_PATH+img[i];
			}
	},

	
//Add tabbable element to each control element
	tabControl:function(items){
		//Place tabbable links into control div's and assign id
		var id=new Array("panUp","panLeft","panRight","panDown","center_result","zoomIn","zoomOut");
		
        for(var i=0;i<id.length;i++){
	        	var a=this.createAnchor(id[i]);
	        	this.items[i].appendChild(a);	 
	        	this.items[i].style.hasLayout="true" ;
	        	this.items[i].style.filter=null;
				this.items[i].style.height="17px";
				this.items[i].style.width="17px";
        }
		this.items[0].parentNode.id="aControl";
	},
	findControls:function(){

		//Find controls that need to be tabbable
		var titles = new Array("Pan up","Pan left","Pan right","Pan down","Return to the last result","Zoom In","Zoom Out");
		var items = new Array();
		
		jQuery.each(titles, function() {
			var div = $("div[title='" + this + "']");
			div[0].className = Defined.CONTROL_CLASSNAME;
			items.push(div[0]);
      return true;
    });
    
    this.items = items;
	},
	
	
	createAnchor:function(name){
		//Create tabbable links to be inserted into control div's
		var a=document.createElement("a");
		var img=document.createElement("img");
	    a.id=name;
	    a.className="controlAnchor";
	    a.setAttribute("href","javascript:void(0);");
	    a.innerHTML="";
	    a.style.hasLayout="true";
	    this.setStyle(a);
    	img.style.borderStyle="none";
    	img.setAttribute("height","17px");
		img.setAttribute("width","17px");
		img.style.display="block";
	    a.appendChild(img);
	    return a;
	},
	setStyle:function(a){
		a.style.display="block";
		a.style.position="absolute";
		a.style.height="17px";
		a.style.width="17px";
		a.style.backgroundColor="white";
	},
	makeTabbable:function(){
		this.findControls();
		this.tabControl(this.items);
		this.insertImages(this.items);
		for(var i=0;i<this.items.length;i++)
			this.items[i].pos=i;
	}
};
Events ={
	register:function(element,type,func) {
		if (element.addEventListener) 
			element.addEventListener(type, func, false);
		else 
			element.attachEvent('on' + type, func);
	}
};

function TabbableMapView(element){
 	this.items=new Array();
	this.map=element;
	this.t=9;
	var obj;
		
}


TabbableMapView.prototype={
	tabbableMapView:function(){
		var element=document.getElementById("amtc_option_0");
		if(element){
			element.parentNode.id="mapView";
			this.parent=element.parentNode;
		    this.mapView("amtc_option_0","mapButton");
			this.mapView("amtc_option_1","satellite");
			this.mapView("amtc_option_2","hybrid");

		}
		else{
			this.checkDomLoad();
		}
	
	},

	loadObject:function(){
		obj.tabbableMapView();
	},

	checkDomLoad:function(){
		obj=this;
		setTimeout(obj.loadObject, 500);
	},

	mapView:function(id,newId){
		//Create links
		//Inject links into map view div's
		var mapButton=document.getElementById(id);
		mapButton=mapButton.firstChild;
		mapButton.className=Defined.CONTROL_CLASSNAME;
		this.items.push(mapButton);
		var a=document.createElement('a');
	    a.id=newId;
	   	a.setAttribute("href","javascript:void(0);");
	    a.innerHTML=mapButton.innerHTML;
	    this.setStyle(a);
	    mapButton.innerHTML="";
	    mapButton.appendChild(a) ;  
	},
	setStyle:function(a){
		a.style.textDecoration="none";
		a.style.color="black";
		a.style.display="block";
		a.style.width="100%";
		a.style.height="100%";
	}

};



function sortTabOrder(element){
	var terms=element.childNodes[1];
	var googleLink=element.childNodes[2];
	element.removeChild(terms);//Remove terms
	element.removeChild(googleLink);//Remove google link
	element.appendChild(googleLink);
	element.appendChild(terms);
}

var MapSettings={
	setMapDimensions:function(element) {
		var height=Defined.MAP_HEIGHT;
		var width=Defined.MAP_WIDTH;
		var mapPoints = document.getElementById("mapLocations");

		for (var i = 0; i < mapPoints.childNodes.length; i++) {
			if(mapPoints.childNodes[i].className=="param"){
			
				var param=mapPoints.childNodes[i];
				for(var z=0;z<param.childNodes.length;z++){
					
					if(param.childNodes[z].className=="mapHeight")
						height=param.childNodes[z].innerHTML;
						
					if(param.childNodes[z].className=="mapWidth")
					
						width=param.childNodes[z].innerHTML;
					
				}
			}
			
		}
		
		this.setMapSize(element,height,width);
		return width;
	},
	
	setMapView:function(param,map){	
		for(var z=0;z<param.childNodes.length;z++){
			if(param.childNodes[z].className=="view"){
				switch (param.childNodes[z].innerHTML){
					case "Satellite":
						map.setMapType(G_SATELLITE_MAP);
					break;
					case "Map":
						map.setMapType(G_NORMAL_MAP);
					break;
					case "Hybrid":
						map.setMapType(G_HYBRID_MAP);
					break;
					default:
						map.setMapType(G_NORMAL_MAP);
					break;
				}
				
			}
		}
	},
	setInitZoom:function(param,map){	
		var zoom=-1;
		for(var z=0;z<param.childNodes.length;z++){
			if(param.childNodes[z].className=="mapZoom"){
				zoom=param.childNodes[z].innerHTML;
				if(zoom.toLowerCase()=="auto")
					return -1;
				zoom=parseInt(zoom);
				if(zoom>17||zoom<0||isNaN(zoom))
					zoom=11;
			}
		}
		return zoom;
		
	},
	
	setInitCenter:function(param,obj){	
		for(var z=0;z<param.childNodes.length;z++){
			if(param.childNodes[z].className=="lat"){
				obj.lat=param.childNodes[z].innerHTML;
			}
			if(param.childNodes[z].className=="lng"){
				obj.lng=param.childNodes[z].innerHTML;
			}
			
		}	
	},
	setMapSize:function(element,height,width){
		var element=document.getElementById("map");
		element.style.width=width+"px";
		element.style.height=height+"px";
	}
};
/*
The following code parse's the document for the marker information and then genrates the marker
*/

function MarkerGenerator(map,width){
	this.lng='';
	this.lat='';
	this.map=map;
	this.mapMarker=new Array();
	this.mapBounds=new GLatLngBounds();
	this.points=new Array();
	this.width=width;
	this.zoom=-1;
}
MarkerGenerator.prototype={

	//Parse doc for marker info and param
	parseDOMforMapDataAndPlot:function(edit) {
		
		var mapPoints = document.getElementById("mapLocations");
		for (var i = 0; i < mapPoints.childNodes.length; i++) {
			if(mapPoints.childNodes[i].className=="mapItem"){
				var mapItem=mapPoints.childNodes[i];
				var mapMarker=new Marker(edit);	
				for (var x = 0; x < mapItem.childNodes.length; x++){
					
					if(mapItem.childNodes[x].className=="title"){
						var titleElement=mapItem.childNodes[x];
						this.getTarget(titleElement,mapMarker);
					}
					//Get content for marker
					if(mapItem.childNodes[x].className=="content"){
						var content=mapItem.childNodes[x];
						mapMarker.content=content.innerHTML;
					}
					//Get co-ordinates for marker
					if(mapItem.childNodes[x].className=="param"){
						var param=mapItem.childNodes[x];
						this.getParam(mapMarker,param);
					}
				
				}
				this.mapMarker.push(mapMarker);
			}
			//Get param to set initial map view
			if(mapPoints.childNodes[i].className=="param"){
				var param=mapPoints.childNodes[i];
				MapSettings.setMapView(param,this.map);
				MapSettings.setInitCenter(param,this);
				var zoom = MapSettings.setInitZoom(param,this.map);
				if (zoom > -1) this.zoom = zoom;
			}
		}
		this.checkMarkerContent();
		this.generateMarkers();
		this.adjustView();
		return this.mapMarker;
		
	},
	checkMarkerContent:function(){
		for (var i = 0; i < this.mapMarker.length; i++) {
			this.mapMarker[i].content=this.mapMarker[i].checkMarkerContent(this.mapMarker[i].content);
		}
	},
	//Generate each marker 
	generateMarkers:function(param){
		for (var i = 0; i < this.mapMarker.length; i++) {
			var point=this.mapMarker[i].generateMarker(this.map,this.width);
			if(point){
				this.mapBounds.extend(point);
				this.points.push(point);
			}
		}
	},
	
	// Add a marker
	addMarker:function(title, content, lat, lng, zoom, image) {
		var mapMarker = new Marker(false);	
		mapMarker.title = title;
		mapMarker.content = content;
		mapMarker.lat = lat;
		mapMarker.lng = lng;
		mapMarker.zoom = zoom;
		mapMarker.image = image;
		this.mapMarker.push(mapMarker);
		mapMarker.target = {marker:null};
		mapMarker.registerEvent = false;
		mapMarker.generateMarker(this.map,this.width);
		
		return mapMarker.target.marker;
	},	
	
	//Get the parameters from the doc
	getParam:function(mapMarker,param){
		for(var z=0;z<param.childNodes.length;z++){
			
			if(param.childNodes[z].className=="lat")
				mapMarker.lat=mapPointLatitude=param.childNodes[z].innerHTML;
	
			if(param.childNodes[z].className=="lng")
				mapMarker.lng=mapPointLongitude=param.childNodes[z].innerHTML;
			
			if(param.childNodes[z].className=="zoom")
				mapMarker.zoom=param.childNodes[z].innerHTML;	
			
			if(param.childNodes[z].className=="image")
				if (param.childNodes[z].innerHTML != "") mapMarker.image=param.childNodes[z].innerHTML;
		}
	},
	

	adjustView:function() {
		if((this.lat==''||this.lng=='')||this.zoom<0){
			this.map.setZoom(this.map.getBoundsZoomLevel(this.mapBounds));
			var clat = (this.mapBounds.getNorthEast().lat() +this.mapBounds.getSouthWest().lat()) /2;
			var clng = (this.mapBounds.getNorthEast().lng() + this.mapBounds.getSouthWest().lng()) /2;
			this.map.setCenter(new GLatLng(clat,clng));
		}
		else{
			this.map.setCenter(new GLatLng(this.lat,this.lng));
			this.map.setZoom(this.zoom);
		}
			
	},
	//Get the target link in doc
	//The target link when clicked will open a marker in the 
	//google map.
	getTarget:function(titleElement,mapMarker){
		
		var anchor=this.checkLinkName(mapMarker,titleElement);
		if(anchor){
			anchor.setAttribute("href","javascript:void(0);");
			if(mapMarker.name)
				anchor.id=mapMarker.name;
			mapMarker.target=anchor;
			mapMarker.title=mapMarker.title;
		}
		
	},
	findHeadingTag:function(titleElement){
		if(titleElement.childNodes){
			for (var i = 0; i <titleElement.childNodes.length; i++){
				if(titleElement.childNodes[i].tagName){
					var name=titleElement.childNodes[i].tagName;
					name=name.toLowerCase();
					if(name.charAt(0)=="h")
						return titleElement.childNodes[i];	
				}
			
			}
		}
		return false;
	},
	checkLinkName:function(mapMarker,titleElement){
		if(titleElement.childNodes){
		for (var i = 0; i <titleElement.childNodes.length; i++)
			if(titleElement.childNodes[i].tagName=="A"){
				mapMarker.name=titleElement.childNodes[i].getAttribute("ID");
				mapMarker.title=titleElement.childNodes[i].innerHTML;
				return titleElement.childNodes[i];	
			}
		}
		return false;
	},
	removeMarkers:function(){
		for (var i = 0; i < this.mapMarker.length; i++) {
			this.map.removeOverlay(this.mapMarker[i].target.marker);
			GEvent.removeListener(this.mapMarker[i].handle);
			this.mapMarker[i]=null;
		}
		
		this.mapMarker = new Array();
	}
};


function Marker(edit){
	this.lat=null;
	this.lng=null;
	this.zoom=null;
	this.content=null;
	this.title=null;
	this.target=null;
	this.name=null;
	this.image='Standard';
	this.edit=edit;
	this.handle=null;
	this.registerEvent = true;
}
Marker.prototype={
	//Generate information for marker
	generateMarker:function(map,width){
		if(this.lat!=null && this.lng!=null && this.target!=null){
			// add the point from a longitude and latitude
			var point = new GLatLng(this.lat, this.lng);
			var marker=this.createMarker(point,map,width);
			this.target.marker=marker;
			this.target.linkName=this.name;
			this.target.zoom=this.zoom;
			this.target.map=map;
			if (this.registerEvent) Events.register(this.target,'click',this.linkToMarker);
			return point;
		}
		return null;
	},
	checkMarkerContent:function(content){
		var pattern=/href=\"#pin(\d+)\"/g;
		return content.replace(pattern,"href=\"javascript:void(0);\" onclick=\"Marker.prototype.openMarker($1)\"");
		
	},
	openMarker:function(name){
		target=document.getElementById(Defined.NAMED_PIN_PREFIX+name);
		if(target){
			if(target.linkName==Defined.NAMED_PIN_PREFIX+name){
				var zoom=parseInt(target.zoom);
				if(zoom>17||isNaN(zoom))
					zoom=11;
				if(target.marker){
					if (zoom > 0) target.map.setZoom(zoom);
					GEvent.trigger(target.marker,"click");
				}
			}
		}
	
	},
	
	
	//Create marker
	createMarker:function(point,map,width) {
		var icon = this.createIcon();
		markerOptions = { icon:icon };
		var marker = new GMarker(point,markerOptions);
	  	marker.content=this.title+this.content;
	  	marker.zoom=this.zoom;
	  	marker.map=map;
	  	// Create our "tiny" marker icon
			if(!this.edit){
		  	this.handle=GEvent.addListener(marker, "click", function() {
		 	var zoom=parseInt(marker.zoom);
			if(zoom>17||isNaN(zoom))
				zoom=11;
			if (zoom > 0) marker.map.setZoom(zoom);
	    marker.openInfoWindowHtml(marker.content,{maxWidth:Defined.PERCENT_OF_WIDTH*width});
		    	
		  	});
	  	}
		
	  return marker;
	},
	
	createIcon:function(){
	 	var icon=new GIcon();
		icon.image = Defined.IMAGE_PATH+"icons/"+this.image+".png";
        icon.shadow = Defined.IMAGE_PATH+"/icons/shadow.png";   
        icon.shadowSize= new GSize(52, 29);    
        icon.iconSize = new GSize(21, 31);
       	icon.iconAnchor = new GPoint(11, 31);
		icon.infoWindowAnchor = new GPoint(11, 31);
		return icon;
	},
	
	
	//Uses target link from doc to save information for the marker
	//This allows the link to be clicked and then use the target saved information
	//to open the marker.
	linkToMarker:function(event){
			if(event.target)
				event.srcElement=event.target;
			
			var target=event.srcElement.parentNode;
			var zoom=parseInt(target.zoom);
			if(zoom>17||zoom<0||zoom==NaN)
				zoom=11;
			if(target.marker){
				target.map.setZoom(zoom);
				GEvent.trigger(target.marker,"click");
			}
	}
	
};


/**
 * The following function loads the google map (standard, CMS-delivered) and all the required functions
 */
function load() {
	if (GBrowserIsCompatible()) {
		// This creates an instance of the map and positions it at the
		// div tag id="map" within the body of the HTML.
		// The size of the map is defined by the boundary of the div tag.
		var element=document.getElementById("map");
		var width=MapSettings.setMapDimensions(element);
		var map = new GMap2(document.getElementById("map"));
		
		// Creates a subclass of GLargeMapControl(), the subclass is tabbable
		var mapControl=new TabbableControl(element);
		
		// adds the "Normal", "Satellite", and "Hybrid" view buttons within the map
		map.addControl(new GLargeMapControl());
		map.addControl(new GMapTypeControl());
		
		var tabMapView=new TabbableMapView(element);
		tabMapView.tabbableMapView();
		sortTabOrder(element);
		
		// This centers the map on 0,0 at the maximum zoom out level.
		// The coordinates are (latitude, longitude).
		// The zoom level is from 0 to 17, with 0 being zoomed out, and 17 being zoomed in.
		map.setCenter(new GLatLng(0,0),0);
		
		// Parse li in page for marker info
		map.markerGenerater= new MarkerGenerator(map,width);
		map.markersArray=new Array();
		tempArray=map.markerGenerater.parseDOMforMapDataAndPlot(false);
		
		for (var i = 0; i < tempArray.length; i++) {
			map.markersArray[i]=tempArray[i].target.marker;
		}
		
		map.cluster=new ClusterMarker(map, { markers:map.markersArray } );
		map.cluster.refresh();
		
		$(document).ready(function () {
			mapControl.makeTabbable();
		});
	}
};

/**
 * The following function loads the google map (user-generated pins / AJAX PHP) and all the required functions
 */
function loadUserMap() {
	if (GBrowserIsCompatible()) {
		// This creates an instance of the map and positions it at the
		// div tag id="map" within the body of the HTML.
		// The size of the map is defined by the boundary of the div tag.
		
		var element=document.getElementById("map");
		var width=MapSettings.setMapDimensions(element);
		map = new GMap2(document.getElementById("map"));

		// Creates a subclass of GLargeMapControl(), the subclass is tabbable
		var mapControl=new TabbableControl(element);
		
		// adds the "Normal", "Satellite", and "Hybrid" view buttons within the map
		map.addControl(new GLargeMapControl());
		map.addControl(new GMapTypeControl());
		
		var tabMapView=new TabbableMapView(element);
		tabMapView.tabbableMapView();
		sortTabOrder(element);
		
		// This centers the map on 0,0 at the maximum zoom out level.
		// The coordinates are (latitude, longitude).
		// The zoom level is from 0 to 17, with 0 being zoomed out, and 17 being zoomed in.
		var center = new GLatLng(0, 0);
		map.setCenter(center, 0);
		
		// Parse li in page for marker and map info
		map.markerGenerater= new MarkerGenerator(map,width);
		map.markersArray=new Array();
		tempArray=map.markerGenerater.parseDOMforMapDataAndPlot(false);
		
		for (var i = 0; i < tempArray.length; i++) {
			map.markersArray[i]=tempArray[i].target.marker;
		}
		
		map.cluster=new ClusterMarker(map, { markers:map.markersArray } );
		map.cluster.refresh();
	}
};

/**
 * Initialise the map
 **/
 
function init() {
	// quit if this function has already been called
	if (arguments.callee.done) return;
	
	// flag this function so we don't do the same thing twice
	arguments.callee.done = true;
	
	// create the "page loaded" message
	load();
	var body=document.getElementsByTagName("body");
	Events.register(body[0],'unload',GUnload);
}

if (typeof mapMode !== 'undefined' && (mapMode == "userMap" || mapMode == "userEditableMap")) {
	// For the UGC Google Maps, we can't use addLoadEvent because it only triggers once - we need it to 
	// trigger every time we load the JS file
	if (mapMode == "userMap") loadUserMap();
	else if (mapMode == "userEditableMap") loadUserEditableMap();

	var body=document.getElementsByTagName("body");
	Events.register(body[0],'unload',GUnload);
} else {
	// For the standard Google map, we trigger after page has finished loading
	addLoadEvent(init);
}

