function showPropsMethods_func(obj){
	var info = "";
	for (pm in obj){
		info+=pm+",  "
	}
	return info;
}

// *** These 2 functions use the jscoord-1.1.1.js script ***
function OS2LatLonWGS84_func(easting, northing){
	var osP = new OSRef(easting, northing);
	var llP = osP.toLatLng();
	llP.OSGB36ToWGS84();
	return llP;
}
function LatLonWGS842OS_func(lat, lng){
	//var ll2 = new LatLng(52.657570301933, 1.7179215806451);
	var llP = new LatLng(lat, lng);
	//alert("Latitude/Longitude: " + llP.toString() + "<br />");
	llP.WGS84ToOSGB36();
	var osP = llP.toOSRef();
	//alert("osP.easting="+osP.easting)
	//alert("Converted to OS Grid Ref: " + osP.toString() + " - " + osP.toSixFigureString());
	return osP;
}
// **********************************************************


// ***** USEFUL/GENERIC Google Map API Function ***********
// ********************************************************

// ***** GClientGeocoder related Functions ****
var geocoder = null; // GClientGeocoder used for verifying address points
function initGeoCoder(country){
	geocoder = new GClientGeocoder();// NOTE due to legal restrictions in UK (because of OS and Royal Mail), the Google Map API cannot perform a full postcode address search, it will always ignore the second part of the postcode.
	geocoder.setCache(null);
	geocoder.setBaseCountryCode(country);// Set all address searches to be in UK only.	
}

function findAddrPt(addr, funcSuc, funcFail){
	if (geocoder) {
		geocoder.getLatLng(addr, function(point) {
			if (!point) {
				//alert(addr + " not found");
				funcFail(addr)
			} else {
				funcSuc(point);
			}
		});
	}
}

function findAddrLocations(addr, funcSuc, funcFail){
	if (geocoder) {	
		//alert("findAddrLocations");
		geocoder.getLocations(addr, function(points) {
			if (!points) {
				//alert(addr + " not found");
				funcFail(addr)
			} else {
				funcSuc(points);
			}
		});
	}
}

function geocoderGetLatLng(pt){
	alert("found address!\n"+pt)
}
function geocoderNotFound(addr){
	alert("not found address for "+addr+"\n"+gmapErrorHandler(response.Status.code));
}

function findAddr_func(address){
	var geocoder = new GClientGeocoder();
	geocoder.getLatLng(
			  address,
			  function(point) {
			  	return point;
				/*if (!point) {
				  return false;
				} else {
					var addrPoint = point;
					return point;
				}*/
			  }
			);
}
// ********************************************************



// ***** All of the Google Map Error Codes ****
function gmapErrorHandler(gCode){
	alert(gCode)
	var res = "";
	if (gCode == 200){ //(200 G_GEO_SUCCESS)
		res = "No errors occurred; the address was successfully parsed and its geocode has been returned. (Since 2.55)"
	} else if (gCode == 400){ //(400 G_GEO_BAD_REQUEST)
		res = "A directions request could not be successfully parsed. For example, the request may have been rejected if it contained more than the maximum number of waypoints allowed. (Since 2.81)"
	} else if (gCode == 500){ //(500 G_GEO_SERVER_ERROR)
		res = "A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known. (Since 2.55)"
	} else if (gCode == 601){ //(601 G_GEO_MISSING_QUERY)
		res = "The HTTP q parameter was either missing or had no value. For geocoding requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input. (Since 2.81)"
	} else if (gCode == 601){ //(601 G_GEO_MISSING_ADDRESS)
		res = "Synonym for G_GEO_MISSING_QUERY. (Since 2.55)"
	} else if (gCode == 602){ //(602 G_GEO_UNKNOWN_ADDRESS)
		res = "No corresponding geographic location could be found for the specified address. This may be due to the fact that the address is relatively new, or it may be incorrect. (Since 2.55)"
	} else if (gCode == 603){ //(603 G_GEO_UNAVAILABLE_ADDRESS)
		res = "The geocode for the given address or the route for the given directions query cannot be returned due to legal or contractual reasons. (Since 2.55)"
	} else if (gCode == G_GEO_UNKNOWN_DIRECTIONS){ //(604)
		res = "The GDirections object could not compute directions between the points mentioned in the query. This is usually because there is no route available between the two points, or because we do not have data for routing in that region. (Since 2.81)"
	} else if (gCode == G_GEO_BAD_KEY){ //(610)
		res = "The given key is either invalid or does not match the domain for which it was given. (Since 2.55)"
	} else if (gCode == G_GEO_TOO_MANY_QUERIES){ //(620)
		res = "The given key has gone over the requests limit in the 24 hour period or has submitted too many requests in too short a period of time. If you're sending multiple requests in parallel or in a tight loop, use a timer or pause in your code to make sure you don't send the requests too quickly. (Since 2.55)"
	}
	return res;
}
// ********************************************************

