	//	main.js
	//	Top-level javascript for main.php
	//	Dunc 2005
	//
	// TD 001 04-Oct-2006
	//	Miscellaneous changes to deal with accessible layout of map controls

	oldColour = "";
	oldSrc = "";
	clip = null;
	searchURL = "" ;

	currEasting = 0;					// now only used for Minimap
	currNorthing = 0;					// ....

	currMinEasting = 0;
	currMaxEasting = 0;
	currMinNorthing = 0;
	currMaxNorthing = 0;

	drawArrow = false;
	updateArrow = false;
	ltisOptions = "";
	updateTimer = null;
	updateSecs = 0;
	countdownElem = null ;
	
	startupTimer = null;


	tmpZoom = 0;
	oldZoom = 0;
	currMapType = maptype;
	redraw=0;
	ltisTextCycle = 10000;

	cmdVMS = 0;
	cmdWho = 0;

	loaded = true;
	
	errNoAerial = "Aerial photos only available for\n750m, 1500m & 3000m maps";



	//	cctv stuff
	//	NB: 'cctvTimeoutSecs' is written to DOM by display.php::displayInitializeJavascript() using
	//	value 'ppl_cctv_timeout_secs' in ppl_default.conf
	cctvCurrSite = null;
	cctvTimer = null;
	cctvCountdownElem = null;
	cctvSecsRemaining = 0;
	cctvCycle = 0;
	cctvTimeoutSecs = 60;

	// CCTV Image dimensions - match tn2007-map.php
	cctvWid = 322;
	cctvHgt = 278;	//	258;
	cctvMinTop = 40 - cctvHgt;
	cctvMinLeft = 40 - cctvWid;

	
	//	New bit for dragging infolib div (07-03-05)...
	//	-----------------------------------------------
	var ie=document.all
	var ie7 = (ie && window.XMLHttpRequest)
	var ns6=document.getElementById&&!document.all

	var dragapproved=false
	var z,x,y

	cctvTimeoutSecs = 60;
	
	//	Set general key handler for this page...
	//	document.onkeypress = keyHandler;	// TD 001
	

	//	pageLoaded()
	//	This is the body onload function

function pageLoaded () {

		var cb = document.getElementById ( 'cbAUTO' );				//	LTIS checkbox
		var tu = document.getElementById ('searchPrintURL') ;		// Search URL

		updateZoomIndicator (zoom) ;
		wonload() ;

		if (tu)
			searchURL = tu.href ;

		if ( !cb ) return;
		if ( cb.checked ) updateTimerFunc();
		}

	function setExtents ( minx, maxx, miny, maxy ) {

		currMinEasting = minx;
		currMaxEasting = maxx;
		currMinNorthing = miny;
		currMaxNorthing = maxy;

		}

	function setMinimap ( e, n ) {

		//	e,n are easting and northing supplied by pinpoint via pinpoint.js when onload event fires.
		//	We use these parameters to draw a small box on the minimap, showing the user where he/she
		//	currently is. The size of the box is a function of the current zoom level.

		//	Clipping (if user scrolls off edge of minimap). This is a homebrew solution as clip:rect will not
		//	work with an empty div with just a border. 

		currEasting = e;
		currNorthing = n;

		var elem = document.getElementById ( "minimapDiv" );
		if ( !elem ) return;

		var tsm = tilesizes[zoom-1];	//	ie, Tile Size Metres

		if ( !clip )
			clip = new clipper ();

		clip.x = Math.round((e - minimap_mineasting) / minimap_mpp);
		clip.y = Math.round((minimap_maxnorthing - n ) / minimap_mpp);
		clip.wid = (tsm * 3) / minimap_mpp;
		clip.hgt = (tsm * 2) / minimap_mpp;

		getClipper ( clip ); 		

		elem.style.width = Math.round(clip.wid);
		elem.style.height = Math.round(clip.hgt);
		elem.style.left = clip.x-(clip.wid/2);
		elem.style.top = clip.y-(clip.hgt/2);

		elem.style.borderLeft = clip.borderLeft;
		elem.style.borderRight = clip.borderRight;
		elem.style.borderTop = clip.borderTop;
		elem.style.borderBottom = clip.borderBottom;

		elem.style.visibility = 'visible';

		
		}


	function setTmpZoom(newZoom) {
	
		tmpZoom = newZoom;
		alert("setTmpZoom: " + tmpZoom);
	}

	//	setZoom() is called from the PinPoint onLoad() event. It is the
	//	mechanism by which we can update UI elements on the host page from
	//	new data from PinPoint.
	function setZoom(newZoom) {
	
		zoom = newZoom;

		//alert ( "New zoom is: " + zoom );

		//zoom > 3 ? setMapType(3,true) : setMapType(3,false);
		
	
		}

		
	function setArrow(value) {
		drawArrow = value;
		}

	function setUpdateArrow(value) {
		updateArrow = value;
		}


