//depot/VEReverseEngineering/CrunchControl.js#10 - edit change 744 (text)
// CrunchControl.js
//
// Copyright 2006 Microsoft Corporation.  All rights reserved.
// Authors: John Douceur and Jeremy Elson
// Version: 1.0
// Date: 16 May 2006

RegisterNamespaces('MSR.CVE');

function xmlDOM(url)
{
	var msxmlDOMs =
	[
		"MSXML2.DOMDocument.5.0",
		"MSXML2.DOMDocument.4.0",
		"MSXML2.DOMDocument.3.0",
		"MSXML2.DOMDocument",
		"Microsoft.XMLDOM"
	];

	var xmlDocument = null;
	if (document.implementation != undefined
		&& document.implementation.createDocument != undefined)
	{
		xmlDocument = document.implementation.createDocument("", "", null);
	}
	if (xmlDocument == null && window.ActiveXObject != undefined)
	{
		for (var ixDom = 0; ixDom < msxmlDOMs.length; ixDom++)
		{
			try
			{
				xmlDocument = new ActiveXObject(msxmlDOMs[ixDom]);
				break;
			}
			catch (dummy) {}
		}
	}
	if (xmlDocument == null)
	{
		alert('This application employs XML, which your browser does not support.');
		return;
	}
	xmlDocument.async = false;
	xmlDocument.load(url);
	return xmlDocument;
}


function getFirstSubTag(node, subTagName)
{
	var subTagList = node.getElementsByTagName(subTagName);
	if (subTagList == null)
	{
		return null;
	}
	if (subTagList.length < 1)
	{
		return null;
	}
	return subTagList[0];
}

function getSubTagText(node, subTagName)
{
	var subTag = getFirstSubTag(node, subTagName);

	if (subTag == null)
	{
		return null;
	}
	else
	{
		return subTag.text;
	}
}

// This function takes an XML description of MapCruncher output layers, and
// produces a list of TileConfig objects.  The members of this list are
// suitable to be passed to the MapControl's AddOrthoTileSource() function
// for defining new tile layers.
MSR.CVE.ImportLayersFromCrunchFile = function(xmlFileName, layerNamePrefix)
{
	var dom = xmlDOM(xmlFileName);
	var crunchLayers = new Array();
	var tileRoot = "";
 
	// Alert the user if the document wasn't found
	//if (dom.text == "")
	//{
	//	alert("Error in ImportLayersFromCrunchFile():\nCouldn't read " + xmlFileName + " -- check URL");
	//	return null;
	//}
       
	// Get the URL prefix where this XML file is located.  The tiles are
	// rooted in the same place.
	if (xmlFileName.lastIndexOf('/') > 0)
	{
		tileRoot = xmlFileName.substring(0, xmlFileName.lastIndexOf('/') + 1);
	}

	var layerNodes = dom.getElementsByTagName("Layer");
	for (var ixLayer = 0; ixLayer < layerNodes.length; ixLayer++)
	{
		var layerNode = layerNodes[ixLayer];
		var crunchLayer = new Function();

	        // Define the MapStyle that will later be passed to SetMapStyle or
	        // ActivateAlphaLayer.
		var layerName = layerNode.getAttribute("DisplayName");
		if (layerNamePrefix == null)
		{
			crunchLayer.MapStyle = layerName;
		}
		else
		{
			crunchLayer.MapStyle = layerNamePrefix + layerName;
		}

		// Compute this layer's zIndex
		crunchLayer.zIndex = layerNodes.length + 1 - ixLayer;

		// Find naming scheme for the tiles
		var namingSchemeNode = getFirstSubTag(layerNode, "TileNamingScheme");
		var layerNamingScheme;
		if (namingSchemeNode == null || (layerNamingScheme = namingSchemeNode.getAttribute("Type")) == null)
		{
			alert("Layer " + layerName + ": no naming scheme specified");
			continue;
		}
		
		// All naming schemes have these attributes.  Some schemes might have additional, special ones.
		var layerFilePrefix = tileRoot + namingSchemeNode.getAttribute("FilePrefix");
		var layerFileSuffix = namingSchemeNode.getAttribute("FileSuffix");


	        // Create a GenerateFilename function based on the tile naming scheme.
	        // The naming schemes define the relationship between a TileX/TileY/Zoom
	        // and a tile URL.
		if (layerNamingScheme == "VE")
		{
			// Note: the GetQuadKey function is in the main MapControl since
			// the VE guys might want to keep it obfuscated.
			crunchLayer.GenerateFilename =
				new Function("TileX", "TileY", "Zoom",
					"str = '" + layerFilePrefix +
					"/' + MSR.CVE.GetQuadKey(TileX, TileY, Zoom) + '"
					+ layerFileSuffix + "'; return str;");
		}
		else if (layerNamingScheme == "MC1")
		{	
			crunchLayer.GenerateFilename =
				new Function("TileX", "TileY", "Zoom",
					"str = '" + layerFilePrefix +
					"' + '/z' + Zoom + '/y' + TileY + '/x' + TileX + '"
					+ layerFileSuffix + "'; return str;");
		}
		else if (layerNamingScheme == "CGI")
		{	
			crunchLayer.GenerateFilename =
				new Function("TileX", "TileY", "Zoom",
					"str = '" + layerFilePrefix +
					"' + '?x=' + TileX + '&y=' + TileY + '&zoom=' + Zoom + '"
					+ layerFileSuffix + "'; return str;");
		}
		else
		{
			alert(xmlFileName + " has unknown tile naming scheme " + layerNamingScheme);
			continue;
		}

		// Get the DefaultView: a LatLonZoom that defines a useful view window
		// for this layer
		var defaultViewNode = getFirstSubTag(layerNode, "DefaultView");
		if (defaultViewNode != null)
		{
			var lat = defaultViewNode.getAttribute("lat");
			var lon = defaultViewNode.getAttribute("lon");
			var zoom = defaultViewNode.getAttribute("zoom");
			
			if (lat != null && lon != null && zoom != null)
			{
				var defaultView = new Object();

				defaultView.Lat = parseFloat(lat);
				defaultView.Lon = parseFloat(lon);
				defaultView.Zoom = parseInt(zoom);

				if (!isNaN(defaultView.Lat) && !isNaN(defaultView.Lon) && defaultView.Zoom > 0)
				{
					crunchLayer.DefaultView = defaultView;
				}
				else
				{
					//alert("Ignoring invalid default view for layer " + layerName);
				}
			}
		}

	        // Find the ExtraBounds structure, which is used to allow zooming
	        // past zoomlevel 19 in areas where the mashup is defined.
		var layerExtraBounds = new Array();
		var ebrNodes = layerNode.getElementsByTagName("ExtraBounds");
		for (var ixEBR = 0; ixEBR < ebrNodes.length; ixEBR++)
		{
			var ebrAtts = ebrNodes[ixEBR].attributes;
			var ebrZ1 = ebrAtts.getNamedItem("z1").value;
			var ebrZ2 = ebrAtts.getNamedItem("z2").value;
			var ebrX1 = ebrAtts.getNamedItem("x1").value;
			var ebrY1 = ebrAtts.getNamedItem("y1").value;
			var ebrX2 = ebrAtts.getNamedItem("x2").value;
			var ebrY2 = ebrAtts.getNamedItem("y2").value;
			layerExtraBounds[ixEBR] = new Msn.VE.Bounds(ebrZ1, ebrZ2, ebrX1, ebrY1, ebrX2, ebrY2);
		}
		crunchLayer.ExtraBounds = layerExtraBounds;

		// Now add this layer to the layer list
		crunchLayers.push(crunchLayer);
	}

	return crunchLayers;
};