function setGmapType(mapType){
	var mapTypes = [
	G_NORMAL_MAP,
	G_SATELLITE_MAP,
	G_HYBRID_MAP,
	G_PHYSICAL_MAP,
	G_MOON_ELEVATION_MAP,
	G_MOON_VISIBLE_MAP,
	G_MARS_ELEVATION_MAP,
	G_MARS_VISIBLE_MAP,
	G_MARS_INFRARED_MAP,
	G_SKY_VISIBLE_MAP,
	G_SATELLITE_3D_MAP,
	G_DEFAULT_MAP_TYPES,
	G_MOON_MAP_TYPES,
	G_MARS_MAP_TYPES,
	G_SKY_MAP_TYPES];
	map.setMapType(mapTypes[mapType]);
}

function updateMapControls(){ // this is only a hack
	var images = map.getContainer().getElementsByTagName("img");
	var imgUpdates=0;
	for(var i=0; i<images.length; i++){		
		if (images[i].src.indexOf("mapcontrols3d") != -1){
			imgUpdates=1;
		}
		images[i].src = images[i].src.replace(/mapcontrols2/,"mapcontrols3d");
	}
	if (imgUpdates==0){
		setTimeout(updateMapControls, 500);
	}
	//window.status += imgUpdates+", ";
}


function setMapBoundary(pt1, pt2){ // pt1 and pt2 must be in "new GLatLng" format
	// This is the work around for getBoundsZoomLevel bug
	var bounds = new GLatLngBounds;
	bounds.extend(pt1);
	bounds.extend(pt2);
	map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));						
}

// ****** JSON reading functions *****
function readJSONPlacemark(JSONPlacemarkObj){
	var addrDisplay = "";
	if (JSONPlacemarkObj.AddressDetails.Country.AdministrativeArea){
		if (JSONPlacemarkObj.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea){
			if (JSONPlacemarkObj.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality){				
				if (JSONPlacemarkObj.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.Thoroughfare){
					// Street Name
					addrDisplay += JSONPlacemarkObj.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.Thoroughfare.ThoroughfareName;
				}	
				// Locality/Location
				addrDisplay += ", "+JSONPlacemarkObj.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;				
				
				// SubArea Name
				addrDisplay += ", "+JSONPlacemarkObj.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.SubAdministrativeAreaName;				
				
				// Area Name - not really needed as it repeats SubArea Name in most cases
				//addrDisplay += ", "+JSONPlacemarkObj.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName;
				
				if (JSONPlacemarkObj.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.PostalCode){
					// Postcode
					addrDisplay += ", "+JSONPlacemarkObj.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.PostalCode.PostalCodeNumber;
				}	
				addrDisplay += " ("+JSONPlacemarkObj.AddressDetails.Accuracy+")"
			}
		}		
	}
	if (addrDisplay == "" || addrDisplay == undefined){
		addrDisplay = JSONPlacemarkObj.address+" ("+JSONPlacemarkObj.AddressDetails.Accuracy+")";
	}
	return addrDisplay;
	/*var jsonNames = {
	JSONobj.name,
	JSONobj.Status.code,
	JSONobj.Status.request,
	JSONobj.Placemark.address,
	JSONobj.Placemark.AddressDetails.Country.CountryNameCode,
	JSONobj.Placemark.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName,
	JSONobj.Placemark.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.SubAdministrativeAreaName,
	JSONobj.Placemark.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName,
	JSONobj.Placemark.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.Thoroughfare.ThoroughfareName,
	JSONobj.Placemark.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.PostalCode.PostalCodeNumber,
	JSONobj.Placemark.AddressDetails.Accuracy,
	JSONobj.Placemark.Point.coordinates,
	JSONobj.Placemark.AddressDetails}*/
}

// A JSON object returned from geocoder
// The only part of this that are arrays is the Placemark and coordinates
/*
{
  "name": "1600 Amphitheatre Parkway, Mountain View, CA, USA",
  "Status": {
    "code": 200,
    "request": "geocode"
  },
  "Placemark": [
    {
      "address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
      "AddressDetails": {
        "Country": {
          "CountryNameCode": "US",
          "AdministrativeArea": {
            "AdministrativeAreaName": "CA",
            "SubAdministrativeArea": {
              "SubAdministrativeAreaName": "Santa Clara",
              "Locality": {
                "LocalityName": "Mountain View",
                "Thoroughfare": {
                  "ThoroughfareName": "1600 Amphitheatre Pkwy"
                },
                "PostalCode": {
                  "PostalCodeNumber": "94043"
                }
              }
            }
          }
        },
        "Accuracy": 8
      },
      "Point": {
        "coordinates": [-122.083739, 37.423021, 0]
      }
    }
  ]
}
*/