function doZoom ( p ) 
{
	

	/* TD 001
		Change this to simply do the zooming - image swapping happens elsewehere
	*/
	var
		elem = document.getElementById("zoomVal");
	var
		newzoom = zoom;
		
	switch (p) 
	{
		case 'zoomin':		//	User has pressed '+' key...
			if ( newzoom - 1 < minzoom ) return;
			newzoom--;
			break;
		case 'zoomout':	//	User has pressed '-' key...
			if ( newzoom + 1 > maxzoom ) return;
			newzoom++;
			break;
		default:
			newzoom = p;
			//alert(oldZoom);
			oldSrc = "";
			break;
	}


	//	Maptype...
	var map = getMapType ();
/* HW: Comment out aerial level 1 check
	if ( map == 'aerial' && newzoom == 1 ) 
	{
		if ( confirm ( "Aerial Photos are unavailable at this zoom level.\nWould you still like to zoom in?" ) == false ) 
		{
			//setZoom( oldZoom );
			if (newzoom < 2) zoom = 2;
			updateZoomIndicator (zoom) ;
			elem.value = zoom ;
			setMapType ( 3 );	// set aerial
			redrawMap();
			return;
		}
		setMapType ( 1 );
	}
*/	
	if ( map == 'os50k' && newzoom > 4 ) 
	{
		if ( confirm ( "OS 1:50k maps are unavailable at this zoom level.\nWould you like a zoomed-in OS map?" ) == true ) 
		{
			//setZoom( oldZoom );
			if (newzoom > 4) zoom = 4;
			updateZoomIndicator (zoom) ;
			elem.value = zoom ;
			setMapType ( 5 );	// set os50k
			redrawMap();
			return;
		}
		setMapType ( 1 );
	}

	if ( map == 'osstreet' && newzoom > 2 ) 
	{
		if ( confirm ( "Detailed Maps are unavailable at this zoom level.\nWould you still like to zoom out?" ) == false ) 
		{
			//setZoom( oldZoom );
			if (newzoom > 2) zoom = 2;
			updateZoomIndicator (zoom) ;
			elem.value = zoom ;
			setMapType ( 6 );	// set street 10k
			redrawMap();
			return;
		}
		setMapType ( 1 );
	}
	
	if ( map == 'oslarge' && newzoom < 4 ) 
	{
		if ( confirm ( "Overview Maps are unavailable at this zoom level.\nWould you still like to zoom in?" ) == false ) 
		{
			//setZoom( oldZoom );
			if (newzoom < 4) zoom = 4;
			updateZoomIndicator (zoom) ;
			elem.value = zoom;
			setMapType ( 4 );	// set detailed
			redrawMap();
			return;
		}
		setMapType ( 1 );	// set colour
	}

	
	zoom = newzoom;
	
	elem.value = zoom ;
	setZoom(zoom);
	updateZoomIndicator (zoom) ;
	redrawMap ();
	// Redraw maptypes according to zoom
	map = getMapType ();
	redrawMaptypeAccordingToZoom( newzoom, map );

}	// doZoom()

// HW: This function dynamically changes the Map Type
// select (dropdown) options according the the current map
// zoom.

function redrawMaptypeAccordingToZoom( newzoom, map )
{
	var
		elem = document.getElementById("maptype");

	if ( !elem ) return;
			
	// Completely clear select box
	elem.options.length = 0;
	
	// Work out allowed options
	var optionMap = new Array();
	var selectedOption = 1;		// Colour is default
	var numOptions = 0;

	switch ( newzoom ) 
	{
	case 6:
	case 5:
	case 4:
		if ( 1 == getTNSCCZLEZ()   ) {
			// OS 10k not available at zoom levels 6-3 for CC. 
			optionMap = new Array( 
				'Overview Map','oslarge', 
				'Colour', 'colour', 
				'Greyscale', 'greyscale'
				//'Aerial', 'aerial'
			);
			numOptions = 3;
		} else {
			optionMap = new Array( 
				'Colour', 'colour', 
				'Greyscale', 'greyscale'
				//'Aerial', 'aerial'
			);
			numOptions = 2;
		}
		break;
	case 3:
		// OS 10k not available at zoom levels 6-3. 
		optionMap = new Array( 
			'Colour', 'colour', 
			'Greyscale', 'greyscale'
			//'Aerial', 'aerial'
		);
		numOptions = 2;
		break;
	case 2:
		if ( 1 == getTNSCCZLEZ() ) {
			// Overview not available at zoom level 2 for CC. 
			optionMap = new Array( 
				'Colour', 'colour', 
				'Greyscale', 'greyscale',
			//	'Aerial', 'aerial', 
				'Detailed Map', 'osstreet'
			);
			numOptions = 3;
		} else {
			optionMap = new Array( 
				'Colour', 'colour', 
				'Greyscale', 'greyscale'
			//	'Aerial', 'aerial'
			);
			numOptions = 2;
		}
		break;
	case 1:
		// HW: Added aerial back in for zoom level 1
		if ( 1 == getTNSCCZLEZ() ) {
			// Overview not available at zoom level 1 for CC. 
			optionMap = new Array( 
				'Colour', 'colour', 
				'Greyscale', 'greyscale',
			//	'Aerial', 'aerial',
				'Detailed Map', 'osstreet'
			);
			numOptions = 3;
		} else {
			optionMap = new Array( 
				'Colour', 'colour', 
				'Greyscale', 'greyscale'
				//'Aerial', 'aerial'
			);
			numOptions = 2;
		}
		break;
	default:
	}
	
	// Populate select box with allowed options
	for( var i = 0; i < numOptions * 2 ; i += 2 )
	{
		elem.options[i/2] = new Option( optionMap[i], optionMap[i+1] );
		if ( optionMap[i+1] == map )
			selectedOption = i/2 ;
	}
	// alert ( map + " " + selectedOption );

	// Set selected option
	elem.selectedIndex = selectedOption;
	
}	// redrawMaptypeAccordingToZoom( newzoom )
	

function checkMapExtents (x, y) {

		var tsm = tilesizes[zoom-1];	//	ie, Tile Size Metres

		var w = tsm * 3;
		var h = tsm * 2;

		var mineast = 0;
		var maxeast = 0;
		var minnorth = 0;
		var maxnorth = 0;

		mineast = x - (w/2);
		maxeast = x + (w/2);

		minnorth = y - (h/2);
		maxnorth = y + (h/2);

		// HW DEBUG 
		// alert ( "x= " + x + " y= " + y + " zoom=" + zoom + " mineast=" + mineast + " maxeast=" + maxeast + " minnorth=" + minnorth + " maxnorth=" + maxnorth + "\nmineasting=" + mineasting + " maxeasting=" + maxeasting + " minnorthing=" + minnorthing + " maxnorthing=" + maxnorthing );
		
		if ( mineast < mineasting ) return false;
		if ( maxeast > maxeasting ) return false;
		if ( minnorth < minnorthing ) return false;
		if ( maxnorth > maxnorthing ) return false;

		return true;

		}

