// Include the AJAX stylesheet
document.write('<link rel="stylesheet" type="text/css" href="/css/ajax-map.css" />');

// The map number
var mapNumber = getURLParam("map");

// The XMLHttpRequest Objects
var mapRequest = false;    // For map AJAX requests
var infoRequest = false;   // For double click AJAX requests
var legendRequest = false; // For legend AJAX requests
			
try {
	mapRequest = new ActiveXObject("Msxml2.XMLHTTP");
	infoRequest = new ActiveXObject("Msxml2.XMLHTTP");
	legendRequest = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
	try {
		mapRequest = new ActiveXObject("Microsoft.XMLHTTP");
		infoRequest = new ActiveXObject("Microsoft.XMLHTTP");
		legendRequest = new ActiveXObject("Microsoft.XMLHTTP");
	}
	catch (e2) {
		mapRequest = new XMLHttpRequest();
		infoRequest = new XMLHttpRequest();
		legendRequest = new XMLHttpRequest();
	}
}
			
// The thing holding the map
var holder;
var width, height, xml;

// The map, loading screen
var theMap, loading;
		
// Drag variables
var dragX, dragY;
			
// Extent variables
var extentLeft, extentRight, extentTop, extentBottom, fullExtent, currentScale;

// Scrolling scalebar variables
var scrollerHeight, handleY;

// From permalink?
var fromPermalink = false;
var plink;

// Records whether the search field is focused
var hasFocus = false;

/*
 * Sets up the map viewer
 */	
function init() {
	// Firstly, stop the form from submiting
	document.forms["mainForm"].onsubmit = function() { return false; };
	
	// Get the map placeholder and its dimensions
	holder = document.getElementById("holder");
	getDimensions();

	// Set up the mapping elements
	holder.innerHTML = '<div id="map" style="position: absolute; top: 0; left: 0; border: 1px solid #000000;"><div id="watermark1"></div></div><div id="watermark2"></div><div id="proximitySearchButton"></div><div id="infobar"><div id="scale"></div><div id="copyright"><span id="permalink"></span>&nbsp;|&nbsp;<strong>&copy; Crown Copyright</strong>, Licence: ' + osLicenseNumber + '</div></div><div id="searchbar"></div><div id="policyInfo"></div><div id="loading"><div></div></div><div id="scroller"><div id="scrollerTop"></div><div id="scrollerBottom"></div><div id="zoomIn"></div><div id="zoomOut"></div><div id="handle"><div id="handleScale"></div></div></div><div id="scalebar"><div id="half"></div><div></div></div><div id="mapTitle">' + mapTitle + '</div><div id="panLeft"></div><div id="panRight"></div><div id="panUp"></div><div id="panDown"></div><div id="firstTime"><div class="handle"><img src="/common/interface/cancel.gif" alt="Close" style="float: right; cursor: pointer;" onclick="hideFirstTime();" /><img src="/common/interface/information.gif" alt="" /> Welcome</div><div class="padded"><h3>Welcome!</h3><p>It would appear that you are using this site for the first time! We would like to take this opportunity to recommend that you <a href="/document.aspx?display=help">read the help page</a> <em>before</em> using the mapping interface. This will allow you to use the maps to their full potential. Thank you.</p></div></div>';

	// Get a reference to the map, loading screen
	theMap = document.getElementById("map");
	loading = document.getElementById("loading");

	// Set up dragable elements
	Drag.init(theMap);
	
	// Set up the watermarks
	setupWatermark();	
				
	// Dragging events
	theMap.onDragStart = mapDragStart;
	theMap.onDrag = mapDrag;
	theMap.onDragEnd = mapDragEnd;
	
	// Mouse event handlers
	theMap.ondblclick = mapDblClick;
	theMap.oncontextmenu = new Function("return false;");
	document.getElementById("zoomIn").onclick = zoomIn;
	document.getElementById("zoomOut").onclick = zoomOut;
	document.getElementById("panLeft").onclick = panLeft;
	document.getElementById("panRight").onclick = panRight;
	document.getElementById("panUp").onclick = panUp;
	document.getElementById("panDown").onclick = panDown;
				
	// Initiate the infobar
	setupInfobar();
	
	// Initiate the scrollbar
	setupScroller();
	
	// Initiate searchbar
	if (searchEnabled) { // searchEnabled is defined by the CMS output
		setupSearchbar();
	}
	
	if (searchByProximity) { // searchByProximity is defined by the CMS output
		setupProximitySearchButton();
	}		
	
	// Show the loading bar
	loading.style.display = "block";
	
	// Generate the legend
	var legendUrl = "/legend_xml.aspx?map=" + mapNumber;
	document.getElementById("legend").innerHTML = "";
	legendRequest.open("GET", legendUrl, true);
	legendRequest.onreadystatechange = processLegend;
	legendRequest.send(null);
				
	// Set the image size
	theMap.style.width = width + "px";
	theMap.style.height = height + "px";
				
	var url;
	// Has the user clicked a permalink?
	if (getURLParam("action") == "setscale") {
		url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&left=" + getURLParam("left") + "&right=" + getURLParam("right") + "&top=" + getURLParam("top") + "&bottom=" + getURLParam("bottom") + "&action=setscale&scale=" + getURLParam("scale") + "&layers=all";
		fromPermalink = true;
	}
	else if (getURLParam("action") == "findlocation") {
		if (getURLParam("policies") != null && getURLParam("policies") != "") {
			fromPermalink = true; // Essentially a permalink
			url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&action=findlocation&policies=" + getURLParam("policies");
		}
		else if (getURLParam("polyid") != null && getURLParam("polyid") != "") {
			fromPermalink = true; // Essentially a permalink
			url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&action=findlocation&polyid=" + getURLParam("polyid");
		}
	}
	else if (getURLParam("x") > 0 && getURLParam("y") > 0) {
		url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&action=gotolocation&x=" + getURLParam("x") + "&y=" + getURLParam("y") + "&scale=" + getURLParam("scale") +  "&layers=all";
		fromPermalink = true;
	}
	// The default URL
	else {
		url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&layers=all";
	}
	sendRequest(url, update);
	
	// Is it the users' first time?
	if(getCookie("firstTime") != "no") {
		var date = new Date();
		date.setFullYear(3000,1,1);
		setCookie("firstTime", "no", date);
		document.getElementById("firstTime").style.display = "block";
		opacity("firstTime", 0, 100, 500);
	}
}