// Given a list of TileConfig structures (created in the Import
// function above), add them to a VE MapControl.
MSR.CVE.AddLayersToMap = function(mapControl, crunchLayers)
{
	if (mapControl == null || crunchLayers == null)
	{
		return;
	}
    
	for (var ixLayer = 0; ixLayer < crunchLayers.length; ixLayer++)
	{
		var crunchLayer = crunchLayers[ixLayer];
		mapControl.AddOrthoTileSource(crunchLayer);
	}
};


// Given a name of a layer and a pointer to a MapControl,
// set the view to be the "best view" for viewing that layer.
MSR.CVE.SetCenterAndZoomForLayer = function(mapControl, layerName)
{
	var TileConfig = mapControl.GetOrthoTileSource(layerName);

	if (TileConfig != null && TileConfig.DefaultView != null)
	{
		var defaultView = TileConfig.DefaultView;

		map.SetCenterAndZoom(defaultView.Lat, defaultView.Lon, defaultView.Zoom);
	}
};


//
// Parse the URL and possibly call ActivateAlphaLayer, SetMapStyle
// and SetCenterAndZoom.  The URL should be of the format:
// YourPage.html?lat=12.34&lon=56.789&zoom=12&style=a&alpha=Some%20Layer&alpha=Another%20Layer
//
MSR.CVE.ApplyPermalink = function(map, form)
{
    var lat;
    var lon;
    var zoom;

    var argStartIndex = document.URL.indexOf('?');

    if (argStartIndex < 0)
    {
        return false;
    }

    // Clear all checkboxes in the form we were passed
    for (var i = 0; i < form.childNodes.length; i++)
    {
	if (form.childNodes[i].checked)
	{
	   form.childNodes[i].checked = false;
	}
    }
    map.ClearAlphaLayers();

    // Parse the argument string
    var argString = unescape(document.URL.substring(argStartIndex+1));
    var argArray = argString.split("&");

    for (var i = 0; i < argArray.length; i++)
    {
        var arg = argArray[i];
        var attr;
        var value;

        if (arg.indexOf("=") >= 0)
        {
            var attrValueArray = arg.split("=");
            attr = attrValueArray[0];
            value = attrValueArray[1];
        }
        else
        {
            attr = arg;
            value = null;
        }

        switch (attr)
        {
            case "lat":
                if (value != null)
                {
                    lat = parseFloat(value);
                }
                break;

            case "lon":
                if (value != null)
                {
                    lon = parseFloat(value);
                }
                break;

            case "zoom":
                if (value != null)
                {
                    zoom = parseInt(value);
                }
                break;

            case "style":
                if (value != null)
                {
                    map.SetMapStyle(value);
                }
                break;

            case "alpha":
                if (value != null)
                {
                    map.ActivateAlphaLayer(value);
                    var checkBoxList = document.getElementsByName("checkbox" + value);

                    if (checkBoxList != null && checkBoxList.length > 0)
                    {
                        checkBoxList[0].checked = true;
                    }
                }
                break;
        }
    }

    if (lat != null && lon != null && zoom != null)
    {
        map.SetCenterAndZoom(lat, lon, zoom);
	return true;
    }
    return false;
};