/* HW: This second version simply checks if x and y are outside the allowable
   rectangle */
	function checkMapExtents2 (x, y) {

		// HW DEBUG 
		// alert ( "x= " + x + " y= " + y + " zoom=" + zoom + " mineast=" + mineast + " maxeast=" + maxeast + " minnorth=" + minnorth + " maxnorth=" + maxnorth + "\nmineasting=" + mineasting + " maxeasting=" + maxeasting + " minnorthing=" + minnorthing + " maxnorthing=" + maxnorthing );
		
		if ( x < mineasting ) return false;
		if ( x > maxeasting ) return false;
		if ( y < minnorthing ) return false;
		if ( y > maxnorthing ) return false;

		return true;

		}
		
		
	//	redrawMap()
	//	This is the ONLY point where the map iframe gets redrawn.
	//	Variable args.

	function redrawMap () {

//	if ( loaded == false ) return; // TD 001: "childLoaded" doesn't always fire if several clicks on navbar

		// TD 001
		// Save altered criteria in form fields - we need to provide limited functionality WITHOUT
		// JavaScript and so we have to have state preserved in form fields so that the document can
		// be resubmitted and the context retained.

		var
			elem = document.getElementById ("mapFrame"),
			elem1 = document.getElementById("eastingVal"),
			elem2 = document.getElementById("northingVal"),
			elem3 = document.getElementById("arrowEVal"),
			elem4 = document.getElementById("arrowNVal"),
			elem5 = document.getElementById("drawArrowVal"),
			elem6 = document.getElementById("updateArrowVal"),
			elemdebug = document.getElementById("curXY") ;

		var 
			east, north, arrowE, arrowN, drawArrow, updateArrow ;

		if ( !elem ) return;
		if ( !elem1 ) return;
		if ( !elem2 ) return;
		if ( !elem3 ) return;
		if ( !elem4 ) return;
		if ( !elem5 ) return;
		if ( !elem6 ) return;

		var url = getURL (zoom);
		if ( url == null ) return;
		
		east = parseInt(elem1.value) ;
		north = parseInt(elem2.value) ;
		arrowE = parseInt(elem3.value) ;
		arrowN = parseInt(elem4.value) ;
		drawArrow = (elem5.value == "true" ? "true" : "false" );
		updateArrow = (elem6.value == "true" ? "true" : "false" );
		
		// HW DEBUG
		// alert ("redrawMap east=" + east + " north=" + north + " arrowE=" + arrowE + " arrow=" + arrowN + " drawArrow=" + drawArrow + " updateArrow=" + updateArrow + " url=" + url );
		
		
		//	Single argument so called via the navigation (panning) function...
		if ( redrawMap.arguments.length == 1 && zoom > 0 && zoom < 7) {
			var neweast = east;
			var newnorth = north;							
			switch ( redrawMap.arguments[0] ) {
				case 'n':	newnorth = north + tilesizes[zoom-1] ;
							break;
				case 'ne':	newnorth = north + tilesizes[zoom-1] ;
							neweast = east + tilesizes[zoom-1] ;
							break;
				case 'e':	neweast = east + tilesizes[zoom-1] ;
							break;
				case 'se':	neweast = east + tilesizes[zoom-1] ;
							newnorth = north - tilesizes[zoom-1] ;
							break;
				case 's':	newnorth = north - tilesizes[zoom-1] ;
							break;
				case 'sw':	neweast = east - tilesizes[zoom-1] ;
							newnorth = north - tilesizes[zoom-1] ;
							break;
				case 'w':	neweast = east - tilesizes[zoom-1] ;
							break;
				case 'nw':	neweast = east - tilesizes[zoom-1] ;
							newnorth = north + tilesizes[zoom-1] ;
							break;
				default:;
			}

			if ( checkMapExtents2 (neweast,newnorth) == false ) {
			//  If at edge, set updateArrow=false.
			//  Do not update E,N, or arrow E,N, or drawArrow.
				alert ( "Edge of map has been reached!\nYou may need to zoom in,\nand move or search the map again." );
				

				updateArrow = "false";
				elem6.value = updateArrow ;
 			}
			else {
			//  If in map, set updateArrow=false.
			//	Update E,N. Do not update arrow E,N, or drawArrow.
				
				east = neweast;
				north = newnorth;
				elem1.value = neweast ;
				elem2.value = newnorth ;
	
				updateArrow = "false";
				elem6.value = updateArrow ;
			}

			// HW DEBUG 
			// alert ("1 east="+east+" north="+north+" arrowE="+arrowE+" arrowN="+arrowN+" drawArrow="+drawArrow+" updateArrow="+updateArrow);
		}

		//	Two args, which must be easting and northing (called from minimap)...
		//  Or user has clicked on canvas.
		if ( redrawMap.arguments.length == 2 ) {
			var neweast = redrawMap.arguments[0];
			var newnorth = redrawMap.arguments[1];

			//	Check map fits...
			if ( checkMapExtents2 (neweast,newnorth) == false ) {
			// if ( false ) {
			//  If at edge, set drawArrow=false, set updateArrow=false.
			//  Don't update E,N or arrow E,N.
				alert ( "Edge of map has been reached!\nYou may need to zoom in,\nand move or search the map again." );
			
				drawArrow = "false";
				elem5.value = drawArrow ;
				url += "&drawArrow=" + drawArrow;
				
				updateArrow = "false";
				elem6.value = updateArrow ;
			}
			else {
			//  If in map, set drawArrow=false, set updateArrow=false
			//  Update E,N but reset arrow E,N
			
				east = neweast;
				north = newnorth;
				elem1.value = neweast ;
				elem2.value = newnorth ;

				arrowE = 0;
				arrowN = 0;
				elem3.value = 0 ;	// Ignore arrowE on initial draw
				elem4.value = 0 ;	// Ignore arrowN on initial draw
				
				drawArrow = "false";
				elem5.value = drawArrow ;
				
				updateArrow = "false";
				elem6.value = updateArrow ;
			}
								
			// HW DEBUG 
			// alert ("2 east="+east+" north="+north+" arrowE="+0+" arrowN="+0+" drawArrow="+drawArrow+" updateArrow="+updateArrow);
			
		}

		//	Three args means a search...
		//	arg[0] = 'search'
		//	arg[1] = 'street' or 'postcode' (literal)
		//	arg[2] = value
		// HW: When a postcode search is done, 
		// redraw is called with 3 args, then again with 4 args.
		if ( redrawMap.arguments.length == 3 ) {
			
			var reloadURL = getFrameURL();

			// HW: Postcode search, so turn on update arrow. Does this do anything?
			// setUpdateArrow(true);

			// HW: Always updateArrow for a postcode search.
			// Arrow will be drawn at easting & northing.
			//reloadURL += "&updateArrow=true";

			//prompt('DEBUG:', url);
			if ( redrawMap.arguments[0] != 'search' ) return;
			if ( redrawMap.arguments[1] != 'street' && redrawMap.arguments[1] != 'postcode' && redrawMap.arguments[1] != 'all' ) return;
			
			var urlSearch = "tn2007-search.php?" + redrawMap.arguments[1] + "_search=" + redrawMap.arguments[2] + "&url=" + reloadURL;
			elem.src = urlSearch;
			
			// HW DEBUG
			// alert ("3 east="+east+" north="+north);
			// alert ( urlSearch );
			return;
			}


		// The 4 arg version will update the arrow E,N
		if ( redrawMap.arguments.length == 4 ) {
			var neweast = redrawMap.arguments[0];
			var newnorth = redrawMap.arguments[1];
			var newarrowE = redrawMap.arguments[2];
			var newarrowN = redrawMap.arguments[3];

			//	Check map fits...
			if ( checkMapExtents2 (neweast,newnorth) == false ) {
			// if ( false ) {
			// If at edge, set updateArrow=false.
			// Don't update E,N or arrow E,N, or drawArrow.
			
				alert ( "Edge of map has been reached!\nYou may need to zoom in,\nand move or search the map again." );

				updateArrow = "false";
				elem6.value = updateArrow ;
			}
			else {
			// If in map, set drawArrow=true, set updateArrow=true
			// Update E,N and arrow E,N.
				east = neweast;
				north = newnorth;
				elem1.value = neweast ;
				elem2.value = newnorth ;
				
				arrowE = neweast;
				arrowN = newnorth;
				elem3.value = neweast ;
				elem4.value = newnorth ;
				
				drawArrow = "true";
				elem5.value = drawArrow ;
				
				updateArrow = "true";
				elem6.value = updateArrow ;
			}
			
			// HW DEBUG 
			// alert ("4 east="+east+" north="+north+" arrowE="+arrowE+" arrowN="+arrowN+" drawArrow="+drawArrow+" updateArrow="+updateArrow);
		}
			
	//	Safari 'bug' -- without a unique URL, Safari will not redraw if 'pan' remains the same. So, 
		//	create a unique URL with the 'cyc' param + an incremented number...

		url += "&easting=" + east + "&northing=" + north;
		url += "&arrowE=" + arrowE + "&arrowN=" + arrowN;
		url += "&drawArrow=" + drawArrow + "&updateArrow=" + updateArrow;
		
		url += "&cyc=" + redraw;
		
		if ( 2 == getTNSCCZLEZ() )
			url += '&lez';
		if ( 1 == getTNSCCZLEZ() )
			url += '&cc';

		// HW DEBUG
		// alert( url );
		
		if (elemdebug && debugMode)
			{
			elemdebug.innerText = east + ":" + north + ";" + zoom;
			}

		elem.src = url;
		
		redraw++;
		
		startupTimer = setTimeout ( 'startupTimerFunc()', 1000 );

		loaded = false;

		}
		
	function startupTimerFunc () {
	
		clearTimeout(startupTimer);						
		updateSecs = 0;

		}

	//Loads the frame
	function getFrameURL()
	{
		var options = "";
		var url;
		var elem;
		var isLT = false;

		url = "tn2007-map.php?q";  //q serves no purpose just allows us to to & for other params
		
		//	HW: always draw drawArrow for LEZ...
		url += "&drawArrow=true";
					


		//	Maptype...
		var map = getMapType ();
		url += "&maptype=" + map;
					
		//	CCTV sites...
		elem = document.getElementById ( 'cbCCTV' );
		if ( elem ) {
			if ( elem.checked )
				url += "&cbCCTV";
			}
			
		//	LTIS on-line...
		ltisOptions = "";
		elem = document.getElementById ( 'cbLTIS' );
		if ( elem ) 
		{
			if ( elem.checked ) 
			{
				if (( ltisOptions = getLTISOptions()) == null )
					url += "&cbLTIS&ltis= today";
				else
					url += "&cbLTIS&ltis="  + ltisOptions;
			}
			
		}
			
		
		
		//	SCOOT (lcon)...
		//	Run lcon in one of three modes: congestion, saturation or speed.
		//	The mode should be specified in the pinpoint.ini
		options = "&lcon=";
		elem = document.getElementById ( 'cbLCON' );
		if ( elem )
			if ( isToggOn(elem) == true )
				url += "&cbLCON";


		setArrow(false);

		return url;		
	}

	//	getURL
	//	This function builds a basic URL dependent on current GUI settings. 

	function getURL () {
	
		var options = "";
		var url;
		var elem;
		var isLT = false;

		url = "index.php?discard_pointer=1&disable_onclick&hovertext=on&sitestatus=LI,PR&icons&ccbounds&zoom=" + zoom;
		
		
		
		//	Commands...
		if ( cmdVMS != 0 ) url += "&vms=" + cmdVMS;

		//	Maptype...
		var map = getMapType ();
		url += "&map=" + map;
					
		//	CCTV sites...
		elem = document.getElementById ( 'cbCCTV' );
		if ( elem ) {
			if ( elem.checked )
				options = "TV";
			url += "&sitetype=" + options;
			}
			
		//	LTIS on-line...
		ltisOptions = "";
		elem = document.getElementById ( 'cbLTIS' );
		if ( elem ) {
			if ( elem.checked ) {
			if (( ltisOptions = getLTISOptions()) == null )
					return null;
				}
			}
			
		url += "&ltis=" + ltisOptions;
		
		//	SCOOT (lcon)...
		//	Run lcon in one of three modes: congestion, saturation or speed.
		//	The mode should be specified in the pinpoint.ini
		options = "&lcon=";
		elem = document.getElementById ( 'cbLCON' );
		if ( elem )
			if ( isToggOn(elem) == true )
				url += options + lcon_mode;

		//url += "&layers=" + options;
		
		//	Planned events...
		//elem = 			

		//	drawArrow (arrow)...
/*
		if ( drawArrow == true )
			url += "&drawArrow=true";

		if ( updateArrow == true )
			url += "&updateArrow=true";
*/

		//	COACHES
		//	=======
		//	VCS-specific items...
		elem = document.getElementById ( 'cbCoachParks' );
		if ( elem )
			if ( isToggOn(elem) == true )
				url += "&vcs";

		//	Access restrictions...
		elem = document.getElementById ( 'cbVCSA' );
		if ( elem )
			if ( isToggOn(elem) == true )
				url += "&vcsa";

		//	TLRN
		elem = document.getElementById ( 'cbTLRN' );
		if ( elem )
			if ( isToggOn(elem) == true )
				url += "&tlrn";

		//	Theatre locations (VCS)...
		elem = document.getElementById ( 'cbTHTR' );
		if ( elem )
			if ( isToggOn(elem) == true )
				url += "&thtr";


		//	FREIGHT
		//	=======
		if ( ppl_variant == 'freight' ) {

			url += "&freight";

			elem = document.getElementById ( 'cbLoading' );
			if ( elem )
				if ( isToggOn(elem) == true )
					url += "&frt_ldg";

			elem = document.getElementById ( 'cbWaiting' );
			if ( elem )
				if ( isToggOn(elem) == true )
					url += "&frt_wtg";

			elem = document.getElementById ( 'cbHeight' );
			if ( elem )
				if ( isToggOn(elem) == true )
					url += "&frt_hgt";

			elem = document.getElementById ( 'cbWidth' );
			if ( elem )
				if ( isToggOn(elem) == true )
					url += "&frt_wid";

			elem = document.getElementById ( 'cbWeight' );
			if ( elem )
				if ( isToggOn(elem) == true )
					url += "&frt_wgt";

			}	//	if freight


		//setArrow(false);

		return url;		
				
		}


	function updateTimerFunc () {

		if ( updateSecs == upd_interval_secs ) {
			updateSecs = 0;
			var elem = document.getElementById("mapFrame");
			if ( elem.contentWindow )
				var doc = elem.contentWindow;
			else if ( elem.contentDocument )
				var doc = elem.contentDocument;
			else if ( elem.document )
				var doc = window.frames.mapFrame;
			else {
				//	IE mac will not execute functions in child document
				clearTimeout (updateTimer);
				updateTimer = setTimeout ( 'updateTimerFunc()', 1000*2 );
				alert ( "Cannot access mapFrame document" );
				return;
				}

			if ( isOn ( 'LTIS' ) ) {
				doc.ltisvmsReload(); 	// NCG 11/07/06 - Merged LTIS and VMS
				//doc.ltisReload();
				//doc.vmsReload();
				}
				
			if ( isOn ( 'LCON' ) )
				doc.scootReload();

			var mapType = 'colour';
			mapType = parent.getMapType();
			
			// HW: Pass tns ccz lez var to JS so it knows what layer_image 
			// to draw.
			doc.ccReload(getTNSCCZLEZ(),mapType) ;

			clearTimeout (updateTimer);
			updateTimer = setTimeout ( 'updateTimerFunc()', 1000*2 );

			return;
			}

		var secsRemaining = upd_interval_secs-updateSecs;
		if ( countdownElem == null ) return;

		var mins = Math.floor(secsRemaining/60);

		var secs = secsRemaining-(mins*60);
		if ( mins > 0 ) {
			var m;
			if ( mins == 1 ) m = ' min'; else m = ' mins'
			var s = 'Update: ' + mins + m;
			if ( secs > 0 )
				s += ', ' + secs + ' secs';
			}
		else {
			var s = 'Update: ' + secs + ' secs';
			}

		if ( mins > 0 ) {
			if ( secsRemaining%10==0 )
				countdownElem.childNodes[0].nodeValue = s;
			}
		else
			countdownElem.childNodes[0].nodeValue = s;

		clearTimeout (updateTimer);
		updateTimer = setTimeout ( 'updateTimerFunc()', 1000 );

		updateSecs++;


		}

	function getLTISOptions () {
		var elem = document.getElementById("selLTIS");
		if ( !elem ) return "today" ;
		
		return elem.value ;
		}
		

	function getMapType () {
		// LKL Bug fix to ensure correct map type goes to Mozilla Firefox
		var elem = document.getElementById("maptype");
		if ( !elem ) return "colour" ;
		
		return elem.value ;
		}


	function getMapType2 () 
		{
		var radios = document.getElementById ('mapContentControls');
		if (radios)
			{
  			var inputs = radios.getElementsByTagName ('input');
  			if (inputs) 
				{
    			for (var i = 0; i < inputs.length; ++i) 
					{
      				if (inputs[i].type == 'radio' && inputs[i].name == 'maptype' && inputs[i].checked)
						return (inputs[i].value) ;
					}
				}
			}
			
		return "unknown";	
		}

	function setMapType (index) {
		
		var elem;

		elem = document.getElementById ( "maptype" );
		if (index == 1 )
		{
			elem.value = "colour";
		}
		else if (index == 2 )
		{
			elem.value = "greyscale";
		}
		else if (index == 3 )
		{
			elem.value = "aerial";
		}
		else if (index == 4 )
		{
			elem.value = "oslarge";
		}
		else if (index == 5 )
		{
			elem.value = "os50k";
		}
		else if (index == 6 )
		{
			elem.value = "osstreet";
		}
		else
		{
			alert("Illegal value "+index+" in setMapType");
		}
		
		// alert(index+" "+elem.value);
/*
		for ( var i=1; i<=3; i++ ) {
			elem = document.getElementById ( "maptype" );
			if ( !elem ) continue;
			if ( i == index ) {
				if ( setMapType.arguments.length == 2 ) {
					elem.disabled = setMapType.arguments[1];
					return;
				}
				elem.checked = true;
				break;
				}
			}
			
*/
	}

		
	function isToggOn ( elem ) {
	
		if (elem.checked) return true;			
		return false;
	
		}


	//	isOn()
	//	This function has been designed to be called from a child page (eg, PinPoint running
	//	in an IFRAME). It returns true or false, depending on whether a UI element is on or off.
	//	This way, a child web page/site can test to see if a parent control is on or off...
	
	function isOn ( what ) {

		var id = 'cb' + what;
		var elem = document.getElementById ( id );
		if ( !elem ) return false;

		return isToggOn(elem);
		
		}
		

	// If ccon	
	function getTNSCCZLEZ() {

		var id = 'tnscczlez';	// HW used to be ccon, now tnscczlez = 0, 1 or 2
		var elem = document.getElementById ( id );
		if ( !elem ) {
			// alert('Cannot find tnscczlez');
			return false;
		}
		
		// alert(elem.value);

		return (elem.value );
		
	}
		

