// $Author: root $
// $Revision: 1.7 $
// $Date: 2007/10/15 01:05:58 $
// Main Javascript file

// Called on load of the body
function onBodyLoad(){
	templateMode = false;
	doneLoading();
}

// Called once screen is set up, XINHA loaded etc.
function doneLoading(){
		pullFromPHP();	// pull needed data (settings, user profile etc from PHP
		initMap();		// start Google Maps API related stuff
}

// called to init JS vars etc needed for GP
function initJS(){
	/*
	InitJS - Stuff in here that is not to do inherently with GP Map functionality goes in here
	the idea is that if you want to edit layout and stuff, gp.php can be renamed to a .html (comment out the PHP)
	and opened in an HTML editor.
	*/
	// ================================== INIT GLOBALS START ==============================
	shiftMode = false; // if true the shift key is down
	ctrlMode = false; // if true the ctrl key is down
	altMode = false; // if true the alt key is down 
	
	newapi=true;		// was set to false for V1 of the API
	
	// UID Variables - Used to enable discarding of old AJAX replies
	mainUID = 0;		// holds ID for main AJAX request. 
	infoUID = 0;		// holds ID for infowindow AJAX request.
	editUID = 0;		// holds ID for click icon in edit mode AJAX request.
	defaultZoom = 16;

	// ============ MARKERS, LINES & ICONS ===============
	markers = new Array();		// markers array - an array of GMarkers
	polylines = new Array();		// polylines array - an array of GPolylines
	icons = new Array();	// holds the main icons
	// icon array can be accessed like:
	addmarker = false;	// global var holds marker object of point being added / edited
	midmarkers=new Array();
	endmarker=false;		// endmarker of the line being edited
	editpolys=false;		// global var holds polyline object for edit line
	regrabPoly=false;	// holds the re-grab (green) box
	cachePoly=false;	// holds the cache (red) box
	lastClicked=-1;
	addrMarker=null;
	location_group_1_Y=0;
	location_group_2_Y=0;
	infoBoxY=0;
	viewportY=$('pat_locations').getHeight();
	// ============ Setup bitmasks ===============
	FREE_PARKING=1;
	NO_PARKING=2;
	METER=4;
	PERMIT=8;
	GARAGE_OPEN=16;
	GARAGE_CLOSE=32;
	p_mask=FREE_PARKING | METER | PERMIT | GARAGE_OPEN;

/* THC ***
	// Edit location items
	selected_location=false;	// set to the location_id (db index) of the existing location being edited
	selected_overlay=false;	// copy of overlay if it needs to go global
	clicked_overlay=false;	// copy of last clicked overlay (For view mode)

	editpath=new Array();	// editpath is an important variable, it holds the point(s) of anything being edited
	editmovr=new Array();	// editmovr is an array of editpath style arrays holding segments of the region mouseover being edited
	
	// It holds arrays of GlatLngs, so editpath[0].lng() is the lng of the first item, editpath[0].lat() is the lat of the first item
	// in line mode, index 0 is the first point of the proposed new line, index 1 the second, etc...
	hiddenEditMarker = false;	// If editing a marker, a copy of the markers entry in the markers[] array is put in here.

	regionmoline=false;		// GPolyline object of the region mouseover currently being displayed.
*** */

	// ========================== COORDINATE HOLDING GLOBALS ===================
	last_center=false;	// last centre of the map. used to determine if map actually moved during mapmoved event. Clicking will call mapmoved as well as dragging...
	last_bounds=false;	// The bounds the last time the map was dragged. If we get up to 2 screens away, then when map is dragged, if new map centre
						// is within these bounds, no real need to grab points again. Saves on server traffic.
						// todo: Plot a polyline showing the last_bounds box in green and the edged of the cached area (2 screens away) as red
						// then the user knows if they drag inside the green box no refresh is needed. and they will also know no points will be showing
						// outside the red box.
	last_zoom=false;	// the last zoom level
	cacheBounds=false;	// holds the bounds to pull points from
	grabBounds=false;	// if the center moves outside these bounds, re-grab
	grabScale=.75;	// grab area as a factor of the bounds area
	cacheScale=.75; // how many screens worth to grab (0= just what is on screen, 1 = one extra screen, 2 = 2 extra screens)
	
	// ====================== VIEW HISTORY RELATED GLOBALS ===================
	view_history = [];	// view history is an array of previous locations. Sort of like a browser history
	zoomThrough=false;	// set to name of a region if you zoom through it. For view history

	// ========================= STATE INDICATING GLOBALS ==================
	aplisten=false;	// holds pointer to map click listener for edit mode. Used to remove listener when leaving edit mode
	infoOpened = false;	// set to true when an info window is opened. If opened and map moves as a result, re-render is not called.
	sideheader_on=false;
	sidefooter_on=false;
	centerMarker=null;
	qaddress = '';
	currentcategory=1;	// holds the current category
	if( isset(window.location.href.toQueryParams()['cid']) ) {
		setCategories(window.location.href.toQueryParams()['cid'],0,1);
	}
	currentday=new Date().getDay();	// holds the current day
	histatus=false;	// whether any highlight is on
	// because mouseover can be fetched by AJAX, the mouse could be out again before we need to plot...

	hold_i=0;
	// SET UP ENVIRONMENT
	
	clearOverlay();	// init the selected_overlay globals
	
		// set logged in
		if (userdata['session_logged_in'] == 1){
			isLoggedIn = true;
		} else {
			isLoggedIn = false;
		}
		
		// set user level
		if (userdata['user_level'] == 1){
			isAdmin=true;
		} else {
			isAdmin=false;
		}
		
		// set geospatial extensions
		if (isset(settings['mysql_41_geo'])){
			mge_enabled = settings['mysql_41_geo'];
		} else {
			mge_enabled = 1;
		}
		
		// set subquery mode
		if (isset(settings['use_subqueries'])){
			use_subqueries = settings['use_subqueries'];
		} else {
			use_subqueries = 1;
		}
		
		// set sql big selects mode
		if (isset(settings['big_selects'])){
			big_selects = settings['big_selects'];
		} else {
			big_selects = 0;
		}
	
		// Assemble standard options for use in query strings
		queryOptions = "geo="+mge_enabled+"&subq="+use_subqueries+"&bigsel="+big_selects;
			
		// Set profile vars to blank if unset
		if (!isset(profile['default_lng'])){
			profile['default_lng']="";
		}
		if (!isset(profile['default_lat'])){
			profile['default_lat']="";
		}
		if (!isset(profile['default_zoom'])){
			profile['default_zoom']="";
		}
		if (!isset(profile['default_region'])){
			profile['default_region']="";
		}
}

// Called to init the map pane
function initMap(){
	// Init Map
	decho ("Entering initMap");
	if (GBrowserIsCompatible()) {
		map = new GMap2(document.getElementById("pat_map"), {draggableCursor: 'default'});
		map.addControl(new GSmallMapControl());	// zoom control
		map.disableDoubleClickZoom();
		//map.addControl(new GMapTypeControl());	// map / satellite buttons
		//map.addControl(new GScaleControl());	// scale bar
		center = new GLatLng(41.89060144786383,-87.62367010116577);
		map.setCenter(center, defaultZoom);

		var mt = map.getMapTypes();
		for (var i=0; i<mt.length; i++) {
			mt[i].getMinimumResolution = function() {return 16;}
			mt[i].getMaximumResolution = function() {return 17;}
		}

		yellowIcon = new GIcon();
		yellowIcon.image = 'images/gp/icons/mm/yellow.png';
		yellowIcon.iconSize = new GSize(12, 20);
		yellowIcon.iconAnchor = new GPoint(6, 20);
		y_marker = new GMarker(new GLatLng(0,0), {icon: yellowIcon,draggable: false});

		arrowIcon = new GIcon();
		arrowIcon.image = 'images/gp/greenarrow.png';
		arrowIcon.shadow = 'images/gp/arrowshadow.png';
		arrowIcon.transparent = 'images/gp/arrowtransparent.png';
		arrowIcon.iconSize = new GSize(39, 34);
		arrowIcon.shadowSize = new GSize(39, 34);
		arrowIcon.iconAnchor = new GPoint(12, 34);

		maploaded=true;
	}
	
	// set up loading pane
	document.getElementById("pat_map").appendChild(document.getElementById("pat_loading"));
	var pos1 = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0,0));
	var pos2 = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(map.getSize().width/2-150,map.getSize().height/2));
	pos1.apply(document.getElementById("pat_loading"));
	pos2.apply(document.getElementById("pat_loading_box"));
	
	var pat_watermark = Builder.node('img',{src: '/images/pat_logo_overlay.png'});
	document.getElementById("pat_map").appendChild(pat_watermark);
	pos1 = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(0,0));
	pos1.apply(pat_watermark);

	loadingPane('init',gp_lang['loading_initialising']);
	
	// Map should be loaded by now
	if (maploaded){
		//	Init Globals
		if (last_bounds==false){	// initialise last_bounds
			last_bounds=map.getBounds();
		}
		if (last_center==false){	// initialise last_center
			last_center = map.getCenter();
		}
		if (last_zoom == false){
			last_zoom=map.getZoom();
		}
		
		// set up marker mouseover tooltip
		tooltip = document.getElementById("pat_tooltip");
		map.getPane(G_MAP_FLOAT_PANE).appendChild(tooltip);
		tooltip.style.visibility="hidden";

		//========================================== START SETTING UP ICONS =================================
		for (var i in iconArray){ // Cycle through icon sets
			for (var icontype in iconArray[i]){		// Cycle through point / line / region etc
				for (var iconeditstatus in iconArray[i][icontype]){	// cycle through edit status
					for (var iconkey in iconArray[i][icontype][iconeditstatus]){	// cycle through key / value pairs
	
						var icon = new GIcon();
						icon.image = 'images/gp/icons/'+iconArray[i][icontype][iconeditstatus]['image'];
						icon.shadow = 'images/gp/icons/'+iconArray[i][icontype][iconeditstatus]['shadow'];
						icon.transparent = 'images/gp/icons/'+iconArray[i][icontype][iconeditstatus]['transparent'];
						icon.imageMap = eval('['+iconArray[i][icontype][iconeditstatus]['imagemap']+']');
						icon.iconSize = eval('new GSize('+iconArray[i][icontype][iconeditstatus]['iconSize']+')');
						icon.shadowSize = eval('new GSize('+iconArray[i][icontype][iconeditstatus]['shadowSize']+')');
						icon.iconAnchor = eval('new GPoint('+iconArray[i][icontype][iconeditstatus]['iconAnchor']+')');
						icon.infoWindowAnchor = eval('new GPoint('+iconArray[i][icontype][iconeditstatus]['infoWindowAnchor']+')');
						icon.infoShadowAnchor = eval('new GPoint('+iconArray[i][icontype][iconeditstatus]['infoShadowAnchor']+')');
						iconArray[i][icontype][iconeditstatus].icon = icon;
					}
				}
			}
		}
		//========================================== END SETTING UP ICONS =================================


		geocoder = new GClientGeocoder();
		var latlng = window.location.href.toQueryParams()['latlng'];
		var point;
		if( isset(latlng) ) {
			var coords = latlng.split(",");
			point = new GLatLng(coords[0], coords[1]);
		}
		if(isset(window.location.href.toQueryParams()['q'])) {
			qaddress = window.location.href.toQueryParams()['q'];
		}
		geocodeAddress(qaddress,point);
		$('s_days').selectedIndex=currentday;

		decho ("Exiting initMap");
	}
}

// Create a location marker
function createMarker(i,point,icon, data){
	markers[i] = new GMarker(point, {icon: icon,draggable: false});
}

function getRegions(target, replot, selbox, postexeccommand){
	// target = region to navigate to
	// replot: 0 - Don't replot markers
	// replot: 1 - Replot markers and make menu generated replot them too
	// replot: 2 - Don't replot the markers, but the generated menu does.
	// selbox: A pointer to the select box (eg document.myform.mysel)
	// postexeccommand: (optional) A command to execute once populated (as a text string)
	//		BEAR IN MIND THIS IS AN AJAX FUNCTION. It does not "End" when it returns from it.
	//		It will come back when the data is ready.
	//		Hence the postexeccommand - to execute something once getRegions has truly finished...
	var noreplot=0;
	if (replot==2){
		noreplot=1;
		replot=1;
	}
	if (templateMode){
		if (selbox.name=="gp_sel_sb_locedit_regionselect"){	// the region select in the sidebar was changed
			// Hide all locedit class boxes
			//divHideChildrenByClass(document.getElementById("gp_div_sb_locedit"),"gp_sb_locedit","div");
			//divOn("gp_div_sb_locedit_reg");			// Show region select div again
			if (selbox.value == 0){	// Simulate no region permissions
				//divOn("gp_div_sb_locedit_noregperm");		// show no region permissions message
				divOff("gp_div_bb_editmode");
				winResize();
			} else {				// Simulate region permissions
				//divOn("gp_div_sb_locedit_name");			// show name edit div
				//divOn("gp_div_sb_locedit_geomtype");		// show geometry type div
				divOn("gp_div_bb_editmode");
				//subMode(currentsubmode[currentmode]);
				winResize();
			}
		}
	} else {
		var request = GXmlHttp.create();
		// Build the call to the PHP script
		var urlstr="pat_read.php?action=regions&"+queryOptions+"&regid="+target;
		decho ('Sending AJAX request for region data <a target="_blank" href="'+urlstr+'">(link)</a>');
		// Start AJAX Request
		request.open('GET', urlstr , true);
		request.onreadystatechange = function () {
			var zoom=map.getZoom();
			if (request.readyState == 4) {
				decho ("Received AJAX reply with region data");
				var xmlDoc = request.responseXML;
				// region holds the XML tags for the region info
				var regions = xmlDoc.documentElement.getElementsByTagName("region");
				// regheading holds the XML tags for the region heading info
				var regheading = xmlDoc.documentElement.getElementsByTagName("heading");
				
				// start building new menu
				clearOption(selbox);	// empty old menu
				selbox.thisreplot=replot;	// set the custom replot option to the (maybe new) replot value
				selbox.thispostexeccommand=postexeccommand;
				
				//selbox.selectedIndex=0;
				
				// Add current region
				addOption(unescape(regheading[0].getAttribute("name")),regheading[0].getAttribute("region_id"),selbox);
				
				// Add .. (Go Up)
				if (regheading[0].getAttribute("parent_id")!=0){	// if it isn't root node...
					addOption(".. ("+gp_lang['go_up']+")",regheading[0].getAttribute("parent_id"),selbox);	// add the .. (up) entry
				}
				
				// populate menu with sub-regions
				if (regions[0].getAttribute("id") != regheading[0].getAttribute("region_id")){ // does the regions "id" tag match the regheading "region_id" tag ?
					for (var i = 0; i < regions.length; i++) {
						addOption(unescape(regions[i].getAttribute("name")+" ("+regions[i].getAttribute("childcount")+")"),regions[i].getAttribute("id"),selbox);
					}
				}
	
				// Stuff to do with sidebar
				if (replot == 1 && noreplot==0){	// If changing region menu replots, replot,
					last_zoom=zoom;
					zoom=regheading[0].getAttribute("zoom");
					if (seek_id != 0){	// if we seeked on page load and do not want to move here. NOTE: 0 is no seek, not unset. -1 means seeked to coords not a location
						//seek_id=0;	// reset
					} else {
						map.setCenter(new GLatLng(regheading[0].getAttribute("lat"),regheading[0].getAttribute("lng")),(+zoom)); // centre there
					}
				} else {	// no replot - region selectbox used in sidebar?
					// getRegions is used to kick off population of the edit form in the sidebar *if* it is a region the user has rights to

					if (selbox.name=="gp_sel_sb_locedit_regionselect"){	// the region select in the sidebar was changed
						// Hide all locedit class boxes
						//divHideChildrenByClass(document.getElementById("gp_div_sb_locedit"),"gp_sb_locedit","div");
						//divOn("gp_div_sb_locedit_reg");			// Show region select div again
						if (regheading[0].getAttribute('admin')!="1"){ // invalid region?
							//divOn("gp_div_sb_locedit_noregperm");		// show no region permissions message
							divOff("gp_div_bb_editmode");
							winResize();
						} else {			
							//divOn("gp_div_sb_locedit_name");			// show name edit div
							//divOn("gp_div_sb_locedit_geomtype");		// show geometry type div
							divOn("gp_div_bb_editmode");
							//subMode(currentsubmode[currentmode]);		// show point, line or bunch_mo box
							//divOn("gp_div_sb_locedit_infowindow");

							//divOn("gp_div_sb_locedit_category");
							winResize();
						}
					} else if (selbox.name=="gp_sel_sb_settings_regforum_r"){		// Region forum in settings mode
						document.gp_frm_sb_settings.gp_sel_sb_settings_regforum_f.selectedIndex=regheading[0].getAttribute('forum_id');
					}
				}
				if (postexeccommand){	// command to execute specified
					eval(postexeccommand);
				}
			}
		}
		request.send(null);
		// End AJAX Request
	}
}

