// Browser detection
var isGecko = (navigator.userAgent.indexOf("Gecko") != -1);
var isIE = (navigator.userAgent.indexOf("MSIE") != -1);
var isIE55Min = getIEVersionNumber() >= 5.5;

function $e(elementName) {
	return document.getElementById(elementName);
}

function findPosX(obj) {
	var curleft = 0;
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			curleft += obj.offsetLeft;
			obj = obj.offsetParent;
		}
	} else if (obj.x) {
		curleft += obj.x;
	}
	return curleft;
}

// ----------------------------------------------------------------------------

function findPosY(obj) {
	var curtop = 0;
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			curtop += obj.offsetTop;
			obj = obj.offsetParent;
		}
	} else if (obj.y) {
		curtop += obj.y;
	}
	return curtop;
}

function normaliseCoordinate( coordinate ) {

	// Subtract two pixels from IE as it seems to be a little off
	if( getIEVersionNumber() <= 7 ) {
		coordinate -= 2;
		
		if( coordinate < 0 ) coordinate = 0;
	}

	return coordinate;
}

function getEventSourceElement( event ) {
	var element = ( event.target ) ? event.target : event.srcElement;
	if( element == null ) throw new Error( "Unable to determine event element" );
	return element;
}

function getElementClickCoords( event ) {
	
	// Returns an object containing the coords and element of the click, neutralising the differences between the browsers
	// Inspired by page 233 of Javascript Cookbook
	
	event = event || window.event;
		
	var coords = new Object();
	
	coords.absoluteX = event.pageX || event.x;
	coords.absoluteY = event.pageY || event.y;
	
	if( coords.absoluteX == null )	coords.absoluteX = 0;
	if( coords.absoluteY == null  ) coords.absoluteY = 0;

	coords.element = getEventSourceElement( event );
	
	coords.x = coords.absoluteX - findPosX( coords.element );
	coords.y = coords.absoluteY - findPosY( coords.element );
	
	coords.x = normaliseCoordinate( coords.x );
	coords.y = normaliseCoordinate( coords.y );
	
	return coords;
}

// ----------------------------------------------------------------------------

function getIEVersionNumber(){

	var ua = navigator.userAgent;
	var MSIEOffset = ua.indexOf("MSIE ");
	if( MSIEOffset == -1 ) {
		return 0;
	} else {
		return parseFloat( ua.substring(MSIEOffset + 5, ua.indexOf( ";", MSIEOffset ) ) );
	}

}

function CompatibleBrowser( userAgent ) {

	if( userAgent.match( /Firefox|Opera|Safari/ ) )		return true;		// Compatible browsers
	if( userAgent.match( /\Bbot\b|crawler|Slurp/ ) )	return true;		// Spiders and crawlers

	// IE 6+
	if( matches = userAgent.match( /^Mozilla.+MSIE (\d+)\./ ) ) {
		return ( matches[1] >= 6 );
	} else {
		// Not IE, none of the above
		return false;
	}
}

// ----------------------------------------------------------------------------

function DeleteTableRows( tableTbody ) {

	// Clear existing rows - need to delete last row as table row count falls with each deletion
	if( tableTbody === null ) {
		return;
	}
	
	var rowCount = tableTbody.rows.length;				// rowCount must be static in the loop because deleting from the table will actually change the number of rows in the table
	for( var r=0; r<rowCount; r++ ){
		tableTbody.deleteRow(tableTbody.rows.length-1);
	}
}

function HTMLEncode( HTMLtext ) {
	return HTMLtext == null ? null :HTMLtext.replace( /\</g, "&lt;" ).replace( /\>/g, "&gt;" );
}

function ReportError( errorDescription, exceptionObject ) {
	
	var caller = GetCallerName();
	
	var errorParameters = new Object();
	
	errorParameters["function"] = HTMLEncode(caller);
	errorParameters["description"] = HTMLEncode(errorDescription);
	
	if( exceptionObject != null ) errorParameters["dump"] = HTMLEncode(BuildExceptionString( exceptionObject ));
	
	// if it originated on the server it's probably already been logged (unless it crashed inside the ServerXmlLoaded code!)
	errorParameters["logError"]		= caller != "ServerXmlLoaded";
	errorParameters["errorType"]	= caller == "ServerXmlLoaded" ? "Server" : "Browser";	// What if it's a config error?
		
	var errorPageUrl = "error.aspx";
	
	if( typeof intraMaps != "undefined" && intraMaps.unitTesting ) {
		intraMaps.unitTestingError =  errorDescription + "\n" + BuildExceptionString( exceptionObject );		
	}
		
	try {
		errorWindow.show();
		errorWindow.position("centre");
			
		post_to_url($e("errorIframe").contentWindow.document, errorPageUrl, errorParameters);
		
		try{
			progressBar.Cancel();
		} catch(e){}
		
	} catch(e) {
	
		// If above fails just take the user to the location by GET
		document.location = errorPageUrl + "?" + UrlEncodeParameters(errorParameters);;
	}
}

