//==================================================
//
//	A2EGMapsViewer.js
//	copyright 2007 Arc2Earth LLC
//
//	This is for use with Arc2Earth viewers only
//
//==================================================


//=======================
//Viewer
var _MP = null;
var vt = "GM";
var map;
var mm;
var levelStart=0;
var levelEnd=0;
var client;
var _App = null;
var events;
var cboLayers;
var panels = [];
var displaySidebar = true;
var currentPanel = "";
var isIE = false;
var isLocal = false;

function Init() 
{
	//if (GBrowserIsCompatible()) 
	//{  

		isIE=(navigator.appName.indexOf("Microsoft")!=-1)?1:0;
		window.onresize = resizeApp; 
		
		isLocal = (baseUrl.indexOf("http://") == -1);
		
		//================
		//Map Provider
		if (typeof(mapID) != "undefined") {
			_App = new A2EApplication(mapID);
		}
		events = new A2EEvents();
		var md = document.getElementById('map');
		md.style.position = "relative";
		md.style.width = "100%";
		md.style.height = "100%";
		switch (vt)
		{
			case "GM": _MP = new GMMapProvider(md, startupLat, startupLon, startupLevel, events); break;
			case "VE": _MP = new VEMapProvider(md, startupLat, startupLon, startupLevel, events); break;
			case "OL": _MP = new OLMapProvider(md, startupLat, startupLon, startupLevel, events); break;
		}
		
		//=================
		//header
		var sidebar = e("sidebar");
		CreatePanels(sidebar);
	
		var toolbar = e("toolbar");
		CreateHeader(toolbar);
		//var cbo = CreateLayerDropdown(toolbar);
		
		resizeApp();

		//=================
		//create layers
		var layers = [];
		if (tl.length > 0) 
		{
			for (var i=0; i<tl.length; i++)
			{
				var l = tl[i];
				var tileLayer;
				switch (l)
				{
					case "STREETS":
					case "SATELLITE":
					case "HYBRID":
						var tileLayer = new A2ETileMapLayer(l, "", true);
						layers.push(tileLayer);
						//cbo.options[cbo.options.length] = new Option(l, l, true, false);
						break;
					default:
						var v = l.split("|");
						var name = v[1];
						var sn = v[2];
						var url = v[3];
						baseUrl = url;
						ls = parseInt(v[4]);
						le = parseInt(v[5]);
						var ex = v[6];
						var o = parseFloat(v[7]);
						var c = v[8];
						var bl = v[9];
						var ol = v[10];
						var ve = useVETileSpec;
						var bds = "";
						if (v.length > 10) {bds = v[11];}
							
						
						tileLayer = new A2ETileMapLayer(name, sn, false, url, ls, le, ex, o, c, bl, ol, ve, bds);
						layers.push(tileLayer);
						

						//cbo.options[cbo.options.length] = new Option(name, name, true, false);
						
						break;
				}
			}
		}
		_MP.AddLayers(layers);

		
		
		//===============================
		//load marker layers
		if (ml.length > 0) 
		{
			client = new A2EClient();
			for (var i=0;i<ml.length;i++)
			{
				var l = ml[i];
				if (typeof l != "undefined") {
					var vals = l.split("|");
					var type = vals[0];
					var url = vals[1];
					switch (type)
					{
						case "kml":
							//async load
							client.AddKMLDocument(url, OnMarkersLoaded);
							break;
					}
				}
			}
		}
	
		
		

	if (isIE)
	{
		resizeApp();
	}
		
	//}
}

function OnMarkersLoaded()
{
	
	//=====================
	//Markers UI
	var html = "<div style='font-family:Arial; font-size:8pt;'>";
	var pms = client.Documents[0].Placemarks;
	var cnt = 0;
	for (var i=0; i<pms.length; i++)
	{
		var pm = pms[i];
		var kml = pm.Markers[0];
		var image = kml.IconUrl;
		

		
		html += "<img src='" + image + "'></img>";
		var name = pm.Name;
		if (name == "") {
			cnt++;
			name = "Marker " + cnt;
		}
		html += "<a href='javascript:OnPanelClick(" + i + ")'>" + name + "</a><br>";
	}
	html += "</div>";
	

	var markers = e('markers');
	markers.innerHTML = html;	
	
	//===============
	//Map Provider
	_MP.AddMarkers(pms);
	
}




function OnMapClick(marker, point)
{
	
	if (marker != null) 
	{
		_MP.ZoomToMarker(marker.A2ETag);
		//marker.openInfoWindowHtml(marker.A2ETag.Description);
	}
}

function OnPanelClick(marker)
{
	
	var pms = client.Documents[0].Placemarks;
	var pm = pms[marker];
	_MP.ZoomToMarker(pm);

}

function OnToolbarClick(panel)
{
	if (panel == -1) 
	{
		ToggleSidebar(!displaySidebar);
	} else {
		for (var i=0; i<panels.length; i++)
		{
			var ii = panels.length-1-i;
			var p = panels[ii];
			if (ii == panel)
			{
				ChangePanel(p.Name);
				ToggleSidebar(true);
				break;
			}
		}
	}
	
}

function ChangePanel(panelName)
{
	currentPanel = panelName;
	for (var i=0; i<panels.length; i++)
	{
		var p = panels[i];
		if (p.Name == panelName)
		{
			p.style.visibility = "visible";
			var pht = e("PanelHeaderText");
			e.innerHTML = p.Name;
			
		} else {
			p.style.visibility = "hidden";
		}
	}
}

