<!--


/* MAP SCRIPT NOTES            */
/* ================            */
/*                             */
/*                             */
/* Function naming convention  */
/* --------------------------  */
/*                             */
/* To make things easier to follow, the functions follow a naming convention as outlined below */
/* depending where they are most likely to be used during the maps process.                    */
/*                                                                                             */
/* • gmap_     : Code very tightly related to Google Maps, eg: based on their examples         */
/* • gen_      : Code which is likely to be useful across the entire script                    */
/*                                                                                             */
/* • gmc_      : Code for saving/editing speech bubble data and sending to 'get map code'      */
/* • gmd_      : Code for processing the pre-existing map data retrieved by ajax_gmdata_       */
/* • gpc_  	   : Code for retriving the long/lat for a given postcode                          */
/* • ggr_	   : Code for calculating the long/lat from a grid reference                       */
/* • gco_	   : Code for plotting a point using direct inputted co-ordinates                  */
/*                                                                                             */
/* • ajax_all_ : AJAX code that can be used by any of the AJAX functions                       */
/*                                                                                             */



/* External Requirements */
/* --------------------- */
/*                       */
/* To translate the grid ref to co-ordinates, we need the coordinates-gridred-script.js        */
/* to be included in the page alongside this script                                            */




/* Troubleshooting */
/* --------------- */
/*                                                                                             */
/* Map type stops saving:                                                                      */
/*                                                                                             */
/* • Due to the lack of reliable ways to find out what map type the user is viewing, we have   */
/*   to use a pottentially unreliable method based on a URL string used by Google Local.       */
/*                                                                                             */
/*   So if the system stops saving the map type and always displays the roads look in the      */
/*   function gmc_generate_post_data() where we collect map.getCurrentMapType().getUrlArg()    */
/*   The output of that is what we use to determine which map type is being shown, so to find  */
/*   the new value run something like this code *after* we've set the initial map centre...    */
/*                                                                                             */
/*   map.setMapType(G_SATELLITE_MAP);                                                         */
/*   alert(map.getCurrentMapType().getUrlArg());                                               */
/*                                                                                             */
/*   ...and then use that value to replace 'c', 'k' and 'h' in the switch statement.           */
/*   Current map types are: G_SATELLITE_MAP, G_HYBRID_MAP & G_NORMAL_MAP                     */
/*                                                                                             */
/*   This won't affect any existing maps as they use numerical values to determine map type    */
/*   ie: 1=Road, 2=Sat, 3=Hybrid                                                               */
/*                                                                                             */





    //<![CDATA[




      if (GBrowserIsCompatible()) {




		/* *** Initialise Map Controls *** */

        var map = new GMap2(document.getElementById("map"));
        map.addControl(new GLargeMapControl());
        map.addControl(new GMapTypeControl());
        map.setCenter(new GLatLng(0, 0), 1);

		map.disableDoubleClickZoom(); // Just incase they enable it by default someday





		/* *** Initialise Custom Settings & Stores *** */

		var set				 		= new Array();
		set['max_icons']	 		= 500; // If changed, also needs changing in AJAX save data script
		set['max_extra_sites']  	= 500;




		var html_iframe_width_def	= 598;	// More than 1 line of extra content
		var html_iframe_height_def	= 530;
		var html_iframe_width_line	= 582;	// 1 Line of extra content boxes (same width as no content)
		var html_iframe_height_line = 530;
		var html_iframe_width_noec	= 582;	// No extra content boxes (or EC hidden)
		var html_iframe_height_noec	= 435;




		// If editing, replace line breaks with \r\n and " with ' or \"
		// If editing final_email, the map code is replaced where MAPCODEHERE is found

		var lang					= new Array();
		lang['gmc_alert_no_icon']	= "";
		lang['gmc_button_getcode']	= "Click to save the map and get the new map code";
		lang['gmc_button_selcode']	= "Copy the appropriate code below to link to your new map";
		lang['gmc_button_loadcode']	= "Loading map code, please wait...";
		lang['gmc_final_email_u']	= "\r\nThank you for using Aardvark Map to produce your free custom map! \r\n\r\nWe have included below your unique map ID along with some helpful reminders about how to use this code to retrieve the map, edit the map and get the final linking code. \r\n\r\n\r\nYour unique map ID is MAPCODEHERE\r\n\r\n\r\nThis ID code allows you to:\r\n===========================\r\n\r\n- Retrieve your map at a later date\r\n- Edit the map or add/remove content overlays\r\n- Get the final linking or embedding web site code \r\n\r\n\r\nTo retrieve your map:\r\n====================\r\n\r\n- Go to http://www.aardvarkmap.net/\r\n- Click the 'Retrieve Old Map' link and enter the code above \r\n\r\n\r\nTo edit your map:\r\n================\r\n\r\n- Follow the instructions to retrieve your map above \r\n- Edit the map as appropriate \r\n- Click to step 2 if you want to add/remove overlay content\r\n- Click the step 3 link to retrieve your new map linking code\r\n\r\n\r\nTo just get the linking code\r\n============================\r\n\r\n- Following the instructions to retrieve the map above \r\n- When the map loads, click on Step 3 on the navigation\r\n- Select the appropriate code from the boxes\r\n\r\n";
		lang['gmc_final_email_d']	= "\r\n\r\n\r\nAardvark Map - Web Designer Notes\r\n=================================\r\n\r\nAardvark Map provides a simple 3 step process allowing anyone to create free maps with custom markers. At the end of the process the user is presented with a number of options for linking to the map.\r\n\r\n\r\nIf you are looking to add the created map into a web site, all you\r\nneed is this map ID code -> MAPCODEHERE <- then follow these instructions:\r\n\r\n1) Go to http://www.aardvarkmap.net/\r\n2) Click the 'Retrieve Old Map' link\r\n3) Enter the map ID code above \r\n4) In a couple of seconds you will be taken to step 1\r\n5) Unless you want to alter the map, click straight to step 3\r\n\r\nAt step 3 you will receive a new map ID code and a number of coding options for integrating Aardvark Map into the site.\r\n\r\n\r\nOther Web designer notes:\r\n\r\n- For embedding into sites with non-white or patterned backgrounds we recommend that you select the 'Use transparent iFrame' option in step 3.\r\n\r\n- If the client has selected extra content overlays you might find the map integrates better if the 'Hide content overlay boxes' is also selected.\r\n\r\n- To create free maps for use on your own or client web sites, visit: http://www.aardvarkmap.net/\r\n\r\n\r\n";
		lang['gpc_marker_not_acc']  = "<br>Postal code could not plot the point exactly.<br>You may need to zoom in and drag the marker for a more accurate position."




		var url_html_gen			= 'http://www.aardvarkmap.net/map/';
		var url_html_iframe			= 'http://www.aardvarkmap.net/mapi/';
		var url_html_iframe_trans	= 'http://www.aardvarkmap.net/mapitrans/';
		var url_html_email			= 'http://www.aardvarkmap.net/mape/';
		var url_html_link			= 'http://www.aardvarkmap.net/maps/';
		var url_html_bbcode			= 'http://www.aardvarkmap.net/mapbb/';
		var url_html_php			= 'http://www.aardvarkmap.net/mapp/';
		var url_html_hide_ec		= '?hideec=1';



		var html						= [];
		html['gmc_raw_url']				= url_html_email  + 'MAPCODEHERE';
		html['gmc_html_iframe']			= '<iframe src="' + url_html_iframe  		+ 'MAPCODEHERE" width="IFRAMEWIDTH" height="IFRAMEHEIGHT"  frameborder="0" scrolling="auto" marginwidth="0" marginheight="0"></iframe>';
		html['gmc_html_iframe_trans']	= '<iframe src="' + url_html_iframe_trans  	+ 'MAPCODEHERE" width="IFRAMEWIDTH" height="IFRAMEHEIGHT"  frameborder="0" scrolling="auto" marginwidth="0" marginheight="0" allowtransparency="true"></iframe>';
		html['gmc_html_bbcode']			= '[url=' 		  + url_html_bbcode	 		+ 'MAPCODEHERE]Click for Aardvark Map[/url]';
		html['gmc_html_link']			= '<a href="'	  + url_html_link    		+ 'MAPCODEHERE" target="_blank">Click for Aardvark Map</a>';
		html['gmc_html_testlink']		= '<a href="'	  + url_html_gen 	 		+ 'MAPCODEHERE" target="aardvarkmap">Click here to see your newly generated map</a>';
		html['gmc_html_hide_ec']		= url_html_hide_ec;

		html['gmc_html_email_link_u']	= '<a href="mailto:?subject=Aardvark Map - Code reminder e-mail&body=' + escape(lang['gmc_final_email_u']) + '">Click here for the users reminder e-mail</a>';
		html['gmc_html_email_link_d']	= '<a href="mailto:?subject=Aardvark Map - New map HTML code&body=' + escape(lang['gmc_final_email_d']) + '">Click here for the web designers e-mail</a>';



		html['gmc_html_iframe']			= "<!-- iFrame code for AardvarkMap.net Start -->\r\n" + html['gmc_html_iframe'] 		+ "\r\n<!-- iFrame code for AardvarkMap.net End -->";
		html['gmc_html_iframe_trans']	= "<!-- iFrame code for AardvarkMap.net Start -->\r\n" + html['gmc_html_iframe_trans'] 	+ "\r\n<!-- iFrame code for AardvarkMap.net End -->";




		// The code which controls the form in the bubbles

//		var info_window_form		= '<form method="post" action="" name="frm_icon_info" onSubmit="return false;">  <table width="310" border="0" cellspacing="0" cellpadding="2">	 <tr> 		<td width="50" class="formtext">Name:</td>		<td> 		  <input type="text" name="frm_bubble_name" id="frm_bubble_name" class="forminput" size="40" maxlength="50" value="FRMVALNAME">		</td>	 </tr>	 <tr> 		<td width="50" class="formtext">URL:</td>		<td> 		  <input type="text" name="frm_bubble_url" id="frm_bubble_url" class="forminput" size="40" maxlength="255" value="FRMVALURL">		</td>	 </tr>	 <tr> 		<td width="50" class="formtext">Desc:</td>		<td> 		  <textarea name="frm_bubble_text" id="frm_bubble_text" class="forminput" cols="37" rows="4" wrap="OFF">FRMVALTEXT</textarea>		</td>	 </tr>	 <tr> 		<td width="50">&nbsp;</td>		<td height="40"> 		  <input type="button" name="Submit" value="Click to save text" onClick="gmc_save_info(FRMVALID)">		</td>	 </tr>	 <tr> 		<td width="50">&nbsp;</td>		<td height="30"> <a href="#themap" onClick="gmc_reset_marker(FRMVALID)" class="formtext">Reset 		  Position</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 		  <a href="#themap" onClick="gmc_remove_marker(FRMVALID)" class="formtext"> 		  Remove Icon</a> </td>	 </tr>  </table></form>';
		var info_window_form		= '<form method="post" action="" name="frm_icon_info" onSubmit="return false;"><table width="310" border="0" cellspacing="0" cellpadding="2"><tr> <td width="50" class="formtext">Name:</td><td><input type="text" name="frm_bubble_name" id="frm_bubble_name" class="forminput" size="40" maxlength="50" value="FRMVALNAME"></td></tr><tr><td width="50" class="formtext">URL:</td><td><input type="text" name="frm_bubble_url" id="frm_bubble_url" class="forminput" size="40" maxlength="255" value="FRMVALURL"></td></tr><tr><td width="50" class="formtext">Desc:</td><td><textarea name="frm_bubble_text" id="frm_bubble_text" class="forminput" cols="37" rows="4" wrap="OFF">FRMVALTEXT</textarea></td></tr><tr><td width="50">&nbsp;</td><td height="40"><input type="button" name="Submit" value="Click to save text" onClick="gmc_save_info(FRMVALID)"></td></tr><tr><td width="50">&nbsp;</td><td height="30"><a href="#themap" onClick="gmc_reset_marker(FRMVALID)" class="formtext">Reset Position</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#themap" onClick="gmc_remove_marker(FRMVALID)" class="formtext">Remove Icon</a></td></tr></table></form>';



		var form						= [];
		form['gmc_html_iframe_output']	= 'frm_gmc_iframe_output';
		form['gmc_html_url_output']		= 'frm_gmc_url_output';
		form['gmc_html_bbcode_output']	= 'frm_gmc_bbcode_output';
		form['gmc_html_link_output']	= 'frm_gmc_link_output';
		form['gmc_html_mapcode_output']	= 'frm_gmc_mapcode_output';
		form['gmc_html_getcode_button']	= 'frm_gmc_getcode_button';
		form['gmc_html_testlink_output'] = 'gmc_link_to_testpage';
		form['gmc_html_hide_ec'] 		= 'frm_gmc_hide_ec';
		form['gmc_html_iframe_trans']	= 'frm_gmc_iframe_trans';
		form['gmc_html_email_link_u']	= 'gmc_email_link_div_u';
		form['gmc_html_email_link_d']	= 'gmc_email_link_div_d';

		form['gmd_mcode_input']			= 'frm_gmd_code_input';
		form['gpc_pcode_input']			= 'frm_gpc_code_input';
		form['gpc_cc_input']			= 'frm_gpc_cc_input';
		form['gpc_pcode_accuracy']		= 'gpc_marker_not_accurate'; // Appears if pcode not 100% accurate

		form['grr_co_gridref_input']	= 'frm_ggr_co_gridref';
		form['grr_co_gridref_t_os']		= 'frm_ggr_co_gridref_type_os';
		form['grr_co_gridref_t_ws']		= 'frm_ggr_co_gridref_type_ws';

		form['gco_co_input_lat']		= 'frm_gco_co_lat';
		form['gco_co_input_lng']		= 'frm_gco_co_lng';

		form['bbl_name']			= 'frm_bubble_name';
		form['bbl_url']				= 'frm_bubble_url';
		form['bbl_text']			= 'frm_bubble_text';




		var script_get_map_code 	= 'http://www.aardvarkmap.net/a_print/print_addamap_local-data_saver.php';
		var script_get_map_data 	= 'http://www.aardvarkmap.net/a_print/print_addamap-data_retriever.php';
		var script_get_pcode_data 	= 'http://www.aardvarkmap.net/a_print/coordinates_from_postcode_cache_live.php';




		var errors					= new Array();
		errors['error_status']		= 0;
		errors['gmd_int_error']		= "Sorry, an internal error has occured preventing retrieval of stored map details, please try again later.<br>Debugging code: " + ajax_error_status;
		errors['gmd_id_missing'] 	= "The ID entered does not match any known map IDs\n\nPlease go back to step 1 and ensure it was entered correctly\nor begin with step 2 and enter the new points";
		errors['gmd_submit_empty']	= "Please enter an existing map ID, or select the points from the map";
		errors['gmd_submit_fake']	= "The map ID provided does not appear to be in a valid format";
		errors['gmc_int_error']		= "Sorry, an internal error has occured preventing the generating of the HTML code<br>Debugging code: M_ID Lookup Failed";
		errors['gpc_int_error'] 	= "Sorry, an internal error has occured preventing retrieval of the postcode details.<br>Please try again later or add the markers by clicking on the map";
		errors['gpc_pcode_missing']	= "We can not find co-ordinate details for the postcode entered";
		errors['gpc_submit_empty']	= "Please enter a postcode, or select points from the map";
		errors['gpc_submit_fake']	= "The postcode provided does not appear to be in a valid format";
		errors['gpc_submit_cc'] 	= "Please select a country from the list before submitting the postcode";
		errors['grr_format_fake']	= "8 character grid reference required\nEg: TQ212693";





		/* SETTINGS ALTERED BY THE SCRIPT ONLY */

		var store_marker_lng 		= []; 	// The long co-oridinate of the icon
		var store_marker_lat 		= []; 	// The lat co-ordinate of the icon
		var store_marker_lng_orig	= []; 	// Copy of lat incase of reset after icon drag
		var store_marker_lat_orig	= []; 	// Copy of lang incase of reset after icon drag
		var store_marker_name 		= []; 	// Name of the icon (displayed in bubble)
		var store_marker_url		= []; 	// URL of the icon (links the name)
		var store_marker_desc		= []; 	// Short description on bubble

		var id_tracker 		 		= []; 	// Tracks which icon IDs are available for use (1=Used;0=Free)

		var store_marker_copy		= []; 	// Copy of the marker object (array elements same as marker.id)

		var st_pos			 		= ''; 	// Temp var storing new icon position
		var icons_count		 		= 0; 	// Count of the current number of icons plotted

		var ajax_error_code 		= 0; 	// AJAX status code on error (set by AJAX function)
		var ajax_error_status 		= 0;    // AJAX status code is above is -2

		var gmc_event_tracker		= 0;  	// Tracks when anything changes on the map for the get_map_code section
		var gmc_move_tracker		= 0;  	// Tracks whether a map was user or infoWindow initiated (1=was infoWindow : reset by 'moveend' listener)

		var gen_map_dbl_clicked		= 0;    // Tracks whether the click was a double click


		var gmc_ajax_cache 			= '';
		var gmc_ajax_got_code		= 0;
		var gmc_prior_save 			= 0;

		var last_click_time			= 0; 	// Tracks double click timing
		var last_marker_id			= '';   // Used to track the last marker (currently for dblclick)
		var dblclick_spotted		= 0;

		var gen_count_ec_sel		= 0; 	// Tracks no. extra content boxes turned on [from gen_extra_sites_sel_log() and gmd_process_data()]




		/* *** Initialise Script Data *** */

		gen_pre_fill_co_arrays(); 	// Setup space for X boxes & icon co-ordinates and pre-set c/o to 0

		gen_clear_error();			// Ensure any errors have been removed

		gen_display_map_zoom(); 	// Setup the zoom indication

		gen_display_map_centre();	// Setup the centre c/o indication






		/* EVENT LISTENER: Listens for the click on the map & adds marker there */
		/*                                                                      */
		/*                 This part listens out for the user clicking and if they clicked on the map */
		/*                 and not a marker (overlay), then it starts the marker add process.         */
		/*                                                                                            */
		/*                 Firstly work out the icons ID, then collect the blank form and call the    */
		/*                 gmap_create_marker() function to actually create the object. Then assuming */
		/*                 we got a marker (not added too many), we add it to the map and open a new  */
		/*                 infoWindow over it with the blank form for the user                        */
		/*                                                                                            */
		/*                 Note: An overlay is either a marker or a speech bubble on the map          */

		GEvent.addListener(map, "click", function(overlay, point) {


			if (!overlay) {



				// Zoom & centre if CTRL and mouseclick occur (only IE)

				if (window.event) {

					if (window.event.ctrlKey == true) {
						map.zoomIn();
						map.setCenter(point);
						return true;
					}

				}




				// Look for double clicks and if spotted, set the double click variable to 1
				//
				// Then set a timeout so this value is reset fairly quickly, but still allows plenty of time
				// for the rest of the code to run even on a slow machine, eg: tripple the dblclick value below

				document.getElementById('map').ondblclick = function() {

					dblclick_spotted = 1;
					setTimeout("dblclick_clear_timeout()", 600);

				};




				// Get the point details and pass them after a timeout to the function
				//
				// The timeout allows time for a double click to be registered above which will cause this
				// function call to be cancelled (within the function). The strange formatting is due to the
				// way setTimeout doesn't like functions with parameters

				var tmp_point_lat = point.lat();
				var tmp_point_lng = point.lng();
				setTimeout("generate_marker("+tmp_point_lat+","+tmp_point_lng+")", 200);




			} // End of if (!overlay)


		});





		/* FUNCTION: Call for marker to be added */
		/*                                       */
		/*           This function is essentially a midway point between the above click listener and the  */
		/*           add icon function below. It's separated to allow us to track clicks and double clicks */
		/*           and won't pass the request on if a double click occurs (to auto centre the map)       */


		function generate_marker(point_lat,point_lng) {

			var point = new GLatLng(point_lat,point_lng);

			if (dblclick_spotted != 1) {

				var tmp_marker_id 		= gen_get_icon_id();
				var tmp_marker_contents = gmc_display_marker_contents(tmp_marker_id);
				var last_marker_id		= tmp_marker_id;

				var marker = gmap_create_marker(point,tmp_marker_id);

				if (marker !== false) {
					map.addOverlay(marker);
					map.openInfoWindowHtml(point,tmp_marker_contents); // Initial InfoWindow...

				}

			}

		}







		/* FUNCTION: Clear double click timeout */
		/*                                      */
		/*           Like the function above, this is an extension of the click add listener code but  */
		/*           this time it clears the double click watch variable to allow a single click watch */
		/*           so single clicks will be allowed usually around a second later                    */

		function dblclick_clear_timeout() {
			dblclick_spotted = 0;
		}







		/* FUNCTION: Adds the marker      */
		/*                                */
		/*           This function actually adds the icon to the map at the point selected as passed */
		/*           by 'point'. Assuming we've not exceeded the total icons allowed it generates a  */
		/*           new marker object, gets an ID for it and increments the total markers count +1  */
		/*           then pass back the new marker object so we can add it to the map page           */
		/*                                                                                           */
		/*                          																 */

		/* EVENT LISTENER: Marker clicked */
		/*                          																 */
		/*                 We also include the listener for the marker being clicked in here simply  */
		/*                 it then connects properly with the right icon since it's hard to pinpoint */
		/*                 exactly which marker has been selected from what Google provide us with   */
		/*                 (Real name 'function closures', should be called ruddy_complicated!)      */


		function gmap_create_marker(point,marker_id) {


			if (gen_max_icons_check() === true) {


				var marker = new GMarker(point,{draggable:true,title:store_marker_name[marker_id]});

				marker.id  = marker_id; 		// Get an ID no. for marker
				id_tracker[marker.id] = 1; 		// Log this ID as used
				icons_count++; 					// Inc. the count of displayed markers


				var tmp_pos 				 	 = marker.getPoint();
				store_marker_lat[marker.id]  	 = tmp_pos.lat();
				store_marker_lng[marker.id]  	 = tmp_pos.lng();


				store_marker_lat_orig[marker.id] = tmp_pos.lat();
				store_marker_lng_orig[marker.id] = tmp_pos.lng();


				store_marker_copy[marker.id] = marker;	// Create marker copy for delete marker function

				gen_map_changed(1);




				/* Useful code for plotting country / area boundaries when clicking a map */
				/* Just add a form and click usually NW corner then SE corner */

				var tmp_pos_write_lat	= parseFloat(tmp_pos.lat());
				var tmp_pos_write_lng	= parseFloat(tmp_pos.lng());
				tmp_pos_write_lat 		= Math.round(tmp_pos_write_lat * 100000)/100000; // Rounds to 6 decimal places
				tmp_pos_write_lng 		= Math.round(tmp_pos_write_lng * 100000)/100000;

				if (document.getElementById('debugareaco')) {
					document.getElementById('debugareaco').value += tmp_pos_write_lat + '|' + tmp_pos_write_lng + '|';
				}




				// If the marker is clicked on, fire these events

				GEvent.addListener(marker, "click", function() {

					var html_form_updated = gmc_display_marker_contents(marker.id);

					marker.openInfoWindowHtml(html_form_updated);

					gmc_move_tracker = 1;

				});




				// If the marker is dragged, fire these events

				GEvent.addListener(marker, "dragstart", function() {
					map.closeInfoWindow();
				});


				GEvent.addListener(marker, "dragend", function() {

					var tmp_pos2 = marker.getPoint();
					gen_icon_dragged_update(marker_id,tmp_pos2.lat(),tmp_pos2.lng());
					gen_map_changed(1);

				});



       			return marker;


			}
			else {

				// Very important otherwise the map goes nuts when you drag (after exceeding max icons)
				return false;

			}



		}







		/* EVENT LISTENER: Map Moved */
		/*                           */
		/*                 A listener which is called everytime the map moves in some way such as the */
		/*                 user drags the map, or the map moves to accommodate an infoWindow opening  */

		GEvent.addListener(map, "move", function() {
			gen_display_map_centre();
		});




		GEvent.addListener(map, "moveend", function() {

			var map_changed_track = (gmc_move_tracker == 1) ? gmc_event_tracker : 1;
			gen_map_changed(map_changed_track);

			gmc_move_tracker = 0;

			gen_display_map_centre();

		});






		GEvent.addListener(map, "zoomend", function() {
			gen_map_changed(1);
			gen_display_map_zoom();
		});







	} // End of GBrowserIsCompatible()








	/* ****************************** */
	/*                                */
	/*     Start Helper Functions     */
	/*                                */
	/* ****************************** */




	/* FUNCTION: Pre-fills the various arrays to the right lengths */
	/*           Also makes sure we don't get any undefined errors */

	function gen_pre_fill_co_arrays() {

		for (var a=0; a < set['max_icons']; a++) {

			store_marker_lat[a]  		= 0;
			store_marker_lng[a]  		= 0;
			store_marker_lat_orig[a]	= 0;
			store_marker_lng_orig[a]	= 0;
			store_marker_name[a] 		= '';
			store_marker_url[a]  		= '';
			store_marker_desc[a]  		= '';
			id_tracker[a]	 	 		= 0;

		}

	}







	/* Function figures out which is the first available icon ID */
	/*                                                           */
	/* The id_tracker is an array of every pottential icon ID    */
	/* linked with it's current usage status. If the icon status */
	/* is 0 then it's free, if it's 1 then it's in use           */
	/*                                                           */
	/* The status is switched in the icon_control() function     */

	function gen_get_icon_id() {

		for (var a=0; a < id_tracker.length; a++) {

			if (id_tracker[a] == 0) {
				return a;
				break;

			}

		}

	}







	/* FUNCTION: Prints an error message */
	/*                                   */
	/*           A quick function to collect and print an error message to the user if the */
	/*           DIV tag (or similar) called 'error_messages' exists on the page           */


	function gen_print_error(error_msg) {

		errors['error_status'] = 1;
		alert(error_msg);

	}






	/* FUNCTION: Clear any error message */
	/*                                   */
	/*           A quick function to remove any error messages from a previous error which should be */
	/*           called by any section of the script which normally generates an error               */


	function gen_clear_error() {

		errors['error_status'] = 0;

	}






	/* FUNCTION: Check Total Markers */
	/*                              */
	/*           A simple function to check whether we've got any more markers available to be added */
	/*           onto a map. If we don't then we alert the user and return 'false', else return true */
	/*                                                                                               */
	/*           This should be run *before* altering the store_ variables to prevent overwriting    */


	function gen_max_icons_check() {


		if ((icons_count + 1) > set['max_icons']) {

			alert("The map can have a maximum of " + set['max_icons'] + " icons\nPlease remove old ones before adding new icons");
			return false;

		}
		else {

			return true;

		}


	}






	/* FUNCTION: Update lat/long after icon drag */
	/*                                           */
	/*           If the marker gets dragged, then we need to update the co-ordinates for the map save */

	function gen_icon_dragged_update(marker_id,lat,long) {

		store_marker_lat[marker_id]  	= lat;
		store_marker_lng[marker_id]  	= long;

		gen_map_changed(1);

		return true;

	}






	/* FUNCTION: Change center */
	/*                         */
	/*           Can be called to change the lat/lang centre c/o on the fly */
	/*           Eg: Useful for links to fly to particular countries        */
	/*                                                                      */
	/*           The map will fly, if the area in question is within the    */
	/*           currently visible area, but most of the time it won't      */

	function gen_change_centre(lat,lng) {

		if ((!isNaN(lat)) && (!isNaN(lng))) {

//			map.panTo(new GLatLng(lat, lng));
			map.setCenter(new GLatLng(lat, lng));

			gen_map_changed(1);

			return true;

		}

		return false;

	}





	/* FUNCTION: Change zoom level */
	/*                             */
	/*           Can be called to change the zoom level    */
	/*           Eg: Could be used with the above function */


	function gen_change_zoom(zoom) {


		if ((!isNaN(zoom)) && (zoom > 0)) {

			gen_map_changed(1);

			map.setZoom(zoom);
			return true;

		}

		return false;


	}





	function gen_display_map_centre() {


		var current_centre_array = new Array();


		current_centre_array[0]	= map.getCenter().lat();
		current_centre_array[1]	= map.getCenter().lng();

		current_centre_array[0]	= parseFloat(current_centre_array[0]);
		current_centre_array[1]	= parseFloat(current_centre_array[1]);

		current_centre_array[0] = Math.round(current_centre_array[0] * 10000000)/10000000; // Rounds to 6 decimal places
		current_centre_array[1] = Math.round(current_centre_array[1] * 10000000)/10000000;


		if (document.getElementById("map_centre_display_latitude")) {
			document.getElementById("map_centre_display_latitude").innerHTML  = 'Centre Latitude: '  + current_centre_array[0];
		}

		if (document.getElementById("map_centre_display_longitude")) {
			document.getElementById("map_centre_display_longitude").innerHTML = 'Centre Longitude: ' + current_centre_array[1];
		}


	}






	function gen_display_map_zoom() {


		if (document.getElementById("map_centre_display_zoom")) {

			document.getElementById("map_centre_display_zoom").innerHTML = "Map Zoom Level: " + map.getZoom();

		}


	}





	/* FUNCTION: Note ES Change */
	/*                          */
	/*           Notes when a checkbox is updated for the map changed tracker */
	/*           This is the only way we can know if the checkboxes change    */
	/*                                                                        */
	/*           Also now used to keep track of how many checkboxes have been */
	/*           selected using the optional ID of the checkbox               */

	function gen_extra_sites_sel_log(the_id) {


		if (document.getElementById(the_id).checked == true) {
			gen_count_ec_sel++;
		}
		else {
			gen_count_ec_sel--;
		}


		gen_map_changed(1);


	}






	/* FUNCTION: Note Map Changed */
	/*                            */
	/*           Notes when anything has happened to the map or related data                 */
	/*                                                                                       */
	/*           Mostly used to prevent too many duplicate maps, but could be used elsewhere */
	/*           1 = Map has changed since code was generated; 0 = map hasn't changed        */
	/*           Reset after we collect new code and print it to step 4 on the form          */
	/*                                                                                       */
	/*           We also update the button incase it's been changed to display the right msg */
	/*           The other changes are made in the gmc_generate_map_code() form function     */


	function gen_map_changed(event) {

		gmc_event_tracker = (event == 1) ? 1 : 0;

		if (gmc_event_tracker == 1) {

			if (document.getElementById(form['gmc_html_getcode_button'])) {
				document.getElementById(form['gmc_html_getcode_button']).value = lang['gmc_button_getcode'];
			}

		}

		return true;

	}







	/* ==================== BUBBLE FORM SECTION ==================== */






	/* FUNCTION: Balloon form control */
	/*                                */
	/*           This prints the form and associated HTML into the speech bubble usually when the  */
	/*           icon is either created or clicked upon. Normally called after the 'click' event   */
	/*                                                                                             */
	/*           The 'info_window_form' is the default copy of the form with placeholders to allow */
	/*           us to replace them on an individual basis without altering the original copy      */

	function gmc_display_marker_contents(marker_id) {


		var dmc = info_window_form;


		var frmname = (store_marker_name[marker_id] !== undefined) ? store_marker_name[marker_id] : '';
		var frmurl	= (store_marker_url[marker_id]  !== undefined) ? store_marker_url[marker_id]  : '';
		var frmdesc	= (store_marker_desc[marker_id] !== undefined) ? store_marker_desc[marker_id] : '';


		dmc = dmc.replace(/FRMVALID/g,marker_id);
		dmc	= dmc.replace(/FRMVALNAME/g,frmname);
		dmc	= dmc.replace(/FRMVALURL/g,frmurl);
		dmc	= dmc.replace(/FRMVALTEXT/g,frmdesc);


		return dmc;


	}







	/* FUNCTION: Updates the arrays with the data from the form */
	/*                                                          */
	/*           The function is called from each info window 'save' button to collect the data   */
	/*           from the textboxes into arrays ready for writing back to the dbase later by AJAX */
	/*                                                                                            */
	/*           Normally called when the button on the form is pressed to save the contents      */
	/*                                                                                            */
	/*           We need to remove the | character as that's used to delimit during the POST      */

	function gmc_save_info(marker_id) {


		var icon_name = document.getElementById(form['bbl_name']).value;
		var icon_url  = document.getElementById(form['bbl_url']).value;
		var icon_desc = document.getElementById(form['bbl_text']).value;

		icon_name = icon_name.replace(/\|/g,'');
		icon_url  = icon_url.replace(/\|/g,'');
		icon_desc = icon_desc.replace(/\|/g,'');

		store_marker_name[marker_id] = icon_name;
		store_marker_url[marker_id]	 = icon_url;
		store_marker_desc[marker_id] = icon_desc;


		map.closeInfoWindow(); // Shut popup after saving


		gen_map_changed(1);


		return true;


	}







	/* FUNCTION: Remove the marker from the map */
	/*                                          */
	/*           Usually called when the user clicks the "remove icon" link in the speech bubble */
	/*           this removes the marker from the map and frees up the memory associated with it */


	function gmc_remove_marker(marker_id) {


		map.closeInfoWindow();

		map.removeOverlay(store_marker_copy[marker_id]);


		store_marker_name[marker_id] = '';
		store_marker_url[marker_id]  = '';
		store_marker_desc[marker_id] = '';

		store_marker_lat[marker_id]  = 0;
		store_marker_lng[marker_id]  = 0;

		store_marker_lat_orig[marker_id]  = 0;
		store_marker_lng_orig[marker_id]  = 0;

		id_tracker[marker_id]		 = 0;

		icons_count--;

		gen_map_changed(1);


		return true;


	}







	/* FUNCTION: Reset marker position */
	/*                                 */
	/*           If the user drags the marker, then wants to reset it's position to the original   */
	/*           point we do this by calling this function, probably from a link within the bubble */
	/*                                                                                             */
	/*           We return false just so the link doesn't try to interfere with operations         */


	function gmc_reset_marker(marker_id) {


		map.closeInfoWindow();


		var tmp_latlng = new GLatLng(store_marker_lat_orig[marker_id], store_marker_lng_orig[marker_id]);

		store_marker_copy[marker_id].setPoint(tmp_latlng);

		store_marker_lat[marker_id]  = store_marker_lat_orig[marker_id];
		store_marker_lng[marker_id]  = store_marker_lng_orig[marker_id];


		gen_map_changed(1);


		return false;


	}





	/* ==================== PRE-EXISTING DATA SECTION ==================== */







	/* FUNCTION: Collect the ID to lookup */
	/*                                    */
	/*           If the user wants to use a pre-existing map, they fill out the map code into a box */
	/*           on the page and this function picks up the map code. Once a few basic checks have  */
	/*           been carried out, we generate the post data (like a query string), and call upon   */
	/*           AJAX to go collect the data about this map ID (very similar to getting map code    */
	/*                                                                                              */
	/*           The AJAX function will call upon the gmd_process_data() function afterwards which  */
	/*           collects and processes the returning data, and eventually plots it onto the map    */


	function gmd_collect_map_id() {



		if (document.getElementById(form['gmd_mcode_input'])) {



			gen_clear_error(); // Clear any previous errors



			var existing_map_id = document.getElementById(form['gmd_mcode_input']).value;
			existing_map_id 	= existing_map_id.replace(/[^A-Za-z0-9]/, '');



			if (existing_map_id.length < 1) {

				gen_print_error(errors['gmd_submit_empty']);
				return false;

			}



			if (existing_map_id.length > 10) {

				gen_print_error(errors['gmd_submit_fake']);
				return false;

			}


			var post_string = 'map_id=' + existing_map_id;
			ajaxpack.postAjaxRequest(script_get_map_data, post_string, gmd_process_data, "txt");


		}


	}







	/* FUNCTION: Collect & Process Pre-Stored Map Data */
	/*                                                 */
	/*           This function is called by the AJAX code once the request has been made, so the first */
	/*           thing we need to do is to call upon the general AJAX receiver function and wait for   */
	/*           the data to arrive (sometimes takes a couple of seconds)                              */
	/*                                                                                                 */
	/*                                                                                                 */
	/*           Once AJAX works we receive the data in the following format:                          */
	/*                                                                                                 */
	/*           0) Status : 0=Internal Error; 1=Data OK; 2=ID Not Found                               */
	/*           1) Sites  : A | delimited list of extra site IDs, eg: 1|3|7 etc. Can be a blank line. */
	/*           2) Zoom level                                                                         */
	/*           3) The map centre latitude | longitude                                                */
	/*           4) The map type (1=Road; 2=Sat; 3=Hybrid)                                             */
	/*           5) First of the data lines, one per line, with | delimited data.                      */
	/*              Blank lines should be ignored, but blank entities are allowed.                     */
	/*              Line breaks are allowed, but should be translated into <br>                        */
	/*                                                                                                 */
	/*              1                                                                                  */
	/*              1|3|7                                                                              */
	/*              14                                                                                 */
	/*              1.557977|-122.55488                                                                */
	/*              3
	/*              Lat|Long|Icon_Name|Icon_URL|Icon_Desc                                              */
	/*                                                                                                 */
	/*                                                                                                 */
	/*           If debugging this script, you may find this function gets called 3-4x although it'll  */
	/*           ignore the first 3. I think this is because AJAX is triggered by the various stages   */
	/*           of the connection (so called readyState 1,2,3,4), but the function skips 1,2 & 3      */


	function gmd_process_data() {



		gen_clear_error(); // Clear any previous errors




		var ajax_existing_map_data = ajax_all_process_data();


		if (ajax_error_code == -1) {
			return;
		}


		if (ajax_error_code > 0) {
			gen_print_error(errors['gmd_int_error']);
			return false;
		}




		// Split the data into the individual lines
		var map_data_lines = ajax_existing_map_data.split("\n");




		if (map_data_lines.length < 1) {

			// Just stop as something serious went wrong at the remote end
			gen_print_error(errors['gmd_int_error']);
			return false;

		}





		// Check the status of the output (0, 1 or 2)
		// Last internal option catches anything that's not 1 or 2

		map_data_lines[0] = parseInt(map_data_lines[0]);


		if (map_data_lines[0] != 1) {


			if (map_data_lines[0] == 2) {

				gen_print_error(errors['gmd_id_missing']);
				return false;

			}
			else {

				gen_print_error(errors['gmd_int_error']);
				return false;

			}


		}





		// Re-select the appropriate checkboxes for extra sites
		//
		// Firstly reset them all to off
		// Then set the ones that were saved as on

		var map_data_sites_array = map_data_lines[1].split("|");


		for (b = 0; b < (set['max_extra_sites'] + 1); b++) {

			if (document.getElementById('uks_sitesel_' + b)) {

				document.getElementById('uks_sitesel_' + b).checked = false;

			}

		}



		for (sa = 0; sa < map_data_sites_array.length; sa++) {

			if (document.getElementById('uks_sitesel_' + map_data_sites_array[sa])) {

				document.getElementById('uks_sitesel_' + map_data_sites_array[sa]).checked = true;

				gen_count_ec_sel++; // Add 1 to EC box selected count

			}

		}





		// Clear existing markers
		//
		// If someone has added markers already, we have to clear them otherwise they might exceed
		// the max allowed on the page and thus some of these dbase held icons won't appear

		map.clearOverlays();
		icons_count = 0;




		// Set the zoom level, new centre & map type

		var tmp_new_zoom = (map_data_lines[2] > 0) ? map_data_lines[2] : 14;
		map.setZoom(parseInt(tmp_new_zoom));

		var tmp_centre_array = map_data_lines[3].split("|");
		map.setCenter(new GLatLng(tmp_centre_array[0], tmp_centre_array[1]), tmp_new_zoom);


		map_data_lines[4] = parseInt(map_data_lines[4]);

		switch (map_data_lines[4]) {

			case 2:
			map.setMapType(G_SATELLITE_MAP);
			break;

			case 3:
			map.setMapType(G_HYBRID_MAP);
			break;

			default:
			map.setMapType(G_NORMAL_MAP);

		}





		// Remove the map only lines
		// Just makes the counting easier in the next section for the data

		map_data_lines.shift(); // Status
		map_data_lines.shift(); // Sites
		map_data_lines.shift(); // Zoom
		map_data_lines.shift(); // Central co-ordinates
		map_data_lines.shift(); // Map type





		// Loop through each of the remaining lines (after status & sites lines to find the data
		// Split each of the lines into it's component parts (each icons data)
		// If the new array of parts is 5 long then it's legit so copy it into the storage vars
		// Else assume it's a blank line or broken line so skip it (shouldn't happen)
		//
		// Create the marker but passing the ID number to keep things in sync
		// Add the marker to the map just like the user clicking the map

		for (mdl = 0; mdl < map_data_lines.length; mdl++) {


			var map_data_single_line_array = map_data_lines[mdl].split("|");

			if (map_data_single_line_array.length == 5) {


				map_data_single_line_array[4] = map_data_single_line_array[4].replace(/<br>/g,"\r\n");


				store_marker_lat[mdl]  	= map_data_single_line_array[0];
				store_marker_lng[mdl]  	= map_data_single_line_array[1];
				store_marker_name[mdl] 	= map_data_single_line_array[2];
				store_marker_url[mdl]  	= map_data_single_line_array[3];
				store_marker_desc[mdl] 	= map_data_single_line_array[4];
				id_tracker[mdl]	 	 	= 1;

				var point 				= new GLatLng(store_marker_lat[mdl], store_marker_lng[mdl])

				var marker 				= gmap_create_marker(point,mdl);

				if (marker !== false) {
					map.addOverlay(marker);
				}


			}
			else {

				continue;

			}

		}

	}






	/* ==================== POSTCODE LOOKUP SECTION ==================== */






	/* FUNCTION: Collect the pcode to lookup */
	/*                                       */
	/*           Looking up postcodes is very similar to looking up map IDs, apart from a few */
	/*           format differences, and sending the requests to another script.              */
	/*                                                                                        */
	/*           When the user enters the pcode and clicks the lookup button, the request is  */
	/*           sent to this function first. It checks the form exists where it can find the */
	/*           data and assuming the formatting looks ok, it generates the POST string then */
	/*           passes this over to AJAX. That will then pass it onto the process function.  */
	/*                                                                                        */
	/*           In case you're wondering, the remote end has a set of tests it runs against  */
	/*           the postcode, especially for the UK, which can generally find a legit code   */
	/*           even when there are no spaces used, eg: LA24JQ or SW1V8SJ                    */


	function gpc_collect_postcode() {



		if (document.getElementById(form['gpc_pcode_input'])) {



			gen_clear_error(); // Clear any previous errors



			var input_selected_country = document.getElementById(form['gpc_cc_input']).options[document.getElementById(form['gpc_cc_input']).selectedIndex].value;
			var input_existing_pcode   = document.getElementById(form['gpc_pcode_input']).value;


			var tmp_existing_pcode	= input_existing_pcode;
			tmp_existing_pcode		= tmp_existing_pcode.replace(/\s*((\S+\s*)*)/, "$1");
			tmp_existing_pcode		= tmp_existing_pcode.replace(/((\s*\S+)*)\s*/, "$1");
			tmp_existing_pcode2		= tmp_existing_pcode.match(/([a-zA-Z0-9\- ]+)/);
			input_existing_pcode	= (tmp_existing_pcode2 != undefined) ? tmp_existing_pcode2[1] : '';




			if (!input_selected_country.match(/^[A-Z]{2,3}$/)) {

				gen_print_error(errors['gpc_submit_cc']);
				return false;

			}



			if (input_existing_pcode.length < 1) {

				gen_print_error(errors['gpc_submit_empty']);
				return false;

			}



			if (input_existing_pcode.length > 10) {

				gen_print_error(errors['gpc_submit_fake']);
				return false;

			}



			var post_string  = 'pc=' + encodeURI(input_existing_pcode);
 			    post_string += '&cc=' + encodeURI(input_selected_country);



			// Debugs the URL if appropriate form element exists
			if (document.getElementById('debugpc')) {
				document.getElementById('debugpc').value = script_get_pcode_data + '?' + post_string;
			}


			ajaxpack.postAjaxRequest(script_get_pcode_data, post_string, gpc_process_data, "txt");



		}



	}







	/* FUNCTION: Collect & Process Pcode Data */
	/*                                        */
	/*           This function is again pretty similar in concept to the get map data equiv. function  */
	/*                                                                                                 */
	/*           It is called by the AJAX call in gpc_collect_pcode() and it's job is to process       */
	/*           the received postal code long/lat data to be injected into the store_ variables and   */
	/*           then to add that point to the map.                                                    */
	/*                                                                                                 */
	/*                                                                                                 */
	/*           Once AJAX works we receive the pcode data in the following format:                    */
	/*                                                                                                 */
	/*           LONG|LAT|GRIDREF|PRECISION|STATUS                                                     */
	/*                                                                                                 */
	/*           • For this script we'll ignore the grid reference as I can't think of any use for it  */
	/*           • The precision tells us if we can pinpoint the pcode (1=precise; 0=not precise)      */
	/*                                                                                                 */
	/*           • Status determines whether the lookup worked ok, or there was an error.              */
	/*             Some numbers are duplicated due to internal status codes being simplified           */
	/*                                                                                                 */
	/*             1 -> Everything OK                                                                  */
	/*             2 -> Postcode format supplied is not valid 				                           */
	/*             3 -> Half postcode supplied, but full code required (n/a)                           */
	/*             4 -> Data returned from server not accurate enough (n/a)                            */
	/*             5 -> Internal error [remote system returned invalid data]                           */
	/*             6 -> Postcode not found                                                             */
	/*             7 -> Internal error [remote lookup timed out]                                       */
    /*                                                                                                 */
    /*                                                                                                 */
    /*           For the purposes of this script we ignore precision as only the UK postcodes can      */
    /*           return a precision value of 1 so we'll plot the icon onto the screen and then give    */
    /*           the user a warning note how this might not be the absolute location                   */
    /*                                                                                                 */
    /*                                                                                                 */
	/*           If debugging this script, you may find this function gets called 3-4x although it'll  */
	/*           ignore the first 3. I think this is because AJAX is triggered by the various stages   */
	/*           of the connection (so called readyState 1,2,3,4), but the function skips 1,2 & 3      */


	function gpc_process_data() {



		gen_clear_error(); // Clear any previous errors



		// Get the data from AJAX
		var ajax_pcode_data = ajax_all_process_data();




		if (ajax_error_code == -1) {
			return; // Not ready yet, skip this call
		}



		if (ajax_error_code > 0) {
			gen_print_error(errors['gpc_int_error']);
			return false; // Server error
		}




		// Split the returning data into parts
		var pcode_data_line_array = ajax_pcode_data.split("|");




		// Check if the data came back in the expected 5 part format
		// If not, assume there's a server glitch and send a generic error

		if (pcode_data_line_array.length != 5) {

			gen_print_error(errors['gpc_int_error']);
			return false;

		}




		// Check the status to see if any errors occured
		// We need to parseInt or it doesn't spot the number

		pcode_data_line_array[4] = parseInt(pcode_data_line_array[4]);

		switch (pcode_data_line_array[4]) {

			case 1:
			break;

			case 2:
			gen_print_error(errors['gpc_submit_fake']);
			return false;
			break;

			case 5:
			gen_print_error(errors['gpc_int_error']);
			return false;
			break;

			case 6:
			gen_print_error(errors['gpc_pcode_missing']);
			return false;
			break;

			case 7:
			gen_print_error(errors['gpc_int_error']);
			return false;
			break;

			default:
			gen_print_error(errors['gpc_int_error']);
			return false;


		}





		// Check if adding this icon will exceed the max number on a map
		// User is sent an alert by the function, so no need to error here

		if (gen_max_icons_check() !== true) {

			return false;

		}





		// Check the precision level of returning data
		// If not accurate, add a note to the page to warn the user

		pcode_data_line_array[3] = parseInt(pcode_data_line_array[3]);

		if (document.getElementById(form['gpc_pcode_accuracy'])) {

			if (pcode_data_line_array[3] != 1) {
				document.getElementById(form['gpc_pcode_accuracy']).innerHTML = lang['gpc_marker_not_acc'];
			}
			else {
				document.getElementById(form['gpc_pcode_accuracy']).innerHTML = '';
			}


		}




		// Get the next free marker ID

		var tmp_nid = gen_get_icon_id();





		// Create the marker, passing the ID number to keep things in sync
		// Add the marker to the map just like the user clicking the map

		store_marker_lng[tmp_nid]  	= pcode_data_line_array[0];
		store_marker_lat[tmp_nid]  	= pcode_data_line_array[1];
		store_marker_name[tmp_nid] 	= '';
		store_marker_url[tmp_nid]  	= '';
		store_marker_desc[tmp_nid] 	= '';
		id_tracker[tmp_nid]	 	 	= 1;

		var point 	= new GLatLng(store_marker_lat[tmp_nid], store_marker_lng[tmp_nid]);

		var marker	= gmap_create_marker(point,tmp_nid);

		var tmp_marker_contents = gmc_display_marker_contents(tmp_nid);


		// Zoom in so they can move the marker
		gen_change_zoom(13);


		// Centre the map on the icon
		gen_change_centre(store_marker_lat[tmp_nid], store_marker_lng[tmp_nid]);


		if (marker !== false) {
			map.addOverlay(marker);
//			map.openInfoWindowHtml(point,tmp_marker_contents); // Initial InfoWindow...
		}


	}









	/* ==================== PLOT BY CO-ORDINATES AND GRID REF ==================== */






	/* FUNCTION: Translate Grid References */
	/*                                     */
	/*           This function controls collection and translation of the grid reference into a */
	/*           longitude and latitude. It works in conjunction with the function to plot c/o  */
	/*           into the map simply by filling in the boxes and then firing that function      */
	/*                                                                                          */
	/*           For this to work, the coordinates-gridref-script.js is required to be included */
	/*           into the page head before this can be called as that does the translations     */
	/*                                                                                          */
	/*           The function doesn't use AJAX at all as all the calculations are internal      */


	function ggr_calc_coordinates() {



		if (document.getElementById(form['grr_co_gridref_input'])) {


			var input_gridref = document.getElementById(form['grr_co_gridref_input']).value.toUpperCase();

			var tmp_input_gridref = input_gridref.match(/([A-Z]{2}[0-9]{6})/);



			if (tmp_input_gridref) {
				input_gridref = tmp_input_gridref[1];
			}
			else {
				gen_print_error(errors['grr_format_fake']);
				return false;
			}



			var grr_type_rad1 = document.getElementById(form['grr_co_gridref_t_os']);
			var grr_type_rad2 = document.getElementById(form['grr_co_gridref_t_ws']);

			if (grr_type_rad1.checked == true) {
				var input_grid_type = 'os';
			}
			else {
				var input_grid_type = 'ws';
			}



			// Do the conversion from grid ref to co-ordinates

			var os6  = input_gridref;
			var os1w = getOSRefFromSixFigureReference(os6);
			var ll1w = os1w.toLatLng(os1w);

			if (input_grid_type == 'ws') {
				ll1w.OSGB36ToWGS84();
			}

			var lnglatstring = ll1w.toString();

			lnglatstring = lnglatstring.replace("(","");
			lnglatstring = lnglatstring.replace(")","");

			lnglatstringarray = lnglatstring.split(",");

			var output_latitude 	= lnglatstringarray[0];
			var output_longitude	= lnglatstringarray[1];




			// If the lat/lang boxes exist, drop the values into there and submit them
			// The gco_ function picks these details up from the boxes we fill in here

			if ((document.getElementById(form['gco_co_input_lat'])) && (document.getElementById(form['gco_co_input_lng']))) {

				document.getElementById(form['gco_co_input_lat']).value = output_latitude;
				document.getElementById(form['gco_co_input_lng']).value = output_longitude;

				gco_plot_by_coordinates();

				return true;

			}
			else {

				return false;

			}


		}


	}







	/* FUNCTION: Plot by co-ordinates */
	/*                                */
	/*           This function collects the long/lat from the textboxes and plots the icon onto */
	/*           the screen in much the same way as clicking the map or plotting by postal code */
	/*                                                                                          */
	/*           It is also used by the grid reference function above as that calculates the    */
	/*           co-ordinates from a grid reference then passes them here to be plotted         */


	function gco_plot_by_coordinates() {


		if ((document.getElementById(form['gco_co_input_lat'])) && (document.getElementById(form['gco_co_input_lng']))) {


			var input_latitude  = document.getElementById(form['gco_co_input_lat']).value;
			var input_longitude = document.getElementById(form['gco_co_input_lng']).value;


			input_latitude  = input_latitude.replace(/[^0-9\.\-]/g, '');
			input_longitude = input_longitude.replace(/[^0-9\.\-]/g, '');


			if ((input_latitude.length < 1) || (input_longitude.length < 1)) {
				return false;
			}


			input_latitude  = parseFloat(input_latitude);
			input_longitude = parseFloat(input_longitude);




			// Check if adding this icon will exceed the max number on a map
			// User is sent an alert by the function, so no need to error here

			if (gen_max_icons_check() !== true) {

				return false;

			}




			// Get the next free marker ID

			var tmp_nid = gen_get_icon_id();





			// Create the marker, passing the ID number to keep things in sync
			// Add the marker to the map just like the user clicking the map

			store_marker_lng[tmp_nid]  	= input_longitude;
			store_marker_lat[tmp_nid]  	= input_latitude ;
			store_marker_name[tmp_nid] 	= '';
			store_marker_url[tmp_nid]  	= '';
			store_marker_desc[tmp_nid] 	= '';
			id_tracker[tmp_nid]	 	 	= 1;   // Sets this marker ID as used


			var point 	= new GLatLng(store_marker_lat[tmp_nid], store_marker_lng[tmp_nid]);
			var marker	= gmap_create_marker(point,tmp_nid);

			var tmp_marker_contents = gmc_display_marker_contents(tmp_nid);


			// Zoom in so they can move the marker
			gen_change_zoom(13);


			// Centre the map on the icon
			gen_change_centre(store_marker_lat[tmp_nid], store_marker_lng[tmp_nid]);


			if (marker !== false) {
				map.addOverlay(marker);
	//			map.openInfoWindowHtml(point,tmp_marker_contents); // Initial InfoWindow...
			}


			return true;


		}



	}







	/* ==================== GET MAP CODE & IFRAME SECTION ==================== */







	/* FUNCTION: Control Post Data */
	/*                             */
	/*           This is the main controller for when the user requests the iFrame HTML code         */
	/*           which takes care of sending off the POST request and receiving back the ID code     */
	/*                                                                                               */
	/*                                                                                               */
 	/*           This section has two basic purposes:                                                */
	/*                                                                                               */
	/*           1) Save the users map data including positions & bubble data                        */
	/*           2) When we get an ID from the remote system, use it to create the iFrame HTML code  */
	/*                                                                                               */
	/*           The iFrame links the end user to the maps page, and the ID number identifies the    */
	/*           map data in the remote database so we can in theory plot as many points on the map  */
	/*           as we want. Using the AJAX & POST in this function, we store the data and it will   */
	/*           either be retrieved back into this page later or when the end user requests a map   */
	/*                                                                                               */
	/*                                                                                               */
	/*           This function calls upon the gmc_generate_post_data() which collects the stored     */
	/*           marker data from stored_ vars, turns it into a query string and makes it postable.  */
	/*                                                                                               */
	/*           Then it we call upon the AJAX functions to POST the data across to the server scr.  */
	/*                                                                                               */
    /*           Finally the AJAX returns and passes the new map ID to gmc_generate_map_code()       */
    /*           where it'll be printed to the textbox                                               */
    /*                                                                                               */
    /*                                                                                               */
    /*           The commented out sections stopped the map code being generated if the map didn't   */
    /*           have any plotted icons, but we decided for the moment to remove this requirement    */


	function gmc_control_post_data() {


//		if (icons_count > 0) {


			if (gmc_event_tracker != 1) {
				return false; // If nothing changed, skip the update
			}
			else {

				/* gmc_generate_post_data() - collect data from vars into & delim string               */
				/* post_string				- The request string generated by gmc_generate_post_data() */
				/* script_get_map_code		- The URL we send the request to                           */
				/* gmc_generate_map_code	- The function to pass the result to                       */

				var post_string = gmc_generate_post_data();

				ajaxpack.postAjaxRequest(script_get_map_code, post_string, gmc_generate_map_code, "txt");

			}


//		}
//		else {

//			alert(lang['gmc_alert_no_icon']);

//		}


	}







	/* FUNCTION: Create POST Data */
	/*                            */
	/*                            */
	/*           This is the 2nd of the functions involved in saving the map and providing the HTML */
	/*                                                                                              */
	/*           It's job is to take the data stored in the store_marker_ variables such as the c/o */
	/*           of the marker along with the bubbble data, and turn it into POSTable data, really  */
	/*           just like a query string. It also needs to collect other data such as the current  */
	/*           map centre & zoom levels and the extra site IDs selected to replay the map later   */


	function gmc_generate_post_data() {


		var marker_name_post = '';
		var marker_url_post  = '';
		var marker_desc_post = '';
		var marker_lat_post  = '';
		var marker_lng_post  = '';

		var extra_sites_list = '';

		var map_centre_lat	 = map.getCenter().lat();
		var map_centre_lng	 = map.getCenter().lng();
		var map_zoom		 = map.getZoom();



		// Set the map type (might need tweaking in the future)

		switch(map.getCurrentMapType().getUrlArg()) {

			case 'k':
			map_type = 2;
			break;

			case 'h':
			map_type = 3;
			break;

			default:
			map_type = 1;

		}




		for (a = 0; a < set['max_icons']; a++) {

			if (id_tracker[a] == 1) {

				marker_name_post += store_marker_name[a] + '|';
				marker_url_post  += store_marker_url[a]  + '|';
				marker_desc_post += store_marker_desc[a] + '|';
				marker_lat_post  += store_marker_lat[a]	 + '|';
				marker_lng_post  += store_marker_lng[a]	 + '|';

			}

		}



		for (b = 0; b < (set['max_extra_sites'] + 1); b++) {

			if (document.getElementById('uks_sitesel_' + b)) {

				if (document.getElementById('uks_sitesel_' + b).checked) {

					extra_sites_list += b + '|';

				}

			}

		}



		var poststr  = "icon_name="  + encodeURIComponent(marker_name_post);
			poststr += "&icon_url="  + encodeURIComponent(marker_url_post);
			poststr += "&icon_desc=" + encodeURIComponent(marker_desc_post);
			poststr += "&icon_lat="  + encodeURIComponent(marker_lat_post);
			poststr += "&icon_lng="  + encodeURIComponent(marker_lng_post);

			poststr += "&sites="	     + encodeURIComponent(extra_sites_list);
			poststr += "&centre_lat="	 + encodeURIComponent(map_centre_lat);
			poststr += "&centre_lng="	 + encodeURIComponent(map_centre_lng);
			poststr += "&zoom="	 		 + encodeURIComponent(map_zoom);
			poststr += "&type="	 		 + encodeURIComponent(map_type);


		return poststr;


	}






	/* FUNCTION: Generate Map HTML */
	/*                             */
	/*           This is the 3rd of the functions involved in saving the map and providing the HTML */
	/*                                                                                              */
	/*           It is called after the AJAX call has been made and it's job is to wait for the map */
	/*           ID to be returned from the remote system. Once the ID returns, the data has been   */
	/*           saved and the function can add the ID onto the iFrame HTML code and print it out   */
	/*                                                                                              */
	/*                                                                                              */
    /*           As with the other AJAX scripts, this one might be called 3/4 times before the data */
    /*           is ready for retrieval. We need to check for a return value other than -1 so we'll */
    /*           know that the lookup is complete and the data ready.                               */
   	/*                                                                                              */
	/*           Once we've got the data, we need to check whether any error code was set in the    */
	/*           ajax_error_code which should be 0. If it's not then it contains the HTTP status    */
	/*           code of the error such as 500 for Internal Server Error or 404 for Not Found       */


	function gmc_generate_map_code(gmc_input) {




		// If we received a do refresh command check if we've previously gotten a code
		// If not then ignore it, otherwise we'll use the cached code instead of a new one

		if (gmc_input == 'dorefresh') {

			if (gmc_ajax_got_code != 1) {
				return false;
			}
			else {
				var tmp_gmc_do_refresh_only = 1;
			}

		}





		// Change button to loading code, if we're not just refreshing...

		if (document.getElementById(form['gmc_html_getcode_button'])) {
			document.getElementById(form['gmc_html_getcode_button']).value = lang['gmc_button_loadcode'];
		}






		if (tmp_gmc_do_refresh_only == 1) {

			ajax_map_code_whole = gmc_ajax_cache;

		}
		else {

			var ajax_map_code_whole = ajax_all_process_data();
			gmc_ajax_cache = ajax_map_code_whole;

		}



		if (ajax_error_code == -1) {
			return false;
		}


		if (ajax_error_code > 0) {
			gen_print_error(errors['gmc_int_error']);
			return false;
		}





		// Once the data arrives, split it into status and map code

		var ajax_map_code_array   = ajax_map_code_whole.split("|");
		var ajax_map_code_status  = ajax_map_code_array[0];
		var ajax_map_code 		  = ajax_map_code_array[1];


		if (ajax_map_code_status != 1) {

			gen_print_error(errors['gmc_int_error']);
			return false;

		}




		// Indicate we've got a code back so now the do_refresh can be activated
		gmc_ajax_got_code = 1;




		// Pulls out a non-QS altered copy for certain parts
		var ajax_map_code_pure 	= ajax_map_code;




		// If the hide extra content checkbox exists, check if it's set
		// If it's set then we update the map code with the hide extra content in the QS

		if (document.getElementById(form['gmc_html_hide_ec'])) {

			var mychkbox = document.getElementById(form['gmc_html_hide_ec']);

			if (mychkbox.checked == true) {

				ajax_map_code 			= ajax_map_code + html['gmc_html_hide_ec'];
				var hide_ec_box_sel		= 1;

			}

		}





		// If the use transparent iframe is set then swap the iframe code over to the transparent URL
		// Otherwise use the original non-transparent code

		if (document.getElementById(form['gmc_html_iframe_trans'])) {

			if (document.getElementById(form['gmc_html_iframe_trans']).checked) {
				html['gmc_html_iframe_sel'] = html['gmc_html_iframe_trans'];
			}
			else {
				html['gmc_html_iframe_sel'] = html['gmc_html_iframe'];
			}

		}
		else {
			html['gmc_html_iframe_sel'] = html['gmc_html_iframe'];
		}




		var html_output 			= [];
		html_output['iframe_code'] 	= html['gmc_html_iframe_sel'].replace(/MAPCODEHERE/,ajax_map_code);
		html_output['email_code']  	= html['gmc_raw_url'].replace(/MAPCODEHERE/,ajax_map_code);
		html_output['forum_code']  	= html['gmc_html_bbcode'].replace(/MAPCODEHERE/,ajax_map_code);
		html_output['link_code']  	= html['gmc_html_link'].replace(/MAPCODEHERE/,ajax_map_code);
		html_output['test_code']  	= html['gmc_html_testlink'].replace(/MAPCODEHERE/,ajax_map_code);
		html_output['email_link_u']	= html['gmc_html_email_link_u'].replace(/MAPCODEHERE/,ajax_map_code);
		html_output['email_link_d']	= html['gmc_html_email_link_d'].replace(/MAPCODEHERE/,ajax_map_code);





		// Set the width & height of the iFrame depending on the extra content state
		//
		// Any extra content is hidden
		// No extra content
		// 1 Line of extra content
		// 2+ lines of extra content

		if (hide_ec_box_sel == 1) {
			tmp_iframe_w = html_iframe_width_noec;
			tmp_iframe_h = html_iframe_height_noec;
		}
		else if (gen_count_ec_sel < 1) {
			tmp_iframe_w = html_iframe_width_noec;
			tmp_iframe_h = html_iframe_height_noec;
		}
		else if ((gen_count_ec_sel > 0) && (gen_count_ec_sel < 4)) {
			tmp_iframe_w = html_iframe_width_line;
			tmp_iframe_h = html_iframe_height_line;
		}
		else {
			tmp_iframe_w = html_iframe_width_def;
			tmp_iframe_h = html_iframe_height_def;
		}



		html_output['iframe_code'] 	= html_output['iframe_code'].replace(/IFRAMEWIDTH/,tmp_iframe_w);
		html_output['iframe_code'] 	= html_output['iframe_code'].replace(/IFRAMEHEIGHT/,tmp_iframe_h);






		// The length test just makes sure things look ok and it's not a server error

		if (ajax_map_code.length < 30) {


			if (document.getElementById(form['gmc_html_iframe_output'])) {
				document.getElementById(form['gmc_html_iframe_output']).value 	= html_output['iframe_code'];
			}

			if (document.getElementById(form['gmc_html_url_output'])) {
				document.getElementById(form['gmc_html_url_output']).value 		= html_output['email_code'];
			}

			if (document.getElementById(form['gmc_html_bbcode_output'])) {
				document.getElementById(form['gmc_html_bbcode_output']).value	= html_output['forum_code'];
			}

			if (document.getElementById(form['gmc_html_link_output'])) {
				document.getElementById(form['gmc_html_link_output']).value		= html_output['link_code'];
			}

			if (document.getElementById(form['gmc_html_testlink_output'])) {
				document.getElementById(form['gmc_html_testlink_output']).style.display = '';
				document.getElementById(form['gmc_html_testlink_output']).innerHTML	= html_output['test_code'];
			}

			if (document.getElementById(form['gmc_html_mapcode_output'])) {
				document.getElementById(form['gmc_html_mapcode_output']).value 	= ajax_map_code_pure;
			}


			if (document.getElementById(form['gmc_html_getcode_button'])) {
//				document.getElementById(form['gmc_html_getcode_button']).value 		= lang['gmc_button_selcode'];
				document.getElementById(form['gmc_html_getcode_button']).innerHTML 	= lang['gmc_button_selcode'];
			}




			if (document.getElementById(form['gmc_html_email_link_u'])) {
				document.getElementById(form['gmc_html_email_link_u']).innerHTML = html_output['email_link_u'];
			}

			if (document.getElementById(form['gmc_html_email_link_d'])) {
				document.getElementById(form['gmc_html_email_link_d']).innerHTML = html_output['email_link_d'];
			}



		}



		gen_map_changed(0); // Reset so we know the map is unchanged again


	}








	/* ==================== AJAX SECTION ==================== */








	/* FUNCTION: AJAX Receive Data (independent) */
	/*                                           */
	/*           This section of the AJAX can be called by any AJAX function to receive data back */
	/*                                                                                            */
	/*           It's essentially independent of the other AJAX code so can be used by any AJAX   */
	/*           call although hopefully it knows which function to return the data to in the     */
	/*           event of different calls and different types of calls                            */
	/*                                                                                            */
	/*                                                                                            */
	/*           The return value doesn't seem to be parseable for use in the status, so use the  */
	/*           global 'ajax_error_code' variable instead. This has 3 possible values:           */
	/*                                                                                            */
	/*           0 means the data is ready so read the function return value                      */
	/*           -1 means data not returned yet so ignore this return                             */
	/*           -2 means something critcal went wrong (read ajax_error_status for http status)   */

	function ajax_all_process_data() {


		var myajax=ajaxpack.ajaxobj;


		if (myajax.readyState == 4) { // if request of file completed


			if (myajax.status==200) {  // if request was successful

				var ajax_response = myajax.responseText;
				ajax_error_code	  = 0;
				return ajax_response;

			}
			else {
				ajax_error_code   = -2;
				ajax_error_status = myajax.status;
				return -2;
			}

		}
		else {
			ajax_error_code = -1;
			return -1;
		}

	}






    //]]>

-->