/*
 * Sets up the proximity search button
 */
function  setupProximitySearchButton() {
	// Get a handle to the button
	var proximitySearchButton = document.getElementById("proximitySearchButton");
	
	proximitySearchButton.innerHTML = "<img src=\"/common/interface/proximity-button.png\" alt=\"\" title=\"Click here to find out what is within 1km of the current map location!\" />";
	proximitySearchButton.style.position = "absolute";
	proximitySearchButton.style.left = "10px";
	proximitySearchButton.style.bottom = "30px";
	proximitySearchButton.style.width = "200px";
	proximitySearchButton.style.height = "30px";
	proximitySearchButton.style.cursor = "pointer";
	proximitySearchButton.onclick = proximitySearch;
}

/*
 * Performs a proximity search
 */
function proximitySearch() {
	var x, y;
	
	// Work out the coords based on the centre of the map			
	x = Math.round(width/2);
	y = Math.round(height/2);
	
	var url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&action=proximitysearch&x=" + x + "&y=" + y + "&left=" + extentLeft + "&right=" + extentRight + "&top=" + extentTop + "&bottom=" + extentBottom + visibleLayers();
	infoRequest.open("GET", url, true);
	infoRequest.onreadystatechange = proximityInfo;
	infoRequest.send(null);

}

/*
 * Sets up the search bar
 */
function setupSearchbar() {
	// Get handle on the search bar
	var searchbar = document.getElementById("searchbar");
	
	// Position the search bar in the bottom left
	searchbar.style.position = "absolute";
	searchbar.style.top = "50%";
	searchbar.style.left = "0px";
	searchbar.style.width = "206px";
	searchbar.style.height = "155px";
	searchbar.style.marginTop = "-77px";
	searchbar.style.marginLeft = "-194px";
	
	// Set some text
	searchbar.style.background = "url(/common/interface/search-tab.png) top right no-repeat";
	
	// A div to contain the search form
	searchbar.innerHTML += "<div id=\"searchform\" style=\"width: 194px; height: 153px; background: #cccccc; border-top: 1px solid #666666; border-bottom: 1px solid #666666;\"></div>";
	
	// Set up the note
	var note;
	if (searchByAddress && searchByPostcode) {
		note = "The search term can be either a postcode, or a partial address. Eg. 'High Street'."
	}
	else if (searchByAddress) {
		note = "The search term should be a partial address. Eg. 'High Street'."
	}
	else if (searchByPostcode) {
		note = "The search term should be a postcode."
	}
	
	// Set contents of search form
	var searchform = document.getElementById("searchform");
	searchform.innerHTML = "<div style=\"margin: 3px; padding: 5px; width: 176px; height: 135px; border: 1px solid #666666; background: #ffffff; text-align: center;\">" +
						   "<h4 style=\"margin-top: 0; margin-bottom: 10px; font-size: 1em;\">Search the map:</h4>" +
						   "<input type=\"text\" autocomplete=\"off\" style=\"border: 1px solid #666666; width: 165px;\" id=\"q\" value=\"enter search term\" /><br />" +
						   "<input type=\"submit\" onclick=\"document.getElementById('searchbar').style.marginLeft = '-194px'; search();\" value=\"search\" style=\"border: 1px solid #666666; background: #cccccc; margin-top: 10px;\" />" +
						   "<p style=\"text-align: left; font-size: x-small; margin-top: 10px; margin-bottom: 0;\">Note: " + note + "</p>" +
						   "</div>";
						   
	// Record focus of search
	document.getElementById("q").onclick = function() { hasFocus = true; document.getElementById("q").value = "" };
	document.getElementById("q").onblur = function() { hasFocus = false; };

	// Set up functions to show/hide
	searchbar.onmouseover = function() { searchbar.style.marginLeft = "0"; };
	searchbar.onmouseout = function() { if (!hasFocus) searchbar.style.marginLeft = "-194px"; };
}