function ToggleSidebar(show)
{
	
	displaySidebar = show;
	var tsb = e("ToggleSidebar");
	if (tsb != null)
	{
		var vs = "visible";
		if (show) 
		{
			ChangePanel(currentPanel);
			tsb.innerHTML = "hide >>";
			vs = "visible";
			
		} else {
		
			tsb.innerHTML = "<< show";
			vs = "hidden";
		}
		
		for (var i=0; i<panels.length; i++)
		{
			var li = e("tb" + i);
			li.style.visibility = vs;
		}
	}
	resizeApp();
}


function CreateHeader(toolbar)
{
	//image
	var spn = document.createElement("div");
	if (imageUrl != "") 
	{
		var img = document.createElement("img");
		img.src = imageUrl;
		spn.appendChild(img);
		toolbar.appendChild(spn);
		
	}
	
	//title
	spn = document.createElement("div");
	var h1 = document.createElement("h1");
	h1.appendChild(document.createTextNode(title));
	spn.appendChild(h1);

	toolbar.appendChild(spn);


	//tools area
	CreateToolbar(toolbar);
}


function CreateToolbar(toolbar)
{
	var ul = e("toolbar-controls");
	ul.style.position = "absolute";
	ul.style.right = "5px";
	ul.style.bottom = "5px";
	
	
	for (var i=0; i<panels.length; i++)
	{
		var p = panels[i];
		
		var html = "<a href='javascript:OnToolbarClick(" + i + ")'>" + p.Name.toLowerCase() + "</a>";
		html += "|";
		var li = document.createElement("li");
		li.id = "tb" + i;
		li.innerHTML = html; 
		ul.appendChild(li);
	}
	
	//hide/show button
	var html = "<a id = 'ToggleSidebar' href='javascript:OnToolbarClick(-1)'>hide >></a>";
	var li = document.createElement("li");
	li.innerHTML = html; 
	ul.appendChild(li);		
	

}


function CreatePanels(sidebar)
{
	sidebar.style.backgroundColor = "white";
	
	//Panels Header
	//var sidebar = CreateSidebar(sidebarHolder);
	
	//Legend
	var panel = CreatePanel("pLegend", "Legend");
	CreateLegendPanel(panel);
	sidebar.appendChild(panel);
	
	//Description
	if (description != "") 
	{
		var panel = CreatePanel("pDescription", "Description");
		CreateDescriptionPanel(panel);
		
		sidebar.appendChild(panel);	
	}
	
	//Tools
	var panel = CreatePanel("pTools", "Tools");
	CreateToolsPanel(panel);
	sidebar.appendChild(panel);		
	
	//Markers
	var panel = CreatePanel("pMarkers", "Search");
	CreateMarkersPanel(panel);
	sidebar.appendChild(panel);			
	
	ChangePanel("Legend");
	
	
}

function CreateSidebar(sidebar)
{
	var ph = document.createElement("div");
	ph.id = "SidebarHeader";	
	ph.style.position = "absolute";
	ph.style.left = 0;
	ph.style.top = 0;
	//ph.style.width = "100%";
	ph.style.height = "20px";
	ph.style.marginLeft = "3px";
	ph.style.marginTop = "3px";
	ph.style.marginRight = "3px";
	ph.style.marginBottom = "3px";
	//ph.style.border = "1px";
	ph.stylebackgroundColor = "red";
	//sidebar.appendChild(ph);


	//span
	var pht = document.createElement("span");
	pht.id = "SidebarHeaderText";
	pht.style.position = "absolute";
	pht.style.left = "3px";
	pht.style.top = "3px";
	//ph.appendChild(pht);
		
	
	
	
	var phc = document.createElement("div");
	phc.id = "SidebarContent";	
	phc.style.position = "absolute";
	phc.style.left = 0;
	phc.style.top = "0px";	
	phc.overflow = "auto";
	phc.style.border = "1px";
	phc.style.backgroundColor = "blue";
	sidebar.appendChild(phc);
	
	return phc;
	
}

function CreatePanel(id, name)
{

		
	var p = document.createElement("div");
	p.id = id;
	p.Name = name;
	p.className  = "sidebarPanel";
	p.overflow = "auto";
	p.style.position = "absolute";
	p.style.left = 3;
	p.style.top = 3;
	//p.style.width = "100%";
	//p.style.height = "100%";
	//p.style.visibility = "hidden";
	p.style.marginTop = "4px";
	p.style.marginLeft = "4px";
	p.style.marginRight = "5px";	
	p.innerHMTL = name;
	panels.push(p);
	return p;
}

function CreateLegendPanel(panel)
{
	var html = sbl("Legend", true) + "";

	var url = baseUrl + "/Legend.png"
	if (isLocal) {
		url = baseUrl + "\\Legend.png"
	}
	//alert("legend " + url);
	html += "<img src='" + url + "'/>";
	panel.style.backgroundColor = "white";
	panel.innerHTML = html;
}

function CreateMarkersPanel(panel)
{
	//var tb = document.createElement("input");
	//tb.id = "txtSearch";
	var html = sbl("Search", true) + "";
	var txt = "Address, Lat/Lng";
	if (ml.length > 0) {txt = "Markers, Address, Lat/Lng";}
	if (!_MP.CanGeocode){txt = txt.replace("Address, ", "");}
	html += sbl(txt, false) + "<br>";
	html += "<input id='txtSearch' onkeyup='OnSearchKeyUp(event)'></input>";
	html += "<div id='lblSearchStatus' ></div><br>";
	html += "<div id='markers' style='width:100%;'></div>";
	

	//panel.appendChild(tb);
	panel.innerHTML = html;
	
	//panel.appendChild(document.createTextNode("Find "));
}

function OnSearchKeyUp(evt)
{
	var oEvent = window.event ? window.event : evt;

	var charID = oEvent.keyCode;
	if (charID == 13)
	{
		var txt = e("txtSearch");
		Search(txt.value);
	}
}