// Called when a location marker is clicked. Initiates editing of the marker in edit mode
function clickLocMarker(overlay){
	//CLM
	clearStuckPopups();
	if (overlay.editable==1 || isAdmin){	// as long as rights to edit
		selected_overlay=overlay;
		// seek the region selecter in the edit window to it's region
		getRegions(overlay.region,0,document.gp_frm_sb_locedit.gp_sel_sb_locedit_regionselect,"getLocData()");
	}	
}

// called when the background is clicked
function clickBackground(point){
	if (getGuiMode()==GP_EDIT_GUI_LOC){
		if (currentmode == GP_EDIT_MODE){	// we are in edit mode
			if (getLocationMode()==GP_EDIT_POINT_MODE){	// ----------------- POINT TYPE ----------------
				editpath=new Array();
				editpath[0]=new Array();
				editpath[0][0]=new GLatLng(rndVar(point.lat()),rndVar(point.lng()));	// set end (point 1) to clicked point
				document.gp_frm_sb_locedit.gp_txt_sb_locedit_lng.value = rndVar(point.lng());
				document.gp_frm_sb_locedit.gp_txt_sb_locedit_lat.value = rndVar(point.lat());
				plotTempMarkers();
			} else {	// --------------------------------------------------------------------- LINE TYPE --------------------
				if (!editpath.length){	// if start of line
					document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value = '';
					editpath=new Array();
					editpath[0]=new Array();
					editpath[0][0]=new GLatLng(rndVar(point.lat()),rndVar(point.lng()));	// set end (point 1) to clicked point
				} else {
					document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value = rndVar(point.lng())+" "+rndVar(point.lat())
				}
				// ToDo: Populate the native box on the form
				editpath[0][editpath[0].length]=new GLatLng(rndVar(point.lat()),rndVar(point.lng()));	// add point to end of path
				plotTempMarkers();	// re-draw, and update edit form
			}
		}
	} else if (getGuiMode()==GP_EDIT_GUI_MOVR){
		var selIndex=document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex;
		editmovr[selIndex][editmovr[selIndex].length]=new GLatLng(point.lat(),point.lng());
		plotTempMarkers();
	}
}

// Called when a temporary marker is clicked in edit mode.
function clickTempMarker(overlay){
	if (getGuiMode()==GP_EDIT_GUI_LOC){
		var tmpArray=editpath;
		var selIndex=0;
	} else {
		var tmpArray=editmovr;
		var selIndex=document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex;
	}
	if (overlay.markertype=="add"){	// ---------------- START MARKER -------------------
		if ((getLocationMode()==GP_EDIT_LINE_MODE) || (getGuiMode()==GP_EDIT_GUI_MOVR) ){	// Line Type ormouseover
			if (tmpArray[selIndex].length!=1){	// not last icon left
				tmpArray[selIndex].shift();	// remove first item
				plotTempMarkers();	// redraw line

			}
		}
	} else if (overlay.markertype=="end"){	// ------------------------------- END MARKER -------------
		tmpArray[selIndex].pop();	// remove last item in line
		plotTempMarkers();	// redraw line
	} else if (overlay.markertype=="mid"){	// ------------------------------- MID MARKER -------------
		tmpArray[selIndex].splice(overlay.midindex,1);
		plotTempMarkers();
	}
}

function showHiddenMarkers(){
	if (hiddenEditMarker){	// a line was being drawn on a different marker
		// try and find marker
		//could have changed id as we could have re-plotted due to zoom etc
		var j=0;
		for (var i=0;i<markers.length;i++){
			if (hiddenEditMarker.id==markers[i].id){
				markerDisplay(markers[i],true);
				if (markers[i].geometrytype=="LINESTRING"){
					lineDisplay(markers[i],true);
				}
				j++;
				break;
			}
		}
	}
}

// Actually processes the edit click once the regions box has been set to the right region.
// If this isn't done, then if the user is in a region they can't edit, clicking a marker they could edit will not work
// because the edit boxes will not exist - the sidepanel will contain "You cannot edit points in this region"
function getLocData(){
	var overlay=selected_overlay;	// pull overlay data back from global var.
	removeTempMarkers();
	showHiddenMarkers();

	// populate boxes
	if (!isset(overlay.name) || overlay.name==''){
		clearOverlay();
		editLocData(selected_overlay);
	} else {
		selected_location=overlay.id;
		if (markers[overlay.markerindex].fulldata){	// got the full amount of data ?
			//infowindowMain(overlay.markerindex);
			editLocData(overlay);	// yes - go straight to populating edit box
		} else {
			// Get full point data
			var request = GXmlHttp.create();
			incEditUID();
			
			var urlstr="pat_read.php?action=points&"+queryOptions+"&locid="+overlay.id+"&uid="+editUID;
			request.open('GET', urlstr, true);	// request XML from PHP with AJAX call
			request.onreadystatechange = function () {
				if (request.readyState == 4) {
					var xmlDoc = request.responseXML;
					var location = xmlDoc.documentElement.getElementsByTagName("location");
					
					markers[overlay.markerindex].rp_zoom=location[0].getAttribute("rp_zoom");
					if (markers[overlay.markerindex].represents_region > 0){ // bunch point
						//markers[overlay.markerindex].rr_zoom=location[0].getAttribute("rr_zoom");	// zoom value of region it represents (or null)
						markers[overlay.markerindex].bunch_mo=location[0].getAttribute("bunch_mo");	// add mouseover line to marker so we don't have to get it again for this zoom
						markers[overlay.markerindex].rc_zoom=location[0].getAttribute("rc_zoom");
						markers[overlay.markerindex].rr_userlist=location[0].getAttribute("rr_userlist");
						markers[overlay.markerindex].rr_grouplist=location[0].getAttribute("rr_grouplist");
					}
					markers[overlay.markerindex].infowindow=unescape((location[0].getAttribute("infowindow")));
					markers[overlay.markerindex].locimport=unescape(location[0].getAttribute("import"));
					markers[overlay.markerindex].pointowner=location[0].getAttribute("pointowner");
					markers[overlay.markerindex].topic_id=location[0].getAttribute("topic_id");

					// set fulldata attribute to stop re-grabbing of data for this point.
					markers[overlay.markerindex].fulldata=true;

					var uniqueid = xmlDoc.documentElement.getElementsByTagName("request");
					uniqueid=uniqueid[0].getAttribute("uniqueid");	// find the uid of the request

					if (editUID==uniqueid && selected_location==overlay.id){
						// only populate the edit box if:
						// another ajax request hasn't been initiated to edit another marker
						// and the selected_location matches the overlay's id
						//overlay.openInfoWindowHtml(renderInfowindow(padMainInfowindow(overlay.markerindex)));
						//infowindowMain(overlay.markerindex);
						editLocData(overlay);
					}
				}
			}
			request.send(null);
		}
	}
	
}

// Takes the attributes from an overlay and populates the edit box accordingly
function editLocData(overlay){
	editpath=[];
	//divOff('gp_div_sb_locedit_regconv');
	//divOff('gp_div_sb_locedit_regperm');
	divOff('gp_div_bb_locedit_add');
	divOff('gp_div_edit_movr_segment');
	divOff('gp_div_line_import');
	document.gp_frm_sb_locedit.gp_chk_sb_locedit_guiedit.checked=false;
	if (selected_location){
		divOn('gp_div_bb_locedit_edit');
		//divOn('gp_div_sb_locedit_regconv');
	} else {
		divOff('gp_div_bb_locedit_edit');
		//divOff('gp_div_sb_locedit_regconv');
	}
	if (overlay.geometrytype=="LINESTRING"){	// is a line
		subMode(GP_EDIT_LINE_MODE);
		document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value=overlay.geometry;
	} else {					// is a point
		subMode(GP_EDIT_POINT_MODE);
		// populate lng lat boxes
		document.gp_frm_sb_locedit.gp_txt_sb_locedit_lng.value = overlay.lng;
		document.gp_frm_sb_locedit.gp_txt_sb_locedit_lat.value = overlay.lat;
		// clear line box
		document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value="";
	}
	// Set category
	document.gp_frm_sb_locedit.gp_sel_sb_locedit_categoryselect.selectedIndex=overlay.category;
	
	// Bunch Point section
	editZoomRange(overlay.rc_zoom,overlay.rp_zoom);
	if (overlay.represents_region==0){	// not bunch point
		// Not bunch point
		document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.value="ON";
		document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.checked=false;
		document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.disabled=false;
	} else {	//	 Bunch point
		//divOn('gp_div_sb_locedit_regperm');
		//divOn('gp_div_sb_locedit_movr');
		if (overlay.childregcount==0){
			// No children - allow changing back to non-bunch point
			document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.value="ON";
			document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.checked=true;	
			document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.disabled=false;
		} else {
			// Has children - do not allow changing back to non-bunch point.
			document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.value="ON";
			document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.checked=true;	
			document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.disabled=true;
		}
		selectOption(document.gp_frm_sb_locedit.gp_sel_sb_locedit_regconv_zoomlevel,overlay.rr_zoom);
		// populate user permissions list for bunch point with current list
		document.gp_frm_sb_locedit.gp_sel_sb_locedit_regperm_users.length=0;
		
		// Region Permissions
		if (!isempty(overlay.rr_userlist)){
			var users=overlay.rr_userlist.split(",");	// split into records
			for (var j = 0;j<users.length;j++){
				var user=users[j].split(":");	// split IDs and names
				document.gp_frm_sb_locedit.gp_sel_sb_locedit_regperm_users.options[j] = new Option(user[1],user[0]);
			}
		}
		if (!isempty(overlay.rr_grouplist)){
			var groups=overlay.rr_grouplist.split(",");	// split into records
			for (var j = 0;j<groups.length;j++){
				var group=groups[j].split(":");	// split IDs and names
				document.gp_frm_sb_locedit.gp_sel_sb_locedit_regperm_groups.options[j] = new Option(group[1],group[0]);
			}
		}
		document.gp_frm_sb_locedit.gp_txt_sb_locedit_movr.value=overlay.bunch_mo;
	}
	document.gp_frm_sb_locedit.gp_txt_sb_locedit_name.value = overlay.name;
	if (settings['xinha_enabled']==1){
		xinha_editors.gp_txt_sb_locedit_infowindow.setHTML(overlay.infowindow)
	} else {
		document.gp_frm_sb_locedit.gp_txt_sb_locedit_infowindow.value = overlay.infowindow;
	}

	if (document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.checked==false && !overlay.isempty){
		//eval(delete_button[0]+"='"+delete_button[1]+"'");	// insert delete button
		divOn('gp_div_bb_locedit_delete');
	} else {
		//eval(delete_button[0]+"='&nbsp'");	// remove delete button
		divOff('gp_div_bb_locedit_delete');
	}
	if (isset(overlay) && overlay.name != ''){
		markerDisplay(overlay,false);		// hide marker being edited
		if (overlay.geometrytype=="LINESTRING"){ // Line Mode
			lineDisplay(overlay,false);		// hide line being edited
		}
	}
	document.gp_frm_sb_locedit.gp_chk_sb_locedit_guiedit.checked=false;	// reset to edit location mode
	plotTempMarkers();
}
// ================================================== editZoomRange =========================================
// creates the zoom selection box for regions.
// only makes needed entries
function editZoomRange(zchild,zparent){
	if (zchild=='' || zchild == null){
		zchild=GP_MAX_ZOOM+1;
	}
	if (zparent=='' || zparent == null){
		zparent=GP_MIN_ZOOM-1;
	}
	zparent = +zparent + 1;
	zchild = +zchild - 1;
	
	clearOption(document.gp_frm_sb_locedit.gp_sel_sb_locedit_regconv_zoomlevel);
	for (var i=zparent;i <= zchild;i++){
		addOption(i,i,document.gp_frm_sb_locedit.gp_sel_sb_locedit_regconv_zoomlevel);
	}
}
// used to set the value of a select box
// Will not try and select something that doesn't exist.
function selectOption(option,set){
	if (option){
		for (var i = 0;i < option.length;i++){
			if (option.options[i].value==set){
				option.selectedIndex=i;
			}
		}
	}
}

// Clears region borders and tooltips that have got stuck on
function clearStuckPopups(){
	tooltip.style.visibility="hidden"
	map.removeOverlay(y_marker);
}

// ================================== getVisibleMarkers ============= GVM =============================
// Plots markers it gets from a call to pat_read.php?action=points
function getVisibleMarkers() {
	decho ("Entering GVM");
	map.closeInfoWindow();

	var urlstr="pat_read.php?action=points&"+queryOptions;	// start building URL string
	// add the selected region to the query
	urlstr += "&region=0"  // set urlstr to region_id of current region
	
	// add the selected category to the query
	urlstr += "&category="+currentcategory;
	
	// add the selected day
	urlstr += "&day="+currentday;
	
	// generate unique ID for request
	incMainUID();
	urlstr += "&uid="+mainUID;
	
	// add zoom factor
	var zoom = map.getZoom()
	urlstr += "&zoom=" + zoom;
	
	// assemble bounds part of URL
	var bounds=map.getBounds();
	
	var tmpBounds=scaleBounds(bounds,cacheScale);
	var left=tmpBounds.getSouthWest().lng();
	var right=tmpBounds.getNorthEast().lng();
	var top=tmpBounds.getNorthEast().lat();
	var bot=tmpBounds.getSouthWest().lat();
	var lngc=destination.lng();
	var latc=destination.lat();
	
	urlstr += "&minx="+left+"&maxx="+right+"&miny="+bot+"&maxy="+top+"&lngc="+lngc+"&latc="+latc;
	
	// clear old markers
	for (var i=0 ; i < markers.length ; i++){ 
		map.removeOverlay(markers[i]);
		if( markers[i].polyline != null ) {map.removeOverlay(markers[i].polyline);}
	}
	
	clearStuckPopups();
	var request = GXmlHttp.create();
	loadingPane('plot',gp_lang['loading_requesting']);
	decho ('Sending AJAX request ID '+mainUID+' for location data <a target="_blank" href="'+urlstr+'">(link)</a>');
	request.open('GET', urlstr , true);	// request XML from PHP with AJAX call
	request.onreadystatechange = function () {
		if (request.readyState == 4) {
			var xmlDoc = request.responseXML;
			var uniqueid = xmlDoc.documentElement.getElementsByTagName("request");
			if (uniqueid[0]==null){
				userMessage("ERROR IN XML RETURNED");
			} else {
				uniqueid=uniqueid[0].getAttribute("uniqueid");	// find the uid of the request
				if (uniqueid == mainUID){	// only process if not an old one
					decho ('AJAX Reply ID '+uniqueid+' received by GVM, passing to PVM');
					plotVisibleMarkers(xmlDoc);
				} else {
					decho ('AJAX Reply ID '+uniqueid+' received by GVM. Old ID, dropping...');
				}
			}
		}
	}
	decho ('AJAX Request ID '+mainUID+' sent - waiting for reply. Exiting GVM');
	request.send(null);
}