function rollover (evt,id) {
	
	evt = (evt) ? evt : ((window.event) ? window.event : "");
    if (!evt) return;
	
	var elem = document.getElementById(id);
	if ( !elem ) return;
	
	var src = elem.src;
	var len = src.length;
	if ( src.indexOf ( "-over.gif" ) != -1 ) {
		elem.src = src.substring ( 0, src.length-9 ) + "-off.gif";
		}
	else if ( src.indexOf ( "-off.gif" ) != -1 ) {
		elem.src = src.substring ( 0, src.length-8 ) + "-over.gif";
		}
	
	return;

	}

function checkboxEvent (evt,id) {

	evt = (evt) ? evt : ((window.event) ? window.event : "");
	if (!evt) return;

	var elem = document.getElementById(id);
	if ( !elem ) return;

	switch(id) {

/*
		case 'cbCCTV':
		if ( elem.checked ) 
		{ 
			alert("Apologies for any inconveience\nThe CCTV system is currently undergoing scheduled maintenance"); 
			elem.checked=false;
		}
		break;
*/
		case 'cbLTIS':

			var taAll 		= document.getElementById("taAll");
			var taNext 		= document.getElementById("taNext");
			var taNextVal 	= document.getElementById("taNextVal");
			var taToday 	= document.getElementById("taToday");
			if ( !taAll || !taNext || !taNextVal || !taToday ) return;
				
			taAll.disabled = !elem.checked;
			taNext.disabled = !elem.checked;
			taNextVal.disabled = !elem.checked;
			taToday.disabled = !elem.checked;
			
			break;
			
		case 'cbLCON':
								
			break;


		case 'cbAUTO':
			//	This is the AUTO REFRESH option
			updateSecs = 0;
			var updateTextDefault = "Auto refresh" ;

			var textID = document.getElementById ( "autoText" );
			if ( !textID ) return;
			
			if ( elem.checked ) {
				countdownElem = textID ;
				updateTimerFunc ();
				}
			else {
				//	Disable timer and hide countdown...
				clearTimeout ( updateTimer );
				textID.innerText = updateTextDefault ;
				countdownElem = null ;
				}

			break;

		case 'cbLGND':
		
			var map = document.getElementById("mapFrame");
			if ( map.contentWindow )
				var doc = map.contentWindow;
			else if ( map.contentDocument )
				var doc = map.contentDocument;
			else if ( map.document ) {	//	msie on Mac
				var doc = window.frames.mapFrame;
				}
			else {
				alert ( "Cannot access mapFrame document" );
				return;
				}
			var what = elem.checked ? 'visible' : 'hidden';
			doc.legend ( what );
			break;

		default:;
		}	// switch


	}