/*
 * Searches the map
 */
function search() {
	// Send the search request
	var url = "/search_xml.aspx?q=" + document.getElementById("q").value;
	infoRequest.open("GET", url, true);
	infoRequest.onreadystatechange = searchInfo;
	document.body.style.cursor = "wait";
	infoRequest.send(null);
	
	// Blur the search field
	document.getElementById("q").blur();
}

/*
 * Displays search results
 */
function searchInfo() {
	if (infoRequest.readyState == 4 && infoRequest.status == 200) {
		// Change cursor to auto
		document.body.style.cursor = "auto";
		
		// Parse the XML
		xml = infoRequest.responseXML;
		
		var results = "";
					
		// Get the records
		var elements = xml.getElementsByTagName("record");
		for(var i=0; elements[i]; i++) {
			results += "<li><a href=\"#\" onclick=\"gotoCoords('" + elements[i].firstChild.nextSibling.firstChild.nodeValue + "', '" + elements[i].lastChild.firstChild.nodeValue + "'); return false;\">" + elements[i].firstChild.firstChild.nodeValue + "</a></li>";
		}
		if (results == "") {
			results = "<li>No results found</li>";
		}
		
		var policyInfo = document.getElementById("policyInfo");
		var html = '<div class="handle"><img src="/common/interface/cancel.gif" alt="Close" style="float: right; cursor: pointer;" onclick="hideResults();" /><img src="/common/interface/information.gif" alt="" /> Results</div><div class="padded"><h3>Results:</h3>';
		if (elements.length == 10) {
			html += '<p style="font-size: small;">More than 10 results were found, but only the first 10 will be shown. Please refine your search.</p>';
		}
		html += '<ul>' + results + '</ul></div>';
		policyInfo.innerHTML = html;
		policyInfo.style.display = "block";
		opacity("policyInfo", 0, 100, 500);
	}
}

/*
 * Goes to the specified coordinates
 */
function gotoCoords(x, y) {
	// Show the loading bar
	loading.style.display = "block";
	
	// Get the map XML
	var url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&action=goto&x=" + x + "&y=" + y + "&left=" + extentLeft + "&right=" + extentRight + "&top=" + extentTop + "&bottom=" + extentBottom + visibleLayers();
	document.body.style.cursor = "wait";
	sendRequest(url, update);
	
	// Hide the results window
	hideResults();
	
	// Set the scale slider to 1:500
	document.getElementById("handle").style.top = "0px";
}

/*
 * Sets up the watermarks
 */
function setupWatermark() {
	// Get handles to the watermarks
	var watermark1 = document.getElementById("watermark1").style;
	var watermark2 = document.getElementById("watermark2").style;

	// Set the width and height of the watermarks
	watermark1.width = watermarkImage.width + "px";
	watermark1.height = watermarkImage.height + "px";
	watermark2.width = watermarkImage.width + "px";
	watermark2.height = watermarkImage.height + "px";
	
	// Position the watermarks
	watermark1.position = "absolute";
	watermark2.position = "absolute";
	watermark1.top = "50%";
	watermark2.top = "50%";
	watermark1.left = "50%";
	watermark2.left = "50%";
	watermark1.marginLeft = "-" + (watermarkImage.width/2) + "px";
	watermark2.marginLeft = "-" + (watermarkImage.width/2) + "px";
	watermark1.marginTop = "-" + (watermarkImage.height/2) + "px";
	watermark2.marginTop = "-" + (watermarkImage.height/2) + "px";
	
	// Hide watermark2 
	watermark2.display = "none";
	
	// Set the watermark images
	if (!document.getElementById("watermark1").filters) {
		watermark1.background = "url(" + watermarkImage.src + ") no-repeat";
		watermark2.background = "url(" + watermarkImage.src + ") no-repeat";
	}
	else {
		// Set the appropriate filters
		watermark1.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + watermarkImage.src + "', sizingMethod='crop')";
		watermark2.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + watermarkImage.src + "', sizingMethod='crop')";
	}
}

/*
 * Sets a cookie
 */
function setCookie(name, value, expires, path, domain, secure) {
    document.cookie= name + "=" + escape(value) +
        ((expires) ? "; expires=" + expires.toGMTString() : "") +
        ((path) ? "; path=" + path : "") +
        ((domain) ? "; domain=" + domain : "") +
        ((secure) ? "; secure" : "");
}

/*
 * Gets a cookie
 */
function getCookie(name) {
    var dc = document.cookie;
    var prefix = name + "=";
    var begin = dc.indexOf("; " + prefix);
    if (begin == -1) {
        begin = dc.indexOf(prefix);
        if (begin != 0) return null;
    } else {
        begin += 2;
    }
    var end = document.cookie.indexOf(";", begin);
    if (end == -1) {
        end = dc.length;
    }
    return unescape(dc.substring(begin + prefix.length, end));
}

/*
 * Retrieves GET parameters from the URL
 */