// ================================== plotVisibleMarkers ============= PVM =============================
// Plots markers it gets from passed XML document
function plotVisibleMarkers(xmlDoc){
	decho("Entering PVM");
	locations = xmlDoc.documentElement.getElementsByTagName("location");
	map.removeOverlay(regrabPoly);
	map.removeOverlay(cachePoly);
	var bounds=map.getBounds();
	
	markers = [];
	polylines=[];
	
	loadingPane('plot',gp_lang['loading_plotting']);
	
	// Delete locations from #pat_locations,
	var deleteDiv = $('pat_locations').immediateDescendants();
	for (var i=deleteDiv.length-1; i>=1 ;i--){
		deleteDiv[i].remove();
	}

	decho ("PVM Plotting "+locations.length+" Markers...");
	if (locations.length > 0){	// if there are markers to plot
		var tmpeditable='noedit';
		var tmpsubtype = 'point';
	
		divOff('pat_no_coverage');
		divOn('pat_locations_slider');
		var loc_grp_id = 'location_group_'+currentcategory;
		var loc_grp = Builder.node('div',{id: loc_grp_id});
		$('pat_locations').appendChild(loc_grp);
		// cycle thru locations
		for (var i = 0; i < locations.length; i++) {
			// used to detect if we need to delete hiddenEditMarker
			// if we plot all the points but find no match, we should delete it to stop...
			// ... things thinking there is a marker hidden they can "unhide"
			var clear_hem = true;
			
			// =================== SET UP ICON ==========================
			var catName = categoryIdToName(locations[i].getAttribute("category_id"));
			
			// use firstNode to get location for icon in case it is a line
			var coords=firstNode(locations[i].getAttribute("geometry"));

			createMarker(i,new GLatLng(coords[1],coords[0]),iconArray[catName][tmpsubtype][tmpeditable].icon);
			configureMarker(i,locations[i]);

			markers[i].polyline=null;
			// Add the line if it is a line
			if (markers[i].geometrytype=="LINESTRING"){
				var polyline = new GPolyline(getPoints(markers[i].geometry), "#60A9D7", 7,  0.5);
				polyline.markerindex=i;
				markers[i].polyline = polyline;
				GEvent.addListener(polyline, "click", function(latlng) {
					onMouseIn(markers[this.markerindex],false,latlng);
				});	  
				map.addOverlay(markers[i].polyline);
			} else {
				map.addOverlay(markers[i]);	// add marker
			}

			// Insert location info
			var tmp_id = 'loc_rec_'+i;
			var tmp_class = 'info';
			var tmpROW = Builder.node('div',{id: tmp_id});
			loc_grp.appendChild(tmpROW);
			var infobox_div = '<div id="'+tmp_id+'" class="'+tmp_class+'"';
			infobox_div += ' onmouseover="onMouseIn(markers['+i+'], true)"';
			infobox_div += ' onmouseout="onMouseOut(markers['+i+'])"></div>';
			$(tmp_id).replace(infobox_div);

			tmpDIV = Builder.node('div',{className: 'street_addr'});
			tmpDIV.innerHTML = '<span class="street_name">'+markers[i].name+'</span>';
			tmpDIV.innerHTML += '<br /><span class="street_loc">'+markers[i].location+'</span>';
			$(tmp_id).appendChild(tmpDIV);

			if(markers[i].infowindow != '') {
			tmpDIV = Builder.node('div',{className: 'street_desc'});
			tmpDIV.innerHTML = '<img class="note" src="/images/note.gif" />';
			tmpDIV.innerHTML  += '<span>'+markers[i].infowindow+'<br />'+markers[i].route_type+'</span>';
			$(tmp_id).appendChild(tmpDIV);
			}

			tmpDIV = Builder.node('div',{className: 'street_sked'});
			tmpDIV.innerHTML = markers[i].sked;
			$(tmp_id).appendChild(tmpDIV);

			$(tmp_id).appendChild(Builder.node('div',{className: 'clear'}));
		}
	} else {
		divOn('pat_no_coverage');
		divOff('pat_locations_slider');
	}
	decho ("PVM Finished plotting markers");
	
	loadingPane('plot','');	// remove loading notice
	
	// Build new polylines to show regrab and cache area for this plot
	var bounds=map.getBounds();
	last_bounds=bounds;
	
	decho ("Drawing ReGrab and Cache boxes");
	regrabPoly = new GPolyline(boundsToPolyLine(scaleBounds(bounds,grabScale)), "#00FF00", 2, 0.5);
	//regrabPoly = new GPolyline(boundsToPolyLine(bounds), "#00FF00", 2, 0.5);
	//map.addOverlay(regrabPoly);
	
	cacheBounds = scaleBounds(bounds,cacheScale);
	//cachePoly = new GPolyline(boundsToPolyLine(cacheBounds), "#FF0000", 2, 0.5);
	//map.addOverlay(cachePoly);

	if (seek_id > 0){	// did it plot all the points but not find the seeked marker ?
		decho ("Seeked marker ("+seek_id+") not found");
		seek_id=0;	// disable seeked
	}

	showHideMarkers();
	decho("Exiting PVM");
}

// Called when user toggles between point and line mode.
function togglePointLine(){
	if (getLocationMode()==GP_EDIT_POINT_MODE){
		subMode(GP_EDIT_POINT_MODE);
		document.gp_frm_sb_locedit.gp_txt_sb_locedit_lat.value=editpath[0][0].lat();
		document.gp_frm_sb_locedit.gp_txt_sb_locedit_lng.value=editpath[0][0].lng();
		editpath= new Array();
		
		plotTempMarkers();
	} else if (document.gp_frm_sb_locedit.gp_rad_sb_locedit_geomtype[GP_EDIT_LINE_MODE].checked==true){
		editpath=new Array();
		if (isset(selected_overlay) && selected_overlay.geometry != ''){	// found selected marker?
			// re-populate line with what is in geometry. Maybe they switched from line to point and back again?
			document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value=selected_overlay.geometry;
		}
		subMode(GP_EDIT_LINE_MODE);
		plotTempMarkers();
	}
}

// Builds editpath from the locedit form
function buildGeometryData(){
	editpath = new Array();
	if (getLocationMode()==GP_EDIT_POINT_MODE){		// POINT
		if (document.gp_frm_sb_locedit.gp_txt_sb_locedit_lng.value != '' && document.gp_frm_sb_locedit.gp_txt_sb_locedit_lat.value != ''){
			editpath[0] = new Array();
			editpath[0][0]=new GLatLng(document.gp_frm_sb_locedit.gp_txt_sb_locedit_lat.value,document.gp_frm_sb_locedit.gp_txt_sb_locedit_lng.value);
		}
	} else {		// LINE
		editpath=geomToArray(document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value);
	}
}

// builds editmovr from the locedit form, initialises the segment selecter drop down box
function buildMovrData(){
	editmovr=geomToArray(document.gp_frm_sb_locedit.gp_txt_sb_locedit_movr.value);
	clearOption(document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment);
	for (var i=0;i<editmovr.length;i++){
		addOption(i+1,i,document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment);
	}
}

// toggles between editing the location and it's region mouseover
function toggleGuiMode(){
	loadingPane('plot',gp_lang['loading_plotting']);
	if (getGuiMode()==GP_EDIT_GUI_LOC){
		buildGeometryData();
	} else {
		editmovr=new Array();
	}
	plotTempMarkers();
}

// adds a segment to the region mouseover
function addMovrSegment(){
	if (editmovr.length){
		editmovr[editmovr.length]=new Array();
	} else {
		editmovr=new Array();
		editmovr[0]=new Array();
	}
	clearOption(document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment);
	for (var i=0;i<editmovr.length;i++){
		addOption(i+1,i,document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment);
	}
	document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex=i-1;
	plotTempMarkers();
}

// Deletes a segment from the region mouseover
function delMovrSegment(){
	if (editmovr.length){
		editmovr.shift(document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex,1);
		clearOption(document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment);
		for (var i=0;i<editmovr.length;i++){
			addOption(i+1,i,document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment);
		}
		if (editmovr.length==0){
			document.gp_frm_sb_locedit.gp_txt_sb_locedit_movr.value='';
		} else {
			document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex=i-1;
		}
		plotTempMarkers();
	}
}

// ==================================================== plotTempMarkers  == PTM =======================================
// plots temp markers and lines. used when editing stuff
// be careful, can get called outside edit mode (ie document.gp_frm_sb_locedit doesn't exist)
function plotTempMarkers(){
	removeTempMarkers();
	
	// Import data from global or form
	if (getGuiMode()==GP_EDIT_GUI_LOC){	// Normal point / line mode
		divOff('gp_div_edit_movr_segment');
		if (!editpath.length){	// editpath empty - take path from form
			buildGeometryData();
		}

		var tmpArray=editpath;
	} else {
		divOn('gp_div_edit_movr_segment');	
		if (!editmovr.length){	
			buildMovrData();
		}
		var tmpArray=editmovr;
	}
	// OK, we should now have a 3D array no matter what - start plottin' them segments!
	var tmpgeom='';	// holds output for geometry field
	//here
	midmarkers=new Array();
	editpolys=new Array();
	for (var segIndex=0;segIndex<tmpArray.length;segIndex++){
		var points = [];	// build polyline to output in here
		if (tmpArray[segIndex].length){	// path in tmpArray[segIndex] - draw it
			for (var i=0;i<tmpArray[segIndex].length;i++){
				points.push(new GLatLng (tmpArray[segIndex][i].lat(),tmpArray[segIndex][i].lng()));
				if (i==0){	// first iteration ?
					tmpgeom += tmpArray[segIndex][i].lng()+" "+tmpArray[segIndex][i].lat();
					// plot this marker if we are in regular loc edit mode or if we are in mouseover edit mode and this is the selected segment
					if (getGuiMode()==GP_EDIT_GUI_LOC || (segIndex == document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex)){
						// ======================================== Start marker
						addmarker=new GMarker(new GLatLng (tmpArray[segIndex][i].lat(),tmpArray[segIndex][i].lng()), {icon:tmpIconArray[settings['default_tmpiconset']]['start'],draggable:true,bouncy:false});
						GEvent.addListener(addmarker, "dragstart", function() {
							map.closeInfoWindow();
						});
						GEvent.addListener(addmarker, "dragend", function() {
							if (getGuiMode()==GP_EDIT_GUI_LOC){
								if (getLocationMode()==GP_EDIT_POINT_MODE){
									document.gp_frm_sb_locedit.gp_txt_sb_locedit_lng.value=addmarker.getPoint().lng();
									document.gp_frm_sb_locedit.gp_txt_sb_locedit_lat.value=addmarker.getPoint().lat();
									editpath=new Array();
								} else {
									editpath[0][0]=new GLatLng(addmarker.getPoint().lat(),addmarker.getPoint().lng());
								}
							} else {
								editmovr[document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex][0]=new GLatLng(addmarker.getPoint().lat(),addmarker.getPoint().lng());
							}
							plotTempMarkers();
						});
						map.addOverlay(addmarker);	// show it
						addmarker.temp=true;
						addmarker.markertype="add";					
					}
				} else if (i!=tmpArray[segIndex].length-1){	// middle node (not end node)
					tmpgeom += ","+tmpArray[segIndex][i].lng()+" "+tmpArray[segIndex][i].lat();
					// plot this marker if we are in regular loc edit mode or if we are in mouseover edit mode and this is the selected segment
					if (getGuiMode()==GP_EDIT_GUI_LOC || (segIndex == document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex)){
						// ======================================== mid marker
						midmarker=new GMarker(new GLatLng (tmpArray[segIndex][i].lat(),tmpArray[segIndex][i].lng()), {icon:tmpIconArray[settings['default_tmpiconset']]['mid'],draggable:true,bouncy:false});
						GEvent.addListener(midmarker, "dragstart", function() {
							map.closeInfoWindow();
						});
						GEvent.addListener(midmarker, "dragend", function() {
							if (getGuiMode()==GP_EDIT_GUI_LOC){
								if (getLocationMode()==GP_EDIT_LINE_MODE){
									editpath[0][this.midindex]=new GLatLng(midmarkers[this.midindex].getPoint().lat(),midmarkers[this.midindex].getPoint().lng());
								}
							} else {
								editmovr[document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex][this.midindex]=new GLatLng(midmarkers[this.midindex].getPoint().lat(),midmarkers[this.midindex].getPoint().lng());
							}
							plotTempMarkers();
						});
						map.addOverlay(midmarker);	// show it
						midmarker.temp=true;
						midmarker.markertype="mid";
						midmarker.midindex=i;
						midmarkers[i]=(midmarker);
					}
				} else if (tmpArray[segIndex].length > 1 && i==tmpArray[segIndex].length-1){	// end node (wont trigger if only one node)
					tmpgeom += ","+tmpArray[segIndex][i].lng()+" "+tmpArray[segIndex][i].lat();
					if (tmpArray.length > 1 && segIndex != tmpArray.length-1){	// if multi-segment line, and this isn't the last segment
						tmpgeom += ":";
					}
					// plot this marker if we are in regular loc edit mode or if we are in mouseover edit mode and this is the selected segment
					if (getGuiMode()==GP_EDIT_GUI_LOC || (segIndex == document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex)){
						// ======================================== end marker
						endmarker=new GMarker(new GLatLng (tmpArray[segIndex][i].lat(),tmpArray[segIndex][i].lng()), {icon:tmpIconArray[settings['default_tmpiconset']]['end'],draggable:true,bouncy:false});
						GEvent.addListener(endmarker, "dragstart", function() {
							map.closeInfoWindow();
						});
						GEvent.addListener(endmarker, "dragend", function() {
							if (getGuiMode()==GP_EDIT_GUI_LOC){
								if (getLocationMode()==GP_EDIT_LINE_MODE){
									editpath[0][editpath[0].length-1]=new GLatLng(endmarker.getPoint().lat(),endmarker.getPoint().lng());
								}
							} else {
								editmovr[document.gp_frm_edit_movr_segment.gp_sel_edit_movr_segment.selectedIndex][editmovr[0].length-1]=new GLatLng(endmarker.getPoint().lat(),endmarker.getPoint().lng());
							}
							plotTempMarkers();
						});
						map.addOverlay(endmarker);	// show it
						endmarker.temp=true;
						endmarker.markertype="end";
					} else if (getGuiMode()==GP_EDIT_GUI_MOVR){	// in mouseover mode but not current segment
						// close border
						points.push(tmpArray[segIndex][0]);
					}
				} else {	// end node - only one node
					endmarker=false;
				}
			}
			//i--;
			editpolys[segIndex]=new GPolyline(points, "#FF0000", 2, 1);	// create overlay
			map.addOverlay(editpolys[segIndex]);	// add line
			
			if (tmpArray[segIndex].length) {	// point or line passed
				if (selected_location == false){	// Add mode
					divOn('gp_div_bb_locedit_add');
					divOff('gp_div_bb_locedit_edit');
					divOff('gp_div_bb_locedit_delete');
				} else {
					divOff('gp_div_bb_locedit_add');
					divOn('gp_div_bb_locedit_edit');
				}
			} else {
					divOff('gp_div_bb_locedit_add');
					divOff('gp_div_bb_locedit_edit');
			}
			
			// write geometry data back to form
			if (getGuiMode()==GP_EDIT_GUI_LOC){
				document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value=tmpgeom;
			} else {
				document.gp_frm_sb_locedit.gp_txt_sb_locedit_movr.value=tmpgeom;
			}
		}
	}
	//tmpArray=new Array();
	loadingPane('plot','');

}