function StringStrip ( str, c ) {

	var retstr = "";
	for ( var i=0; i<str.length; i++ )
		if ( str.charAt(i) != c )
			retstr += str.charAt(i);
	
	return retstr;

	}

function DL_GetElementLeft(eElement) {
    	var nLeftPos = eElement.offsetLeft;
    	var eParElement = eElement.offsetParent;
    	while (eParElement != null) {
        	nLeftPos += eParElement.offsetLeft;
        	eParElement = eParElement.offsetParent;
    		}
    	return nLeftPos;
		}

function DL_GetElementTop(eElement)
		{
    	var nTopPos = eElement.offsetTop;
    	var eParElement = eElement.offsetParent;
    	while (eParElement != null) {
        	nTopPos += eParElement.offsetTop;
        	eParElement = eParElement.offsetParent;
    		}
    	return nTopPos;
		}

function doLTISText () {

	ltisTextCycle++;
	}


function mapSearch(evt, keyPushed)
{
	var elem = document.getElementById ('searchtextmap') ;

	if (!elem)
		return;
		
	// LKL bug fix stop the memory leak when you enter nothing 
	// into the postcode/street search box 
	if ( (elem.value.length==0) || (elem.value==null) ) 
      return;


	if (!keyPushed || (keyPushed && ((evt.keyCode && evt.keyCode == 13) || (evt.which && evt.which == 13))))
	{
		redrawMap('search', 'all', elem.value);
	}
	//Perform the search
}