function CreateToolsPanel(panel)
{

	var html = sbl("Tools", true) + "";
	html += sth("Current Position");
	html += sbl("X:", false) + "<input id='txtX'></input><br>";
	html += sbl("Y:", false) + "<input id='txtY'></input><br>";
	
	
	html += spc();
	html += sth("Measure");
	html += spc();
	html += spc();
	
	html += spc();
	html += sth("Print");
	html += spc();
	html += spc();
	
	panel.innerHTML = html;
	
}

function CreateDescriptionPanel(panel)
{

	var html = sbl("Description", true);
	panel.innerHTML = html + "<p>" + description + "</p>";
}

function sbl(text, header)
{
	if (header)
	{
		return "<div class='sidebarHeaderLabel'>" + text + "</div>" + spc();
	} else {
		return "<span class='sidebarLabel'>" + text + "</span>";
	}
}

function spc()
{
	return "<div class='sidebarSpacer'></div>"; 
}

function sth(tool)
{

	return "<div class='sidebarToolHeader'>" + tool + "</div>";

}


function CreateLayerDropdown(header)
{
	cboLayers = document.createElement("select");
	cboLayers.id = "cboLayers";
	cboLayers.style.width = 150;
	//header.appendChild(cboLayers);
	//cboLayers.onchange = OnLayerChanged();
	
	return cboLayers;
}

function OnLayerChanged()
{
	//alert(cboLayers.selectedIndex);
	if (cboLayers.selectIndex > -1)
	{
		map.setMapType(map.mapTypes(cboLayers.selectIndex));
	}
}



function e(id)
{
    return document.getElementById(id);
}


function getWindowHeight() 
{
	// Standard browsers (Mozilla, Safari, etc.)
	if (self.innerHeight)
	return self.innerHeight;
	// IE 6
	if (document.documentElement && document.documentElement.clientHeight)
	return document.documentElement.clientHeight;
	if (document.body)
	return document.body.clientHeight;
	// Just in case.
	return 0;
	
}

function resizeApp() 
{
	var mapWrap = e("map-wrapper");
	var sidebar = e("sidebar");
	var map = e("map");
	var height = getWindowHeight() - document.getElementById('toolbar').offsetHeight - 30;
	map.style.height = height + 'px';
	


	
	if (displaySidebar) 
	{
		sidebar.style.height = height + 'px';
		
		sidebar.style.visibility = "visible";
		sidebar.style.width = "250";
		mapWrap.style.marginRight = "260px";
		if (isIE)
		{
			sidebar.style.right = 10;
		} else {
			sidebar.style.right = 0;
		}
		
		
		//panels
		for (var i=0; i<panels.length; i++)
		{
			var p = panels[i];
			p.style.left = "0px";
			p.style.top = "0px";
			p.style.right = "0px";
			p.style.bottom = "0px";
		}
			
	} else {
		
		mapWrap.style.marginRight = "2px";
		
		sidebar.style.visibility = "hidden";
		for (var i=0; i<panels.length; i++)
		{
			var p = panels[i];
			p.style.visibility = "hidden";
		}
	}
	
	_MP.Resize(mapWrap.offsetWidth, height);
	
}

function getWindowHeightOld()
{
    if (window.self && self.innerHeight)
    {
        return self.innerHeight;
    }
    if (document.documentElement && document.documentElement.clientHeight)
    {
        return document.documentElement.clientHeight;
    }
    return 0;
}


function Search(text)
{
	//look for lat/lng, then Markers, then address
	try
	{
		//alert("begin search");
		//quick checks
		if (text == "")
		{
			var lbl = e("lblSearchStatus");
			lbl.innerHTML = "";		
			return;
		}
	
		var found = false;
		var status = "(no results)";
	
		//lat/lng
		if (text.indexOf(",") > -1)
		{
			var v = text.split(",");
			if (v.length == 2)
			{
				var lat = v[0];
				var lng = v[1];
				if ((!isNaN(lat)) && (!isNaN(lng)))
				{
					lat = parseFloat(lat);
					lng = parseFloat(lng);
					found = true;
					status = "Found Lat/Lng";
					
					_MP.CenterAt(lat, lng);
					
				}
				
			}
		}
	
		//markers
		var isMarker = false;
		if ((!found) && (client != null))
		{
			var doc = client.Documents[0];
			var pm = doc.FindPlacemark(text);
			if (pm != null)
			{
				found = true;
				status = "Found Marker";
				_MP.ZoomToMarker(pm);
			}
		
		}
		
		//try geocode address
		if ((_MP.CanGeocode) && (!found))
		{
			status = "Geocoding...";
			if (_MP.GeocodeAddress(text)) 
			{
				found = true;
				
			}
			
		}
		
		var lbl = e("lblSearchStatus");
		lbl.innerHTML = status;
		

	
	} catch (exp) {
		var lbl = e("lblSearchStatus");
		lbl.innerHTML = "(Search Error)";	
		alert(exp.message);
	}
}




//=======================
//Common App hook
function A2EApplication(mapID)
{
	this.MapID = mapID;
	this.BaseUrl = "http://www.arc2earth.net/ArcToEarth/Services/A2EGateway.ashx?"	//http://www.arc2earth.net/ArcToEarth/Services/Maintenance.asmx/";
	this.SetMapUsage();
}

A2EApplication.prototype.SetMapUsage = function()
{
	var url = this.BaseUrl + "method=mapusage&mapID=" + this.MapID + "&vt=" + vt;
	//alert(url);
	A2ETransport.ExecuteOneWay(url);
}

A2EApplication.prototype.MapDigg = function()
{
	var url = this.BaseUrl + "method=MapDigg&mapID=" + this.MapID + "&name=''";
	A2ETransport.ExecuteOneWay(url);
}


