﻿// Client-side browser printing patch for Virth Earth
function VEPrintableMap(sourceId,destinationId,originalMap){
    // Define SVG namespaces, required objects
    var SVG_NS='http://www.w3.org/2000/svg';
    var XLink_NS='http://www.w3.org/1999/xlink';
    var browser=null;
    var mapDiv=document.getElementById(sourceId);
    var targetDiv=document.getElementById(destinationId);
    var sourceMap=originalMap;
    
    targetDiv.setAttribute("style",mapDiv.getAttribute("style"));
    DetermineBrowser();
    
    // Determine the user's browser
    function DetermineBrowser(){
        if(navigator.appVersion.indexOf("MSIE")!=-1){
            if(parseFloat(navigator.appVersion.split("MSIE")[1])>=5.5)
                browser="msie";
        }
        else if(navigator.userAgent.indexOf("Firefox")!=-1){
            if(parseInt(navigator.userAgent.charAt(navigator.userAgent.indexOf("Firefox")+8))>=1)
                browser="firefox";
        }
    }
    
    // Scrape all VE tile img tags and creates SVG compatible versions
    function GetTiles(){
        // Create an array to hold the svg tile images
        var tileImages=new Array();
        
        // Get a handle to all original tile images
        var originalTiles=mapDiv.getElementsByTagName("img");
        
        // Iterate through all known tiles (last element is powered by logo)
        for(var i=0; i<originalTiles.length; i++){
            if((originalTiles[i].id!=null && originalTiles[i].id!="") || originalTiles[i].className=="MSVE_PoweredByLogo")
                continue;

            // Create SVG image for tile
            var svgImage=document.createElementNS(SVG_NS,"image");
            
            // Set SVG attributes based on tile's image attribytes
            svgImage.setAttributeNS(null,"x",originalTiles[i].offsetLeft);
            svgImage.setAttributeNS(null,"y",originalTiles[i].offsetTop);
            svgImage.setAttributeNS(null,"width",originalTiles[i].clientWidth);
            svgImage.setAttributeNS(null,"height",originalTiles[i].clientHeight);
            svgImage.setAttributeNS(null,"transform","translate("+originalTiles[i].parentNode.offsetLeft+","+originalTiles[i].parentNode.offsetTop+")");
            svgImage.setAttributeNS(null,"opacity",originalTiles[i].style.opacity);
            
            // Set tile's image via original tile's link
            svgImage.setAttributeNS(XLink_NS,"xlink:href",originalTiles[i].src);

            // Add the new SVG tile to our array
            tileImages.push(svgImage);
        }
        return tileImages;
    }
    
    // Scrape all VE pin img tags and creates SVG compatible versions
    function GetPins(pinImages){
        // Get a handle to all original pin links
        var pinLinks=mapDiv.getElementsByTagName("a");
        
        // Iterate through all known pins
        for(var i=0; i<pinLinks.length; i++){
            var svgImage=GetPushpinShape(pinLinks[i]);
            // Add the new SVG pin to our array
            pinImages.push(svgImage);
        }
        return pinImages;
    }
    
    // Scape SVG shapes from the original map and return them
    function GetSvgShapes(pins){
        var shapes=new Array();
        
        // Iterate through all the visible shapes layers
        for(var i=0; i<sourceMap.GetShapeLayerCount(); i++){
            if(sourceMap.GetShapeLayerByIndex(i).Visibility!=true)
                continue;
            // Grab only visible SVG shapes, extract all the SVG elements
            for(var x=0; x<sourceMap.GetShapeLayerByIndex(i).GetShapeCount(); x++){
                var shape=sourceMap.GetShapeLayerByIndex(i).GetShapeByIndex(x);
                if(shape.Visibility!=true)
                    continue;
                // Polylines and polygons are SVG shapes
                if(shape.Type=="Polyline" || shape.Type=="Polygon"){
                    for(var y=0; y<shape.Primitives.length; y++){
                        shapes.push(GetPolyLine(shape.Primitives[y].iid));
                        // Add a shape pushpin if present
                        if(shape.Primitives[y]._iconElement!=null){
                            var svgImage=GetPushpinShape(shape.Primitives[y]._iconElement,shape.IconUrl);
                            pins.push(svgImage);
                        }
                    }
                }
                // Only handle the conditions below for pushpins in VE6
                else if(!Msn.VE.V6Control)
                    continue;
                else if(shape.Type=="Point" && i>0){
                    var svgImage=GetPushpinShape(shape.Primitives[0]._iconElement,shape.IconUrl);
                    pins.push(svgImage);
                }
                else{
                    // Extract base layer pushpins
                    var element=document.getElementById(shape.Primitives[0].iid);
                    if(!element)
                        continue;
                    var svgImage=element!=null?GetPushpinShape(element,shape.IconUrl):null;
                    pins.push(svgImage);
                }
            }
        }
        
        // Extract the route polyline if present
        if(document.getElementById("veDDHighlight")!=null)
            shapes.push(GetPolyLine("veDDHighlight"));
        
        return shapes;
    }
    
    // Extract pushpins and generate corresponding SVG images
    function GetPushpinShape(pin,icon){
        // Create SVG image for pin
        var svgImage=document.createElementNS(SVG_NS,"image");

        if(!icon)
            // Set pin's image via its anchor
            icon=pin.firstChild.src;

        // Set SVG attributes based on pin's image (link) location
        svgImage.setAttributeNS(null,"x",pin.offsetLeft);
        svgImage.setAttributeNS(null,"y",pin.offsetTop);
        svgImage.setAttributeNS(null,"width",pin.clientWidth);
        svgImage.setAttributeNS(null,"height",pin.clientHeight);
        svgImage.setAttributeNS(null,"opacity","1");
        svgImage.setAttributeNS(XLink_NS,"xlink:href",icon);

        if(pin.offsetParent!=null)
            svgImage.setAttributeNS(null,"transform","translate("+pin.offsetParent.offsetLeft+","+pin.offsetParent.offsetTop+")");
        
        return svgImage;
    }
    
    // Scrape the requested polylines to place on the new map
    function GetPolyLine(element){
        // Get existing VE SVG shape
        var originalPolyline=document.getElementById(element);
        
        // Create new SVG polyline
        var newPolyLine=document.createElementNS(SVG_NS,"polyline");
        
        if(originalPolyline!=null){
            // Copy existing SVG shape attributes
            newPolyLine.setAttributeNS(null,"points",originalPolyline.getAttribute("points"));
            newPolyLine.setAttributeNS(null,"stroke",originalPolyline.getAttribute("stroke"));
            newPolyLine.setAttributeNS(null,"stroke-width",originalPolyline.getAttribute("stroke-width"));
            newPolyLine.setAttributeNS(null,"stroke-linejoin",originalPolyline.getAttribute("stroke-linejoin"));
            newPolyLine.setAttributeNS(null,"stroke-opacity",originalPolyline.getAttribute("stroke-opacity"));
            newPolyLine.setAttributeNS(null,"stroke-dasharray",originalPolyline.getAttribute("stroke-dasharray"));
            newPolyLine.setAttributeNS(null,"fill",originalPolyline.getAttribute("fill"));
            newPolyLine.setAttributeNS(null,"fill-opacity",originalPolyline.getAttribute("fill-opacity"));
            newPolyLine.setAttributeNS(null,"style",originalPolyline.getAttribute("style"));
        }
        return newPolyLine;
    }
    
    // Scrape the copyright to put on the print preview map
    function GetCopyrights(){
        // Find copyrights relative to map element's last element/child
        var element=mapDiv.lastChild;

        // Get a handle to all 5 copyright elements
        var elements=new Array();
        for(var i=0; i<6; i++){
            element=element.previousSibling;
            var cloned=element.cloneNode(true);
            cloned.id=element.id+"_ff"+i;
            elements.push(cloned);
        }
        
        // Get the handle for powered by VE image
        for(var i=0; i<mapDiv.childNodes.length; i++){
            if(mapDiv.childNodes[i].className=="MSVE_PoweredByLogo"){
                element=mapDiv.childNodes[i];
                var cloned=element.cloneNode(true);
                cloned.id=element.id+"_ff"+elements.length;
                elements.push(cloned);
                break;
            }
        }
        return elements;
    }
   
    // Create the SVG map and insert it into the desired element
    function WriteSVG(){
        // Create our root SVG element
        var svgRoot=document.createElementNS(SVG_NS,"svg");
 
        // Set the element's common attributes
        svgRoot.setAttribute("xmlns",SVG_NS);
        svgRoot.setAttribute("xmlns:xlink",XLink_NS);
        svgRoot.setAttribute("version","1.1");
        svgRoot.setAttribute("width",mapDiv.style.width);
        svgRoot.setAttribute("height",mapDiv.style.height);

        // Get SVG version of tiles
        var tiles=GetTiles();
        for(var i=0; i<tiles.length; i++){
            svgRoot.appendChild(tiles[i]);
        }

        // Get SVG polylines and route polyline
        var pushpins=new Array();
        var svgShapes=GetSvgShapes(pushpins);
        for(var i=0; i<svgShapes.length; i++){
            svgRoot.appendChild(svgShapes[i]);
        }

        // Get SVG version of pins
        var pins=GetPins(pushpins);
        for(var i=0; i<pins.length; i++){
            svgRoot.appendChild(pins[i]);
        }

        // Append SVG map /w route & pins to new map container
        while(targetDiv.hasChildNodes()){
            targetDiv.removeChild(targetDiv.lastChild);
        }
        targetDiv.appendChild(svgRoot);

        // Append copyrights to new map.
        var copyrights=GetCopyrights();
        for(var i=0; i<copyrights.length; i++){
            targetDiv.appendChild(copyrights[i]);
        }
    }
    
    // Create a duplicate map for IE as it should be printable
    function CloneMap(){
        targetDiv.style.width=mapDiv.style.width;
        targetDiv.style.height=mapDiv.style.height;
        targetDiv.style.position=mapDiv.style.position;
        
        cloneMap=new VEMap(targetDiv.id);
        cloneMap.LoadMap(sourceMap.GetCenter(),sourceMap.GetZoomLevel(),sourceMap.GetMapStyle(),true,VEMapMode.Mode2D,false);

        // Clone tile layers if present
        if(sourceMap.m_vetilesourcemanager.m_vetilesources.length>0){
            for(var i=0; i<sourceMap.m_vetilesourcemanager.m_vetilesources.length; i++){
                cloneMap.m_vetilesourcemanager.AddTileSource(sourceMap.m_vetilesourcemanager.m_vetilesources[i]);
            }
            // Use server-side fix for tile layer transparency
            TileLayerFix(targetDiv.id);
        }

        // Clone the route if it exists
        if(sourceMap._dm.veroutecache.length>0){
            var routeType=(sourceMap._dm.lasttype==null || sourceMap._dm.lasttype=="q")?VERouteType.Quickest:VERouteType.Shortest;
            cloneMap.GetRoute(sourceMap._dm.veroutecache[0].LatLong,sourceMap._dm.veroutecache[sourceMap._dm.veroutecache.length-1].LatLong,null,routeType,function(){cloneMap._dm.RemoveRoutePins();cloneMap.SetCenter(sourceMap.GetCenter());});
        }
        
        // Clone VE4 (and route) pushpins
        for(var i=0; i<sourceMap.pushpins.length; i++){
            cloneMap.AddPushpin(sourceMap.pushpins[i]);
        }
        
        // Clone all visible shapes
        for(var x=0; x<sourceMap.GetShapeLayerCount(); x++){
            if(sourceMap.GetShapeLayerByIndex(x).Visibility!=true)
                continue;
            // Create a new shape layer if this is above the base
            if(x>0){
                var cloneLayer=new VEShapeLayer();
                cloneMap.AddShapeLayer(cloneLayer);
            }
            // Iterate through every visible shape
            for(var y=0; y<sourceMap.GetShapeLayerByIndex(x).GetShapeCount(); y++){
                var shape=sourceMap.GetShapeLayerByIndex(x).GetShapeByIndex(y);
                if(shape.Visibility!=true)
                    continue;
                // Handle base and custom layer shape addition
                var newShape=new VEShape(shape.Type,shape.GetPoints());
                newShape.Primitives[0].symbol=shape.Primitives[0].symbol;
                if(x>0)
                    cloneLayer.AddShape(newShape);
                else
                    cloneMap.AddShape(newShape);
            }
        }
        
        // Non-moving pan to keep original shapes from becoming invisible
        sourceMap.PanToLatLong(sourceMap.GetCenter());
    }
    
    // Select appropriate printed map generation method
    function PrintMap(){
        switch(browser){
            case "msie":
                CloneMap();
                break;
            case "firefox":
                WriteSVG();
                break;
            default:
                alert("Unsupported browser detected");
        } 
    }

    // Fix grey background when printing layered tiles
    function TileLayerFix(elementId){
        var targetDiv=document.getElementById(elementId);
        var imgs=targetDiv.getElementsByTagName("img");
        var divs=targetDiv.getElementsByTagName("div");
		var images=new Array();
        var matched=new Array();

		// Grab all tile-sized images
		for(var i=0; i<imgs.length; i++){
			if(imgs[i].clientWidth==256 && imgs[i].clientHeight==256)
				images.push(imgs[i]);
		}

		// Grab any divs that may be tile overlays (IE6)
        for(var i=0; i<divs.length; i++){
			if(divs[i].filters!=null && divs[i].filters.length>0 && divs[i].id=="")
				images.push(divs[i]);
        }

        // Iterate through each possible tile image/div contained in the map DIV
        for(var i=0; i<images.length; i++){
            var current=images[i];
			// Skip tiles that have been previously matched
			if(current.longDesc=="matched")
                continue;

            var topIndex=current.style.zIndex;
            var topImage=current;
            matched.length=0;
            matched.push(current);

            // Compare the current image with others
            for(var x=0; x<images.length; x++){
                var compared=images[x];
                // Exclude a comparison to itself
                if(x==i)
                    continue;
                // Check whether the current tiles are stacked and determine which image is on top
                if(current.offsetLeft==compared.offsetLeft && current.offsetTop==compared.offsetTop){
                    matched.push(compared);
                    topIndex=Math.max(topIndex,compared.style.zIndex);
                    images[x].longDesc="matched";
                    // Determine if this is the top image
                    if(compared.style.zIndex==topIndex)
                        topImage=compared;
                }
            }
            
            // Use the server provided images if overlapping tiles were found
            if(matched.length<1)
                continue;
			// Build the URL for the server-based image 
            var layeredUrl="MergeLayers.ashx?";
            for(var y=0; y<matched.length; y++){
                var opacity=1;
				// Extract the overlay URL from the current IMG (IE7) or DIV (IE6)
				var url=(matched[y].tagName=="IMG")?matched[y].src:/src=\'(.*)\',.*/.exec(matched[y].style.filter)[1];
                // Handle the image URL and disable the Alpha filter for partially transparent tiles
                if(matched[y].filters!=null && matched[y].filters.length>0){
                    // Determine the level of opacity if less than fully opaque
                    for(var z=0; z<matched[y].filters.length; z++){
                        if(matched[y].filters[z].opacity==null)
                            continue;
                        opacity=matched[y].filters[z].opacity/100;
                        matched[y].filters[z].Enabled=false;
                    }
				}
				matched[y].style.filter="";
				layeredUrl+="&src="+url+"!"+matched[y].style.zIndex+"!"+opacity;
            }
			// Apply the combined server provided image to the top IMG or DIV
			if(topImage.tagName=="img")
	            topImage.src=layeredUrl;
			else
				topImage.outerHTML="<img style='width:256px; height:256px; z-index:"+topImage.style.zIndex+"; position:absolute; top:"+topImage.offsetTop+"px; left:"+topImage.offsetLeft+"px;' src='"+layeredUrl+"'/>"
		}
    }
    
    // Public function to write the new map to specified container
    this.Print=PrintMap;
}    