// Convert bounds to polyline (for drawing bounds boxes etc)
function boundsToPolyLine(tmpBounds){
	var points = [];
	var tmpCoords = boundsToCoords(tmpBounds);
	if (tmpBounds.getNorthEast().lng() < tmpBounds.getSouthWest().lng()){	// left edge more east than right edge
		// draw bounds that crosses a date line
		points = polySteps(points,tmpBounds.getNorthEast().lat(),-180,tmpBounds.getNorthEast().lng()); // top mid to top right
		points.push(new GLatLng(tmpCoords.bot,tmpCoords.right)); //se
		points = polySteps(points,tmpBounds.getSouthWest().lat(),tmpBounds.getNorthEast().lng(),-180);	// bot right to bot mid
		points = polySteps(points,tmpBounds.getSouthWest().lat(),180,tmpBounds.getSouthWest().lng()); // bot mid to bot left
		points.push(new GLatLng(tmpCoords.top,tmpCoords.left)); // nw
		points = polySteps(points,tmpBounds.getNorthEast().lat(),tmpBounds.getSouthWest().lng(),180);	// top left to top mid
	} else {
		// draw normal bounds constrained by date line
		points = polySteps(points,tmpBounds.getNorthEast().lat(),tmpBounds.getSouthWest().lng(),tmpBounds.getNorthEast().lng());
		points.push(new GLatLng(tmpCoords.bot,tmpCoords.right)); //se
		points = polySteps(points,tmpBounds.getSouthWest().lat(),tmpBounds.getNorthEast().lng(),tmpBounds.getSouthWest().lng());
		points.push(new GLatLng(tmpCoords.top,tmpCoords.left)); // nw
	}
	return points;
}

// converts a bounds to coordinates, sort of V1 minx, maxx... style
function boundsToCoords(tmpBounds){
	var top=tmpBounds.getNorthEast().lat();
	var right=tmpBounds.getNorthEast().lng();
	var bot=tmpBounds.getSouthWest().lat();
	var left=tmpBounds.getSouthWest().lng();
	return {top : top, right : right, left : left, bot : bot};
}

// Scales a bounds object
function scaleBounds(tmpBounds,scale){
	var tmpCoords = boundsToCoords(tmpBounds);
	
	if (tmpBounds.getNorthEast().lng() < tmpBounds.getSouthWest().lng()){	// left edge more east than right edge
		var tmpd = (tmpCoords.right-tmpCoords.left);
		var tmps = ((tmpd * scale) - tmpd)/2;	// how much to add / remove each edge?
		tmpCoords.right = tmpCoords.right - tmps;
		tmpCoords.left = tmpCoords.left + tmps;
	} else {
		var tmpd = (tmpCoords.right-tmpCoords.left);
		var tmps = ((tmpd * scale) - tmpd)/2;	// how much to add / remove each edge?
		tmpCoords.right = tmpCoords.right + tmps;
		tmpCoords.left = tmpCoords.left - tmps;
	}		
	tmpd = (tmpCoords.top-tmpCoords.bot);
	tmps = ((tmpd * scale) - tmpd)/2;	// how much to add / remove each edge?
	tmpCoords.top = tmpCoords.top + tmps;
	tmpCoords.bot = tmpCoords.bot - tmps;
	
	if (tmpCoords.top > 85.932567920988){
		tmpCoords.top = 85.932567920988;
	}
	if (tmpCoords.right > 180){
		tmpCoords.right = +180;
	}
	if (tmpCoords.bot < -128.8235826668448){
		tmpCoords.bot = -128.8235826668448;
	}
	if (tmpCoords.left < -180){
		tmpCoords.left = -180;
	}
	
	var newBounds = new GLatLngBounds(new GLatLng(tmpCoords.bot, tmpCoords.left), new GLatLng(tmpCoords.top, tmpCoords.right));
	return (newBounds);
}

// Function calculates numerous steps between start and end
// Needed because if you try and draw a line from one corner to the other at low zooom levels,
// it may go the "wrong" way around th world. this fixes that for bounds.
function polySteps(points,yval, begx, endx){
	var tmpd = (begx-endx);	// diff
	var iter = 10;	// number of points on line
	var ctr = iter;	// ctr used to make sure loop doesn't go on too long (Not sure why it does this)
	tmpd = tmpd * -1;	// invert diff to get increment direction
	if (tmpd > 0){	// draw left to right
		for (var i= begx; (i <= endx) && (ctr) ; i += parseInt(tmpd/iter)){
			points.push(new GLatLng(yval,i));
			ctr--;
		}
	} else {	// draw right to left
		for (var i= begx; (i >= endx) && (ctr) ; i += parseInt(tmpd/iter)){
			points.push(new GLatLng(yval,i));
			ctr--;
		}
	}
	if (points[points.length-1].lng() != endx){	// last point is not endx due to it not dividing equally
		points.push(new GLatLng(yval,endx));	// push endx
	}
	return(points);
}

// Increment the uniqueid for the main AJAX points request
function incMainUID(){
	mainUID++;
	if (mainUID == 1001){
		mainUID = 0;
	}
}

// Increment the uniqueid for the infowindow AJAX points request
function incInfoUID(){
	infoUID++;
	if (infoUID == 1001){
		infoUID = 0;
	}
}

// Increment the uniqueid for the click location in edit point AJAX points request
function incEditUID(){
	editUID++;
	if (editUID == 1001){
		editUID = 0;
	}
}

// returns a geometry type given an SQL geometry string
function geometryType(geom){
	geom=geom.split(",");
	if (geom.length > 1){
		return ("LINESTRING");
	} else {
		return ("POINT");
	}
}

// returns the lat and lng of the first node in a geometry string
function firstNode(geom){
	var ret=[];
	geom=geom.split(",");
	geom=geom[0].split(" ");
	return (geom);
}

// returns the lat and lng of the second node in a geometry string
function secondNode(geom){
	var ret=[];
	geom=geom.split(",");
	geom=geom[1].split(" ");
	return (geom);
}

// create points array for GPolyline from lineString
function getPoints(geom){
	var points = new Array();
	var gpoints = new Array();
	points=geom.split(",");
	for(var i=0; i<points.length; i++) {
		point=points[i].split(" ");
		gpoints.push(new GLatLng(point[1],point[0]));
	}
	return(gpoints);
}

// Configures a marker in the markers array
// appends various properties to the marker which are useful when the overlay is clicked
// various other properties can get added to a marker during it's life, eg on mouseover or click.
function configureMarker(i,data){
	markers[i].isempty=false;	// provides a proper way to detect if an overlay has been reset or has data
	markers[i].fulldata=false;	// tells UI if we have full data loaded for this location - only partial data loaded by default
	markers[i].temp=false;	// not a temporary marker
	markers[i].markertype="loc";
	markers[i].markerindex=i;	// the index in the markers array, so we know what it is when we click it.
	markers[i].id=data.getAttribute("id");	// the location ID, so we can edit it in the DB
	markers[i].sked=data.firstChild.nodeValue;

	markers[i].distance=data.getAttribute("dis"); // Distance from center of the map
	markers[i].geometry=data.getAttribute("geometry");
	markers[i].geometrytype=geometryType(markers[i].geometry);
	var coords=firstNode(markers[i].geometry);
	markers[i].lng=rndVar(coords[0]);
	markers[i].lat=rndVar(coords[1]);
	
	markers[i].name=data.getAttribute("name");
	if(data.getAttribute("side")!="") {
		markers[i].name=markers[i].name+" ("+data.getAttribute("side")+")";
	}
	markers[i].side=data.getAttribute("side");
	markers[i].start_loc=data.getAttribute("start_loc");
	markers[i].end_loc=data.getAttribute("end_loc");

	var location_txt=data.getAttribute("start_loc");
	if(data.getAttribute("end_loc")!="") {
		location_txt=location_txt+" - "+data.getAttribute("end_loc");
	}
	markers[i].location = location_txt;
	markers[i].tooltip = '<b>'+markers[i].name+'</b><br />'+location_txt;
	markers[i].infowindow=data.getAttribute("infowindow");
	markers[i].loc_mask=data.getAttribute("loc_mask");
	markers[i].route_type=data.getAttribute("route_type");
	markers[i].represents_region=data.getAttribute("represents_region");
	markers[i].category=data.getAttribute("category_id");
	markers[i].childcount=data.getAttribute("childcount");
	markers[i].childregcount=data.getAttribute("childregcount");
	
	markers[i].region=data.getAttribute("region_id");
	markers[i].rr_zoom=data.getAttribute("rr_zoom");	// zoom value of region it represents (or null)

	markers[i].editable=data.getAttribute("editable");
	// if it is a line, create the polyline and add the overlay
	// =====================   END ADD TO MARKERS ARRAY ========================
	
	// ===================== BEGIN MOUSEOVER LISTENERS =========================
	GEvent.addListener(markers[i], 'click', function (){
		onMouseIn(this);
	});
	// ===================== END MOUSEOVER LISTENERS =========================
}
function slideInfoBox(obj){
}
function onMouseIn(obj,mouseInInfoBox,latlng){
	var tmp_id = 'loc_rec_'+obj.markerindex;
	if(!isset(latlng)) latlng=obj.getLatLng();
	if( $(tmp_id).getElementsByClassName('dimmed').length > 0 ) return; // Marker is hidden/dimmed

	if ( lastClicked < 0 ) {
		// first time
		lastClicked=obj.markerindex;
	} else if ( lastClicked != obj.markerindex ) {
		// mouse into a differnent marker
		clearHighlight(markers[lastClicked]);
		lastClicked=obj.markerindex;
	} else if (histatus) {
		// mouse into the same marker
		return;
	}
	$(tmp_id).addClassName('highlight')

	if(!mouseInInfoBox) {
		var loc_grp_id = 'location_group_'+currentcategory;
		var op = Position.offsetParent($(tmp_id));
		var y = (Position.positionedOffset($(tmp_id)))[1] + (Position.positionedOffset(op))[1]
		var diff = -(y - 80);
		new Effect.MoveBy($(loc_grp_id), diff, 0, {duration: 1, transition: Effect.Transitions.slowstop});
	}

	if (markers[obj.markerindex].geometrytype=="LINESTRING" && markers[obj.markerindex].polyline != null){
		map.removeOverlay(markers[obj.markerindex].polyline);
		markers[obj.markerindex].polyline.color='#176997';
		markers[obj.markerindex].polyline.opacity=1;
		map.addOverlay(markers[obj.markerindex].polyline);
	}
	y_marker = new GMarker(latlng,yellowIcon);
	map.addOverlay(y_marker);

	// Show tooltip
	tooltip.innerHTML = '<span class="street_name">'+obj.name+'</span><br /><span class="street_loc">'+obj.location+'</span>';
	var point=map.getCurrentMapType().getProjection().fromLatLngToPixel(map.fromDivPixelToLatLng(new GPoint(0,0),true),map.getZoom());
	var offset=map.getCurrentMapType().getProjection().fromLatLngToPixel(latlng,map.getZoom());
	var anchor=obj.getIcon().iconAnchor;
	var width=obj.getIcon().iconSize.width;
	var height=tooltip.clientHeight;
	var offsetX = offset.x - point.x - anchor.x + width;
	offsetX = offsetX < map.getSize().width-tooltip.clientWidth-10 ? offsetX : map.getSize().width-tooltip.clientWidth-10;
	var offsetY = offset.y - point.y - anchor.y - height;
	offsetY = offsetY-tooltip.clientHeight-10 > 0 ? offsetY : offset.y - point.y;
	var pos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(offsetX, offsetY)); 
	pos.apply(tooltip);
	tooltip.style.visibility="visible";
	histatus=true;
}
function onMouseOut(obj){
}
function clearHighlight(obj){
	if(obj == null) {
		if(markers[lastClicked] != null) {
			obj = markers[lastClicked];
		} else {
			return;
		}
	}
	var tmp_id = 'loc_rec_'+obj.markerindex;
	if( $(tmp_id).getElementsByClassName('dimmed').length > 0 ) return; // Marker is hidden/dimmed
	$(tmp_id).removeClassName('highlight')

	if(markers[obj.markerindex].geometrytype=="LINESTRING" && markers[obj.markerindex].polyline != null){
		map.removeOverlay(markers[obj.markerindex].polyline);
		markers[obj.markerindex].polyline.color='#60A9D7';
		markers[obj.markerindex].polyline.opacity=0.8;
		map.addOverlay(markers[obj.markerindex].polyline);
	}
	tooltip.style.visibility="hidden"
	map.removeOverlay(y_marker);
	histatus=false;
}

// ====================================================== geomToArray ======================
// converts mySQL Geometry type linestrings into arrays of GLatLngs (for a Polyline)
// Input format is x y,x y
// Can also handle multiple polylines separated by a : for the input.
// eg: x y,x y:x y,x y
// In this case, it will return a multidimensional array
// multi-lines are mainly used for region mouseovers
function geomToArray(geom){
	if (geom != ''){
		var polyout=[];
		var chunks=geom.split(":");	// split into seperate polylines
		for (var i=0;i<chunks.length;i++){
			var polytmp=[];
			var linetmp=chunks[i].split(",");	// split into lng lat pairs (native format is lng lat,lng lat)
			if (linetmp.length){	// any results ?
				//var polytmp=[];
				// cycle through coordinates appending them to the end of polytmp.
				for (var j = 0; j < linetmp.length;j++){
					var coords=linetmp[j].split(" ");
					polytmp.push(new GLatLng(coords[1],coords[0]));
				}
			}
			polyout[i]=polytmp;
		}
		//polyout=polyout[0];
		return (polyout);
	}
	return (geom);	// return empty array
}

// ====================================================== arrayToGeom ======================
// converts arrays of GLatLngs (for a Polyline) into mySQL Geometry type linestrings
function arrayToGeom(polytmp){
	var tmpstr='';
	for (var i=0;i<polytmp.length;i++){
		if (i > 0){	// not first line ?
			tmpstr += ":";	// add line separator
		}
		tmparray=polytmp[i];
		if (tmparray != ''){
			if (tmparray.length){
				for (var x=0;x<tmparray.length;x++){
					if (x != 0){	// not first entry ?
						tmpstr += ",";	// add comma separator
					}
					tmpstr+=rndVar(tmparray[x].lng())+" "+rndVar(tmparray[x].lat());
				}
			}
		}
	}
	return (tmpstr);
}

function showMoLines(line){
	var polyarray = [];
	var polytmp = [];
	polyarray=geomToArray(line);	// polyarray could be multidimensional
	// clear old line
	if (regionmoline.length){
		for (var j=0;j < regionmoline.length;j++){
			map.removeOverlay(regionmoline[j]);
		}
	}
	regionmoline=[];
	// end clear
	for (var j=0;j<polyarray.length;j++){
		polytmp=polyarray[j];	// polytmp is an array within the array
		if (polytmp.length){
			polytmp.push(polytmp[0]);
			regionmoline[j]=new GPolyline(polytmp, "#FF0000", 3, 0.5);
			map.addOverlay(regionmoline[j]);	// draw polyline - addoverlay method
		}
	}
}