function checkForCommands ()
	{
	var
		cmd,
		elem = document.getElementById ('searchtext') ;
		
	if (!elem) return true ;
	
	cmd = (elem.value) ;
	
	cmd = cmd.replace( /^\s+/g, "" ) ;
	cmd = cmd.replace( /\s+$/g, "" ) ;

	
	if (cmd.length < 3) 
		return true ;
	
	if (cmd.substr (0, 2) != '::')
		return true ;
		
	cmd = cmd.substr(2, cmd.length -2) ;
	cmd = cmd.replace( /^\s+/g, "" ) ;
	cmd = cmd.replace( /\s+$/g, "" ) ;
		
	if (cmd == 'server')
		alert (serverName) ;
		
	if (cmd.substr(0,4) == 'vms=')
		{
		cmdVMS = cmd.substr (4, cmd.length-4) ;
		redrawMap() ;
		}
	
	return false ;
	}


function showJSVal ( val ) {

	var identifier = eval(val);
	alert ( identifier );

	}

function showVCSLegend ( evt, what ) {

	evt = (evt) ? evt : ((window.event) ? window.event : "");
	if (!evt) return;

	var elem = document.getElementById("vcsLegend");
	if ( !elem ) return;

	var vis = what == true ? 'visible' : 'hidden';

	elem.style.left = evt.clientX;
	elem.style.top = evt.clientY;
	elem.style.visibility = vis;
	}


//LKL Accessibility
function updateLTISText(html) {

	//Should be unused - TD001
	
	var elem = document.getElementById("ltisTextDiv");
	if ( !elem ) return;

	
	elem.style.visibility = 'visible';
	elem.innerHTML = "";
	elem.innerHTML = html;

	}
	
function clearLTISText() {

	//Should be unused - TD001

var elem = document.getElementById("ltisTextDiv");
	if ( !elem ) return;

	elem.innerHTML = "";

	}