function A2EEvents (mapID)
{
	this.MapID = mapID;
}

A2EEvents.prototype.OnMouseMove = function (xPixel, yPixel, lat, lon)
{
	var x = e("txtX");
	x.value = lon.toFixed(8);
	var y = e("txtY");
	y.value = lat.toFixed(8);	
}

A2EEvents.prototype.OnMarkerClick = function (marker)
{
	OnMapClick(marker);
}

A2EEvents.prototype.OnGeocodeCallback = function (status)
{
	var lbl = e("lblSearchStatus");
	lbl.innerHTML = status;
}


//=======================
//MapProviders - GM, VE, OL
function GMMapProvider (mapDiv, startupLat, startupLon, startupLevel, events)
{
	window.onunload = GUnload;
			
	//create map
	this.MapDiv = mapDiv;
	this.Map = new GMap(mapDiv);
	this.MM = null;
	this.Events = events;
	this.GC = new GClientGeocoder();
	this.GCMarker = null;
	this.CanGeocode = true;
	
	//setup initial extent
	this.Map.setCenter(new GLatLng(startupLat,startupLon), startupLevel);
	this.Map.addControl(new GLargeMapControl());
	this.Map.addControl(new GMapTypeControl());
	this.Map.addControl(new GOverviewMapControl());
	this.Map.addControl(new GScaleControl());
	this.Map.enableDoubleClickZoom();
	this.Map.enableContinuousZoom();
	GEvent.bind(this.Map, "click", this, this.OnMarkerClick);
	GEvent.bind(this.Map, "mousemove", this, this.OnMouseMove);
	var kbh = new GKeyboardHandler(this.Map); 	
	
	this.MM = new GMarkerManager(this.Map,{trackMarkers:true});
}

GMMapProvider.prototype.OnMouseMove = function(latlng)
{
	var pixel = this.Map.fromLatLngToDivPixel(latlng);
	this.Events.OnMouseMove(pixel.X, pixel.Y, latlng.lat(), latlng.lng());
}

GMMapProvider.prototype.OnMarkerClick = function(overlay, point)
{
	if (overlay != null) {
		this.Events.OnMarkerClick(overlay);
	}
}

GMMapProvider.prototype.AddLayers = function(layers)
{
	var custommap = null;
	
	//clear out default layers
	//Map.getMapTypes()
	
	
	for (var i=0; i<layers.length; i++)
	{
		var layer = layers[i];
		if (layer.IsBaseLayer)
		{
			//base layers (sat, streets, hybrid)
			
		} 
		else 
		{
			//a2e layer
			var gmtl = new GMTileMapLayer(layer);
			
			if (layer.BaseLayer == "STREETS"){layer.BaseLayer = G_NORMAL_MAP;}
			if (layer.BaseLayer == "SATELLITE"){layer.BaseLayer = G_SATELLITE_MAP;}
								
							
			var GLayer=null;
			if (layer.BaseLayer == "")
			{
				GLayer=[gmtl.TileLayer];
			} else {
				GLayer=[layer.BaseLayer.getTileLayers()[0], gmtl.TileLayer];
			}
					
			if (layer.OverLayer != "") 
			{
				//GLayer = [gmtl.TileLayer, G_HYBRID_MAP.getTileLayers()[1]];
				GLayer.push(G_HYBRID_MAP.getTileLayers()[1]);
			}
			var name = layer.SmallName;
			if (name == ""){name = layer.Name;}
			var custommap = new GMapType(GLayer, G_SATELLITE_MAP.getProjection(), name, G_SATELLITE_MAP);
			this.Map.addMapType(custommap);
			this.Map.setMapType(custommap);
		
		}

	}
}

GMMapProvider.prototype.AddMarkers = function(markers)
{
	
	for (var i=0; i<markers.length; i++)
	{
		var pm = markers[i];
		var kml = pm.Markers[0];
		var icon = null;
		if (kml.IconUrl != "") 
		{
			icon = null;
			if (kml.Style.Tag != null) {
				icon = kml.Style.Tag;
			} else {
				icon = new GIcon();
				icon.image = kml.IconUrl;
				icon.iconSize = new GSize(kml.Style.IconStyle.Icon.Width,kml.Style.IconStyle.Icon.Height);
				var pt = new GPoint(kml.Style.IconStyle.Icon.Width/2, kml.Style.IconStyle.Icon.Height/2);
				icon.iconAnchor = pt;
				icon.infoWindowAnchor = pt;
				kml.Style.Tag = icon;
			}
		}
		
		var marker = new GMarker(new GPoint(kml.Point.x, kml.Point.y), icon);
		marker.A2ETag = pm;
		pm.Tag = marker;
		this.MM.addMarker(marker, levelStart);
		
	}
	
	this.MM.refresh();
}

GMMapProvider.prototype.ZoomToMarker = function(marker)
{
	if (marker != null)
	{
		this.Map.closeInfoWindow();
		marker.Tag.openInfoWindowHtml(marker.Description);
	}
}

GMMapProvider.prototype.GetLon = function(xPixel)
{
	
}
GMMapProvider.prototype.GetLat = function(yPixel)
{
	
}

GMMapProvider.prototype.CenterAt = function(lat, lng)
{
	var center = new GLatLng(lat, lng);
	this.Map.setCenter(center);
}


GMMapProvider.prototype.GeocodeAddress = function(address)
{
	this.GC.getLatLng(address, GEvent.callback(this, this.GeocodeAddressCallback));
	
}