// =========================== Formatted Print Function =======================
// usage: sprintf("The answer to life, the universe, and everything is: %s", ["42"]);
function sprintf(S, L) {
	var nS = "";
	var tS = S.split("%s");
	if (tS.length > 1){
		if (tS.length != L.length+1) return "sprintf error";
		for(var i=0; i<L.length; i++){
			nS += tS[i] + L[i];
		}
		return nS + tS[tS.length-1];
	} else {
		return S;
	}
}

// ==================================================== escapePlus =========================================
// escapes characters to % values for transmission via HTTP POST
// functionally the same as escape() except it encodes + to %2B to avoid confusion with space going to +
function escapePlus(html){
	html = escape(html);
	html = html.replace ('+','%2B');
	return (html);
}

// ==================================================== rndVar =========================================
// rounds something to 6 decimal places
function rndVar(rndvar,places){
	if (!places){
		places=6;	// default # of decimal places
	}
	places=Math.pow(10,places);
	return (Math.round(rndvar*places)/places);
}

// converts a category ID to a category name
function categoryIdToName(tmpid){
	if (tmpid == '0'){
		return ('all');
	} else {
		for (var i in catArray){
			if (catArray[i]['category_id'] == tmpid){
				return(catArray[i]['name']);
			}
		}
		userMessage ("Error: Cannot find category name for ID "+tmpid);
	}
}

// populates a categories listbox.
function getCategories(selected, replot, update, selbox){
	// selected = the category id of the record that will be selected after the menu is built
	// replot: 0 - Don't replot markers
	// replot: 1 - Replot markers and make menu generated replot them too
	// replot: 2 - Don't replot the markers, but the generated menu does.
	// update: 0 for don't update the current category mode, 1 for do.
	// selbox: The select box to manipulate
	//		BEAR IN MIND THIS IS AN AJAX FUNCTION. It does not "End" when it returns from it.
	//		It will come back when the data is ready.
	if (typeof(selbox)=="string"){;
		selbox=eval(selbox);
	}
	var noreplot=0;
	if (replot==2){
		noreplot=1;
		replot=1;
	}
	
	clearOption(selbox);
	addOption(gp_lang['all'],'0',selbox);
	for(var i in catArray){
		if (catArray[i]['name'] != 'all'){
			addOption(catArray[i]['name'],catArray[i]['category_id'],selbox);
		}
	}
	// set the category and maybe replot
	if (update==1){	// only if we are updating with this menu
		if (noreplot==1){
			setCategories(selected,0,update);
		} else {
			setCategories(selected,replot,update);
		}
	}
}

// called when changing category in the main filter box
// Does NOT change the selection of a box, just updates vars and replots if asked to.
function setCategories(category,replot,update){
	if(category==2) {
		// redirect to garage
		window.location='/garage/?q='+qaddress+'&lat='+destination.lat()+'&lng='+destination.lng();
	}
	if (update==1){
		var tmpID_0='pat_cat_'+currentcategory;
		var key_0='legend_group_'+currentcategory;
		var tmpID_1='pat_cat_'+category;
		var key_1='legend_group_'+category;
		currentcategory=category;
		document.getElementById(tmpID_0).className='off';
		divOff(key_0);
		document.getElementById(tmpID_1).className='on';
		divOn(key_1);
		if (replot==1){
			getVisibleMarkers();
		}
	}
}

function setDay(newday){
	currentday=newday;
	$('s_days').selectedIndex=currentday;
	getVisibleMarkers();
}

function mainMode(mode){
	// Check if allowed to change mode
	if (!templateMode){
		removeTempMarkers();
		showHiddenMarkers();
	}
	if (mode==GP_VIEW_MODE){
		divOn("gp_div_bb");
		document.gp_frm_hdr_mode.gp_rad_hdr_mode[GP_VIEW_MODE].checked=true;	// set radio - we could be initialising
	} else if (mode==GP_EDIT_MODE){
		divOn("gp_div_bb");
		if (templateMode){
			document.gp_frm_hdr_mode.gp_rad_hdr_mode[GP_EDIT_MODE].checked=true;
		} else {
			if (isLoggedIn){
				document.gp_frm_hdr_mode.gp_rad_hdr_mode[GP_EDIT_MODE].checked=true;
				map.closeInfoWindow();
			} else {
				userMessage(gp_lang['log_in_to_edit']);
				document.gp_frm_hdr_mode.gp_rad_hdr_mode[currentmode].checked=true;
				return(0);
			}
		}
	} else if (mode==GP_SETTINGS_MODE){
		divOff("gp_div_bb");
		if (templateMode){
			document.gp_frm_hdr_mode.gp_rad_hdr_mode[GP_SETTINGS_MODE].checked=true;
		} else {
			if (isAdmin){
				document.gp_frm_hdr_mode.gp_rad_hdr_mode[GP_SETTINGS_MODE].checked=true;
			} else {
				userMessage(gp_lang['settings_notadmin']);
				document.gp_frm_hdr_mode.gp_rad_hdr_mode[currentmode].checked=true;
				return(0);
			}
		}
	} else if (mode==GP_PROFILE_MODE){
		divOff("gp_div_bb");
		if (templateMode){
			document.gp_frm_hdr_mode.gp_rad_hdr_mode[GP_PROFILE_MODE].checked=true;
		} else {
			if (isLoggedIn){
				document.gp_frm_hdr_mode.gp_rad_hdr_mode[GP_PROFILE_MODE].checked=true;
			} else {
				userMessage(gp_lang['profile_not_logged_in']);
				document.gp_frm_hdr_mode.gp_rad_hdr_mode[currentmode].checked=true;
				return(0);
			}
		}
	}

	// Hide all Topbar items
	divHideChildrenByClass(document.getElementById("gp_div_tb"),"gp_topbar","div");
	
	// Collapse the sidebar (Main) stack
	divHideChildrenByClass(document.getElementById("gp_div_sb"),"gp_sidebar","div");
	//divOff("aaa");
	
	// Hide all Bottombar items
	divHideChildrenByClass(document.getElementById("gp_div_bb"),"gp_bottombar","div");

	winResize();
	
	currentmode=mode;
			
	if (mode==GP_VIEW_MODE){
		divOff("gp_div_tb_viewmode");
		subMode(currentsubmode[GP_VIEW_MODE]);
		winResize();
		return(1);
	} else if (mode==GP_EDIT_MODE){
		divOn("gp_div_tb_editmode");
		//divOn("gp_div_sb_locedit_reg");
		
		divOff('gp_div_bb_locedit_add');
		divOff('gp_div_bb_locedit_edit');
		divOff('gp_div_bb_locedit_delete');
		
		//subMode(currentsubmode[GP_EDIT_MODE]);
		clearOverlay();
		// Init the next box
		getRegions(document.gp_frm_sb_locedit.gp_sel_sb_locedit_regionselect.value,0,document.gp_frm_sb_locedit.gp_sel_sb_locedit_regionselect,"getLocData()");
		winResize();
		return(1);
	} else if (mode==GP_SETTINGS_MODE){
		var tmp = getElementsByClass(document,"gp_sb_settings","div");
		for (var i=0;i < tmp.length;i++){
			divOn(tmp[i].id);
		}

		if (!templateMode){
			// Root Region Permissions
			var request = GXmlHttp.create();
			var urlstr="pat_read.php?action=root_permissions";
			request.open('GET', urlstr, true);	// request XML from PHP with AJAX call
			request.onreadystatechange = function () {
				if (request.readyState == 4) {
					var xmlDoc = request.responseXML;
					var permission = xmlDoc.documentElement.getElementsByTagName("permission");
					
					// populate user permissions list for bunch point with current list
					clearOption(document.gp_frm_sb_settings.gp_sel_sb_settings_regperm_users);
					var tmpusers=permission[0].getAttribute("userlist");
					if (!isempty(tmpusers)){
						var users=tmpusers.split(",");	// split into records
						for (var j = 0;j<users.length;j++){
							var user=users[j].split(":");	// split IDs and names
							addOption(user[1],user[0],document.gp_frm_sb_settings.gp_sel_sb_settings_regperm_users);
						}
					}
					// populate group permissions list for bunch point with current list
					clearOption(document.gp_frm_sb_settings.gp_sel_sb_settings_regperm_groups);
					var tmpgroups=permission[0].getAttribute("grouplist");
					if (!isempty(tmpgroups)){
						var groups=tmpgroups.split(",");
						// Add the group to the menu
						for (var j = 0;j<groups.length;j++){
							var group=groups[j].split(":");	// split IDs and names
							addOption(group[1],group[0],document.gp_frm_sb_settings.gp_sel_sb_settings_regperm_groups);
						}
					}
				}
			}
			request.send(null);
	
			// Default region		
			getRegions(+settings['default_region'], 0, document.gp_frm_sb_settings.gp_sel_sb_settings_regionselect);
	
			// Welcome HTML
			if (settings['xinha_enabled']==1){
				xinha_editors['gp_txt_sb_settings_welcome_html'].setHTML(settings['welcome_html']);
			} else {
				document.gp_frm_sb_settings.gp_txt_sb_settings_welcome_html.value=settings['welcome_html'];
			}
			// Default View
			document.gp_frm_sb_settings.gp_txt_sb_settings_lng.value=settings['default_lng'];
			document.gp_frm_sb_settings.gp_txt_sb_settings_lat.value=settings['default_lat'];
			document.gp_frm_sb_settings.gp_txt_sb_settings_zoom.value=settings['default_zoom'];
	
			// Region Forums
			initRegionForum();
			
			// Debug Mode
			document.gp_frm_sb_settings.gp_sel_sb_settings_debug_mode.selectedIndex=settings['debug_mode'];
			
			// Help Mode
			document.gp_frm_sb_settings.gp_sel_sb_settings_help_mode.selectedIndex=settings['showhelp_status'];
			
			// XINHA stuff
			document.gp_frm_sb_settings.gp_sel_sb_settings_xinha_status.selectedIndex=settings['xinha_enabled'];
			document.gp_frm_sb_settings.gp_txt_sb_settings_xinha_buttons.value=settings['xinha_buttons'];
			document.gp_frm_sb_settings.gp_txt_sb_settings_xinha_filename.value=settings['xinha_file'];
			document.gp_frm_sb_settings.gp_txt_sb_settings_xinha_path.value=settings['xinha_path'];
			
			// Region Branch Import / Export
			getRegions(1, 0, document.gp_frm_sb_settings.gp_sel_sb_settings_rb_import);
			getRegions(1, 0, document.gp_frm_sb_settings.gp_sel_sb_settings_rb_export);
			
		}
		winResize();
		return(1);
	} else if (mode==GP_PROFILE_MODE){
		divOn("gp_div_tb_profilesmode");
		var tmp = getElementsByClass(document,"gp_sb_profile","div");
		for (var i=0;i < tmp.length;i++){
			divOn(tmp[i].id);
		}
			getRegions(+profile['default_region'], 0, document.gp_frm_sb_profile.gp_sel_sb_profile_regionselect);
		
		winResize();
		return(1);
	}
	// Dropped through - unknown mode
	userMessage ("Tried to change to unkown mode - MODE: "+mode);
}

function subMode(mode){
	// Hide all modeblocks (middle sidebar items)
	divHideChildrenByClass(document.getElementById("gp_div_sb"),"gp_sb_viewmode","div");

	// What main mode are we in?
	if (currentmode==GP_VIEW_MODE){
		// divOff('gp_div_sb_viewmode_search_results_geo');
		// divOff('gp_div_sb_viewmode_search_results_gp');
		if (mode == GP_VIEW_HELP_MODE){
			currentsubmode[currentmode] = mode;
			document.gp_frm_tb_viewmode_submode.gp_rad_viewmode_submode[GP_VIEW_HELP_MODE].checked=true;
			divOn("gp_div_sb_viewmode_welcome");
			
			winResize();
		} else if (mode == GP_VIEW_POINTLIST_MODE){
			currentsubmode[currentmode] = mode;
			document.gp_frm_tb_viewmode_submode.gp_rad_viewmode_submode[GP_VIEW_POINTLIST_MODE].checked=true;
			divOn("gp_div_sb_viewmode_loclist");
			
			winResize();
		} else if (mode == GP_VIEW_SEARCH_MODE){
			currentsubmode[currentmode] = mode;
			document.gp_frm_tb_viewmode_submode.gp_rad_viewmode_submode[GP_VIEW_SEARCH_MODE].checked=true;
			// divOn("gp_div_sb_viewmode_search");
			
			winResize();
		}
		
		if (currentsubmode[currentmode] == mode){ // Currentsubmode[mode] got set - known submode
		
		}
		
	} else if (currentmode == GP_EDIT_MODE){
		if (mode == GP_EDIT_POINT_MODE){
			currentsubmode[currentmode] = mode;
			document.gp_frm_sb_locedit.gp_rad_sb_locedit_geomtype[GP_EDIT_POINT_MODE].checked=true;
			//divOn("gp_div_sb_locedit_point");		// Show edit point box
			//divOff("gp_div_sb_locedit_line");
			
			
		} else if (mode == GP_EDIT_LINE_MODE){
			currentsubmode[currentmode] = mode;
			document.gp_frm_sb_locedit.gp_rad_sb_locedit_geomtype[GP_EDIT_LINE_MODE].checked=true;
			//divOff("gp_div_sb_locedit_point");
			//divOn("gp_div_sb_locedit_line");		// Show edit line box
			
		}
		if (currentsubmode[currentmode] == mode){ // Currentsubmode[mode] got set - known submode
		}

	} else {	// Did not find mode
		userMessage ("Bad current main mode: "+currentmode);
		return(0);
	}

	if (currentsubmode[currentmode] != mode){ // Currentsubmode[mode] did not get set - unknown submode
		userMessage ("Tried to change to unkown submode - MODE: "+currentmode+", SUBMODE:"+mode);
		return(0);
	}
	
	return(0);
}

function winResize(){	// Handles resizing of window - sets vertical height of map elements to fill browser.
	// Find the size of the GP "body" - the bit between the GP header and footer (map and sidebar)
	if (window.innerHeight){	// Mozilla
		gpBodyHeight=window.innerHeight;	// find the size of the window
		//gpBodyHeight=gpBodyHeight-getDivHeight("gp_div_hdr");	// minus the size of the header
		gpBodyHeight=gpBodyHeight-getDivHeight("gp_div_ftr");	// minus the size of the footer
		gpBodyHeight=gpBodyHeight-200; // Take out another 200px, so the map is above the fold
	} else {		// IE
		document.body.style.height="100%";	// need this to make sure body is full size of window before calc.
		gpBodyHeight=document.body.clientHeight;	// Best IE can do - find size in px of body
		gpBodyHeight = parseInt((gpBodyHeight / 100) * 75);	// IE cludge to "guess" GP body size
	}
	
	gpBodyHeight=gpBodyHeight-10; // Take out another 10px, so the ad is above the fold
	// Set the Map height to the body size
	setDivHeight("gp_div_map",gpBodyHeight);
	setDivHeight("gp_div_sidepanel",gpBodyHeight);
	
	// Now work out the size that the main (middle) section of the sidebar should be
	var mainHeight = gpBodyHeight;	// take a copy
	
	if (divStatus("gp_div_tb")){	// if the sidebar header is visible...
		mainHeight=mainHeight-getDivHeight("gp_div_tb");	// subtract it's height from mainHeight
	}
	if (divStatus("gp_div_bb")){	// if the sidebar footer is visible...
		mainHeight=mainHeight-getDivHeight("gp_div_bb");	// subtract it's height from mainHeight
	}
	
	// Set the main (middle) section of the sidebar to whatever is left
	setDivHeight("gp_div_sb",mainHeight);
	return(0);	// this return is VERY important else IE fires onresize constantly
}