function getLTISText (opt) {

	//Should be unused - TD001

var elem = document.getElementById("ltisTextFrame");
	if ( !elem ) {
		return;
		}
	
	var url = "ltistext.php?ltis=" + opt + "&minx=" + currMinEasting + "&maxx=" + currMaxEasting + "&miny=" + currMinNorthing + "&maxy=" + currMaxNorthing;	
	//alert(url);
	
	elem.src = url;

	}

function openHAWindow (url)
{
	//Should be unused - TD001

this.aWindow=window.open(url,"HAWin",
		"scrollbars=yes,status=yes,menubar=no,resizable");
}

function reposition()
{
	window.scrollBy(0,700); // horizontal and vertical scroll increments

}

function childClickNotification (x,y)
{
	// Put in here any code to be executed if there is a mouse click in the map IFRAME.
	
	var
		elem1 = document.getElementById("eastingVal"),
		elem2 = document.getElementById("northingVal"),
		elem3 = document.getElementById("updateArrowVal"),
		elemdebug = document.getElementById("curXY") ;

		
	if (!elem1 && !elem2 && !elem3)
		return ;
		
	elem1.value = x ;
	elem2.value = y ;
	elem3.value = 'false' ;	// HW Don't update arrow if user clicks on map
	
	doZoom('zoomin') ;
	
	if (elemdebug && debugMode) {
		elemdebug.innerText = elem1.value + ":" + elem2.value + ";" + zoom;
	}

	return ;
}
	
function updateZoomIndicator (zoom)
		{
		var tZoom = 0;

		var radios = document.getElementById ('mapNavControl2');
		if (radios)
			{
			var inputs = radios.getElementsByTagName ('input');
			if (inputs) 
				{
				for (var i = 0; i < inputs.length; ++i) 
					{
					if (inputs[i].type == 'radio' && inputs[i].name == 'zoomind')
						inputs[i].checked = (inputs[i].value == zoom.toString()) ;
						//elem1 = document.getElementById("zoomind");
						//alert(zoom+" "+i+" "+inputs[i].checked);

					}
				}
			}
		}
		

	function cctvImagePopup ( site ) {
					
		//var elem = document.getElementById ("cctvFrame").style;
		var elem = document.getElementById ("cctvDiv");
		
		if (!elem)
			return;

		if ( cctvCountdownElem == null )
			if (( cctvCountdownElem = document.getElementById("cctvCountdown")) == null )
				return;
	
		//elem.width = '322px'; 
		//elem.height = '258px';
		
		if ( cctvTimer != null ) {
			clearTimeout (cctvTimer); 
			cctvTimer = null;
			}

		cctvSecsRemaining = cctvTimeoutSecs;
		
		//	DJEM 28-04-04 Reload the iframe...
		//document.getElementById("cctvFrame").src = "cctvimage.php?siteno=" + site;
		document.getElementById("cctvImage").src = "cctvimage.php?siteno=" + site + "&cycle=" + cctvCycle;
		cctvCycle++;

		cctvCurrSite = site;
		
		elem.style.visibility = "visible";		

		cctvTimer = setTimeout ( 'cctvTimerFunc()', 1000 );

		if (wchExists)
			WCH.Apply(elem,'',true);
		}

	function cctvTimerFunc() {

		var s = 'Check for new image in ';
		cctvSecsRemaining--;

		s += cctvSecsRemaining + ' secs';
		
		cctvCountdownElem.childNodes[0].nodeValue = s;

		if ( cctvSecsRemaining == 0 ) {
			cctvImagePopup (cctvCurrSite); 
			}
		else {
			clearTimeout (cctvTimer);
			cctvTimer = setTimeout ( 'cctvTimerFunc()', 1000 );
			}


		}
		
	function closeCCTVPopup () {

		//var elem = document.getElementById ("cctvFrame").style;
		var elem = document.getElementById ("cctvDiv").style;
	
		if (!elem) return;
		
		if (wchExists) 
			WCH.Discard('cctvDiv');

		elem.visibility = "hidden";
		if ( cctvTimer != null ) {
			clearTimeout (cctvTimer); 
			cctvTimer = null;
			}
	
		}
				

/**
 * Drag.js: drag absolutely positioned HTML elements.
 *
 * This module defines a single drag() function that is designed to be called
 * from an onmousedown event handler.  Subsequent mousemove events will
 * move the specified element. A mouseup event will terminate the drag.
 * If the element is dragged off the screen, the window does not scroll.
 * This implementation works with both the DOM Level 2 event model and the
 * IE event model.
 * 
 * Arguments:
 *
 *   elementToDrag:  the element that received the mousedown event or
 *     some containing element. It must be absolutely positioned.  Its 
 *     style.left and style.top values will be changed based on the user's
 *     drag.
 *
 *   event: the Event object for the mousedown event.
 **/