GMMapProvider.prototype.GeocodeAddressCallback = function(latlng)
{
	var status = "(no results)";
	if (latlng != null)
	{
		status = "Found Address";
		this.Events.OnGeocodeCallback(status);
		if (this.GCMarker != null) 
		{
			this.GCMarker.setPoint(latlng);
		} 
		else 
		{
			var pt = new GPoint(latlng.lng(), latlng.lat());
			this.GCMarker = new GMarker(pt);
			this.GCMarker.A2ETag = "geocode";
			this.MM.addMarker(this.GCMarker, 0);	
			this.MM.refresh();			
		}
		this.Map.setCenter(latlng);
		
	}
	
	
}

GMMapProvider.prototype.Resize = function(width, height)
{
	this.Map.checkResize();
}



function VEMapProvider (mapDiv, startupLat, startupLon, startupLevel, events)
{

	try
	{
		//create map
		this.MapDiv = mapDiv;
		this.Map = new VEMap(mapDiv.id);
		
		this.Events = events;
		this.PinID = 0;
		this.GCMarker = null;
		this.CanGeocode = true;
		this.VELS = null;	//allow for only one layer?
		this.VETL = null;
		this.LayerAdded = false;
		
		var ffv = 0;
		var ffn = "Firefox/"
		var ffp = navigator.userAgent.indexOf(ffn);
		if (ffp != -1) ffv = parseFloat(navigator.userAgent.substring(ffp + ffn.length));
		//alert(ffv);
		if (ffv >= 1.5) 
		{ // If we're using Firefox 1.5 or above override the Virtual Earth drawing functions to use SVG
			Msn.Drawing.Graphic.CreateGraphic=function(f,b) { return new Msn.Drawing.SVGGraphic(f,b)} 
		}
		
		
		//setup initial extent
		this.Map.LoadMap(new VELatLong(startupLat,startupLon),startupLevel,'s' ,false);
		
		this.MapDiv.onmousemove = A2ETransport.Callback(this, this.OnMouseMove);
		//this.Map.AttachEvent('onmousemove', A2ETransport.Callback(this, this.OnMouseMove));
		//this.Map.vemapcontrol.EnableGeoCommunity(true);
		
		//Remove Black streaks
		this.Map.AttachEvent('onchangeview', A2ETransport.Callback(this, this.OnChangeView));
		
	}
	catch (e)
	{
		alert(e.message);
	}
}

VEMapProvider.prototype.OnMouseMove = function(e)
{

	//Why does VE not supprot mousemove event??
	try
	{
		var x = 0;
		var y = 0;
		var e = e || window.event; 
		 if (e.pageX || e.pageY){ 
		   x = e.pageX; 
		   y = e.pageY; 
		 } else if (e.clientX || e.clientY) { 
		   x = event.clientX + document.body.scrollLeft; 
		   y = event.clientY + document.body.scrollTop; 
		 } 
	
		var ll = this.Map.PixelToLatLong(x,y);
		if (ll != null) {
			var alt = this.Map.GetAltitude();
			this.Events.OnMouseMove(0, 0, ll.Latitude, ll.Longitude);	
		}
	} catch (exp) {
		//eat
	}
}

VEMapProvider.prototype.OnMarkerClick = function(overlay, point)
{
	if (overlay != null) 
	{
		this.Events.OnMarkerClick(overlay);
	}
}

VEMapProvider.prototype.AddLayers = function(layers)
{
	var custommap = null;
	
	//clear out default layers
	//Map.getMapTypes()
	
	//try 
	//{
		for (var i=0; i<layers.length; i++)
		{
			var layer = layers[i];
			if (layer.IsBaseLayer)
			{
				//base layers (sat, streets, hybrid)
				
			} 
			else 
			{
				//a2e layer
				this.VETL = new VETileMapLayer(layer);
				this.Map.AddTileSource(this.VETL.TileSourceSpec);
				
				this.VELS = new VELayerSpecification(VELayerType.VETileSource, layer.Name, layer.Name);
				this.VELS.ZIndex = 100;
				this.VELS.Opacity = layer.Opacity;				
				this.Map.AddLayer(this.VELS);
				this.LayerAdded = true;
				
				//hack - add layer to navigator
				//<div id="navAction_HybridMapStyle" class="MapStyle" style="display: block;">Hybrid</div>
				var parent = e("navAction_mapStyleCell");
				var div = document.createElement("div");
				div.id = "navAction_" + layer.Name + "MapStyle";
				div.className = "MapStyle";
				div.onclick = A2ETransport.Callback(this, this.OnChangeLayer);
				div.style.display = "block";
				div.appendChild(document.createTextNode(layer.SmallName));
				
				parent.appendChild(div);
				
				this.RemoveBlack(this.MapDiv.id);
			}
	
		}
	//}
	//catch (e)
	//{
	//	alert("AddLayers " + e.message);
	//}	
}

VEMapProvider.prototype.OnChangeLayer = function()
{
	try 
	{
		if (this.LayerAdded) 
		{	
			this.Map.DeleteLayer(this.VELS.ID);
			this.Map.DeleteTileSource(this.VETL.TileSourceSpec.ID);
			
		} else {
			this.Map.AddTileSource(this.VETL.TileSourceSpec);
			this.Map.AddLayer(this.VELS);
		}
		this.LayerAdded = !this.LayerAdded;
		
	} catch (exp) 
	{
		alert(exp.message);
	}
	
}

VEMapProvider.prototype.AddMarkers = function(markers)
{
	
	
	for (var i=0; i<markers.length; i++)
	{
		var pm = markers[i];
		var kml = pm.Markers[0];
	
		this.PinID++;
		var pt = new VELatLong(kml.Point.y, kml.Point.x);
		var pin = new VEPushpin(this.PinID, pt, kml.IconUrl, pm.Name, pm.Description);
		pin.A2ETag = pm;
		pm.Tag = pin;
		this.Map.AddPushpin(pin);
		
	}
	
}