// Gets height of a DIV
function getDivHeight(tmpDiv){
	return(document.getElementById(tmpDiv).clientHeight);
}

// Sets height of a DIV
function setDivHeight(tmpDiv, tmpHeight){
	var tmpDiv2 = document.getElementById(tmpDiv);
	tmpDiv2.style.height=tmpHeight+"px";
}

// Gets status of a DIV
function divStatus(tmpDiv){
	if (document.getElementById){	// standards
		var tmpStyle = document.getElementById(tmpDiv).style;
	}
	else if (document.all){		// old ie
		var tmpStyle = document.all[tmpDiv].style;
	}
	else if (document.layers){	// old moz
		var tmpStyle = document.layers[tmpDiv].style;
	}
	if (tmpStyle.display=="block"){
		return(true);
	} else {
		return(false);
	}
}

// Shows a DIV
function divOn(tmpDiv){
	if (document.getElementById){	// standards
		var tmpStyle = document.getElementById(tmpDiv).style;
	}
	else if (document.all){		// old ie
		var tmpStyle = document.all[tmpDiv].style;
	}
	else if (document.layers){	// old moz
		var tmpStyle = document.layers[tmpDiv].style;
	}
	tmpStyle.display="block";
}

//Hides a DIV
function divOff(tmpDiv){
	if (document.getElementById){	// standards
		var tmpStyle = document.getElementById(tmpDiv).style;
	}
	else if (document.all){		// old ie
		var tmpStyle = document.all[tmpDiv].style;
	}
	else if (document.layers){	// old moz
		var tmpStyle = document.layers[tmpDiv].style;
	}
	tmpStyle.display="none";
}

/* THC ***
// Inits XINHA WYSIWYG editor
function xinha_init()
{
	if(!Xinha.loadPlugins(xinha_plugins, xinha_init)) return;
	var xinha_config = new Xinha.Config();
	
	xinha_config.toolbar=eval(settings['xinha_buttons']);
	xinha_config.width="300px";
	xinha_config.height="400px";
	
	xinha_editors = Xinha.makeEditors(xinha_editors, xinha_config, xinha_plugins);
	Xinha.startEditors(xinha_editors);
}

// Detects when XINHA boxes have been loaded and then executes exec
function onXinhaLoad(editors,exec){
	for ( var i in editors ){
		if (editors[i]._iframeLoadDone != true){
			t=setTimeout("onXinhaLoad(editors,exec)",1000);
			return(false);
		}
	}
	clearTimeout(t);
	eval(exec);
}
*** */

// returns true if object type is not "undefined"
function isset(object){
	if (typeof(object) == "undefined"){
		return (false);
	} else {
		return (true);
	}
}

// getElementsByClass from http://www.dustindiaz.com/getelementsbyclass/
function getElementsByClass(node,searchClass,tag) {
	var classElements = new Array();
	var els = node.getElementsByTagName(tag); // use "*" for all elements
	var elsLen = els.length;
	var pattern = new RegExp("\\b"+searchClass+"\\b");
	for (var i = 0, j = 0; i < elsLen; i++) {
		 if ( pattern.test(els[i].className) ) {
			 classElements[j] = els[i];
			 j++;
		 }
	}
	return classElements;
}

// Hides all children with tag tag that are a child of node and have class searchClass
function divHideChildrenByClass(node,searchClass,tag){
	var tmp = getElementsByClass(node,searchClass,tag);
	for (var i=0;i<tmp.length;i++){
			divOff(tmp[i].id);
	}
}

// Hides all children with tag tag that are a child of node and have class searchClass
function divShowChildrenByClass(node,searchClass,tag){
	var tmp = getElementsByClass(node,searchClass,tag);
	for (var i=0;i<tmp.length;i++){
			divOn(tmp[i].id);
	}
}

function divHideChildren(node,tag){
	var tmp = node.getElementsByTagName(tag);
	//var tmp = getElementsByClass(node,searchClass,tag);
	for (var i=0;i<tmp.length;i++){
			divOff(tmp[i].id);
	}
}

// Adds an element to a select box
// Note: VALUE IS A STRING NOT AN INT, EVEN THOUGH IT IS A NUMBER
function addOption(text,value,box) {
	if(text) {
		var opt = new Option(text,value);
		var count = box.options.length;
		box.options[count] = opt;
	}
}

// Clears a select box
function clearOption(box) {
	if (box.length){
		var tmp = box.length;
		for (var i=0;i<tmp;i++){	// Dont ecal box.length each time else it won't remove all.
			box.options[0] = null;	// Clear ZERO not i.
		}
	}
}

// Sends a string to the debug window
function decho(string){
	if (settings['debug_mode']==1 && isAdmin){	// only show in settings mode and if a phpBB admin
		GLog.writeHtml(string);
	}
}

// sets or hides the loading message
function loadingPane(channel,message){
	if (!isset(messages)){
		var messages = new Array();		// init array for loading messages
	}
	
	messages[channel]=message;
	// init any vars that aren't set to make comparisons easier
	if (!messages['init']){
		messages['init']='';
	}
	if (!messages['plot']){
		messages['plot']='';
	}
	var tmpstr = '';
	if (messages['init'] != ''){	// if there is an initialising message
		tmpstr += messages['init']+"<br>";
	}
	if (messages['plot'] != ''){	// if there is an plotting message
		tmpstr += messages['plot']+"<br>";
	}
	document.getElementById("pat_loading_msg").innerHTML = tmpstr;
	if (messages['init'] != '' || messages['plot'] != ''){
		document.getElementById("pat_loading").style.display="block";
	} else {
		document.getElementById("pat_loading").style.display="none";
	}
}

// returns true if an object is "empty"
function isempty(object){
	if (!isset(object)){
		return(true);
	} else {
		if (object == ""){
			return (true);
		} else {
			return (false);
		}
	}
}

// moves to a location and opens the infowindow of a marker by location_id
function seekLocationId(id,lat,lng,zoom){
	var tmpvar=infowindowMainById(id);
	if (tmpvar == false){	// if it fails to open it, it is not in the cache
		seek_id = id;
		zoom_through = 0;
		// Move the map to the location specified
		// should call GVM - if it does it should open the infowindow because seek_id is set.
		// if it doesn't, we are already here, why did infowindowMainById() fail ??
		map.setCenter(new GLatLng(lat,lng),zoom);
	}
}

// tries to open an infowindow by location_id
// If fails, returns false
function infowindowMainById(id){
	for (var i=0;i<markers.length;i++){
		if (markers[i].id == id){
			infowindowMain(markers[i].markerindex);
			return (markers[i].markerindex);
		}
	}
	return(false);
}

// ====================================================== goHistory ======================
// goes to a certain place in the view history
function goHistory(i){
	var x=view_history[i][0];
	var y=view_history[i][1];
	var z=view_history[i][2];
	view_history=view_history.splice(0,i);
	map.setCenter(new GLatLng(y,x),z);
}

// ====================================================== infowindowMain ======================
// opens the main (user set) page in the infowindow over marker i
function infowindowMain(i) {
	if (!isset(markers[i].infowindow)){		// infowindow data not present - load it
		getInfowindowData(i);
	}
	populateInfowindow(i);
	if(hold_i >= 0) {
		document.getElementById('loc_rec_'+hold_i).style.background='';
		document.getElementById('sked_rec_'+hold_i).style.background='';
	}
	hold_i=i
	document.getElementById('loc_rec_'+hold_i).style.background='#fffa73';
	document.getElementById('sked_rec_'+hold_i).style.background='#fffa73';
	sdepth=parseInt(65*(i-2));
	setTimeout("document.getElementById('gp_div_sb').scrollTop = sdepth", 0);
}

function getInfowindowData(i){
	var request = GXmlHttp.create();
	incInfoUID();
	var urlstr="pat_read.php?action=infowindow&locid="+markers[i].id+"&uid="+infoUID+"&"+queryOptions;
	request.open('GET', urlstr, true);	// request XML from PHP with SJAX call
	request.onreadystatechange = function () {
		if (request.readyState == 4) {
			var xmlDoc = request.responseXML;
			var uniqueid = xmlDoc.documentElement.getElementsByTagName("request");
			uniqueid=uniqueid[0].getAttribute("uniqueid");	// find the uid of the request
			var location = xmlDoc.documentElement.getElementsByTagName("location");
			markers[i].infowindow=unescape(location[0].getAttribute("infowindow"));
			markers[i].pointowner=location[0].getAttribute("pointowner");
			markers[i].topic_id=location[0].getAttribute("topic_id");
			markers[i].locimport=unescape(location[0].getAttribute("import"));
		}
	}
	request.send(null);
}

function populateInfowindow(i){
	document.getElementById('gp_txt_iw_near').value=markers[i].lat+','+markers[i].lng+' ('+markers[i].name+')';
	document.getElementById('gp_txt_iw_to_end').value=markers[i].lat+','+markers[i].lng+' ('+markers[i].name+')';
	document.getElementById('gp_txt_iw_from_start').value=markers[i].lat+','+markers[i].lng+' ('+markers[i].name+')';
	if (markers[i].represents_region !=0){	// is a region
		if (markers[i].geometrytype=="LINESTRING"){		// line region
			var linetmp=markers[i].geometry.split(",");	// split into lng lat pairs (native format is lng lat,lng lat)
			if (linetmp.length){
				var coords=linetmp[linetmp.length-1].split(" ");
				var mx=coords[0];
				var my=coords[1];
			}
		} else {	// point bunch
			var mx=markers[i].lng;
			var my=markers[i].lat;
		}
		var mz=markers[i].rr_zoom;
		document.getElementById('gp_spn_iw_reg_name').innerHTML=markers[i].name;
		document.getElementById('gp_div_iw_reg_html').innerHTML=markers[i].infowindow;

		var mainwindow = document.getElementById('gp_div_infowindow_reg').cloneNode(true);
		
		markers[i].openInfoWindowTabs([new GInfoWindowTab(gp_lang['info'],mainwindow)]);
		
	} else {	// Is a location
		var mx=markers[i].lng;
		var my=markers[i].lat;
		var mz=GP_MAX_ZOOM-1;

		document.getElementById('gp_div_iw_loc_name').innerHTML=markers[i].name;
		document.getElementById('gp_div_iw_loc').innerHTML=markers[i].location;
		document.getElementById('gp_div_iw_loc_html').innerHTML=markers[i].infowindow;
		
		var mainwindow = document.getElementById('gp_div_infowindow_loc').cloneNode(true);

		markers[i].openInfoWindowTabs([new GInfoWindowTab(gp_lang['info'],mainwindow)]);
		// Add the line if it is a line
		eval ('document.gp_frm_sb_viewmode_loclist.loc_chk_'+i+'.checked=true');
	}
}

// Send a message to the user.
// literally a replacement for alert() at the moment
// but means I can be sure any alert() statement other than the one in here is for debugging
function userMessage(msg){
	alert(msg);
}

// ==================================================== removeTempMarkers =========================================
// removes all temporary overlays from the map
function removeTempMarkers(){
	if (addmarker){
		map.removeOverlay(addmarker);
		addmarker = false;
	}
	if (endmarker){
		map.removeOverlay(endmarker);
		endmarker=false;
	}
	if (editpolys){
		for (var i=0;i<editpolys.length;i++){
			map.removeOverlay(editpolys[i]);
		}
		editPoly=false;
	}
	if (midmarkers){
		for (var i=0;i<midmarkers.length;i++){
			map.removeOverlay(midmarkers[i]);
		}
		midmarkers=new Array();
	}
}

// Show or Hide a Marker
function markerDisplay(marker,show) {
	var i = marker.markerindex;
	if (show){
		map.addOverlay(markers[i]);
		hiddenEditMarker=false;
	} else {
		map.removeOverlay(markers[i]);
		hiddenEditMarker=marker;
	}
}

// Show or Hide a Line
function lineDisplay(marker,show) {
	if (show){
		map.addOverlay(polylines[marker.polyline]);
	} else {
		map.removeOverlay(polylines[marker.polyline]);	// remove overlay
	}
}

// Finds out if we are in point or line mode
function getLocationMode(){
	if(document.gp_frm_sb_locedit.gp_rad_sb_locedit_geomtype[GP_EDIT_LINE_MODE].checked){
		return (GP_EDIT_LINE_MODE);
	} else {
		return (GP_EDIT_POINT_MODE);
	}
}

// Finds out if we are editing the underlying location data or the region mouseover
function getGuiMode(){
	if (document.gp_frm_sb_locedit.gp_chk_sb_locedit_guiedit.checked==true){
		return(GP_EDIT_GUI_MOVR);
	} else {
		return(GP_EDIT_GUI_LOC);
	}
}

// Clears the selected_overlay global and associated vars
function clearOverlay(){
	var overlay=new Array();
	overlay.isempty=true;	// so we can easily test overlay.isempty to see if overlay passed to something is reset.
	overlay.name='';
	overlay.geometry='';
	overlay.lat='';
	overlay.lng='';
	overlay.markerindex='';
	overlay.bunch_mo='';
	overlay.infowindow='';
	overlay.category='0';
	overlay.represents_region='0';
	overlay.geometrytype="POINT";
	overlay.bunch_mo='';
	selected_overlay=overlay;	// reset global selected_overlay too
	selected_location=false;
	//return(overlay);
}

// ==================================================== pointReset =========================================
// resets the point edit form
function pointReset(){
	if (newapi){
		map.closeInfoWindow();
	}
	removeTempMarkers();
	editpath=[];
	//mainMode(GP_EDIT_MODE);
	clearOverlay();
	getRegions(0,0,document.gp_frm_sb_locedit.gp_sel_sb_locedit_regionselect, "getLocData()");

}

// ==================================================== pointSubmit ========================================
// submits a point to the back end php database
function pointSubmit(){
	// perform checks
	if (isempty(document.gp_frm_sb_locedit.gp_txt_sb_locedit_name.value)){
		// No name
		userMessage(gp_lang['no_name_error']);
	} else {
		// submit location
		if (newapi){
			map.closeInfoWindow();
		}
		if (settings['xinha_enabled'] == 1){
			var tmpInfo=xinha_editors.gp_txt_sb_locedit_infowindow.getHTML();
		} else {
			tmpInfo=document.gp_frm_sb_locedit.gp_txt_sb_locedit_infowindow.value;
		}
		/*
		if (document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value.match(/http:\/\//)){	// URL in import
			document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value=""; // clear it
		}
		*/
		request = GXmlHttp.create();
		var sendstr = 'PointName=' + escapePlus(document.gp_frm_sb_locedit.gp_txt_sb_locedit_name.value);
		sendstr += '&PointImport=' + escapePlus(document.gp_frm_line_import.gp_txt_line_import.value);
		sendstr += '&PointInfowindow=' + escapePlus(tmpInfo);
		sendstr += '&PointRegion=' + document.gp_frm_sb_locedit.gp_sel_sb_locedit_regionselect.value;
		sendstr += '&PointCategory=' + document.gp_frm_sb_locedit.gp_sel_sb_locedit_categoryselect.value;
		sendstr += '&PointBunch=' + document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.checked;
		if (getLocationMode()==GP_EDIT_POINT_MODE){ // Point
			var urlstr="gp_write.php?action=addpoint&"+queryOptions;
			sendstr += '&PointLat=' + escapePlus(document.gp_frm_sb_locedit.gp_txt_sb_locedit_lat.value);
			sendstr += '&PointLng=' + escapePlus(document.gp_frm_sb_locedit.gp_txt_sb_locedit_lng.value);
		} else if (getLocationMode()==GP_EDIT_LINE_MODE){	// Line
			var urlstr="gp_write.php?action=addline&"+queryOptions;
			sendstr += '&PointLine=' + escapePlus(document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value);
		}
		request.open('POST', urlstr , true);
		request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
		request.onreadystatechange = function () {
			if (request.readyState == 4) {
				var xmlDoc = request.responseXML;
				replies = xmlDoc.documentElement.getElementsByTagName("reply");
				if (replies[0].getAttribute("id")==1){
					//userMessage (gp_lang['setting_ok']+gp_lang['please_refresh']);
				} else {
					userMessage ("ERROR: "+replies[0].getAttribute("message"));
				}
				//request.setRequestHeader("Connection","close");	// help: needed ?
				//map.setCenter(new GLatLng(document.gp_frm_sb_locedit.gp_txt_sb_locedit_lat.value,document.gp_frm_sb_locedit.gp_txt_sb_locedit_lng.value),+map.getZoom());
				
				hiddenEditMarker=false;		// stop old version of marker showing again
				pointReset();				// clear temp markers and such
				getVisibleMarkers();
			}
		}
		request.send(sendstr);
	}
}