function getURLParam(strParamName) {
	var strReturn = "";
	var strHref = window.location.href;
	if (strHref.indexOf("?") > -1) {
		var strQueryString = strHref.substr(strHref.indexOf("?")).toLowerCase();
		var aQueryString = strQueryString.split("&");
		for (var iParam = 0; iParam < aQueryString.length; iParam++) {
			if (aQueryString[iParam].indexOf(strParamName + "=") > -1) {
				var aParam = aQueryString[iParam].split("=");
				strReturn = aParam[1];
				break;
			}
		}
	}
	return strReturn;
}

/*
 * Sets up the info bat that shows the scale etc
 */
function setupInfobar() {
	document.getElementById("infobar").style.width = width + "px";
}

/*
 * Sets up the scroller for zooming in/out
 */
function setupScroller() {
	var handle = document.getElementById("handle");
	var scroller = document.getElementById("scroller");
	
	scrollerHeight = height - 180;
	
	scroller.style.height = scrollerHeight + "px";
	
	Drag.init(handle, null, 0, 0, 0, scrollerHeight - 15);
	handle.onDragStart = handleDragStart;
	handle.onDrag = handleDragging;
	handle.onDragEnd = handleDragEnd;
	
	handle.style.top = scrollerHeight - 15 + "px";
}

/*
 * Records the coordinates at start of map dragging
 */	
function mapDragStart(x, y) {
	dragX = x;
	dragY = y;
}

/*
 * Changes the cursor during mpa dragging
 */
function mapDrag(x, y) {
	theMap.style.cursor = "move";
	// Hide the original watermark
	document.getElementById("watermark1").style.display = "none";
	// Show the other watermark instead
	document.getElementById("watermark2").style.display = "block";
}

/*
 * Update the map when the user stops dragging it
 */
function mapDragEnd(x, y) {
	theMap.style.cursor = "auto";
			
	if (dragX == x && dragY == y) {
		return;
	}
	
	// Show the loading bar
	loading.style.display = "block";
		
	var clickX = Math.round((theMap.clientWidth/2) - (x));
	var clickY = Math.round((theMap.clientHeight/2) - (y));
				
	// Reload map
	getDimensions();
	var url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&action=pan&x=" + clickX + "&y=" + clickY + "&left=" + extentLeft + "&right=" + extentRight + "&top=" + extentTop + "&bottom=" + extentBottom + visibleLayers();
	document.body.style.cursor = "wait";
	sendRequest(url, update);
	
	// Hide the other watermark
	document.getElementById("watermark2").style.display = "none";
	// Show the original watermark instead
	document.getElementById("watermark1").style.display = "block";
}

/*
 * When the user starts zooming in/out with the drag thing
 */
function handleDragStart(x, y) {
	handleY = y;
	
	var range = fullExtent - 500;
		
	// Work out the %age at which the handle ended up
	var percent = (y/(scrollerHeight-15))*100;
		
	// The new scale is the %age of the range + 500
	var scale = Math.round((range/100)*percent)+500;
		
	document.getElementById("handleScale").innerHTML = "<b>Scale:</b>&nbsp;1:" + scale;
	document.getElementById("handleScale").style.display = "block";
}

/*
 * When the user is zoom in/out with the drag thing
 */
function handleDragging(x, y) {
	// The range is between the full extent and 1:500
	var range = fullExtent - 500;
		
	// Work out the %age at which the handle ended up
	var percent = (y/(scrollerHeight-15))*100;
		
	// The new scale is the %age of the range + 500
	var scale = Math.round((range/100)*percent)+500;
		
	document.getElementById("handleScale").innerHTML = "<b>Scale:</b>&nbsp;1:" + scale;
}

/*
 * When the user stops zooming in/out with the drag thing
 */
function handleDragEnd(x, y) {
	if (y != handleY) {
		// The range is between the full extent and 1:500
		var range = fullExtent - 500;
		
		// Work out the %age at which the handle ended up
		var percent = (y/(scrollerHeight-15))*100;
		
		// The new scale is the %age of the range + 500
		var scale = Math.round((range/100)*percent)+500;
	
		// Set the scale
		setscale(scale);
	}
	document.getElementById("handleScale").style.display = "none";
}

/*
 * Gets the width and height of the map display area
 */
function getDimensions() {
	width = holder.clientWidth;
	height = holder.clientHeight;
}

/*
 * Updates the map after an action has been peformed
 */