VEMapProvider.prototype.ZoomToMarker = function(marker)
{
	if (marker != null)
	{
		this.Map.SetCenter(marker.Tag.LatLong);
	}
}

VEMapProvider.prototype.GetLon = function(xPixel)
{
	
}
VEMapProvider.prototype.GetLat = function(yPixel)
{
	
}

VEMapProvider.prototype.CenterAt = function(lat, lng)
{
	var center = new VELatLong(lat, lng);
	this.Map.SetCenter(center);
}


VEMapProvider.prototype.GeocodeAddress = function(address)
{
	this.Map.FindLocation(address, A2ETransport.Callback(this, this.GeocodeAddressCallback));
}

VEMapProvider.prototype.GeocodeAddressCallback = function(results)
{
	if ((results != null) && (results.length > 0))
	{
		this.Events.OnGeocodeCallback("Found Address");
		if (this.GCMarker != null) 
		{
			this.Map.DeletePushpin(this.GCMarker);
		} 

		var result = results[0];
		var pt = result.LatLong;
		this.GCMarker = new VEPushpin(this.PinID++, pt);
		this.GCMarker.A2ETag = "geocode";
		this.Map.AddPushpin(this.GCMarker);		

		this.Map.SetCenter(pt);
		
	}
}

VEMapProvider.prototype.Resize = function(width, height)
{
	//alert("w" + width + " h" + height);
	this.Width = width;
	this.Height = height;
	window.setTimeout(A2ETransport.Callback(this, this.ResizeCallback), 250);
	
}

VEMapProvider.prototype.ResizeCallback = function()
{
	this.Map.Resize(this.Width, this.Height);
}


VEMapProvider.prototype.OnChangeView = function()
{
	//this.RemoveBlack(this.MapDiv.id);
}

VEMapProvider.prototype.RemoveBlack = function(mapId)
{
	//Lewis Harvey - 2006
	//ALL THIS NEEDS TO BE DONE FOR IE7 ONLY
	if(!navigator.appVersion.indexOf('MSIE 7.0')==0)
	{
		var parentMapDiv = document.getElementById(mapId);
		var childMapDiv = parentMapDiv.firstChild;
		var childDivs = childMapDiv.childNodes;
		for(var i = 0; i < childDivs.length; i++)
		{
			var childNode = childDivs[i];
			if(childNode.nodeName == 'DIV' && childNode.style.height != '')
			if(childNode.style.height == '256px' && childNode.style.width == '256px' && childNode.style.filter != 'none' && childNode.id == '' && childNode.className == '')
			{
			var imageSrc = childNode.style.filter.substring(childNode.style.filter.indexOf('http://'));
			imageSrc = imageSrc.substring(0, imageSrc.indexOf('.png')+4);
			childNode.style.background= 'url(' + imageSrc + ')';
			childNode.style.filter = 'none';
			}
		}
	}
}



//===================
//OpenLayers provider
function OLMapProvider (mapDiv, startupLat, startupLon, startupLevel, events)
{

	//try
	//{
		//create map
		this.MapDiv = mapDiv;
	    var options = {projection: "EPSG:41001",units: 'meters', maxResolution:156543, maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),numZoomLevels: 19,controls: []};
		options = {projection: "EPSG:41001",units: 'meters',maxResolution:156543,maxResolution: "auto",maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34)};
		options = {'maxResolution':1.40625/2, 'maxExtent': new OpenLayers.Bounds(-180,-90,180,90)};
		//options = {'maxExtent': new OpenLayers.Bounds(-180,-90,180,90), minZoomLevel:0,maxZoomLevel:17,RESOLUTIONS:[1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.001373291015625,0.0006866455078125,0.00034332275390625,0.000171661376953125,0.0000858306884765625,0.00004291534423828125]}
		this.Map = new OpenLayers.Map(this.MapDiv.id, options);	//
		
		
		this.Events = events;
		this.PinID = 0;
		this.GCMarker = null;
		this.Markers = null;
		this.CanGeocode = false;
		this.LayerAdded = false;
		
		//setup initial extent
        var layer = new OpenLayers.Layer.TMS( "Basic", "http://labs.metacarta.com/wms-c/Basic.py/", {layername: 'basic', type:'png'} );
                    
        this.Map.addLayer(layer);		
		this.Map.setBaseLayer(layer);
	    this.Map.addControl(new OpenLayers.Control.PanZoom());
	    this.Map.addControl(new OpenLayers.Control.MouseToolbar());		
		this.Map.addControl(new OpenLayers.Control.LayerSwitcher());
		this.Map.setCenter(new OpenLayers.LonLat(startupLon, startupLat), startupLevel);
		//this.Map.setCenter(new OpenLayers.LonLat(5, 40), 5);
		
		//this.Map.addControl(new OpenLayers.Control.PanZoomBar());
		
		this.MapDiv.onmousemove = A2ETransport.Callback(this, this.OnMouseMove);

		
	//}
	//catch (e)
	//{
	//	alert(e.message);
	//}
}


OLMapProvider.prototype.OnMouseMove = function(e)
{

	//Why does VE not supprot mousemove event??
	//try
	//{
		var x = 0;
		var y = 0;
		var e = e || window.event; 
		 if (e.pageX || e.pageY){ 
		   x = e.pageX; 
		   y = e.pageY; 
		 } else if (e.clientX || e.clientY) { 
		   x = event.clientX + document.body.scrollLeft; 
		   y = event.clientY + document.body.scrollTop; 
		 } 
	
		var pixel = new OpenLayers.Pixel(x,y);
		var ll = this.Map.getLonLatFromPixel(pixel);
	
		if (ll != null) {
			this.Events.OnMouseMove(0, 0, ll.lat, ll.lon);
		}
	//} catch (exp) {
		//eat
	//}
}