// ==================================================== pointUpdate =========================================
// Updates an existing point in the database
function pointUpdate(){
	// perform checks
	if (isempty(document.gp_frm_sb_locedit.gp_txt_sb_locedit_name.value)){
		// No name
		userMessage(gp_lang['no_name_error']);
	} else {
		// update location
		if (newapi){
			map.closeInfoWindow();
		}
		if (settings['xinha_enabled'] == 1){
			var tmpInfo=xinha_editors.gp_txt_sb_locedit_infowindow.getHTML();
		} else {
			tmpInfo=document.gp_frm_sb_locedit.gp_txt_sb_locedit_infowindow.value;
		}
		/*
		if (document.gp_frm_sb_locedit.gp_txt_sb_locedit_infowindow.value.match(/http:\/\//)){	// URL in import
			document.gp_frm_sb_locedit.gp_txt_sb_locedit_infowindow.value=""; // clear it
		}
		*/
		request = GXmlHttp.create();
		sendstr = 'update_id='+selected_location;
		sendstr += '&PointName=' + escapePlus(document.gp_frm_sb_locedit.gp_txt_sb_locedit_name.value);
		sendstr += '&PointImport=' + escapePlus(document.gp_frm_line_import.gp_txt_line_import.value);
		sendstr += '&PointInfowindow='+escapePlus(tmpInfo);
		sendstr += '&PointRegion=' + escapePlus(document.gp_frm_sb_locedit.gp_sel_sb_locedit_regionselect.value);
		sendstr += '&PointCategory=' + document.gp_frm_sb_locedit.gp_sel_sb_locedit_categoryselect.value;
		sendstr += '&PointBunch=' + document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.checked;
		sendstr += '&PointRrZoom=' + document.gp_frm_sb_locedit.gp_sel_sb_locedit_regconv_zoomlevel.value;
		if (getLocationMode()==GP_EDIT_POINT_MODE){ // Point
			var urlstr="gp_write.php?action=editpoint&"+queryOptions;
			sendstr += '&PointLat=' + escapePlus(document.gp_frm_sb_locedit.gp_txt_sb_locedit_lat.value);
			sendstr += '&PointLng=' + escapePlus(document.gp_frm_sb_locedit.gp_txt_sb_locedit_lng.value);
		} else if (getLocationMode()==GP_EDIT_LINE_MODE){	// Line
			var urlstr="gp_write.php?action=editline&"+queryOptions;
			sendstr += '&PointLine=' + escapePlus(document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value);
		}
		if (document.gp_frm_sb_locedit.gp_chk_sb_locedit_regconv.checked==true){	// bunch point
			// clean bunch_mo to decimal places dependant on zoom
			var polytmp=geomToArray(document.gp_frm_sb_locedit.gp_txt_sb_locedit_movr.value);
			polytmp=arrayToGeom(polytmp);
			sendstr += '&PointBunchMo='+polytmp;
			// Build user and group lists from option list
			sendstr += '&PointRrUsers=';
			for (var i=0;i < document.gp_frm_sb_locedit.gp_sel_sb_locedit_regperm_users.length;i++){
				if (i>0){
					sendstr += ",";
				}
				sendstr += document.gp_frm_sb_locedit.gp_sel_sb_locedit_regperm_users.options[i].value;
			}
			sendstr += '&PointRrGroups=';
			for (var i=0;i < document.gp_frm_sb_locedit.gp_sel_sb_locedit_regperm_groups.length;i++){
				if (i>0){
					sendstr += ",";
				}
				sendstr += document.gp_frm_sb_locedit.gp_sel_sb_locedit_regperm_groups.options[i].value;
			}
		}
		request.open('POST', urlstr , true);
		request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
		request.onreadystatechange = function () {
			if (request.readyState == 4) {
				var xmlDoc = request.responseXML;
				replies = xmlDoc.documentElement.getElementsByTagName("reply");
				if (replies[0].getAttribute("id")==1){
					//userMessage (gp_lang['setting_ok']+gp_lang['please_refresh']);
				} else {
					userMessage ("ERROR: "+replies[0].getAttribute("message"));
				}
				// refresh the main region select, but don't replot the map
				getRegions(document.gp_frm_hdr_regionselect.gp_sel_hdr_regionselect.value,2,document.gp_frm_hdr_regionselect.gp_sel_hdr_regionselect);
				// centre on the new location
				//map.setCenter(new GLatLng(document.gp_frm_sb_locedit.gp_txt_sb_locedit_lat.value,document.gp_frm_sb_locedit.gp_txt_sb_locedit_lng.value),+map.getZoom());
				
				hiddenEditMarker=false;		// stop old version of marker showing again
				pointReset();				// clear temp markers and such
				getVisibleMarkers();
			}
		}
		request.send(sendstr);
	}
}

// ==================================================== pointDelete =========================================
// Deletes an existing point in the database
function pointDelete(){
	if (newapi){
		map.closeInfoWindow();
	}
	var request = GXmlHttp.create();
	var urlstr="gp_write.php?action=delpoint&"+queryOptions;
	var sendstr='update_id='+selected_location;
	request.open('POST', urlstr , true);
	request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
	request.onreadystatechange = function () {
		if (request.readyState == 4) {
			var xmlDoc = request.responseXML;
			replies = xmlDoc.documentElement.getElementsByTagName("reply");
			if (replies[0].getAttribute("id")==1){
				//userMessage (gp_lang['setting_ok']+gp_lang['please_refresh']);
			} else {
				userMessage ("ERROR: "+replies[0].getAttribute("message"));
			}
			
			hiddenEditMarker=false;		// stop old version of marker showing again
			pointReset();				// clear temp markers and such
			// shouldn't need to getVisibleMarkers, everything should be gone
		}
	}
	request.send(sendstr);
}

// ==================================================== textToWkt =========================================
// converts point / line data from various formats into the WKT-like format.
// Will just output the point / line data and NOT the linestring() or point() wrapper.
function textToWkt(linetmp){
	if (linetmp.match(new RegExp("^Date,Longitude,Latitude,Altitude"))){	// chtiGPS format trace detected.
		linetmp=linetmp.split("\n");
		var lineout="";
		var coords="";
		for (var i = 1; i < linetmp.length;i++){	// cycle through lines
			if (linetmp[i]){	// if not a blank line
				if (i>1){			// if not first iteration ...
					lineout += ",";	// add a comma after end of existing string
				}
				//linetmp[i]=linetmp[i].replace (/,/g, '.' )	// replace , with .
				coords=linetmp[i].split(",");				// split on the fields
				lineout+= (coords[1]+" "+coords[2]);	// assemble linestring in standard format
			}
		}
	} else {	// no specific format detected - return what was passed
		lineout=linetmp;
	}
	return (lineout);
}

// ==================================================== editSetting =========================================
// edits a default setting in the DB via an AJAX call
// set_key: lookup to key name in settings table
// set_value: name of control to take value from on gp_frm_sb_settings
function editSetting(set_key, set_value){
	decho ("Adding setting to phpBB db start");
	// Get setting from form
	switch (set_key){
		case "debug_mode":
			set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			break;
		case "xinha_settings":
			editSetting ('xinha_enabled',document.gp_frm_sb_settings.gp_sel_sb_settings_xinha_status.value);
			editSetting ('xinha_file',set_value+'filename');
			editSetting ('xinha_path',set_value+'path');
			set_key="xinha_buttons";
			set_value=set_value+"buttons";
			set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			break;
		case "xinha_file":
			set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			break;
		case "xinha_path":
			set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			break;
		case "xinha_enabled":
			//set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			break;
		case "showhelp_status":
			set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			break;
		case "default_view":	// aka default_lat, recalls editSetting with values for default_lng and default_zoom
			editSetting("default_lng",set_value+'lng');
			editSetting("default_zoom",set_value+'zoom');
			set_key="default_lat";	// re-write set_key for this run to lat
			set_value=set_value+"lat"	// re-write set_value for this run to that for lat
			set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			break;
		case "default_lng":
			set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			break;
		case "default_zoom":
			set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			break;
		case "default_region":
			set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			break;
		case "welcome_html":
			if (settings['xinha_enabled'] == 1){
				set_value=xinha_editors.gp_txt_sb_settings_welcome_html.getHTML();
			} else {
				set_value=eval ('document.gp_frm_sb_settings.'+set_value+'.value');
			}
			set_value=escapePlus(set_value);
			break;
		case "root_permissions":
			var root_users = '';
			var root_groups = '';
			for (var i=0;i<document.gp_frm_sb_settings.gp_sel_sb_settings_regperm_users.options.length;i++){
				if (i > 0){
					root_users += ",";
				}
				root_users += document.gp_frm_sb_settings.gp_sel_sb_settings_regperm_users.options[i].value;
			}
			for (var i=0;i<document.gp_frm_sb_settings.gp_sel_sb_settings_regperm_groups.options.length;i++){
				if (i > 0){
					root_groups += ",";
				}
				root_groups += document.gp_frm_sb_settings.gp_sel_sb_settings_regperm_groups.options[i].value;
			}
			
			break;
		default:
			userMessage("ERROR: UNKOWN CONTROL "+set_value);
			return (0);
	}

	if (set_key=="root_permissions"){
		var urlstr="gp_write.php?action=root_permissions&"+queryOptions;
		var sendstr="PointRrUsers="+root_users+"&PointRrGroups="+root_groups;
		var usermessage=gp_lang['setting_ok'];
	} else {
		var urlstr="gp_write.php?action=settings&"+queryOptions;
		var sendstr="setting="+set_key+"&value="+set_value;
		var usermessage=gp_lang['setting_ok']+gp_lang['please_refresh'];
	}
	var request = GXmlHttp.create();
	request.open('POST', urlstr , true);
	request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
	request.onreadystatechange = function () {
		if (request.readyState == 4) {
			var xmlDoc = request.responseXML;
			replies = xmlDoc.documentElement.getElementsByTagName("reply");
			if (replies[0].getAttribute("id")==1){
				settings[set_key]=unescape(set_value);		// set it in the array in memory too
				if (set_key != "default_lng" && set_key != "default_lat" && set_key != "xinha_path" && set_key != "xinha_file" && set_key != "xinha_enabled" ){	// mask these values as 3 are made at once
					userMessage (usermessage);
				}
			} else {
				userMessage ("ERROR: "+replies[0].getAttribute("message"));
			}
			decho ("Adding setting to phpBB db end");
			return(true);
		}
	}
	request.send(sendstr);
}

// ==================================================== editProfile =========================================
// edits a user profile setting in the DB via an AJAX call
function editProfile(set_key, set_value){
	decho ("Adding setting to phpBB db start");
	// Get setting from form
	switch (set_key){
		case "default_view":	// set default lng, lat and zoom
			set_value = document.gp_frm_sb_profile.gp_txt_sb_profile_lng.value+",";
			set_value += document.gp_frm_sb_profile.gp_txt_sb_profile_lat.value+",";
			set_value += document.gp_frm_sb_profile.gp_txt_sb_profile_zoom.value;
			break;
		case "default_region":
			if (set_value != ""){	// if it hasn't been set to blank to clear the setting
				set_value=eval ('document.gp_frm_sb_profile.'+set_value+'.value');
			}
			break;
		default:
			return (0);
	}

	var urlstr="gp_write.php?action=profile&"+queryOptions;
	var sendstr="setting="+set_key+"&value="+set_value;
	var usermessage=gp_lang['setting_ok']+gp_lang['please_refresh'];

	var request = GXmlHttp.create();
	request.open('POST', urlstr , true);
	request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
	request.onreadystatechange = function () {
		if (request.readyState == 4) {
			var xmlDoc = request.responseXML;
			replies = xmlDoc.documentElement.getElementsByTagName("reply");
			if (replies[0].getAttribute("id")==1){
				profile[set_key]=unescape(set_value);
				userMessage (usermessage);
			} else {
				userMessage ("ERROR: "+replies[0].getAttribute("message"));
			}
		}
		decho ("Adding setting to phpBB db end");
		return(true);
	}
	request.send(sendstr);
}


// opens a small size window (users)
function small_window(url,id) {
	var config = 'scrollBars=yes,resizable=yes,toolbar=no,menubar=no,location=no,directories=no,width=300,height=120';
	var newWindow = window.open(url, id, config);
}

// opens a medium sized window (groups)
function med_window(url,id) {
	var config = 'scrollBars=yes,resizable=yes,toolbar=no,menubar=no,location=no,directories=no,width=400,height=220';
	var newWindow = window.open(url, id, config);
}

// Adds a user to the region permissions list
// called by popup php script, may well not be used in this script.
function addRegionUser(id,name){
	if (currentmode == GP_EDIT_MODE){
		var destinationList = window.document.gp_frm_sb_locedit.gp_sel_sb_locedit_regperm_users;
	} else if (currentmode == GP_SETTINGS_MODE){
		var destinationList = window.document.gp_frm_sb_settings.gp_sel_sb_settings_regperm_users;
	}
	$ctr=0;
	for(var i = 0; i < destinationList.options.length; i++) {
		if (destinationList.options[i] != null){
			if (destinationList.options[i].value == id){	// user already in list
				$ctr++;
				break;
			}
		}
	}
	if ($ctr == 0){	// no matches - add user
		addOption(name,id,destinationList);
	}
}

// Adds a group to the region permissions list
// called by popup php script, may well not be used in this script.
function addRegionGroup(id,name){
	if (currentmode == GP_EDIT_MODE){
		var destinationList = window.document.gp_frm_sb_locedit.gp_sel_sb_locedit_regperm_groups;
	} else if (currentmode == GP_SETTINGS_MODE){
		var destinationList = window.document.gp_frm_sb_settings.gp_sel_sb_settings_regperm_groups;
	}
	$ctr=0;
	for(var i = 0; i < destinationList.options.length; i++) {
		if (destinationList.options[i] != null){
			if (destinationList.options[i].value == id){	// user already in list
				$ctr++;
				break;
			}
		}
	}
	if ($ctr == 0){	// no matches - add user
		addOption(name,id,destinationList);
	}
}

// Deletes an item from a select list
function delListItem(tmpitem){
	var i=tmpitem.selectedIndex;
	if (i >= 0){	// will be -1 if nothing selected.
		tmpitem.options[i] = null;
	}
}