function update() {
	switch (mapRequest.readyState) {
		case 1:
			// Set the loading bar to 25%
			loading.getElementsByTagName("div")[0].style.width = "75px";
		break;
		case 2:
			// Set the loading bar to 50%
			loading.getElementsByTagName("div")[0].style.width = "150px";
		break;
		case 3:
			// Set the loading bar to 75%
			loading.getElementsByTagName("div")[0].style.width = "225px";
		break;
		case 4:
			// Set the loading bar to 100%
			loading.getElementsByTagName("div")[0].style.width = "300px";
			
			if (mapRequest.status == 200) {
				// Parse the XML
				xml = mapRequest.responseXML;
			
				// Now be really silly by setting a temporary background, hiding the original image, moving it, showing it,
				// and finally removing the temporary image!
				document.getElementById("holder").style.background = "url(" + xml.getElementsByTagName("url")[0].firstChild.nodeValue + ")";
				theMap.style.display = "none";
				theMap.style.background = "url(" + xml.getElementsByTagName("url")[0].firstChild.nodeValue +") no-repeat";
				theMap.style.top = "-1px";
				theMap.style.left = "-1px";
				theMap.style.display = "block";
				document.getElementById("holder").style.backgroundImage = "none";
					
				// Attempt to get the scale
				try {
					document.getElementById("scale").innerHTML = "<b>Scale:</b> 1:" + xml.getElementsByTagName("scale")[0].firstChild.nodeValue;
					currentScale = xml.getElementsByTagName("scale")[0].firstChild.nodeValue;
				}
				catch (e) {
				}
					
				// Get the full extent value
				try {
					fullExtent = xml.getElementsByTagName("fullExtent")[0].firstChild.nodeValue;
				}
				catch (e) {
				}
				
				// Attempt to get the distance covered by the map width
				try {
					var distance = xml.getElementsByTagName("distance")[0].firstChild.nodeValue;
					var full = Math.round((distance / width) * 300);
					var half = Math.round((distance / width) * 150);
					
					if (full >= 1000) {
						document.getElementById("scalebar").getElementsByTagName("div")[1].innerHTML = roundNumber(full/1000, 2) + "km&nbsp;";
					}
					else {
						document.getElementById("scalebar").getElementsByTagName("div")[1].innerHTML = full + "m&nbsp;";
					}
					
					if (half >= 1000) {
						document.getElementById("scalebar").getElementsByTagName("div")[0].innerHTML = roundNumber(half/1000, 2) + "km&nbsp;";
					}
					else {
						document.getElementById("scalebar").getElementsByTagName("div")[0].innerHTML = half + "m&nbsp;";
					}
				}
				catch (e) {
				}
					
				extentTop = xml.getElementsByTagName("top")[0].firstChild.nodeValue;
				extentRight = xml.getElementsByTagName("right")[0].firstChild.nodeValue;
				extentBottom = xml.getElementsByTagName("bottom")[0].firstChild.nodeValue;
				extentLeft = xml.getElementsByTagName("left")[0].firstChild.nodeValue;
				
				// Hide the loading bar
				loading.style.display = "none";
				loading.getElementsByTagName("div")[0].style.width = "0";
				
				// Update permalink
				permaLink();
				
				// Update proximity search
				updateProximitySearchButton();
				
				// Did the user visit via a permalink?
				if (fromPermalink) {
					// Work out where the handle should be on the scroller
					var range = fullExtent - 500;
					var percent = (currentScale - 500)/range;
					var position = Math.round((height-115) * percent);
					
					document.getElementById("handle").style.top = position + "px";
					
					fromPermalink = false;
				}
				
				// Change cursor to auto
				document.body.style.cursor = "auto";
			}
			else {
				alert("Error: " + mapRequest.status);
			}
		break;
	}
}

/*
 * Updates the state of the proximity search button
 */
function updateProximitySearchButton() {
	// If proximity search is enabled...
	if (searchByProximity) {
		// If the current scale is 1:5000 or higher
		if (currentScale <= 5000) {
			// Show the button
			document.getElementById("proximitySearchButton").style.display = "block";
		}
		else {
			// Hide the button
			document.getElementById("proximitySearchButton").style.display = "none";
		}
	}
}


/*
 * Rounds a number to the specified decimal places
 */
function roundNumber(num, places) {
	var newnumber = Math.round(num * Math.pow(10, places)) / Math.pow(10, places);
	return newnumber;
}

/*
 * Sets the scale of the map
 */
function setscale(scale) {
	// Show the loading bar
	loading.style.display = "block";
	
	var url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&action=setscale&scale=" + scale + "&left=" + extentLeft + "&right=" + extentRight + "&top=" + extentTop + "&bottom=" + extentBottom + visibleLayers();
	document.body.style.cursor = "wait";
	sendRequest(url, update);
}

/*
 * Performs a policy search on double click
 */
function mapDblClick(e) {
	var x, y;
				
	// IE doesn't use the same event model
	if (!e)
		var e = window.event;
				
	// Get the coordinates
	if (e.pageX || e.pageY) {
		x = e.pageX - holder.offsetLeft;
		y = e.pageY - holder.offsetTop;
	}
	else if (e.clientX || e.clientY) {
		x = e.clientX - holder.offsetLeft;
		y = e.clientY - holder.offsetTop;
	}
	
	var url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&action=policyinfo&x=" + x + "&y=" + y + "&left=" + extentLeft + "&right=" + extentRight + "&top=" + extentTop + "&bottom=" + extentBottom + visibleLayers();
	infoRequest.open("GET", url, true);
	infoRequest.onreadystatechange = policyInfo;
	infoRequest.send(null);
}

/*
 * Trims whitespace from a string
 */
function trim(sString) {
	while (sString.substring(0,1) == ' ') {
		sString = sString.substring(1, sString.length);
	}
	while (sString.substring(sString.length-1, sString.length) == ' ') {
		sString = sString.substring(0,sString.length-1);
	}
	return sString;
}


/*
 * Displays the results of a policy search
 */