OLMapProvider.prototype.OnMarkerClick = function(overlay, point)
{
	alert(overlay);
	if (overlay != null) 
	{
		this.Events.OnMarkerClick(overlay);
	}
}

OLMapProvider.prototype.AddLayers = function(layers)
{
	var custommap = null;
	
	//clear out default layers
	//Map.getMapTypes()
	
	//try 
	//{
		for (var i=0; i<layers.length; i++)
		{
			var layer = layers[i];
			if (layer.IsBaseLayer)
			{
				//base layers (sat, streets, hybrid)
				
			} 
			else 
			{
				//a2e layer
				this.OLTL = new OLTileMapLayer(layer, this.Map);
				this.Map.addLayer(this.OLTL.TMS); 

			}
	
		}
	//}
	//catch (e)
	//{
	//	alert("AddLayers " + e.message);
	//}	
}



OLMapProvider.prototype.AddMarkers = function(markers)
{
	
	this.Markers = new OpenLayers.Layer.Markers("Markers");
	this.Map.addLayer(this.Markers);
	for (var i=0; i<markers.length; i++)
	{
		var pm = markers[i];
		var kml = pm.Markers[0];
	
		this.PinID++;
		var pt = new OpenLayers.LonLat(kml.Point.x, kml.Point.y);
		
		var popup = new OpenLayers.Popup(12,pt,new OpenLayers.Size(150, 100),pm.Description);
		popup.hide();
		
		var icon = new OpenLayers.Icon(kml.IconUrl, new OpenLayers.Size(kml.Style.IconStyle.Icon.Width,kml.Style.IconStyle.Icon.Height));
		var marker = new OpenLayers.Marker(pt, icon);
		this.Markers.addMarker(marker);
		marker.events.register( "click", marker, A2ETransport.Callback(this, this.OnMarkerClick) );
		
		//popup.setBackgroundColor('Yellow');
		var olp = new OLPopup(marker, popup);
		popup.A2ETag = pm;
		pm.Tag = popup;
		this.Map.addPopup(popup);
		
	}
	
}

OLMapProvider.prototype.ZoomToMarker = function(marker)
{
	if (marker != null)
	{
		this.Map.setCenter(marker.Tag.position);
	}
}

OLMapProvider.prototype.GetLon = function(xPixel)
{
	
}
OLMapProvider.prototype.GetLat = function(yPixel)
{
	
}

OLMapProvider.prototype.CenterAt = function(lat, lng)
{
	var center = new OpenLayers.LonLat(lng, lat);
	this.Map.setCenter(center);
}


OLMapProvider.prototype.GeocodeAddress = function(address)
{

}

OLMapProvider.prototype.GeocodeAddressCallback = function(results)
{

}

OLMapProvider.prototype.Resize = function(width, height)
{
	//eat
}

function OLPopup(marker, popup)
{
	this.Marker = marker;
	this.Popup = popup;
}






//=======================
//MapTile class
function A2ETileMapLayer (name, smallName, isBaseLayer, url, start, end, ext, opacity, copyright, baseLayer, overLayer, useVESpec, bounds) 
{ 
	this.Name = name;
	this.SmallName = smallName;
	this.IsBaseLayer = isBaseLayer;
	this.Url = url;
	this.Extension = ext;
	this.Start = start;
	this.End = end;
	this.Copyright = copyright;
	this.Opacity = opacity;
	this.BaseLayer = baseLayer;
	this.OverLayer = overLayer;
	this.UseVESpec = useVESpec;
	this.Bounds = bounds;	//TODO -parse this
	this.Server = 1;
	this.ServerCount = 2;
}

A2ETileMapLayer.prototype.GetUrl = function(x,y,zoom)
{
	var url = "";
	var isLocal = (this.Url.indexOf("\\") != -1);
	
	if (this.UseVESpec)	
	{
		//VE spec
		var key = "";
		var cell = 0;
		for(var i=zoom; i>0; i--)
		{
			cell = 0;
			var mask = 1 << (i-1);
			if((x & mask) != 0)
			{
				cell++;
			}
			if((y & mask) != 0)
			{
				cell += 2;
			}
			key += cell + "";
		}
		//var i = (cell % 1); // 1 is the number of tile servers.
		url = this.Url + "/tiles/" + key + "." + this.Extension;
		if (isLocal) 
		{
			url = this.Url + "\\tiles\\" + key + "." + this.Extension;
		}
	} else {
		//Google etc.
		url = this.Url + "/" + zoom + "/" + x + "/" + y + "." + this.Extension;
		if (isLocal) 
		{
			url = this.Url + "\\" + zoom + "\\" + x + "\\" + y + "." + this.Extension;
		}
	}
	
	//S3 DNS change
	//if (url.indexOf("http://s3") > -1)
	//{
	//	this.Server++; if(this.Server>this.ServerCount){this.Server=1;}
	//	var svr = "s3-" + this.Server;
	//	url = url.replace("http://s3", "http://" + svr);
		//alert(url + "  " + svr);
	//}
	
	return url;
}


//==============
//GM TIle Layer
function GMTileMapLayer (a2eTileLayer) 
{ 
	this.TL = a2eTileLayer;

	var cr = new GCopyright(1, new GLatLngBounds(new GLatLng(-90, -180),new GLatLng(90, 180)),0, this.TL.Copyright);
	var cc = new GCopyrightCollection("");
	cc.addCopyright(cr);

	
	this.TileLayer = new GTileLayer(cc, this.TL.Start, this.TL.End);
	this.TileLayer.isPng = GEvent.callback(this, this.isPng);
	this.TileLayer.getOpacity = GEvent.callback(this, this.getOpacity);
	this.TileLayer.getTileUrl = GEvent.callback(this, this.getTileUrl);	
} 