function drags(e) {

	if (!ie&&!ns6)
		return;

	var elementToDrag=ns6? e.target : event.srcElement ;
	var topelement=ns6? "HTML" : "BODY" ;
		
	if (elementToDrag == null)
		return;	// null event

	while (elementToDrag != null && elementToDrag.tagName!=topelement&&elementToDrag.className!="drag") {
		elementToDrag=ns6? elementToDrag.parentNode : elementToDrag.parentElement
	}

	if (elementToDrag == null)
		return;	// null event
	
	// HW: See note below to avoid setCapture in IE7.
    if ( ie7 && elementToDrag.className != "drag" )
        return;

	// The mouse position (in window coordinates)
    // at which the drag begins 
    var startX = ns6?e.clientX:event.clientX, startY = ns6?e.clientY:event.clientY;    

    // The original position (in document coordinates) of the
    // element that is going to be dragged.  Since elementToDrag is 
    // absolutely positioned, we assume that its offsetParent is the
    // document body.
    var origX = elementToDrag.offsetLeft, origY = elementToDrag.offsetTop;

    // Even though the coordinates are computed in different 
    // coordinate systems, we can still compute the difference between them
    // and use it in the moveHandler() function.  This works because
    // the scrollbar position never changes during the drag.
    var deltaX = startX - origX, deltaY = startY - origY;

    // Register the event handlers that will respond to the mousemove events
    // and the mouseup event that follow this mousedown event.  
	// HW: Added check for class name so that select elements
	// work in Firefox
    if (document.addEventListener && elementToDrag.className == "drag" ) {  // DOM Level 2 event model
        // Register capturing event handlers
        document.addEventListener("mousemove", moveHandler, true);
        document.addEventListener("mouseup", upHandler, true);
        document.addEventListener("mouseout", outHandler, true);
		
    }
    else if (document.attachEvent) {  // IE 5+ Event Model
        // In the IE event model, we capture events by calling
        // setCapture() on the element to capture them.
        // HW: Added check for className above to setCapture only
        // for CCTV/LTIS (drag class) 
        // elements to prevent a bug in IE7 where
        // clicking on drop downs/scrollbars doesn't work.
        elementToDrag.setCapture();
        elementToDrag.attachEvent("onmousemove", moveHandler);
        elementToDrag.attachEvent("onmouseup", upHandler);
        // Treat loss of mouse capture as a mouseup event
        elementToDrag.attachEvent("onlosecapture", upHandler);
    }
    else {  // IE 4 Event Model
        // In IE 4 we can't use attachEvent() or setCapture(), so we set
        // event handlers directly on the document object and hope that the
        // mouse events we need will bubble up.  
        var oldmovehandler = document.onmousemove; // used by upHandler() 
        var olduphandler = document.onmouseup;
        document.onmousemove = moveHandler;
        document.onmouseup = upHandler;
    }
	

    // We've handled this event. Don't let anybody else see it.  
		if (e && e.stopPropagation) e.stopPropagation();  // DOM Level 2
	    else event.cancelBubble = true;                      // IE


    // The following prevents any default action. 
    // HW: Added check for className above to prevent default action only
    // for  CCTV/LTIS (drag class) elements to prevent a bug in Safari 3.1
	// where clicking on drop downs/scrollbars doesn't work.
	
     if ( elementToDrag.className == "drag" )
		if (e && e.preventDefault) e.preventDefault();   // DOM Level 2
	    else event.returnValue = false;                     // IE
	

     //
     // This is the handler that captures mousemove events when an element
     // is being dragged. It is responsible for moving the element.
     //
    function moveHandler(e) {
        if (!e) e = window.event;  // IE Event Model

		if (wchExists)
			WCH.Apply(elementToDrag,'',true);

        // Move the element to the current mouse position, adjusted as
        // necessary by the offset of the initial mouse-click.
        elementToDrag.style.left = ( (ns6?e.clientX:event.clientX) - deltaX) + "px";
        elementToDrag.style.top = ((ns6?e.clientY:event.clientY) - deltaY) + "px";

		// Prevent the box being dragged outside the bounds of the 
		// parent container
		// ------------------------------------------
		var curleft = parseInt(elementToDrag.style.left, 10)
			
		if ( curleft < 0 ) {
			elementToDrag.style.left = 0 + "px"
		}

		var curtop = parseInt( elementToDrag.style.top, 10 )
			
		if ( curtop < 0 ) {
			elementToDrag.style.top = 0 + "px"
		}

		// And don't let anyone else see this event.
        if (e && e.stopPropagation) e.stopPropagation();  // DOM Level 2
        else event.cancelBubble = true;                  // IE
    }

     //
     // This is the handler that captures the final mouseup event that
     // occurs at the end of a drag.
     //
    function upHandler(e) {
        if (!e) e = window.event;  // IE Event Model

        // Unregister the capturing event handlers.
        if (document.removeEventListener) {  // DOM event model
            document.removeEventListener("mouseup", upHandler, true);
            document.removeEventListener("mousemove", moveHandler, true);
        }
        else if (document.detachEvent) {  // IE 5+ Event Model
            elementToDrag.detachEvent("onlosecapture", upHandler);
            elementToDrag.detachEvent("onmouseup", upHandler);
            elementToDrag.detachEvent("onmousemove", moveHandler);
            elementToDrag.releaseCapture();
        }
        else {  // IE 4 Event Model
            // Restore the original handlers, if any
            document.onmouseup = olduphandler;
            document.onmousemove = oldmovehandler;
        }

        // And don't let the event propagate any further.
        if (e && e.stopPropagation) e.stopPropagation();  // DOM Level 2
        else event.cancelBubble = true;                  // IE
    }
}

		// Mozilla does not have a onlosecapture event like IE5.
		// Mozilla does not fire a onmouseup event when the mouse is released
		// outside of the browser window.
		// However, Mozilla has the interesting habit of sending a mouseout 
		// event with an 'html' element as the target when the mouse is 
		// released   outside of the browser window.  
		// Check if 'html' is equal to the lower case tagname of the event.
		// 
		// When this occurs, we SYNTHESIZE a mouseup event, which is  
		// useful for all sorts of dragging code.
		//
		// This patch cleans up the way we were handling mouse capture on 
		// Mozilla, Opera, and Safari. There was a partially working hack 
		// in DOMImplStandard that was attempting to catch the case where 
		// the mouse was captured and left the browser window.

		// It turns out that on Opera and Safari this was completely 
		// unnecessary, as these browsers appear to capture mouse events 
		// naturally when the button is held. We moved a modified version 
		// of this hack into Firefox to catch one weird case that occasionally
		// occurs (see the doc in DOMImplMozilla) to synthesize a mouseup.
function outHandler(e) {
	if (!ie&&!ns6)
		return;

	var elementToHandle=ns6? e.target : event.srcElement ;
		
	if (elementToHandle == null)
		return;	// null event

	if ( 'html' == elementToHandle.tagName.toLowerCase() ) {
		// Simulate mouseup to CCTV image
		var simulatedEvent;
		
		var el = document.getElementById('cctvImage');
		
		if (document.createEvent){
			simulatedEvent = document.createEvent("MouseEvents");
			simulatedEvent.initMouseEvent("mouseup", true, true, window,
			0, 0, 0, 0, 0, false, false, false, false, 0, null);
		}
		
		if (el && simulatedEvent)
			el.dispatchEvent(simulatedEvent)

		// Simulate mouseup to LTIS/VMS sign
		
		el = document.getElementById('infoDiv');
		
		if (document.createEvent){
			simulatedEvent = document.createEvent("MouseEvents");
			simulatedEvent.initMouseEvent("mouseup", true, true, window,
			0, 0, 0, 0, 0, false, false, false, false, 0, null);
		}
		
		if (el && simulatedEvent)
			el.dispatchEvent(simulatedEvent)
		// else
			// el.click && el.click();
			
	}

}