function BuildExceptionString( exceptionObject ) {

	// Concatinate the error object into a large string
	var exceptionString = "";
	if( typeof exceptionObject != 'undefined' && exceptionObject != null && exceptionObject != "" ) {
	
		var exceptionDump = new Array;
		for( var i in exceptionObject ) {
			exceptionDump[exceptionDump.length] = i + ": " + exceptionObject[i];
		}
	
		exceptionString = exceptionDump.join( "\n" );
	}
	
	return exceptionString;
}


function GetCallerName() {

	if( matches = GetCallerName.caller.caller.toString().match( /^function ([^(\s]+)\(/ ) ) {
		return matches[1];
	} else {
		return null;
	}
}

// ----------------------------------------------------------------------------

function EndSession() {

	// Called when the browser is closed. Used to clear up the sessions on the server
	try{
		CallServerMethod( "EndSession", null, "EndSessionLoaded" );     // callback is a dummy function just so we can detect and skip the message when doing Application Engine session restarting
	} catch(e) {}
}

function EndSessionLoaded() {}

// ----------------------------------------------------------------------------

function ShowPrintDialog() {

	if( intraMaps.printTemplateEnabled ) {
	
		if( intraMaps.GetApplicationType() == "Enterprise" || intraMaps.GetApplicationType() == "Standard" ) {
			if( !printTemplateWindow.movedByUser ) printTemplateWindow.position( "center" );				
			printTemplateWindow.show();							
			PopulatePrintTemplateDialog();
		} else {
			// Go straight to the first html or PDF print template
			var ResponseXml = CallServerMethod( "GetPrintDialogData", null );
			
			// find first template that's html or PDF
			var printObjects	= DeserializeXmlListShallow(ResponseXml.getElementsByTagName("printSet")[0].getElementsByTagName("print"));
			var templateObjects	= DeserializeXmlListShallow(ResponseXml.getElementsByTagName("templateSet")[0].getElementsByTagName("print"));
			
			var printTemplate = null;
			
			for( var i=0; i<printObjects.length; i++ ) {
			
				for( var j=0; j<templateObjects.length; j++ ) {
				
					if( printObjects[i].templateId == templateObjects[j].id && templateObjects[j].type in Set("html", "pdf") ) {
						printTemplate = templateObjects[j];
						break;
					}
				}
				
				if( printTemplate != null ) break;
			}
			
			if( printTemplate == null ) throw Error("This module doesn't have any HTML or PDF templates available.");
			
			// Disable nodes that require a selection			
			if( !SelectionExists && printTemplate.withData == "True" ) {
			
				alert("The configured print template requires a selection before it can print.");
			
			} else {
							
				// open corresponding print template
				
				var scale = $e('viewScale').value.replace(/^1:/, "");
				
				switch( printTemplate.type ) {

					case "html":
						OpenHtmlPrintTemplate( printTemplate.id, printTemplate.imageType, scale );
						break;

					case "pdf":
						OpenPdfPrintTemplate( printTemplate.id, printTemplate.imageType, scale );
						break;
						
					default:
						throw Error("Unsupported print template type: " + printTemplate.type );
						break;
				}
			}
		}
   	}
}

// ----------------------------------------------------------------------------

function ShowLegend() {

	if (intraMaps.legendUrl != null && intraMaps.legendUrl != "") {

		// Toggle legend display
		if (!legendWindow.visible) {

			// Size legend window amd set frame source
			legendWindow.setWidth(intraMaps.legendWidth + 25); 	// extra to accomodate the scroll button
			legendWindow.setHeight(intraMaps.legendHeight + 25); // extra bit for toolbar

			var legendPanel = $e("legendPanel");
			legendPanel.innerHTML = "";

			embedObject(legendPanel, intraMaps.legendUrl);

			// Force the panel to be the size specified in the config file, and show scrollbars if needed
			legendPanel.style.width = intraMaps.legendWidth + "px";
			legendPanel.style.height = intraMaps.legendHeight + "px";
			legendPanel.style.overflow = "auto";

			// Position window
			if (!legendWindow.movedByUser) {
				legendWindow.position( "bottom-right" );
			}

			legendWindow.show();

		} else { 
			legendWindow.close();
		}

	}
}

// ----------------------------------------------------------------------------

function Help() {
	
	// Open help window
	window.open( "Help/index.html", "help", "resizable=yes,location=no,status=no,menubar=no,toolbar=no", true );
}

// ----------------------------------------------------------------------------

function round2dp(number,X) {
    X = (typeof X == "undefined" ? 2 : X);
    return Math.round(number*Math.pow(10,X))/Math.pow(10,X);
}

function AboutBox() {
	alert( intraMaps.AboutBoxText );
}

// ----------------------------------------------------------------------------

function GroupDigits( number ) {

	number = number.toString();

	var re = /(-?\d+)(\d{3})/;
	while( re.test( number ) ) {
		number = number.replace( re, "$1,$2" );
	}
	return number;
}

// ----------------------------------------------------------------------------

function trim(str) {
    if( str != null ) {
	    return str.replace(/^\s*|\s*$/g,"");
	}
}

// ----------------------------------------------------------------------------

function CalculatePixelZoomRatio() {

	// mapImageWidth will be update when we go in and out of full screen mode - so we need to keep recalculating it
	var mapImageWidth = dimensions.GetMapWidth();

	return intraMapsHistory.CurrentZoom()/mapImageWidth;	
}

// ----------------------------------------------------------------------------

function toggleModuleSidebar() {
	
	// Toggles module sidebar visibility
	
	var sidebarElement = $e( "ModuleSelector" );
	var sidebar_button = $e( "ModuleSidebarButton" );
		
	if( sidebarElement.style.display == "" || sidebarElement.style.display == "block") {
		sidebarElement.style.display = "none";
		sidebar_button.src = SHOW_PANEL_IMAGE;
	} else {
		sidebarElement.style.display = "block";
		sidebar_button.src = HIDE_PANEL_IMAGE;
	}
}


function StringFormat() {
	
	// Javascript partial implementation of c#'s string.format
	// See ms-help://MS.VSCC.2003/MS.MSDNQTR.2006JAN.1033/cpref/html/frlrfsystemstringclassformattopic1.htm

	if( arguments.length < 1) return;
		
	var StringFormatArgs = arguments;
	return arguments[0].replace( /{(\d+)}/g, function(match,capture){ 
		var index = parseInt(capture)+1;
		if( index > StringFormatArgs.length-1 ) throw new Error( StringFormat( "argument {0} not found", match ) );
		return StringFormatArgs[index];
	} );
}


function CSharpInvoke() {
	
	// Used in NUnit to allow C# to be able to invoke Javascript functions 
	
	var functionName = arguments[0];
	
	// decode parameters
	var parameters = new Array();
	for( var CSharpInvoke_i=1; CSharpInvoke_i<arguments.length; CSharpInvoke_i++ ) {
	
		try{
			// See if we can parse the argument as valid JS -
			var testObject;
			var parameterAsString = arguments[CSharpInvoke_i]
			eval( "testObject = " + parameterAsString + ";" );
			switch( typeof testObject ) {
			
				case "undefined":
					parameters[CSharpInvoke_i-1] = "null";
					break;
					
				case "boolean":
					throw new Error();
					break;
					
				default:
					parameters[CSharpInvoke_i-1] = parameterAsString;
					break;
			}
			
		} catch(e) {
		
			// Failed to be parsed, assume it must be a string
			parameters[CSharpInvoke_i-1] = "\"" + arguments[CSharpInvoke_i] + "\"";
		}
	}
	
	intraMaps.unitTestingError = null;
	
	var evalString = "var rv = " + functionName + "(" + parameters.join() + ")";
	eval( evalString );
	
	// Hack to pass the error up to the CSharp caller
	if( intraMaps.unitTestingError ) {
		rv = "Unit Testing Error: " + intraMaps.unitTestingError;
	}
	
	return rv;
}

function TestUnitTestingError() {

	intraMaps.unitTestingError = "Test Error";
}

function ClearUnitTestingErrorMessage() {
	intraMaps.unitTestingError = null;
}


function TestUnitTestingErrorServerSide() {

	CallServerMethod( "_UnhandledException", null );
}

function TestUnitTestingSuccessServerSide() {

	CallServerMethod( "_TestMethodCall", null );
}

function CheckUnitTestingErrorMessage() {
	if( typeof intraMaps != "undefined" ) return intraMaps.unitTestingError;
}


function GetWindowCoordinates( event ) {

	// Get "event" whether Netscape-style (function param) or IE-style (window.event)
	event = event || window.event;
			    
	var event_x = event.pageX || event.x;
	var event_y = event.pageY || event.y;
	
	return {x:event_x, y:event_y};
}

function Window2Map( windowX, windowY ) {

	// realtive to the map image			
	var tgt = $e("mapInputImage");
	
	var map_image_bounds = new Object();
	map_image_bounds.top	= findPosY( tgt );
	map_image_bounds.left	= findPosX( tgt );
			
	var mapX	= ( windowX > map_image_bounds.left )	? windowX - map_image_bounds.left : 0;
	var mapY	= ( windowY > map_image_bounds.top )	? windowY - map_image_bounds.top  : 0;

	return {x:mapX, y:mapY};
}

// ----------------------------------------------------------------------------

function Stack() {

	this._stack;
	this._index;
	
	this._SetIndex = function( index ) {
	
		if( index < 0 ) index = 0;
		if( index > this._stack.length ) index == this._stack.length;
		this._index = index;
	}
	
	this.Clear = function() {
	
		this._stack = new Array();
		this._SetIndex( 0 );
	}
	this.Clear();	// Clear on startup to initialise the stack
	
	
	this.SetPosition = function( offset ) {
	
		// Goes to a position (offset) in the map history
		this._SetIndex( this._index + offset );
	}
	
	
	this.Current = function() {
	
		if( this._stack.length == 0 ) throw new Error("stack is empty");
	
		return this._stack[this._index];
	}
	
	
	this._AtStart = function() {
		return this._index == 0;
	}
	
	
	this.AtEnd = function() {
		return this._index == this._GetEndIndex();
	}
	

	this.Push = function( content ) {

		// Create a new empty item on the stack
		
		// What's the point of this line? It makes the length one larger if we are not at the beginning or the end
		if( !this._AtStart() && !this.AtEnd() ) this._stack.length = this._index+1;	

		this._stack[this._stack.length] = content;

		// Go to the end
		this._SetIndex( this._GetEndIndex() );
	}
	
	
	this._GetEndIndex = function() {
		return this._stack.length-1;
	}
	
	
	this.IsEmpty = function() {
		return this._stack.length <= 0;
	}
}


function View( x, y, zoom, x1, y1, x2, y2 ) {
	// data structure for holding a view when used in history
	this.x = x;
	this.y = y;
	this.zoom = zoom;
	
	// Note that this is not the standard computer coordinate system of 0,0 in the top left corner, but the cartographic origin system
	this.x1 = x1;
	this.y1 = y1;
	this.x2 = x2;
	this.y2 = y2;

	if( isNaN(x) ) throw new Error( "view cannot be created, x is invalid" );
	if( isNaN(y) ) throw new Error( "view cannot be created, y is invalid" );
	if( isNaN(zoom) ) throw new Error( "view cannot be created, zoom is invalid" );
	if( isNaN(x1) ) throw new Error( "view cannot be created, x1 is invalid" );
	if( isNaN(y1) ) throw new Error( "view cannot be created, y1 is invalid" );
	if( isNaN(x2) ) throw new Error( "view cannot be created, x2 is invalid" );
	if( isNaN(y2) ) throw new Error( "view cannot be created, y2 is invalid" );
	
	this.Equal = function( that ) {
		return this.x == that.x && this.y == that.y && this.zoom == that.zoom && this.x1 == that.x1 && this.y1 == that.y1 && this.x2 == that.x2 && this.y2 == that.y2;
	}
}


function History() {

	this._stack = new Stack();

	this._home; // For home button

	this.CurrentZoom = function() {
		return parseFloat( this._stack.Current().zoom );
	};
	
	this.GetCurrentView = function() {
		return this._stack.Current();
	};
	
	this.Clear = function() {

		this._stack.Clear();

		this._SetButtons();
	};
	
	this._SetButtons = function() {

		// Back button
		if( this._stack._AtStart() ) {
			toolbar.disableButton( $e("button_back") );
		} else {
			toolbar.enableButton( $e("button_back") );
		}

		// Forward button
		if( this._stack.AtEnd() ) {
			toolbar.disableButton( $e("button_forward") );
		} else {
			toolbar.enableButton(  $e("button_forward") );
		}
	};
	
	this._ignoreNextAdd = false;	//HACK: really the server side shouldn't send up map coordinates for calls which need this
	
	this.Go = function( offset ) {

		this._ignoreNextAdd = true;

		// Goes to a position (offset) in the map history
		this._stack.SetPosition( offset );
		CallServerMethod( "AbsoluteZoomAndCenter", {centerX: this._stack.Current().x, centerY: this._stack.Current().y, zoomValue: this._stack.Current().zoom}, "" );	
			
		this._SetButtons();
	};
	
	this.Add = function( mapObject, boundsObject ) {
				
		if( this._ignoreNextAdd ) {	
			this._ignoreNextAdd = false;
		} else {						
			if( this._ValidView( mapObject.x, mapObject.y, mapObject.zoom ) ) {
								
				var view = new View( mapObject.x, mapObject.y, mapObject.zoom, boundsObject.x1, boundsObject.y1, boundsObject.x2, boundsObject.y2 );

				// Exit function if it's exactly the same as the previous view in the stack, skipping the history stack	
				if( !this._stack.IsEmpty() && view.Equal( this._stack.Current() ) ) {
					return;
				}

				this._stack.Push( view );
				
				this._SetButtons();
			}
		}
	};
	
	this.SetHome = function( x, y, zoom, x1, y1, x2, y2 ) {
	
		// Only set if they are not all zeros (which happens when the module has the same workspace as the previous one)
		if( this._ValidView( x, y, zoom ) ) {
			this._home = new View( x, y, zoom, x1, y1, x2, y2 );
		}
	};
	
	this.Home = function(){

		if( !this._ValidView( this._home.x, this._home.y, this._home.zoom ) ) {
		
			alert( "Home location is unavailable on map" );
		
		} else {

			// Perform home operation
			CallServerMethod( "AbsoluteZoomAndCenter", {centerX: this._home.x, centerY: this._home.y, zoomValue: this._home.zoom}, "" );
		} 
	};
	
	this._ValidView = function( x, y, zoom ) {
		return !isNaN(x) && !isNaN(y) && !isNaN(zoom) && x!=0 && y!=0 && zoom!=0;
	};
}


function map( expression, list ) {

	// Simple implementation of the perl map function
	// https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Objects:Array:map
	var newList = new Array();

	for( var i in list ) newList[i] = expression(list[i], i);
	return newList;
}


function Interpolate( sourceCoords, sourceBBox, targetBBox ) {

	// returns sourceCoords in sourceBBox projected into targetBBox
	
	if( sourceBBox.originType == null ) throw new Error( "originType must be specified for sourceBBox" );
	if( targetBBox.originType == null )	throw new Error( "originType must be specified for targetBBox" );
	
	if( sourceBBox.originType != "computer" && sourceBBox.originType != "map" )	throw new Error( "invalid originType for sourceBBox" );
	if( targetBBox.originType != "computer" && targetBBox.originType != "map" )	throw new Error( "invalid originType for targetBBox" );

	// Force to floats
	sourceBBox.x1 = parseFloat( sourceBBox.x1 );
	sourceBBox.y1 = parseFloat( sourceBBox.y1 );
	sourceBBox.x2 = parseFloat( sourceBBox.x2 );
	sourceBBox.y2 = parseFloat( sourceBBox.y2 );

	targetBBox.x1 = parseFloat( targetBBox.x1 );
	targetBBox.y1 = parseFloat( targetBBox.y1 );
	targetBBox.x2 = parseFloat( targetBBox.x2 );
	targetBBox.y2 = parseFloat( targetBBox.y2 );

	// calculate targetX
	var targetX = targetBBox.x1 + (targetBBox.x2-targetBBox.x1)*((sourceCoords.x-sourceBBox.x1)/(sourceBBox.x2-sourceBBox.x1));
	
	// calculate targetY
	var targetY;
	if( sourceBBox.originType != targetBBox.originType  ) {
	
		// invert target y's
		targetY = targetBBox.y2 + (targetBBox.y1-targetBBox.y2)*((sourceCoords.y-sourceBBox.y1)/(sourceBBox.y2-sourceBBox.y1));
	
	} else {
	
		// both origins are the same
		targetY = targetBBox.y1 + (targetBBox.y2-targetBBox.y1)*((sourceCoords.y-sourceBBox.y1)/(sourceBBox.y2-sourceBBox.y1));
	}
		
	return {x:targetX, y:targetY};
}

function TestInterpolate( sourceCoords, sourceBBox, targetBBox, expectedTargetCoords ) {

	var results = Interpolate( sourceCoords, sourceBBox, targetBBox );
	
	if( round2dp(results.x,5) != round2dp(expectedTargetCoords.x,5) ) throw new Error( StringFormat( "x coordinate result: {0} doesn't match expected result: {1}", results.x, expectedTargetCoords.x ) );
	if( round2dp(results.y,5) != round2dp(expectedTargetCoords.y,5) ) throw new Error( StringFormat( "y coordinate result: {0} doesn't match expected result: {1}", results.y, expectedTargetCoords.y ) );
	
	return true;
}

function Set()
{
    // based on http://laurens.vd.oever.nl/weblog/items2005/setsinjavascript/
  
    var result = {};

    for (var i = 0; i < arguments.length; i++)
      result[arguments[i]] = true;

    return result;
}

function getStyle(el, prop) {

    // based on http://erik.eae.net/archives/2007/07/27/18.54.15/
    // see also http://www.strictly-software.com/CSSStyleObject.asp

  if (document.defaultView && document.defaultView.getComputedStyle) {
    return document.defaultView.getComputedStyle(el, null)[prop];
  } else if (el.currentStyle) {
    return el.currentStyle[prop];
  } else {
    return el.style[prop];
  }
}

function GetInnerText( element ) {

    // based on http://blog.coderlab.us/2005/09/22/using-the-innertext-property-with-firefox/

    if(element.innerText){
         return element.innerText;
    } else {
        return element.textContent;
    }
}

function ScreenLine2MapLength(lineWidth, lineHeight, pixelZoomRatio) {
	return round2dp(Math.sqrt(lineWidth * lineWidth + lineHeight * lineHeight) * pixelZoomRatio, 1);
}

function TrDefaultDisplayHack() {

	// http://www.velocityreviews.com/forums/t160487-firefox-and-stylequotdisplayblockquot-on-table-row.html

	return isIE ? "block" : "table-row";
}

function CoordsLookLikeLatLong( x, y ) {

	if( typeof x == "undefined" || typeof y == "undefined" ) throw new Error("point parameters look invalid (no x or y property)");
	
	return x <= 360 && x >= -360 && y <= 90 && y >= -90;
}

function RoundCoords( point ) {

	if( CoordsLookLikeLatLong(point.x, point.y) ) {
		point.x = round2dp(point.x,6);
		point.y = round2dp(point.y,6);
	} else {
		// if not lat long, remove the decimal places
		point.x = round2dp(point.x,0);
		point.y = round2dp(point.y,0);
	}

	return point;
}

function EnterPressed(evt) {

	// Based on function in "Javascript & DHTML Cookbook" p205
	evt = (evt) ? evt : event;
	var charCode = (evt.charCode) ? evt.charCode : 
		((evt.which) ? evt.which : evt.keyCode);
	
	if( charCode == KEYCODE_ENTER || charCode == 3 ) {			// Enter key on various browsers
		return true;
	} else {
		return false;
	}
}

function TestGetSelectionLayer() {
	return toolbar.GetSelectionLayer();
}

function GetClipboardText() {
	return window.clipboardData.getData("Text");
}

function SetClipboardText(text) {
	window.clipboardData.setData("Text",text);
}

function CopyMapImageToClipboard() {

	// Copy the map from the browser to the system clipboard
	var r = document.body.createControlRange();
	r.add($e("mapInputImage"));
	r.select();
	r.execCommand("Copy");
}

var WshShell = null;

function StartApplication( application ) {
	WshShell.Run( application, 1, false );
}

function SendKeysToApp( appTitle, keys, tries )
{
	// normally this function will be called without tries, and it will call itself until it's reached that many attempts
	if( typeof tries == "undefined" ) tries = 1;

	if( tries < 50 ) {
		
		if( WshShell.AppActivate( appTitle ) ) {
			WshShell.SendKeys(keys);
		} else {
			tries++;
			setTimeout("SendKeysToApp('" + appTitle + "', '" + keys + "', " + tries + ")", 100 );
		}
	} else {
		throw Error("Could not find the running application: " + appTitle);
	}
}

function ExportMapImageToPaint()
{
	try{

		WshShell = new ActiveXObject("WScript.Shell");
		
		CopyMapImageToClipboard();

		StartApplication("mspaint.exe");
		
		setTimeout("SendKeysToApp('untitled - Paint', '^v');", 500 );
	} catch(e) {
		alert("An error occurred while starting Paint in order to export the map image.\n\nPlease check with your system administrator.\n\n" + e.message );
	}
}