GMTileMapLayer.prototype.getTileUrl = function(tile, zoom)
{

	//var url = this.TL.Url + "/" + zoom + "/" + tile.x + "/" + tile.y + "." + this.TL.Extension;
	//alert(tile.x + ", " + tile.y + ", " + zoom);
	var url = this.TL.GetUrl(tile.x, tile.y, zoom);
	return url;
}

GMTileMapLayer.prototype.isPng = function()
{
	return (this.TL.Extension == "png");
}

GMTileMapLayer.prototype.getOpacity = function()
{
	return this.TL.Opacity;
}


//===============
//VE Tile layer
function VETileMapLayer (a2eTileLayer) 
{ 
	this.TL = a2eTileLayer;

	this.TileSourceSpec = new VETileSourceSpecification();
	this.TileSourceSpec.ID = this.TL.Name;
	//this.TileSourceSpec.Bounds = bounds;
	this.TileSourceSpec.MinZoom = 0;	//this.TL.Start;
	this.TileSourceSpec.MaxZoom = 22;	//this.TL.End;
	if (this.TL.UseVESpec)
	{
		this.TileSourceSpec.TileSource = this.TL.Url + "/tiles/%4." + this.TL.Extension;
	} 
	else 
	{
		this.TileSourceSpec.GetTilePath = A2ETransport.Callback(this, this.GetTilePath);
	}
			
} 

VETileMapLayer.prototype.GetTilePath = function(tc)
{
	var url = "";
	if(tc != null && tc != 'undefined')
	{
		//var key = '/' + tc.ZoomLevel + '/' + tc.XPos + '/' + tc.YPos;
		//url = this.TL.Url + key + '.png';
		url = this.TL.GetUrl(tc.XPos, tc.YPos, tc.ZoomLevel);
	}

	return url;
}

//===============
//OL Tile layer
function OLTileMapLayer (a2eTileLayer, map) 
{ 
	this.TL = a2eTileLayer;
	var options = '{minZoomLevel:0,maxZoomLevel:17,RESOLUTIONS:[1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.001373291015625,0.0006866455078125,0.00034332275390625,0.000171661376953125,0.0000858306884765625,0.00004291534423828125]';
	//this.TMS = new OpenLayers.Layer.LikeGoogle(this.TL.SmallName, "", {type:'png'}); //{'maxExtent': new OpenLayers.Bounds(-180,-90,180,90)}
	
	var origin = new OpenLayers.LonLat(map.maxExtent.left,map.maxExtent.top);
	var options = {type:'png'};
	//options = {type:'png', 'tileOrigin':origin};
	this.TMS = new OpenLayers.Layer.TMS(this.TL.SmallName, "", options); //{'maxExtent': new OpenLayers.Bounds(-180,-90,180,90)}
	this.TMS.getURL = A2ETransport.Callback(this, this.getURL);
	
	
		
} 

OLTileMapLayer.prototype.getURL = function(bounds)
{
	var res = this.TMS.map.getResolution();  
	var x = (bounds.left - this.TMS.tileOrigin.lon) / (res * this.TMS.tileSize.w);  
	var y = (bounds.bottom - this.TMS.tileOrigin.lat) / (res * this.TMS.tileSize.h);  
	var z = this.TMS.map.getZoom();  
	
	//alert(x + ", " + y + ", " + z);
	return this.TL.GetUrl(x, y, z)
}



//=======================================================================================
//Universal HTTP async callback for class instance methods
function A2ETransport(instance, delegate)
{
	this.Instance = instance;
	this.Delegate = delegate;
	this.ResponseText = "";
	this.Request = this.Create();
	this.Request.onreadystatechange = this.Callback(this, this.OnLoad);	
}


A2ETransport.CreateTransport = A2ETransport_CreateTransport;
function A2ETransport_CreateTransport()
{
    if(typeof ActiveXObject!="undefined"){
        return new ActiveXObject("Microsoft.XMLHTTP")
    }
    else if(window.XMLHttpRequest){
        return new XMLHttpRequest
    }
}

A2ETransport.prototype.Create = function()
{
    if(typeof ActiveXObject!="undefined"){
        return new ActiveXObject("Microsoft.XMLHTTP")
    }
    else if(window.XMLHttpRequest){
        return new XMLHttpRequest
    }
}


A2ETransport.ExecuteOneWay = A2ETransport_ExecuteOneWay;
function A2ETransport_ExecuteOneWay(url)
{
	//var req = A2ETransport.CreateTransport();
	//req.open("GET", url, true);
	//req.send(null);
	
	//json-y
	var scr = document.createElement("<script>");
	scr.type = 'text/javascript'; 
	scr.src = url;
	document.body.appendChild(scr);
}

A2ETransport.prototype.Execute = function(url)
{
	this.Request = this.Create();
	this.Request.onreadystatechange = this.Callback(this, this.OnLoad);	
	
	this.Request.open("GET", url, true);
	this.Request.send(null);

}

A2ETransport.prototype.Callback = function(instance, delegate)
{
    var wrap=function(){return delegate.apply(instance,arguments)}
    return wrap;	
}

A2ETransport.Callback = A2ETransport_Callback;
function A2ETransport_Callback(instance, delegate)
{
    var wrap=function(){return delegate.apply(instance,arguments)}
    return wrap;	
}

A2ETransport.prototype.OnLoad = function() 
{
	//XmlHttp request
	//alert("readyState " + this.Request.readyState);
	if (this.Request.readyState == 4 && this.Request.status == 200) 
	{
		this.ResponseText = this.Request.responseText;
		this.Delegate.call(this.Instance, this);
	}
}