function policyInfo() {
	if (infoRequest.readyState == 4 && infoRequest.status == 200) {
		// Parse the XML
		xml = infoRequest.responseXML;
					
		var policies = "";
		var areawide = "";
		var elements = xml.getElementsByTagName("policy");
		for(var i=0; elements[i]; i++) {
			policies += "<li>";
			// Shows the layer title
			for (var j=0; j<elements[i].lastChild.childNodes.length; j++) {
				// Depending on the supported method
				if (elements[i].lastChild.childNodes[j].xml) {
					policies += elements[i].lastChild.childNodes[j].xml;
				}
				else {
					policies += (new XMLSerializer()).serializeToString(elements[i].lastChild.childNodes[j]);
				}
			}
			// Shows a list of policies
			if (elements[i].firstChild.firstChild.nodeValue != "null") {
				policies += " - ";
				var policyLinks = elements[i].firstChild.firstChild.nodeValue.split(",");
				for (var j=0; j<policyLinks.length; j++) {
					policies += '<a href="/document.aspx?display=policy&amp;map=' + mapNumber + '&amp;policy=' + trim(policyLinks[j]) + '&amp;referer=' + encodeLink(plink) + '">' + trim(policyLinks[j]) + '</a>';
					if (j < policyLinks.length-2) {
						policies += ", ";
					}
					if (j == policyLinks.length-2) {
						policies += " &amp; ";
					}
				}
			}
			// Shows an external link for the layer
			if (elements[i].firstChild.nextSibling.firstChild.nodeValue != "null") {
				policies += ' (See: <a href="' + elements[i].firstChild.nextSibling.firstChild.nodeValue + '" target="_blank">external document</a>)';
			}
			policies += "</li>";
		}
		if (policies == "") {
			policies = "<li>No map layers were found at this location!</li>";
		}
		
		// Area-wide policies
		var elements2 = xml.getElementsByTagName("areaWide");
		if (elements2[0].firstChild.nodeValue != "null") {
			areawide = "<p>The following policies apply to all areas within this plan:</p><p>";
			var policyLinks2 = elements2[0].firstChild.nodeValue.split(",");
			for (var j=0; j<policyLinks2.length; j++) {
				areawide += '<a href="/document.aspx?display=policy&amp;map=' + mapNumber + '&amp;policy=' + policyLinks2[j] + '&amp;referer=' + encodeLink(plink) + '">' + policyLinks2[j] + '</a>';
				if (j < policyLinks2.length-2) {
					areawide += ", ";
				}
				if (j == policyLinks2.length-2) {
					areawide += " &amp; ";
				}
			}
			areawide += "</p>";
		}
		
		// In the plan area?
		var element3 = xml.getElementsByTagName("inPlanArea");
		if (element3[0].firstChild.nodeValue.toLowerCase() == "false") {
			policies = "<li>The selected location is not within the area covered by this map. Please consult the appropriate neighbouring authority if applicable.</li>";
		}
		
		var policyInfo = document.getElementById("policyInfo");
		policyInfo.innerHTML = '<div class="handle"><img src="/common/interface/cancel.gif" alt="Close" style="float: right; cursor: pointer;" onclick="hideResults();" /><img src="/common/interface/information.gif" alt="" />Results</div><div class="padded"><h3>Results:</h3><ul>' + policies + '</ul>' + areawide + '</div>';
		policyInfo.style.display = "block";
		opacity("policyInfo", 0, 100, 500);
	}
}

/*
 * Displays the results of a proximity search
 */
function proximityInfo() {
	if (infoRequest.readyState == 4 && infoRequest.status == 200) {
		// Parse the XML
		xml = infoRequest.responseXML;
					
		var policies = "";
		var areawide = "";
		var elements = xml.getElementsByTagName("policy");
		for(var i=0; elements[i]; i++) {
			policies += "<li>";
			// Shows the layer title
			for (var j=0; j<elements[i].lastChild.childNodes.length; j++) {
				policies += elements[i].firstChild.nextSibling.firstChild.nodeValue;
			}
			// Shows a list of policies
			if (elements[i].firstChild.firstChild.nodeValue != "null") {
				policies += " - ";
				var policyLinks = elements[i].firstChild.firstChild.nodeValue.split(",");
				for (var j=0; j<policyLinks.length; j++) {
					policies += '<a href="/document.aspx?display=policy&amp;map=' + mapNumber + '&amp;policy=' + trim(policyLinks[j]) + '&amp;referer=' + encodeLink(plink) + '">' + trim(policyLinks[j]) + '</a>';
					if (j < policyLinks.length-2) {
						policies += ", ";
					}
					if (j == policyLinks.length-2) {
						policies += " &amp; ";
					}
				}
			}
			// Shows an link to the item on the map
			policies += ' (<a href="javascript:gotoCoords(' + elements[i].firstChild.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nodeValue + ',' + elements[i].firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nodeValue + '); opacity(\'policyInfo\', 100, 0, 500);">view on map</a>)';
			policies += "</li>";
		}
		if (policies == "") {
			policies = "<li>Nothing was found!</li>";
		}
				
		// In the plan area?
		var element3 = xml.getElementsByTagName("inPlanArea");
		if (element3[0].firstChild.nodeValue.toLowerCase() == "false") {
			policies = "<li>The selected location is not within the area covered by this map. Please consult the appropriate neighbouring authority if applicable.</li>";
		}
		
		var policyInfo = document.getElementById("policyInfo");
		policyInfo.innerHTML = '<div class="handle"><img src="/common/interface/cancel.gif" alt="Close" style="float: right; cursor: pointer;" onclick="hideResults();" /><img src="/common/interface/information.gif" alt="" />Results</div><div class="padded"><h3>Results:</h3><p>The following places were found within 1km:</p><ul>' + policies + '</ul></div>';
		policyInfo.style.display = "block";
		opacity("policyInfo", 0, 100, 500);
	}
}