// initialises the region forum system in the settings menu.
// Gets forum list via AJAX, populates box select_region_forum_f
// then calls getregions with postexec command to populate the region box
function initRegionForum(){
	var request = GXmlHttp.create();
	var urlstr="pat_read.php?action=forums";
	request.open('GET', urlstr, true);	// request XML from PHP with AJAX call
	request.onreadystatechange = function () {
		if (request.readyState == 4) {
			var xmlDoc = request.responseXML;
			var forums = xmlDoc.documentElement.getElementsByTagName("forum");
			
			clearOption(document.gp_frm_sb_settings.gp_sel_sb_settings_regforum_f);
			addOption("None",0,document.gp_frm_sb_settings.gp_sel_sb_settings_regforum_f);
			for (var i=0;i<forums.length;i++){
				//menu += '<option value="'+forums[i].getAttribute("id")+'">'+forums[i].getAttribute("name");
				addOption(forums[i].getAttribute("name"),forums[i].getAttribute("id"),document.gp_frm_sb_settings.gp_sel_sb_settings_regforum_f);
			}
			getRegions(1, 0, document.gp_frm_sb_settings.gp_sel_sb_settings_regforum_r);
		}
	}
	request.send(null);
}

// Updates the forum for a region in the database
function regionForumUpdate(region_id, forum_id){
	var request = GXmlHttp.create();
	var urlstr="gp_write.php?action=region_forum&"+queryOptions;
	var sendstr="&regid="+region_id+"&fid="+forum_id;
	request.open('POST', urlstr , true);
	request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
	request.onreadystatechange = function () {
		if (request.readyState == 4) {
			var xmlDoc = request.responseXML;
			var replies = xmlDoc.documentElement.getElementsByTagName("reply");
			if (replies[0].getAttribute("id")==1){
				userMessage (gp_lang['setting_ok']+gp_lang['please_refresh']);
			} else {
				userMessage ("ERROR: "+replies[0].getAttribute("message"));
			}
		}
	}
	request.send(sendstr);
}

// Populates fields with current location info
function getCenter(lng_box,lat_box,zoom_box){
	var center = map.getCenter();
	var xattr="lng()";
	var yattr="lat()";
	if (!isempty(lng_box) && !isempty(lat_box)){
		eval(lng_box+".value=rndVar(center."+xattr+")");
		eval(lat_box+".value=rndVar(center."+yattr+")");
	}
	if (!isempty(zoom_box)){
		eval (zoom_box+".value=map.getZoom()");
	}
}

// Does a search on an online geocoding engine
function searchGeo(site, words){
	if (site == "ws.geonames.org-fulltext"){
		var urlstr = 'http://ws.geonames.org/search?q='+escapePlus(words)+'&maxRows=10';
	} else if (site == "ws.geonames.org-postcodes"){
		var urlstr = 'http://ws.geonames.org/postalCodeSearch?postalcode='+escapePlus(words)+'&maxRows=10';
	}
	var urlstr='pat_read.php?action=geocode&ajaxpassthru='+escapePlus(urlstr);	// yes, words is escaped twice !
	var request = GXmlHttp.create();
	
	var x=document.getElementById('gp_tab_sb_viewmode_search_results_geo').insertRow(1);
	var y=x.insertCell(0);
	y.colSpan="3";
	y.innerHTML='<center>'+gp_lang['searching']+'... '+document.getElementById('gp_div_waitbar').innerHTML+'</center>';
	
	divOff('gp_div_sb_viewmode_search_results_gp');
	divOn('gp_div_sb_viewmode_search_results_geo');
	
	request.open('GET', urlstr , true);	// request XML from PHP with AJAX call
	request.onreadystatechange = function () {
		if (request.readyState == 4) {
			searchGeoResults(site,request.responseXML);
		}
	}
	request.send(null);
}

/* THC ***
// parses the results from a GeoCoder search
function searchGeoResults(site,xmlDoc){
	if (site=="ws.geonames.org-fulltext"){
		var results = xmlDoc.documentElement.getElementsByTagName("geoname");
	} else if (site=="ws.geonames.org-postcodes"){
		var results = xmlDoc.documentElement.getElementsByTagName("code");
	}
	
	deleteRows('gp_tab_sb_viewmode_search_results_geo');
	deleteRows('gp_tab_sb_viewmode_search_results_gp');

	//document.getElementById('gp_tab_sb_viewmode_search_results_geo').deleteRow(1);
	
	if (results.length){
		var rowtype = 1;
		for (var i=0;i<results.length;i++, rowtype++){
			if  (rowtype==4){
				rowtype=1;
			}
			var x=document.getElementById('gp_tab_sb_viewmode_search_results_geo').insertRow(i+1);
			var y=x.insertCell(0);
			y.innerHTML=i+1;
			var y=x.insertCell(1);
			y.innerHTML='<a href="javascript:map.setCenter(new GLatLng('+results[i].getElementsByTagName('lat')[0].firstChild.nodeValue+','+results[i].getElementsByTagName('lng')[0].firstChild.nodeValue+'))">'+results[i].getElementsByTagName("name")[0].firstChild.nodeValue+'</a>';
			var y=x.insertCell(2);
			y.innerHTML=results[i].getElementsByTagName("countryCode")[0].firstChild.nodeValue;

		}
	} else {
		var x=document.getElementById('gp_tab_sb_viewmode_search_results_geo').insertRow(1);
		var y=x.insertCell(0);
		y.colSpan=3;
		y.innerHTML='<center>'+gp_lang['no_match']+'</center>';
	}
}
*** */

// Deletes rows in a table
function deleteRows(tmpTable){
	tmpTable=document.getElementById(tmpTable);
		if(tmpTable){
		for (var i=tmpTable.rows.length-1;i>0;i--){
			tmpTable.deleteRow(i);
		}
	}
}

// Searches for a GP location
function searchLocs(words){
	if (isset(document.gp_frm_sb_viewmode_search)){	// form is drawn
		deleteRows('gp_tab_sb_viewmode_search_results_gp');
		divOn('gp_div_sb_viewmode_search_results_gp');
		divOff('gp_div_sb_viewmode_search_results_geo');
		var x=document.getElementById('gp_tab_sb_viewmode_search_results_gp').insertRow(1);
		var y=x.insertCell(0);
		y.colSpan="3";
		y.innerHTML='<center>'+gp_lang['searching']+'... '+document.getElementById('gp_div_waitbar').innerHTML+'</center>';
		var request = GXmlHttp.create();
		var urlstr="pat_read.php?action=search&words="+escape(words)+"&"+queryOptions;
		request.open('GET', urlstr , true);	// request XML from PHP with AJAX call
		request.onreadystatechange = function () {
			if (request.readyState == 4) {
				document.getElementById('gp_tab_sb_viewmode_search_results_gp').deleteRow(1);
				var xmlDoc = request.responseXML;
				var results = xmlDoc.documentElement.getElementsByTagName("result");
				if (results.length){
					var rowtype = 1
					for (var i=0;i<results.length;i++, rowtype++){
						if  (rowtype==4){
							rowtype=1;
						}
						var coords = results[i].getAttribute("geometry");
						coords=coords.split(",");	// seperate into points if a polyline
						coords=coords[0];	// take first point
						coords=coords.split(" ");	// split into lng, lat pairs
						var html = '<a href="javascript:';
						html += 'seekLocationId('+results[i].getAttribute("location_id")+','+coords[1]+','+coords[0]+','+results[i].getAttribute("zoom")+')';
						html += '">'+results[i].getAttribute("name")+'</a>';
						var x=document.getElementById('gp_tab_sb_viewmode_search_results_gp').insertRow(i+1);
						var y=x.insertCell(0);
						y.innerHTML=i+1;
						var y=x.insertCell(1);
						y.innerHTML=results[i].getAttribute("score");
						var y=x.insertCell(2);
						y.innerHTML=html;
					}
				} else {
					var x=document.getElementById('gp_tab_sb_viewmode_search_results_gp').insertRow(1);
					var y=x.insertCell(0);
					y.colSpan="3";
					y.innerHTML='<center>'+gp_lang['no_match']+'</center>';
				}
			}
		}
		request.send(null);
	}
}

// moves to a location and opens the infowindow of a marker by location_id
function seekLocationId(id,lat,lng,zoom){
	var tmpvar=infowindowMainById(id);
	if (tmpvar == false){	// if it fails to open it, it is not in the cache
		seek_id = id;
		zoom_through = 0;
		// Move the map to the location specified
		// should call GVM - if it does it should open the infowindow because seek_id is set.
		// if it doesn't, we are already here, why did infowindowMainById() fail ??
		map.setCenter(new GLatLng(lat,lng),zoom);
	}
}

// ==================================================== addPost =========================================
// Adds a post to phpBB
function addPost(location_id, marker_id){
	decho ("Adding post to phpBB start");
	var request = GXmlHttp.create();
	var urlstr="gp_write.php?action=addpost&"+queryOptions;
	var sendstr="update_id="+location_id;
	
	request.open('POST', urlstr , true);	// request XML from PHP with AJAX call
	request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	request.onreadystatechange = function () {
		if (request.readyState == 4) {
			var xmlDoc = request.responseXML;
			replies = xmlDoc.documentElement.getElementsByTagName("reply");
			if (replies[0].getAttribute("id")==1){
				decho ("Received AJAX reply - post added OK");
				// refresh the infowindow
				markers[marker_id].topic_id=replies[0].getAttribute("topic_id");
				infowindowMain(marker_id);
			} else {
				decho ("Received AJAX reply - post add FAILED");
				userMessage ("ERROR: "+replies[0].getAttribute("message"));
			}
			decho ("Adding post to phpBB end");
		}
	}
	request.send(sendstr);
}

/* THC ***
// Initializes the line import box
function lineImportInit(){
	//alert(selected_overlay);
	if (!selected_overlay.isempty && selected_overlay.markerindex >= 0){
		document.gp_frm_line_import.gp_txt_line_import.value=markers[selected_overlay.markerindex].locimport;
	} else {
		document.gp_frm_line_import.gp_txt_line_import.value='';
	}
	lineImportChange();
	divOn('gp_div_line_import');
}

// Called when user changes format selectbox
function lineImportChange(){
	if (document.gp_frm_line_import.gp_sel_line_import.value == 'gp'){
		document.getElementById('gp_spn_line_import').innerHTML = gp_lang['gp_format_desc'];
	} else {
		document.getElementById('gp_spn_line_import').innerHTML = gp_lang['chtigps_format_desc'];
	}
}
*** */

// Handles line import
function lineImport(){
	if (document.gp_frm_line_import.gp_sel_line_import.value == 'gp'){
		document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value=document.gp_frm_line_import.gp_txt_line_import.value;
		divOff('gp_div_line_import');
		editpath=new Array();
		plotTempMarkers();
	} else {
		var tmpStr=textToWkt(document.gp_frm_line_import.gp_txt_line_import.value);
		if (tmpStr != document.gp_frm_line_import.gp_txt_line_import.value){	// if contents changed
		
			divOff('gp_div_line_import');
			document.gp_frm_sb_locedit.gp_txt_sb_locedit_line.value=tmpStr;
			editpath=new Array();
			plotTempMarkers();
		} else {
			userMessage("NOT RECOGNISED");
		}
	}
}

// Opens import data in a new broswer window
function viewImportData(i){
	var load = window.open();
	load.document.write('<textarea style="width:100%; height:100%">'+unescape(markers[i].locimport)+'</textarea>');
}

function geocodeAddress(address,point) {
	if(isset(point)) {
		setDestination(point, defaultZoom);
		getVisibleMarkers();
	} else if(address != '' && isset(address)) {
		if (geocoder) {
			geocoder.getLatLng(
			address,
			function(point) {
			if (point) {
				setDestination(point, defaultZoom);
				getVisibleMarkers();
			} else {
				userMessage('The Address you entered could not be found. Please check your address and try again.');
				setDestination(center, defaultZoom);
				getVisibleMarkers();
			}
			});
		}
	} else {
		setDestination(center, defaultZoom);
		getVisibleMarkers();
	}
}

function setDestination(latlng, zoom) {
	destination = latlng;
	map.setCenter(latlng, zoom);
	if(addrMarker == null) {
		addrMarker = new GMarker(latlng, {icon:arrowIcon, draggable:true, autoPan:true});
		GEvent.addListener(addrMarker, "dragstart", function() {
			clearStuckPopups();
		});
		GEvent.addListener(addrMarker, "dragend", function() {
			destination = this.getPoint();
			map.setCenter(destination);
			getVisibleMarkers();
		});
	}
	addrMarker.setPoint(latlng);
	map.removeOverlay(addrMarker);
	map.addOverlay(addrMarker);
}

function hidePolyline(checked,i) {
	if (checked) {
		infowindowMain(i)
	} else if (markers[i].geometrytype=="LINESTRING" && polylines[markers[i].polyline] != null){
	   	map.removeOverlay(polylines[markers[i].polyline]);	
	}
}

function changeDay(d) {
	idx=$('s_days').selectedIndex;
	setDay($('s_days').options[idx].value);
}

function showHideMarkers() {
	clearStuckPopups();
	clearHighlight();
	var i=0;
	for (i;i<markers.length;i++){
		var l_id = 'loc_rec_'+i;
		if (markers[i].loc_mask & p_mask) {
			markers[i].show();
			if( markers[i].polyline != null ) {markers[i].polyline.show();}
			$(l_id).removeClassName('collapsed')
			if ( $(l_id).getElementsByClassName('dimmed').length > 0 )
				$(l_id).getElementsByClassName('dimmed')[0].remove();
		} else {
			markers[i].hide();
			if( markers[i].polyline != null ) {markers[i].polyline.hide();}
			$(l_id).addClassName('collapsed')
			if ( $(l_id).getElementsByClassName('dimmed').length <= 0 ) {
				var tmpDIV = Builder.node('div',{className: 'dimmed'});
				$(l_id).appendChild(tmpDIV);
			}
		}
	}
	// Get the Y offset of the last marker info box plus its height to get the height of
	// location_group_i div
	var tmp_id = 'location_group_'+currentcategory;
	if($(tmp_id) != null) {
		$(tmp_id).style.top='0px';
		var tmp_id = 'loc_rec_'+(i-1);
		infoBoxY = (Position.positionedOffset($(tmp_id)))[1]+$(tmp_id).getHeight();
		if (currentcategory==1) {
			location_group_1_Y=infoBoxY;
		} else {
			location_group_2_Y=infoBoxY;
		}
	}
}

function toggleParkingType(mask) {
	var l_id = 'legend_'+mask;
	if( p_mask & mask ) {
		p_mask &= ~mask;
	} else {
		p_mask |= mask;
	}
	showHideMarkers();
}
function pat_submit() {
    var url = 'pat_submit.php';
    var target = 'response_msg';

    var params = $('submit_form').serialize(true);
    var ajax = new Ajax.Updater(
    target, url, {parameters: params});
    document.getElementById('pat_f_div').style.display="none";
    document.getElementById('response_msg').style.display="block";
}
function pat_locations_up() {
	var tmp_id = 'location_group_'+currentcategory;
	var rem = -(Position.positionedOffset($(tmp_id)))[1];
	var move = rem > (viewportY-10)? (viewportY-10): rem;
	move = move > 0 ? move : 0;

	new Effect.MoveBy($(tmp_id), move, 0, {duration: 1,  transition: Effect.Transitions.slowstop});
}
function pat_locations_down() {
	var tmp_id = 'location_group_'+currentcategory;
	var rem = infoBoxY-(viewportY-10)+(Position.positionedOffset($(tmp_id)))[1];
	var move = rem > (viewportY-10)? -(viewportY-10): -(rem);
	move = move < 0 ? move : 0;

	new Effect.MoveBy($(tmp_id), move, 0, {duration: 1,  transition: Effect.Transitions.slowstop});
}
