/*******************************************************************************************
 * map
 * Written by Craig Francis
 * Functionality for the map
 *******************************************************************************************/

	var map = new function() {

		//--------------------------------------------------
		// Old browsers

			if (!document.getElementById || !document.getElementsByTagName) {
				return;
			}

		//--------------------------------------------------
		// Initialisation

			this.init = function() {

				//--------------------------------------------------
				// Debug

					console.log('map.js: Initialisation');

				//--------------------------------------------------
				// Defaults

					map.webRoot = '';

					map.canvasTileSize = 256;
					map.canvasTileHolder = [];
					map.canvasZoomMin = 1;
					map.canvasZoomMax = 4;
					map.canvasZoomCurrent = null;
					map.canvasMarginTop = 1033;
					map.canvasMarginLeft = 248;

				//--------------------------------------------------
				// Body

					var body = document.getElementsByTagName('body');
					if (body.length == 1) {
						body = body[0];
					} else {
						return;
					}

				//--------------------------------------------------
				// Start using JS enabled CSS

					$('html').addClass('jsMapEnabled');

				//--------------------------------------------------
				// Stop text selection - Safari allows the
				// text selection to scroll the window.

					// Disabled as it does not allow users

					//$('html').mousedown(function(){
					//	return false;
					//});

				//--------------------------------------------------
				// Ensure viewport is at the top... useful if
				// someone used the web developer to disable styles,
				// scrolled down the page, then refreshed the page.

					scroll(0, 0);

				//--------------------------------------------------
				// Search form

					//--------------------------------------------------
					// References

						map.searchFormRef = document.getElementById('searchForm');
						map.searchFormTypeRef = document.getElementById('searchFormType');
						map.searchFormKeywordRef = document.getElementById('searchFormKeyword');
						map.searchFormKeywordInputRef = document.getElementById('fldKeywords');

						if (!map.searchFormRef || !map.searchFormTypeRef || !map.searchFormKeywordRef || !map.searchFormKeywordInputRef) {
							return;
						}

						map.searchResults = $('#resultMessage');

					//--------------------------------------------------
					// Drag

						drag.setup(map.searchFormRef, {
							boundUpdate: map.searchBoundsUpdate
						});

						var initialLeft = 20;
						var initialTop = ($('#pageTitle').height() + 20);

						drag.setPosition(initialLeft, initialTop, map.searchFormRef);

 							// Needs to set a location so the script
							// knows where it is, otherwise it would
							// visually jump (to 0, 0) on first move.

					//--------------------------------------------------
					// Try to stop the click on the keyword input field
					// from doing a mouse drag.

						map.searchFormKeywordInputRef.onmousedown = function(e) {

							if (!e) e = window.event;
							e.cancelBubble = true;
							if (e.stopPropagation) e.stopPropagation();

						}

					//--------------------------------------------------
					// Search results

						var resultsWrapper = createElement('div');
						var resultsHeader = createElement('h2');
						var resultsList = createElement('ul');
						var resultsNone = createElement('li');

						resultsHeader.appendChild(document.createTextNode('Results'));

						resultsWrapper.appendChild(resultsHeader);
						resultsWrapper.appendChild(resultsList);

						resultsNone.appendChild(document.createTextNode('Please perform a search first'));
						resultsList.appendChild(resultsNone);

						resultsWrapper.style.position = 'absolute';
						resultsWrapper.style.left = '-5000px';

						map.searchFormTypeRef.appendChild(resultsWrapper);

						map.searchResultsRef = resultsList;

					//--------------------------------------------------
					// Type search

						map.searchFormTypeRef.onsubmit = function() {

							map.searchResults.html('<img src="' + map.webRoot + '/a/img/loading/greenWhite.gif" alt="Loading" width="16" height="16" />');

							var action = map.searchFormTypeRef.action;
							var search = $(map.searchFormTypeRef).serialize() + '&xml=true';

							$.post(action, search, map.stationSearchResults, 'xml');

							return false;

						};

					//--------------------------------------------------
					// Keyword search

						map.searchFormKeywordRef.onsubmit = function() {

							var url = map.searchFormKeywordRef.action;
							url += '?keywords=' + escape(map.searchFormKeywordInputRef.value);

							map.triggerLink(url);

							return false;

						};

				//--------------------------------------------------
				// Default zoom

					//var defaultZoom = ($(window).width() / map.canvasTileSize);
					//defaultZoom = Math.floor(Math.pow(defaultZoom, 0.5));
					//
					//if (defaultZoom < 1) {
					//	defaultZoom = 1;
					//}

					var defaultZoom = 3;

					this.canvasZoomChange(defaultZoom);

				//--------------------------------------------------
				// Map tools

					//--------------------------------------------------
					// Holder

						map.toolsRef = createElement('div');
						map.toolsRef.id = 'mapTools';

						body.appendChild(map.toolsRef);

					//--------------------------------------------------
					// Overview

						map.overviewRef = createElement('div');
						map.overviewRef.id = 'mapOverview';

						map.toolsRef.appendChild(map.overviewRef);

						map.overviewLayerRef = createElement('div');
						map.overviewLayerRef.style.zIndex = 5;
						map.overviewLayerRef.style.display = 'none';
						map.overviewLayerRef.id = 'mapOverviewLayer';
						map.overviewRef.appendChild(map.overviewLayerRef);

						map.overviewPinHolder = createElement('div');
						map.overviewPinHolder.id = 'mapOverviewPinHolder';
						map.overviewRef.appendChild(map.overviewPinHolder);

						map.overviewWidth = 170;
						map.overviewHeight = 96;

						drag.setup(map.overviewLayerRef, {
							onUpdate: map.overviewMoved,
							boundUpdate: map.overviewBoundsUpdate,
							relative: true
						});

					//--------------------------------------------------
					// Zoom

						//--------------------------------------------------
						// More

							var zoomLinkLess = createElement('img');
							zoomLinkLess.src = map.webRoot + '/a/img/global/overviewZoomLess.gif';
							zoomLinkLess.id = 'zoomLinkLess';
							zoomLinkLess.alt = 'Zoom out';
							zoomLinkLess.title = 'Zoom out';
							zoomLinkLess.onmouseup = map.canvasZoomChangeDecrease;

							map.toolsRef.appendChild(zoomLinkLess);

						//--------------------------------------------------
						// Less

							var zoomLinkMore = createElement('img');
							zoomLinkMore.src = map.webRoot + '/a/img/global/overviewZoomMore.gif';
							zoomLinkMore.id = 'zoomLinkMore';
							zoomLinkMore.alt = 'Zoom in';
							zoomLinkMore.title = 'Zoom in';
							zoomLinkMore.onmouseup = map.canvasZoomChangeIncrease;

							map.toolsRef.appendChild(zoomLinkMore);

						//--------------------------------------------------
						// Slider

							var zoomControl = createElement('div');
							zoomControl.id = 'mapZoom';
							map.toolsRef.appendChild(zoomControl);

							map.zoomControl = $(zoomControl);

							map.zoomControl.slider({
								handle: $('#mapZoom div'),
								min: map.canvasZoomMin,
								max: map.canvasZoomMax,
								stepping: 1,
								startValue: defaultZoom,
								slide: function(e, ui) {
									map.canvasZoomChange(ui.value);
								},
								stop: function(e, ui) {
									map.canvasZoomChange(ui.value);
								}
							});

				//--------------------------------------------------
				// Side bar banners

					//--------------------------------------------------
					// My places

						map.bannerPlacesRef = createElement('div');
						map.bannerPlacesRef.id = 'mapPlaces';

						var myPlacesImg = createElement('img');
						myPlacesImg.src = map.webRoot + '/a/img/global/placesBg.png';
						myPlacesImg.alt = 'My Places';

						var myPlacesLink = createElement('a');
						myPlacesLink.href = map.webRoot + '/myPlaces/';
						myPlacesLink.appendChild(myPlacesImg);
						map.bannerPlacesRef.appendChild(myPlacesLink);

						body.appendChild(map.bannerPlacesRef);

					//--------------------------------------------------
					// Win banner

						// map.bannerWinRef = createElement('div');
						// map.bannerWinRef.id = 'winBanner';
						// 
						// var winBannerImg = createElement('img');
						// winBannerImg.src = map.webRoot + '/a/img/global/winTickets.png';
						// winBannerImg.alt = 'Enter a review or attraction to win free rail tickets - Terms and conditions apply.';
						// 
						// var winBannerLink = createElement('a');
						// winBannerLink.href = map.webRoot + '/win/';
						// winBannerLink.appendChild(winBannerImg);
						// map.bannerWinRef.appendChild(winBannerLink);
						// 
						// body.appendChild(map.bannerWinRef);

				//--------------------------------------------------
				// Canvas

					//--------------------------------------------------
					// References

						map.canvasRef = createElement('div');
						map.canvasRef.id = 'mapHolder';

						body.appendChild(map.canvasRef);

						map.canvasPinHolder = createElement('div');
						map.canvasRef.appendChild(map.canvasPinHolder);

						map.LondonLinkRef = createElement('a');
						map.LondonLinkRef.href = 'http://www.daysoutguide.co.uk/attraction-types/2for1london.aspx';
						map.LondonLinkRef.style.position = 'absolute';
						map.LondonLinkRef.style.zIndex = 1;
						map.canvasRef.appendChild(map.LondonLinkRef);

						map.LondonLinkRef.style.backgroundImage = 'url("/a/img/global/transparent.gif")'; // IE6 needs something to "render"

						cssjs('add', map.LondonLinkRef, 'pdfLink');

					//--------------------------------------------------
					// Canvas maximum size

						map.canvasTilesMax = Math.pow(2, map.canvasZoomMax);
						map.canvasSizeMax = (map.canvasTilesMax * map.canvasTileSize);

					//--------------------------------------------------
					// Drag

						drag.setup(map.canvasRef, {
							onUpdate: map.canvasMoved,
							boundUpdate: map.canvasBoundsUpdate,
							onMouseClick: map.canvasClick
						});

				//--------------------------------------------------
				// Viewport dimensions

					map.viewportSizeUpdate();

					$(window).resize(function(){
						map.viewportSizeUpdate();
						map.overviewUpdateSize();
					});

				//--------------------------------------------------
				// Links

					$('a').click(function() {
						if (cssjs('check', this, 'popup')) {
							return false;
						} else if (cssjs('check', this, 'pdfLink')) {
							window.open(this.href);
						} else {
							map.triggerLink(this.href);
						}
						this.blur();
						return false;
					});

				//--------------------------------------------------
				// Show welcome screen

					if (window.location.search.match(/(\?|&)win/i)) {
						map.triggerLink(map.webRoot + '/win/');
					} else {
						map.triggerLink(map.webRoot + '/welcome/');
					}

			}

		//--------------------------------------------------
		// Update links

			this.triggerLink = function(url) {

				if (url.indexOf('javascript:void') >= 0) {
					return; // jQuery UI puts a link for IE6/7 on the zoom handle.
				}

				if (url.indexOf('/help/') >= 0 || url.indexOf('/welcome/') >= 0) {
					var height = 300;
				} else {
					var height = (map.viewportHeight - 150);
				}

				url += (url.indexOf('?') >= 0 ? '&' : '?');
				url += 'overlay=true&TB_iframe=true&height=' + escape(height) + '&width=600';

				tb_show(null, url, false);

			}

			this.updateMemberStatus = function() {

				//--------------------------------------------------
				// See if the members status has changed

					var loggedOn = document.cookie.match(/user_sessionIdS=[0-9]+/i);

					if (loggedOn) {
						$('#linkSignIn').text('Sign-out');
						$('#linkRegister').text('Profile');
					} else {
						$('#linkSignIn').text('Sign-in');
						$('#linkRegister').text('Register');
					}

			}

		//--------------------------------------------------
		// Station search

			this.stationSearchResults = function(data) {

				//--------------------------------------------------
				// Remove old pins

					if (map.pinsShown) {
						map.pinPositionRemove();
					}

				//--------------------------------------------------
				// Number of results

					var results = $(data).find('stations').attr('results');
					var message = results + ' result' + (results == 1 ? '' : 's') + ' found';

					map.searchResults.text(message);

				//--------------------------------------------------
				// Save the pins

					map.pinLocations = [];
					var htmlResults = '';

					$(data).find('station').each(function() {

						var id = $(this).attr('id');
						var url = $(this).attr('url');

						if (stations[id]) {

							map.pinLocations[id] = url;

							htmlResults += '<li><a href="' + url + '">' + stations[id].name + '</a></li>'; // HTML encoding???

						}

					});

					if (htmlResults == '') {
						htmlResults = '<li>No results found</li>';
					}

					$(map.searchResultsRef).html(htmlResults); // Accessible alternative - hopefully screen readers can pick this up

				//--------------------------------------------------
				// Position the pins

					map.pinPositionSet();

			}

		//--------------------------------------------------
		// Inject pin positions

			this.pinPositionInject = function(pins) {

				//--------------------------------------------------
				// Remove old pins

					if (map.pinsShown) {
						map.pinPositionRemove();
					}

				//--------------------------------------------------
				// Over-ride

					map.pinLocations = pins;

				//--------------------------------------------------
				// Position the pins

					map.pinPositionSet();

			}

		//--------------------------------------------------
		// Pin positions

			this.pinPositionSet = function() {

				//--------------------------------------------------
				// Got pins?

					if (!map.pinLocations) {
						return;
					}

				//--------------------------------------------------
				// Add stations

					var overviewMultiplier = (map.overviewWidth / (map.canvasSizeMax - (map.canvasMarginLeft * 2)));

					for (var k in map.pinLocations) {

						//--------------------------------------------------
						// Quick reference

							var station = stations[k];
							var url = map.pinLocations[k];

						//--------------------------------------------------
						// Position

							var left = ((map.canvasSizeCurrent / map.canvasSizeMax) * (station.mapX + map.canvasMarginLeft));
							var top = ((map.canvasSizeCurrent / map.canvasSizeMax) * (station.mapY + map.canvasMarginTop));

						//--------------------------------------------------
						// Create image

							var img = createElement('img');
							img.src = map.webRoot + '/a/img/global/pin.png';
							img.style.position = 'absolute';
							img.style.width = '29px';
							img.style.height = '27px';
							img.style.left = (left - 14) + 'px'; // Variation to get to centre of pin (visually)
							img.style.top = (top - 13) + 'px';
							img.style.cursor = 'pointer';
							img.style.zIndex = 2;
							img.alt = station.name;
							img.title = station.name;

						//--------------------------------------------------
						// Event

							img.pinUrl = url;

							$(img).click(function() {
								console.log('map.js: Show Station');
								map.triggerLink(this.pinUrl);
								this.blur();
								return false;
							});

						//--------------------------------------------------
						// Add

							map.canvasPinHolder.appendChild(img);

						//--------------------------------------------------
						// Overview pin

							var img = createElement('img');
							img.src = map.webRoot + '/a/img/global/pinSmall.png';
							img.style.position = 'absolute';
							img.style.width = '3px';
							img.style.height = '3px';
							img.style.left = ((station.mapX * overviewMultiplier) - 1) + 'px';
							img.style.top = ((station.mapY * overviewMultiplier) - 1) + 'px';
							img.style.zIndex = 4;
							img.alt = station.name;
							img.title = station.name;

							map.overviewPinHolder.appendChild(img);

					}

				//--------------------------------------------------
				// Shown

					map.pinsShown = true;

			}

			this.pinPositionRemove = function() {

				//--------------------------------------------------
				// Remove

					var ch = map.canvasPinHolder.childNodes;
					for (k = (ch.length-1); k >= 0; k--) {
						map.canvasPinHolder.removeChild(ch[k]);
					}

					var ch = map.overviewPinHolder.childNodes;
					for (k = (ch.length-1); k >= 0; k--) {
						map.overviewPinHolder.removeChild(ch[k]);
					}

			}

		//--------------------------------------------------
		// Canvas click

			this.canvasClick = function(mousePos) {

				//--------------------------------------------------
				// Don't bother when not at max zoom... if this is
				// going to be used though, you will need to update
				// the left/top values to the correct scale

					if (map.canvasZoomMax != map.canvasZoomCurrent) {
						return;
					}

				//--------------------------------------------------
				// Apply offset

					//var elementOffset = $(loc.formRef).offset();

					var left = mousePos.x - map.canvasMarginHorizontal;
					var top = mousePos.y - map.canvasMarginVertical;

				//--------------------------------------------------
				// Debug

					console.log('map.js: Station search (' + left + ', ' + top + ')');

				//--------------------------------------------------
				// Perform station search

					//--------------------------------------------------
					// Cache

						var leftL = (left - 15);
						var leftU = (left + 15);
						var topL = (top - 15);
						var topU = (top + 15);

					//--------------------------------------------------
					// Stations

						for (var k in stations) {
							if (stations[k].mapX > leftL && stations[k].mapX < leftU && stations[k].mapY > topL && stations[k].mapY < topU) {

								if (map.pinLocations && map.pinLocations[k]) { // Already shown as a pin

									console.log('map.js: Station search, ignored "' + stations[k].name + '"');

									return;

								} else {

									console.log('map.js: Station search, found "' + stations[k].name + '"');

									map.triggerLink(map.webRoot + '/attractions/?id=' + escape(k));

									return;

								}

							}
						}

					//--------------------------------------------------
					// Aliases

						for (var k in aliases) {
							if (aliases[k].mapX > leftL && aliases[k].mapX < leftU && aliases[k].mapY > topL && aliases[k].mapY < topU) {

								var stationId = aliases[k].stationId;

								if (map.pinLocations && map.pinLocations[stationId]) { // Already shown as a pin

									console.log('map.js: Station alias search, ignored "' + stations[stationId].name + '"');

									return;

								} else {

									console.log('map.js: Station alias search, found "' + stations[stationId].name + '"');

									map.triggerLink(map.webRoot + '/attractions/?id=' + escape(stationId));

									return;

								}

							}
						}

			}

		//--------------------------------------------------
		// Canvas zoom

			this.canvasZoomChangeIncrease = function() {
				map.canvasZoomChange(map.canvasZoomCurrent + 1);
				map.zoomControl.slider('moveTo', map.canvasZoomCurrent);
			}

			this.canvasZoomChangeDecrease = function() {
				map.canvasZoomChange(map.canvasZoomCurrent - 1);
				map.zoomControl.slider('moveTo', map.canvasZoomCurrent);
			}

			this.canvasZoomChange = function(newZoomLevel) {

				//--------------------------------------------------
				// Invalid zoom level

					if (newZoomLevel < map.canvasZoomMin) return;
					if (newZoomLevel > map.canvasZoomMax) return;

				//--------------------------------------------------
				// Don't bother if zoom hasn't changed... slider
				// triggers on mouse move, even if zoom didn't change.
				// We must also set the current zoom level now, as
				// the time-out allows this function to be called
				// many times before the end of canvasZoomChangeRun().

					var oldZoomLevel = map.canvasZoomCurrent;

					if (newZoomLevel == oldZoomLevel) {
						return;
					}

					map.canvasZoomCurrent = newZoomLevel;

				//--------------------------------------------------
				// Loading

					// NOTE: For some reason, FireFox keeps the CPU
					// usage high when this background image is used,
					// even when it has been removed.

					//$('html').addClass('jsMapLoading');

					//$('html').css('background', '#F00 url("/a/img/loading/background.gif") no-repeat 50% 50%');

				//--------------------------------------------------
				// Remove pins - won't be in the right position

					if (map.pinsShown) {
						map.pinPositionRemove();
					}

				//--------------------------------------------------
				// Remove current canvas holder

					if (oldZoomLevel !== null) {
						map.canvasTileHolder[oldZoomLevel].style.display = 'none';
					}

				//--------------------------------------------------
				// Run the main zoom function - done later so IE6
				// will redraw the page before continuing

					setTimeout(function() { // IE6 should re-draw the screen
						map.canvasZoomChangeRun(newZoomLevel, oldZoomLevel)
					}, 1);

			}

			this.canvasZoomChangeRun = function(newZoomLevel, oldZoomLevel) {

				//--------------------------------------------------
				// Debug

					console.log('map.js: Change map zoom (' + oldZoomLevel + ' > ' + newZoomLevel + ')');

				//--------------------------------------------------
				// Dimensions

					map.canvasTilesCurrent = Math.pow(2, newZoomLevel);
					map.canvasSizeCurrent = (map.canvasTilesCurrent * map.canvasTileSize);

					map.canvasMarginHorizontal = map.canvasSizeCurrent * (map.canvasMarginLeft / map.canvasSizeMax);
					map.canvasMarginVertical = map.canvasSizeCurrent * (map.canvasMarginTop / map.canvasSizeMax);

					map.canvasMapWidth = map.canvasSizeCurrent - (map.canvasMarginHorizontal * 2);
					map.canvasMapHeight = map.canvasSizeCurrent - (map.canvasMarginVertical * 2);

				//--------------------------------------------------
				// Update the dragging bounds

					map.canvasBoundsUpdate();

				//--------------------------------------------------
				// Add images

					map.canvasImagesToLoad = 0;

					if (!map.canvasTileHolder[newZoomLevel]) {

						console.log('map.js: Create zoom level (' + newZoomLevel + ')');

						map.canvasTileHolder[newZoomLevel] = createElement('div');
						map.canvasTileHolder[newZoomLevel].style.position = 'relative'; // Its the parent (map.canvasRef) which moves

						drag.setHandle(map.canvasTileHolder[newZoomLevel], map.canvasRef);

						for (var x = 0; x < map.canvasTilesCurrent; x++) {
							for (var y = 0; y < map.canvasTilesCurrent; y++) {

								var file = map.webRoot + '/a/img/map/' + escape(newZoomLevel) + '-' + escape(x) + '-' + escape(y) + '.jpg';

								if (true) {

									var img = new Image(); // Keep Konqueror happy (according to GAIV), as onload only triggers on JS Image object.
									img.src = file;

									// map.canvasImagesToLoad++;
									//
									// img.onload = function() {
									// 	map.canvasImagesToLoad--;
									// 	map.canvasLoaderRemove();
									// }

								} else {

									var img = createElement('div');
									img.style.background = 'url("' + file + '") no-repeat 0 0';

								}

								img.style.position = 'absolute';
								img.style.width = map.canvasTileSize + 'px';
								img.style.height = map.canvasTileSize + 'px';
								img.style.left = (map.canvasTileSize * x) + 'px';
								img.style.top = (map.canvasTileSize * y) + 'px';

								map.canvasTileHolder[newZoomLevel].appendChild(img);

								img = null;

							}
						}

						map.canvasRef.appendChild(map.canvasTileHolder[newZoomLevel]);

					} else {

						map.canvasTileHolder[newZoomLevel].style.display = 'block';

					}

				//--------------------------------------------------
				// Position

					if (oldZoomLevel == null) { // First load

						var canvasLeft = ((map.viewportWidth - map.canvasSizeCurrent) / 2);
						var canvasTop = ((map.viewportHeight - map.canvasSizeCurrent) / 2);

						canvasTop += $('#pageTitle').height() + $('#pageFooter').height(); // Centre calculated without title/footer

					} else {

						var zoomChange = (newZoomLevel - oldZoomLevel);

							// Take the "left" of the image, which may be
							// negative with it being outside of the new port,
							// and then work out its offset from the centre of
							// the viewport (i.e. not top/left of view port),
							// then multiply that offset from visual centre
							// by the change in size of image... afterwards,
							// switch back to using the top/left, rather than
							// centre of viewport.

						var viewportCenterOffsetLeft = Math.round(((map.viewportWidth  / 2) - map.canvasRef.dragPosCurrentLeft) * Math.pow(2, zoomChange));
						var viewportCenterOffsetTop  = Math.round(((map.viewportHeight / 2) - map.canvasRef.dragPosCurrentTop)  * Math.pow(2, zoomChange));

						var canvasLeft = ((map.viewportWidth / 2) - viewportCenterOffsetLeft);
						var canvasTop = ((map.viewportHeight / 2) - viewportCenterOffsetTop);

					}

					drag.setPosition(canvasLeft, canvasTop, map.canvasRef);

					map.canvasMoved(); // Cannot be called in setPosition, as it causes recursion

				//--------------------------------------------------
				// Overview size

					map.overviewUpdateSize();

				//--------------------------------------------------
				// Re-position the pins

					map.pinPositionSet();

				//--------------------------------------------------
				// Add London connections map

					var multiplier = (map.canvasSizeCurrent / map.canvasSizeMax);

					map.LondonLinkRef.style.left = (multiplier * (2090 + map.canvasMarginLeft)) + 'px';
					map.LondonLinkRef.style.top = (multiplier * (877 + map.canvasMarginTop)) + 'px';
					map.LondonLinkRef.style.width = (multiplier * 149) + 'px';
					map.LondonLinkRef.style.height = (multiplier * 77) + 'px';

				//--------------------------------------------------
				// Try to remove the loader

					//map.canvasLoaderRemove();

			}

			this.canvasLoaderRemove = function() { // Calling code (x2) has been disabled, as this function does not do anything atm
				if (map.canvasImagesToLoad <= 0) {
					//$('html').removeClass('jsMapLoading');
					//$('html').css('background', '#FFF');
				}
			}

		//--------------------------------------------------
		// Overview update size

			this.overviewUpdateSize = function() {

				if (map.viewportWidth < map.canvasMapWidth && map.viewportHeight < map.canvasMapHeight) {

					var overviewLayerWidth = ((map.viewportWidth / map.canvasMapWidth) * map.overviewWidth);
					var overviewLayerHeight = ((map.viewportHeight / map.canvasMapHeight) * map.overviewHeight);

					map.overviewLayerRef.style.width = overviewLayerWidth + 'px';
					map.overviewLayerRef.style.height = overviewLayerHeight + 'px';
					map.overviewLayerRef.style.display = 'block';

				} else {

					map.overviewLayerRef.style.width = '0px';
					map.overviewLayerRef.style.height = '0px';
					map.overviewLayerRef.style.display = 'none';

				}

			}

		//--------------------------------------------------
		// Overview or canvas move

			this.overviewMoved = function() {

				//--------------------------------------------------
				// Canvas position

					var canvasLeft = (((0 - map.overviewLayerRef.dragPosCurrentLeft) * (map.canvasMapWidth / map.overviewWidth)) - map.canvasMarginHorizontal);
					var canvasTop = ((((0 - map.overviewLayerRef.dragPosCurrentTop) * (map.canvasMapHeight / map.overviewHeight)) - map.canvasMarginVertical) + map.viewportSizeTitleHight);

					drag.setPosition(canvasLeft, canvasTop, map.canvasRef);

			}

			this.canvasMoved = function() {

				//--------------------------------------------------
				// Overview position

					var overviewLeft = (((0 - (map.canvasRef.dragPosCurrentLeft + map.canvasMarginHorizontal)) / map.canvasMapWidth) * map.overviewWidth);
					var overviewTop = (((0 - (map.canvasRef.dragPosCurrentTop + map.canvasMarginVertical - map.viewportSizeTitleHight)) / map.canvasMapHeight) * map.overviewHeight);

					drag.setPosition(overviewLeft, overviewTop, map.overviewLayerRef);

			}

		//--------------------------------------------------
		// Update bounds

			this.overviewBoundsUpdate = function() {
				map.canvasBoundsUpdate();
			}

			this.canvasBoundsUpdate = function() {

				//--------------------------------------------------
				// Bounds - must allow for half of the screen to be
				// white space (with the white area in the map also
				// being considered as valid) so that when the map
				// zooms in, the user can have the central point on
				// any position on the map.

					var left = (0 - (map.canvasSizeCurrent - (map.viewportWidth  / 2) - map.canvasMarginHorizontal));
					var right = ((map.viewportWidth  / 2) - map.canvasMarginHorizontal);

					var top = (0 - (map.canvasSizeCurrent - map.canvasMarginVertical - map.viewportSizeTitleHight - (map.viewportHeight / 2)));
					var bottom = (0 - (map.canvasMarginVertical - map.viewportSizeTitleHight - (map.viewportHeight / 2)));

				//--------------------------------------------------
				// Apply

					map.canvasRef.dragBoundValues = {
							left: left,
							right: right,
							top: top,
							bottom: bottom
						};

				//--------------------------------------------------
				// Overlay

					var overviewLeft = (0 - (((right + map.canvasMarginHorizontal) / map.canvasMapWidth) * map.overviewWidth));
					var overviewRight = (0 - (((left + map.canvasMarginHorizontal) / map.canvasMapWidth) * map.overviewWidth));

					var overviewTop = (0 - ((((bottom + map.canvasMarginVertical) - map.viewportSizeTitleHight) / map.canvasMapHeight) * map.overviewHeight));
					var overviewBottom = (0 - ((((top + map.canvasMarginVertical) - map.viewportSizeTitleHight) / map.canvasMapHeight) * map.overviewHeight));

					map.overviewLayerRef.dragBoundValues = {
							left: overviewLeft,
							right: overviewRight,
							top: overviewTop,
							bottom: overviewBottom
						};

			}

			this.searchBoundsUpdate = function() {

				//--------------------------------------------------
				// Dimensions

					var searchWidth = $('#searchForm').width();
					var searchHeight = $('#searchForm').height();

					searchHeight += 100; // There is 100px padding on the top, which isn't included in height().

				//--------------------------------------------------
				// Set the bounds

					var displayBy = 100;

					map.searchFormRef.dragBoundValues = {
							left: (0 - (searchWidth - displayBy)),
							right: (map.viewportWidth - displayBy),
							top: (0 - (searchHeight - displayBy - map.viewportSizeTitleHight)),
							bottom: (map.viewportHeight - displayBy + map.viewportSizeTitleHight)
						};

			}

		//--------------------------------------------------
		// Update viewport size

			this.viewportSizeUpdate = function() {

				console.log('map.js: Viewport size update');

				//var windowHeight = $(window).height(); // Does not work in Opera 9.5
				var windowHeight = ($('#pageFooter').offset().top + $('#pageFooter').height() + 4);

				map.viewportSizeTitleHight = $('#pageTitle').height();
				map.viewportSizeFooterHight = $('#pageFooter').height();
				map.viewportHeight = windowHeight - map.viewportSizeTitleHight - map.viewportSizeFooterHight;
				map.viewportWidth = $(window).width();

			}

		//--------------------------------------------------
		// On page load

			$(window).load(function () {
				map.init();
			});

	}