/*
 * Encodes a string as a link
 */
function encodeLink(string) {
	// Replace ampersands with %26
	string = string.replace(/&/g, "%26");
	string = string.replace(/&amp;/g, "%26");
	
	// Replace question mark with %3F
	string = string.replace(/\?/g, "%3F");
	
	// Replace equals sign with %3D
	string = string.replace(/=/g, "%3D");
	
	return string;
}

/*
 * Hides the results of a policy search
 */
function hideResults() {
	// Fade the results out
	opacity("policyInfo", 100, 0, 500);
	// Then hide them when they're done fading :)
	setTimeout("document.getElementById(\"policyInfo\").style.display = \"none\"", 500);
	theMap.style.cursor = "auto";
}

/*
 * Hides the "first time" message
 */
function hideFirstTime() {
	opacity("firstTime", 100, 0, 500);
	setTimeout("document.getElementById(\"firstTime\").style.display = \"none\"", 500);
}

/*
 * Generates a permalink for the current map view
 */
function permaLink() {
	plink = "?map=" + mapNumber + "&left=" + extentLeft + "&right=" + extentRight + "&top=" + extentTop + "&bottom=" + extentBottom + "&action=setscale&scale=" + currentScale + "&layers=all";
	document.getElementById("permalink").innerHTML = '<a href="' + plink + '">Permalink</a>';
}

/*
 * Fades the specified object in/out
 */
function opacity(id, opacStart, opacEnd, millisec) {
	//speed for each frame
	var speed = Math.round(millisec / 100);
	var timer = 0;

	//determine the direction for the blending, if start and end are the same nothing happens
	if(opacStart > opacEnd) {
		for(i = opacStart; i >= opacEnd; i--) {
			setTimeout("changeOpac(" + i + ",'" + id + "')",(timer * speed));
			timer++;
		}
	}
	else if(opacStart < opacEnd) {
		for(i = opacStart; i <= opacEnd; i++) {
			setTimeout("changeOpac(" + i + ",'" + id + "')",(timer * speed));
			timer++;
		}
	}
}

/*
 * Change the opacity for different browsers
 */
function changeOpac(opacity, id) {
	var object = document.getElementById(id).style;
	object.opacity = (opacity / 100);
	object.MozOpacity = (opacity / 100);
	object.KhtmlOpacity = (opacity / 100);
	object.filter = "alpha(opacity=" + opacity + ")";
}

/*
 * Processes the legend XML
 */
function processLegend() {
	if (legendRequest.readyState == 4 && legendRequest.status == 200) {
		// Parse the XML
		xml = legendRequest.responseXML;
		var legend = "";
		
		legend += "<div id=\"allOnAllOff\" style='text-align: center;'><strong>Map Layers:</strong> <a href='#' onclick='allOn(); return false;'>all on</a> | <a href='#' onclick='allOff(); return false;'>all off</a></div>";
	
		var sections = xml.getElementsByTagName("section");
		for (var i=0; sections[i]; i++) {
			// Get the section title
			var sectionTitle = sections[i].attributes[0].nodeValue;
			legend += "<h3 id=\"toggle" + i + "\" onclick=\"toggleLegend(" + i + ");\"><span>[&minus;]</span> " + sectionTitle + "</h3>";
			
			// Begin a table
			legend += "<table id=\"table" + i + "\">";
			
			// Get the items within the section
			var items = sections[i].getElementsByTagName("item");
			for (var j=0; items[j]; j++) {
				var id = items[j].childNodes[0].firstChild.nodeValue;
				var title = items[j].childNodes[1].firstChild.nodeValue;
				var image = items[j].childNodes[2].firstChild.nodeValue;
				legend += '<tr><td><img src="/legend_image.aspx' + image + '" /></td><td><input type="checkbox" onclick="layerChanges()" name="l' + id + '" id="l' + id + '"';
				// Is the layer on?
				if (getURLParam("l" + id) == "on" || getURLParam("layers") == "all") {
					legend += ' checked="checked"';
				}
				legend +=  '/></td><td class="label"><label for="l' + id + '">' + title + '</label></td></tr>';
			}
			
			// End the table
			legend += "</table>";
		}
		document.getElementById("legend").innerHTML = legend;
	}
}

/*
 * Turns all the layers on
 */
function allOn() {
	// Get all the checkboxes in the legend
	var elements = document.getElementById("legend").getElementsByTagName("input");
	
	// Loop through them all
	for (var i=0; elements[i]; i++) {
		// Tick them
		elements[i].checked = true;
	}
	
	// Reload the map
	layerChanges();
}

/*
 * Turns all the layers off
 */
function allOff() {
	// Get all the checkboxes in the legend
	var elements = document.getElementById("legend").getElementsByTagName("input");
	
	// Loop through them all
	for (var i=0; elements[i]; i++) {
		// Untick them
		elements[i].checked = false;
	}
	
	// Reload the map
	layerChanges();
}

/*
 * Shows or hides the legend section specified
 */
function toggleLegend(id) {
	var table = document.getElementById("table" + id);
	var toggle = document.getElementById("toggle" + id);
	
	if (table.style.display == "none") {
		table.style.display = "block";
		toggle.getElementsByTagName("span")[0].innerHTML = "[&minus;]";
	}
	else {
		table.style.display = "none";
		toggle.getElementsByTagName("span")[0].innerHTML = "[+]";
	}
}

/*
 * Zoom in to the next pre-defined scale
 */
function zoomIn() {
	var scales = new Array(200000, 100000, 75000, 50000, 25000, 10000, 5000, 2500, 1250, 500);
	
	// Loop through the scales and test to see which comes next
	for (var i=0; i<scales.length; i++) {
		if (currentScale > scales[i]) {
			setscale(scales[i]);
			
			// Work out where the handle should be on the scroller
			var range = fullExtent - 500;
			var percent = (scales[i] - 500)/range;
			var position = Math.round((height-195) * percent);
			document.getElementById("handle").style.top = position + "px";
			break;
		}
	}
}

/*
 * Zoom out to the next pre-defined scale
 */
function zoomOut() {
	var scales = new Array(1250, 2500, 5000, 10000, 25000, 50000, 75000, 100000, 200000, fullExtent);
	
	// Loop through the scales and test to see which comes next
	for (var i=0; i<scales.length; i++) {
		if (currentScale < scales[i] && scales[i] <= fullExtent) {
			setscale(scales[i]);
			
			// Work out where the handle should be on the scroller
			var range = fullExtent - 500;
			var percent = (scales[i] - 500)/range;
			var position = Math.round((height-195) * percent);
			document.getElementById("handle").style.top = position + "px";
			break;
		}
	}
}

/*
 * The following 4 functions handle the panning button onclick events
 */
function panLeft() {
	moveMap(width/2, "left", 300);
}
function panRight() {
	moveMap(width/2, "right", 300);
}
function panUp() {
	moveMap(height/2, "up", 300);
}
function panDown() {
	moveMap(height/2, "down", 300);
}

/*
 * The next three functions are for moving the map when the user clicks on a pan button,
 * and then updating the map as appropriate
 */
function moveMap(distance, direction, time) {
	// How often should it move?
	var interval = Math.round(time/distance);
	
	for(var i=1; i <= distance; i++) {
		setTimeout("setMapPosition(" + i + ",'" + direction + "')",(interval * i));
	}
	
	setTimeout("mapMoved()", (time+200)); // Leave 200ms extra just in case
}

function setMapPosition(position, direction) {
	switch(direction) {
		case "left":
			theMap.style.left = position + "px";
			break;
		case "right":
			theMap.style.left = -position + "px";
			break;
		case "up":
			theMap.style.top = position + "px";
			break;
		case "down":
			theMap.style.top = -position + "px";
			break;
	}
}

function mapMoved() {
	// Show the loading bar
	loading.style.display = "block";
	
	var clickX = Math.round((theMap.clientWidth/2) - (theMap.offsetLeft));
	var clickY = Math.round((theMap.clientHeight/2) - (theMap.offsetTop ));
				
	// Reload map
	getDimensions();
	var url = "/map_xml.aspx?map=" + mapNumber + "&width=" + width + "&height=" + height + "&action=pan&x=" + clickX + "&y=" + clickY + "&left=" + extentLeft + "&right=" + extentRight + "&top=" + extentTop + "&bottom=" + extentBottom + visibleLayers();
	sendRequest(url, update);
}

/*
 * This function sends a request for the URL, then runs the function specified
 */
function sendRequest(url, func) {
	mapRequest.open("GET", url, true);
	mapRequest.onreadystatechange = func;
	mapRequest.send(null);
}

/*
 * This function works out which layers should be displayed
 */
function visibleLayers() {
	var layerString = "";
	
	// Get a list of policies within the legend
	var policies = document.getElementById("legend").getElementsByTagName("input");
	for (var i=0; policies[i]; i++) {
		if (policies[i].checked == true)
			layerString += "&" + policies[i].id + "=on";
	}
	return layerString;
}

/*
 * The layers to be displayed have changed...
 */
function layerChanges() {
	setscale(currentScale);
}

/*
 * This checks that the browser really has resized - FF has a bug that fires the onresize event
 * after opening a tab and switching to the old one, or when closing a tab and switching to the old one!
 */
function checkResize() {
	var newWidth = holder.clientWidth;
	var newHeight = holder.clientHeight;
	
	if (Math.abs(height - newHeight) > 1 || Math.abs(width - newWidth) > 1) {
		init();
	}
}
			
window.onload = init;
window.onresize = checkResize;
