/**
 * Creates a new iConeManager that will manage the display of iCones
 *
 * @constructor
 * @param {Map} map The map to manage
 * @param {Object} opts Optional container for the following items:
 *	{String} mainXML The link to the main xml page
 *	{String} histXML The link to the history xml page
 *	{String} timeTag The div tag name for the timestamp display
 */
function iConeManager(map, opts){
	var me = this;
	//create a private variable for the map object.
	me._map	= map;
	
	//set the options
	me.setOptions(opts);
	
	//create and set private variables for overlayID prefixes
	me._iconePref = "a";
	me._labelPref = "k";
	
	//create private variables to force re-downloading cached dynamic files.
	me._instance=Math.floor(Math.random() * 100001);
	me._count=0;
	
	//create private variables for managed overlays
	me._icons = me._buildIconArray();
	me._numCones=0;
	me._ownedCones=0;
	me._rcMarker=null;
	me._overlays = [];
	me._infoWindows = [];
	me._openInfoID=null;
	me._MM = new MarkerManager(me._map, {maxZoom:me._maxZoom});
	me._currZoom = me._map.getZoom();
	
	//create private variables to manage "Loading" notifications
	me._loadingCones=null;
	me._loadingHist=null;
	
	//Bind map events to local functions
	me.startClickListeners();
	me._listener_zoomend = GEvent.bind(me._map, "zoomend", me, me._onMapZoomEnd);
	me._listener_singlerightclick = GEvent.bind(me._map, "singlerightclick", me, me._onMapRightClick);
};
/**
 * Set Options available to the iConeManager.
 *
 * @param {Object} opts Optional container for the following items:
 *	{String} mainXML The link to the main xml page
 *	{String} histXML The link to the history xml page
 *	{String} timeTag The div tag name for the timestamp display
 *	{String} histTag The div tag name for the history display
 *	{int} minZoom  The minimum zoom to manage overlays to
 *	{int} maxZoom  The maximum zoom to manage overlays to
 */
iConeManager.prototype.setOptions = function(opts){
	var me=this;
		
	me._mainXML = (opts.mainXML!=null)?opts.mainXML : "iconexml.aspx";
	me._histXML = (opts.histXML!=null)?opts.histXML : "historyxml.aspx";
	me._timeTag = (opts.timeTag!=null)?opts.timeTag : "timestamp";
	me._histTag = (opts.histTag!=null)?opts.histTag : "left";
	
	var types = me._map.getMapTypes();
	var tMinZ=999;
	var tMaxZ=-1;
	for (var i=0; i<types.length; i++){
		var temp = types[i].getMinimumResolution();
		if(temp<tMinZ) tMinZ=temp;
		
		temp = types[i].getMaximumResolution();
		if(temp>tMaxZ) tMaxZ=temp;
	}
	me._minZoom = (opts.minZoom!=null)?opts.minZoom : tMinZ;
	me._maxZoom = (opts.maxZoom!=null)?opts.maxZoom : tMaxZ;
};

iConeManager.prototype.stopClickListeners = function(){
	if(this._listener_click != null){
		GEvent.removeListener(this._listener_click);
		this._listener_click=null;
	}
}
iConeManager.prototype.startClickListeners = function(){
	if(this._listener_click == null)
		this._listener_click = GEvent.bind(this._map, "click", this, this._onMapClick);
}

/**
 * Removes all current Markers
 */
iConeManager.prototype.clearOverlays = function(){
	var me = this;
	me._numCones=0;
	me._ownedCones=0;
	me._overlays=[];
	me._infoWindows=[];
	me._MM.clearMarkers();
};

/**
 * Add a new info window to the managed info windows array.
 */
iConeManager.prototype.addInfoWindow = function(markerID, tabs){
	var me = this;
	if(me._overlays[markerID]!=null){
		var overlay = me._overlays[markerID];
		var iA = overlay.marker.getIcon().iconAnchor;
		var iWA = overlay.marker.getIcon().infoWindowAnchor;
		
		if(iA!=null && iWA!=null){
			var newInfo = new Object();
			newInfo.loc = overlay.marker.getLatLng();
			newInfo.tabs = tabs;
			newInfo.offset = new GSize(iWA.x-iA.x, iWA.y-iA.y);
			newInfo.minZoom = overlay.minZoom;
			newInfo.maxZoom = overlay.maxZoom;
					
			me._infoWindows[markerID] = newInfo;
		}
	}
};
/**
 * Opens info window for a designated marker
 */
iConeManager.prototype.openInfo = function(markerID){
	var me = this;
	
	if(markerID!=null)
		me._openInfoID=markerID;
	
	var info = me._infoWindows[me._openInfoID];
	
	if(info!=null && info.minZoom<=me._currZoom && me._currZoom<=info.maxZoom){
		me._map.openInfoWindowTabs(info.loc, info.tabs, {pixelOffset:info.offset});
	} else {
		me._map.closeInfoWindow();
	}
};
/**
 * Closes the open info window, if one is open.
 */
iConeManager.prototype.closeInfo = function(){
	var me = this;
	if(me._openInfoID!=null){
		me._openInfoID = null;
		me._map.closeInfoWindow();
	}
}

/**
 * zooms and moves map to view all cones;
 */
iConeManager.prototype.viewAllCones = function(){
	var me = this;
	if (me._numCones<1) {
		me._map.setCenter(new GLatLng(39.2, -96.4), 4);
		return;
	}
	
	var minLat=90, minLng=180, maxLat=-90, maxLng=-180;
	for( i in me._overlays){
		if(me._overlays[i].marker!=null && (me._ownedCones==0 || me._overlays[i].owned)){
			var lat = parseFloat(me._overlays[i].marker.getPoint().lat());
			var lng = parseFloat(me._overlays[i].marker.getPoint().lng());
			if(lat<minLat) minLat=lat;
			if(lat>maxLat) maxLat=lat;
			if(lng<minLng) minLng=lng;
			if(lng>maxLng) maxLng=lng;
		}
	}
	
	var bounds = new GLatLngBounds( new GLatLng(minLat,minLng), new GLatLng(maxLat,maxLng) );
	var zoom = me._map.getBoundsZoomLevel(bounds);
	me._map.setCenter(bounds.getCenter(), zoom);
};
/**
 * Refreshes iCones from the specified iCone xml link.
 *
 * @param {String} time Optional timestamp to send to main xml link OR "true" to auto pan and zoom to view all cones
 */
iConeManager.prototype.refreshCones = function(time, allCones){
	var me = this;
	
	if(me._conesXHR!=null){
		me._conesXHR.abort();
	}
	me._conesXHR=null;
	
	var link = me._mainXML+"?";
	if(time!=null && time!=true)
		link+="timestamp="+time+"&";
	if(allCones!=null)
		link+="allcones="+allCones+"&";
	link+="offset="+((new Date()).getTimezoneOffset()/-60)+"&";
	link+="instance="+me._instance+"&";
	link+="refresh="+me._count;
	
	me._count++;
	
	me._ShowLoadingCones();
	me._conesXHR = xhr(link, function(data, responseCode){
		me.clearOverlays();
		me._parseMainXML(data);
		
		if(me._openInfoID!=null) me.openInfo(me._openInfoID);
		
		if(me._ownedCones>0){
			document.getElementById("viewAllCones").innerHTML = "view all "+me._ownedCones+" of my iCones&reg;";
		} else {
			document.getElementById("viewAllCones").innerHTML = "view all "+me._numCones+" iCones&reg;";
		}
		
		if(time!=null && time==true) me.viewAllCones();
		
		
		me._HideLoadingCones();
	});
};
/**
 * Refreshes history data, setting innerHTML of histTag
 *
 * @param {String} time Time string of oldest history to return
 * @param {Int} id ICone ID of specific iCone to return history for
 */
iConeManager.prototype.refreshHistory = function(oldest, newest, id, lat, lng, miles){
	var me = this;
	
	if(me._histXHR!=null) {
		me._histXHR.abort();
	}
	me._histXHR=null;
	
	var link = me._histXML+"?";
	if(oldest!=null && oldest!="")
		link+="oldest="+oldest+"&";
	if(newest!=null && newest!="")
		link+="newest="+newest+"&";
	if(id!=null && id!="")
		link+="iconeid="+id+"&";
	if(lat!=null && lat!="")
		link+="lat="+lat+"&";
	if(lng!=null && lng!="")
		link+="lng="+lng+"&";
	if(miles!=null && miles!="")
		link+="miles="+miles+"&";
	link+="offset="+((new Date()).getTimezoneOffset()/-60)+"&";
	link+="instance="+me._instance+"&";
	link+="rand="+Math.floor(Math.random() * 1001);
	
	me.loadLeftData(link,175);
	/*me._ShowLoadingHist();
	me._histXHR = xhr(link, function(data, responseCode){
		document.getElementById(me._histTag).innerHTML = data;//me._parseHistXML(data);
		me._HideLoadingHist();
	});*/
};
iConeManager.prototype.loadLeftData = function(link,width,callback){
	var me = this;
	
	if(link==null || link==""){
		document.getElementById(me._histTag).innerHTML = "";
		document.getElementById(me._histTag).style.width = width+"px";
		return;
	}
	
	me._ShowLoadingHist();
	me._histXHR = xhr(link, function(data, responseCode){
		document.getElementById(me._histTag).innerHTML = data;
		document.getElementById(me._histTag).style.width = width+"px";
		me._HideLoadingHist();
		if(callback!=null) callback();
	});
};
/**
 * Removes all history data from the History Tag
 */
iConeManager.prototype.closeHistory = function(){
	document.getElementById(this._histTag).innerHTML = "";
};

/**
 * Updates a marker based on a markerID.  If the marker does not currently exist, it is added
 *
 * @param {String} markerID The ID of a marker.
 * @param {GMarker} newMarker The new marker to use.
 */
iConeManager.prototype._updateMarker = function(markerID, newPoint, newIcon, info, drawOrder, minZoom, maxZoom){
	var me = this;
	markerID = me._iconePref+markerID;
	
	function overlapOrder(marker,b) {
		var addition = (marker.importance!=null)?marker.importance : 1;
		
		return GOverlay.getZIndex(-90)+addition;
	}
	
	var newOverlay = new Object();
	newOverlay.minZoom = (minZoom!=null)?minZoom : me._minZoom;
	newOverlay.maxZoom = (maxZoom!=null)?maxZoom : me._maxZoom;
	if(newIcon==null) {
		newOverlay.marker = new GMarker(newPoint, {zIndexProcess:overlapOrder});
		newOverlay.owned=false;
	} else {
		newOverlay.marker = new GMarker(newPoint, {icon:newIcon,zIndexProcess:overlapOrder});
		newOverlay.owned=newIcon.owned;
	}
	newOverlay.marker.importance = drawOrder;
	newOverlay.marker.id = markerID;
	
	var oldOverlay = me._overlays[markerID];
	
	//ensure that the old overlay has been removed from the map
	if(oldOverlay!=null)	me._MM.removeMarker(oldOverlay.marker);
	
	//ensure that the _numCones is correct
	if(oldOverlay==null)	me._numCones++;
	
	//ensure that the _ownedCones is correct
	if(oldOverlay!=null && oldOverlay.owned){
		me._ownedCones--;
	}
	if(newOverlay.owned){
		me._ownedCones++;
	}
	
	//set the newOverlay.Marker as the markerID value in the _overlays array
	me._overlays[markerID]=newOverlay;
	
	//if info is set, add it to the infoWindow array
	if(info!=null && info!=""){
		me.addInfoWindow(markerID, info, minZoom, maxZoom);
	}
	
	//me._map.addOverlay( me._overlays[markerID] );
	me._MM.addMarker( newOverlay.marker, newOverlay.minZoom, newOverlay.maxZoom );
};
/**
 * Updates a label based on labelID.  If the label does not currently exist, it is added.
 */
iConeManager.prototype._updateLabel = function(labelID,location,fixedPoint,text, minZoom,maxZoom, styleName){
	if (styleName==null || styleName=="") { styleName = "LabelStyle1"; }

	if (text!=null && text!="" && text!="<br />"){
		var me = this;
		labelID=me._labelPref+labelID;
		
		var newElabel = new Object();
		newElabel.minZoom = (minZoom!=null)?minZoom : me._minZoom;
		newElabel.maxZoom = (maxZoom!=null)?maxZoom : me._maxZoom;
		newElabel.marker = new ELabel(location, text, styleName, null, 75);
		newElabel.marker.setFixedPoint(fixedPoint);
		newElabel.marker.id = labelID;
		
		var oldElabel = me._overlays[labelID];
		
		if(oldElabel!=null) me._MM.removeMarker(oldElabel.marker);
		
		me._overlays[labelID] = newElabel;
		
		me._MM.addMarker( newElabel.marker, newElabel.minZoom, newElabel.maxZoom);
	}
};


/**
 * Returns HTML of iCone data
 */
iConeManager.prototype._iConeInfo = function(id, serial, groupID, lTime, dTime,
												vph, avgSpeed, hwCount, avgHW, battery, visibility, fahrenheit,
												iconStr,lat,lng,projName,projID,projOrd, metric){
	if(dTime==null && avgSpeed==null) return null;
	
	var str="<table id='info'>";
	if(id!=null)		str+=" <tr style='text-align:center'><td colspan=2><b><i>i</i>Cone&reg; "+id+"</b></td></tr>";
	if(serial!=null)	str+=" <tr style='text-align:center'><td colspan=2>Serial#:"+serial+"</td></tr>";
	if(groupID!=null)	str+=" <tr style='text-align:center'><td colspan=2>Group ID:"+groupID+"</td></tr>";
	if(projName!=null && projID!=null && projOrd!=null){
		str+=" <tr style='text-align:center'><td colspan=2>Project "+projID+"("+projOrd+"): "+projName+"</td></tr>";
	}
	if(lTime!=null) 	str+=" <tr><td style='text-align:left'><b>Location Time:</b></td>	<td style='text-align:left'>"+lTime+"</td></tr>";
	if(dTime!=null) 	str+=" <tr><td style='text-align:left'><b>Data Time:</b></td>		<td style='text-align:left'>"+dTime+"</td></tr>";
	if(vph!=null)		str+=" <tr><td style='text-align:left'><b>Traffic:</b></td>			<td style='text-align:left'>"+vph+" vph</td></tr>";
	if(avgSpeed!=null) {
		str+=" <tr><td style='text-align:left'><b>Avg Speed:</b></td>		<td style='text-align:left'>";
		if(metric!=null && metric=="true")	str+=parseInt(avgSpeed*1.60934400061)+" km/h"; /*changed from "kph" to "km/h"*/
		else								str+=avgSpeed+" mph";
		str+="</td></tr>";
	}
	if(hwCount!=null)	str+=" <tr><td style='text-align:left'><b>Headway Count:</b></td>	<td style='text-align:left'>"+hwCount+"</td></tr>";
	if(avgHW!=null)		str+=" <tr><td style='text-align:left'><b>Avg Headway:</b></td>		<td style='text-align:left'>"+avgHW+" s</td></tr>";
	if(fahrenheit!=null){
		str+=" <tr><td style='text-align:left'><b>Temperature:</b></td>		<td style='text-align:left'>";
		if(metric!=null && metric=="true")	str+=parseInt((fahrenheit-32)*5/9)+" C";
		else								str+=fahrenheit+" F";
		str+="</td></tr>";
	}
	if(battery!=null)	str+=" <tr><td style='text-align:left'><b>Battery:</b></td>			<td style='text-align:left'>"+battery+" V</td></tr>";
	if(visibility!=null)str+=" <tr><td style='text-align:left'><b>Visibility:</b></td>		<td style='text-align:left'>"+visibility+"</td></tr>";
	str +="</table>";
	if(id!=null){
		var reportsLink = "reports.aspx?icone="+id;
		reportsLink += "&offset="+((new Date()).getTimezoneOffset()/-60);
		reportsLink += "&iconetime="+dTime.replace(/ /,"%20");
		if(projID!=null)reportsLink += "&projectID="+projID;
		if(lat!=null)	reportsLink += "&latitude="+lat;
		if(lng!=null)	reportsLink += "&longitude="+lng;
		str +="<a href=\""+reportsLink+"\" onClick=\"return popup(this, 'Reports', 380, 550);\">Get Historical Report</a>";
	}
	
	var tabs=[];
	tabs[0] = new GInfoWindowTab("Info.",str);
	
	if(id!=null){ //build configuration tab.
		str = "<form id='configForm' name='configForm'>";
		str+= "  <label for='deployType'><b>Deployment Type</b></label>";
		str+= "  <br />";
		str+= "  <select id='deployType' name='deployType' onchange=\"setConfig(this.value,'"+visibility+"',true)\">";
		
		var selected=-1;
		var selectedStr="selected='true'";
		if(iconStr.indexOf("X")!=-1){ //Closed Road
			selected=3;
		} else if (iconStr.indexOf("info")!=-1){ //Survey Cone
			selected=2;
		} else { //Construction Cone
			selected=1;
		}
		str+= "    <option value='construction' "+ (selected==1?selectedStr:"") +">Construction</option>";
		str+= "    <option value='survey' "+ (selected==2?selectedStr:"") +">Survey</option>";
		str+= "    <option value='closed' "+ (selected==3?selectedStr:"") +">Closed Road</option>";
		//str+= "    <option value='caution' "+ (selected==4?selectedStr:"") +">Caution</option>";
		
		str+= "  </select>";
		str+= "  <br />";
		str+= "  <br />";
		str+= "  <div><b>Visibility</b></div>";
		
		selectedStr="checked='checked'";
		str+= "  <label for='public'>public</label>";
		str+= "  <input id='public' type='radio' name='visibility' value='public' "+ (visibility=="public"?selectedStr:"") +"/>";
		str+= "  <label for='private'>private</label>";
		str+= "  <input id='private' type='radio' name='visibility' value='private' "+ (visibility=="private"?selectedStr:"");
		str+= " "+ (selected==1?"disabled=true":"") +"/>";
		
		str+= "  <br />";
		str+= "  <br />";
		str+= "  <input type='button' onclick='changeSettings(\""+serial+"\",\""+lTime+"\",document.configForm.deployType.value,getCheckedValue(document.configForm.visibility));' value='Update' />";
		str+= "  <input type='button' onclick=\"setConfig('"
		if (selected==1)		str+="construction";
		else if (selected==2)	str+="survey";
		else if (selected==3)	str+="closed";
		str+= "','"+visibility+"',false);\" value='Reset' />";
		str+= "</form>";
		
		tabs[1] = new GInfoWindowTab("Config.",str);
	}
	
	return tabs;
};
/**
 * Parses the xml string returned from the main xml link, adding all markers available
 *
 * @param {String} xmlStr XML formatted string of main data
 * expected formate:
 * <current TimeStamp="2007-10-17 18:34:02" TimeZone="0">
 *	<iCone ID="3" serial="4150" groupID="3">
 *		<overview icon="red" latitude="38.1033328" longitude="-76.5589446"/>
 *		<details LocTime="2007-08-31 13:06:16" DataTime="2007-08-31 14:57:16" congestion="9.05" avgSpeed="54.06" maxSpeed="85.15" sdSpeed="9.38422" battery="10.87839" visibility="public"/>
 *	</iCone>
 * </current>
 */
iConeManager.prototype._parseMainXML = function(xmlStr){
	if (xmlStr==null || xmlStr=="") return;

	var me = this;
	var xml = getXML(xmlStr, "current");

	if (xml==null || xml.getElementsByTagName("Error").length!=0) {
		var left = document.getElementById("left");
		if(left!=null){
			showDisplay('left','manageLeftBar');
			var error = document.getElementById("ERROR");
			if(error==null) {
				error = document.createElement("div");
				error.id="ERROR";
				
				left.appendChild(error);
			}
			error.innerHTML = "<div id='ERROR'>"
			error.innerHTML += "<a href=\"javascript:document.getElementById('left').style.display='none';\">close</a>";
			error.innerHTML += "<br />There was an unexpected error downloading the iCone data.  Please try refreshing the page.";
			error.innerHTML += "<br /><br />If this problem persists, please contact <a href='mailto:web@iconeproducts.com'>web@iconeproducts.com</a>";
			error.innerHTML += "<br /><br />----------<br />"+xmlStr.replace("<","&lt;");
		}
		return;
	}

	var errDiv = document.getElementById("ERROR");
	if(errDiv!=null) document.removeElement(errDiv);
	
	var cones = xml.getElementsByTagName("iCone");
	var metric = xml.getAttribute("Metric");
	
	for ( var i=0; i<cones.length; i++ ){
		var id		= cones[i].getAttribute("ID");
		var serial	= cones[i].getAttribute("serial");
		var groupID	= cones[i].getAttribute("groupID");
		var projName= cones[i].getAttribute("projectName");
		var projID	= cones[i].getAttribute("projectID");
		var projOrd	= cones[i].getAttribute("projectOrder");
		var view	= cones[i].getElementsByTagName("overview")[0];
		var detail	= cones[i].getElementsByTagName("details")[0];
		
		var icon = view.getAttribute("icon");
		var lat  = view.getAttribute("latitude");
		var lng  = view.getAttribute("longitude");
		
		var lTime, dTime, vph, avgSpeed, hwCount, avgHW, battery, visibility, fahrenheit;
		if (detail!=null) {
			lTime		= formatDate(detail.getAttribute("LocTime"));
			dTime		= formatDate(detail.getAttribute("DataTime"));
			vph			= detail.getAttribute("vph");
			avgSpeed	= detail.getAttribute("avgSpeed");
			hwCount		= detail.getAttribute("hwCount");
			avgHW		= detail.getAttribute("avgHW");
			battery		= detail.getAttribute("battery");
			visibility	= detail.getAttribute("visibility");
			fahrenheit	= detail.getAttribute("fahrenheit");
		} else {
			lTime = dTime = vph = avgSpeed = hwCount = avgHW = battery = visibility = fahrenheit = null
		}
		
		var iconeMsg;
		if (battery==null && fahrenheit==null){
			iconeMsg=me._iConeInfo(null,null,null,null,dTime,null,avgSpeed,null,null,null,null,null,null,null,null,null,null, null);
		} else {
			iconeMsg=me._iConeInfo(id, serial, groupID, lTime, dTime, vph, avgSpeed, hwCount, avgHW, battery, visibility, fahrenheit, icon, lat,lng, projName, projID, projOrd, metric);
		}
		
		me._updateMarker(id, new GLatLng(lat,lng), me._icons[icon], iconeMsg, i);
	}
	
	var label = xml.getElementsByTagName("Label");
	for ( var l=0; l<label.length; l++){
		var id		= label[l].getAttribute("ID");
		var view	= label[l].getElementsByTagName("overview")[0];
		var display	= label[l].getElementsByTagName("display")[0];
		
		var min			= view.getAttribute("minzoom");
		var latitude	= view.getAttribute("latitude");
		var longitude	= view.getAttribute("longitude");
		
		var title	= display.getAttribute("title");
		var text	= display.getAttribute("text");
		if(text != null){
			text = text.replace("&lt;","<");
			text = text.replace("&gt;",">");
		}
		var fixp	= display.getAttribute("fixedpoint");
			
		me._updateLabel(id, new GLatLng(latitude, longitude), fixp, title+"<br />"+text,min,null,"LabelStyle1");
	}
	
	var label2 = xml.getElementsByTagName("Label2");
	for ( var l=0; l<label2.length; l++){
		var id		= label2[l].getAttribute("ID");
		var view	= label2[l].getElementsByTagName("overview")[0];
		var display	= label2[l].getElementsByTagName("display")[0];
		
		var min			= view.getAttribute("minzoom");
		var latitude	= view.getAttribute("latitude");
		var longitude	= view.getAttribute("longitude");
		
		var title	= display.getAttribute("title");
		var text	= display.getAttribute("text");
		if(text != null){
			text = text.replace("&lt;","<");
			text = text.replace("&gt;",">");
		}
		var fixp	= display.getAttribute("fixedpoint");
			
		me._updateLabel(id, new GLatLng(latitude, longitude), fixp, title+"<br />"+text,min,null,"LabelStyle2");
	}
				
	if (me._timeTag!=null){
		var dt = formatDate(xml.getAttribute("TimeStamp"));
		var tz = xml.getAttribute("TimeZone");
		document.getElementById(me._timeTag).innerHTML = "Displaying data at: "+dt+" ("+tz+")";
	}
};


/**
 * Add an available icon to the icons array
 *
 * @param {String} name The name this icon is referenced by
 * @param {GIcon} icon The icon that the name refers to.
 */
iConeManager.prototype.addIcon = function(name, icon){
	if(name!=null && icon!=null)
		this._icons[name] = icon;
};
/**
 * Removes all available icons
 */
iConeManager.prototype.removeIcons = function(){
	this._icons = [];
};
/**
 * Function to build an array of icons
 */
iConeManager.prototype._buildIconArray = function(){
	var me = this;
	var icons = [];
	var baseIcon;
	
	//create a right-click marker
	baseIcon = me._buildIconBase("images/info-trans.png", new GSize(20,20), new GPoint(10,10), new GPoint(18,5), [0,0,20,0,20,20,0,20]);
	icons["locMarker"] = me._buildIcon(baseIcon, "images/dot1.png" , null, "images/dot1.gif" , "images/dot1.gif" , null);

	//create icons - unowned iCones
	baseIcon = me._buildIconBase("images/iCone-trans.png", new GSize(13,20), new GPoint(6,18), new GPoint(6,4), [0,0,13,0,13,20,0,20]);
	baseIcon.owned=false;
	icons["blue"]	= me._buildIcon(baseIcon,"images/iCone-blue.png"  ,null,"images/iCone-blue-ie.gif"  ,"images/iCone-blue-ff.gif"  ,null);
	icons["gray"]	= me._buildIcon(baseIcon,"images/iCone-gray.png"  ,null,"images/iCone-gray-ie.gif"  ,"images/iCone-gray-ff.gif"  ,null);
	icons["green"]	= me._buildIcon(baseIcon,"images/iCone-green.png" ,null,"images/iCone-green-ie.gif" ,"images/iCone-green-ff.gif" ,null);
	icons["orange"]	= me._buildIcon(baseIcon,"images/iCone-orange.png",null,"images/iCone-orange-ie.gif","images/iCone-orange-ff.gif",null);
	icons["purple"]	= me._buildIcon(baseIcon,"images/iCone-purple.png",null,"images/iCone-purple-ie.gif","images/iCone-purple-ff.gif",null);
	icons["red"]	= me._buildIcon(baseIcon,"images/iCone-red.png"   ,null,"images/iCone-red-ie.gif"   ,"images/iCone-red-ff.gif"   ,null);
	icons["yellow"]	= me._buildIcon(baseIcon,"images/iCone-yellow.png",null,"images/iCone-yellow-ie.gif","images/iCone-yellow-ff.gif",null);
	
	//create icons - owned iCones
	baseIcon = me._buildIconBase("images/iCone-trans.png", new GSize(16,25), new GPoint(7,22), new GPoint(7,4), [0,0,16,0,16,25,0,25]);
	baseIcon.owned=true;
	icons["bigblue"]	= me._buildIcon(baseIcon,"images/iCone-blue.png"  ,null,"images/iCone-blue-ie.gif"  ,"images/iCone-blue-ff.gif"  ,null);
	icons["biggray"]	= me._buildIcon(baseIcon,"images/iCone-gray.png"  ,null,"images/iCone-gray-ie.gif"  ,"images/iCone-gray-ff.gif"  ,null);
	icons["biggreen"]	= me._buildIcon(baseIcon,"images/iCone-green.png" ,null,"images/iCone-green-ie.gif" ,"images/iCone-green-ff.gif" ,null);
	icons["bigorange"]	= me._buildIcon(baseIcon,"images/iCone-orange.png",null,"images/iCone-orange-ie.gif","images/iCone-orange-ff.gif",null);
	icons["bigpurple"]	= me._buildIcon(baseIcon,"images/iCone-purple.png",null,"images/iCone-purple-ie.gif","images/iCone-purple-ff.gif",null);
	icons["bigred"]		= me._buildIcon(baseIcon,"images/iCone-red.png"   ,null,"images/iCone-red-ie.gif"   ,"images/iCone-red-ff.gif"   ,null);
	icons["bigyellow"]	= me._buildIcon(baseIcon,"images/iCone-yellow.png",null,"images/iCone-yellow-ie.gif","images/iCone-yellow-ff.gif",null);
	
	//create icons - unowned ITS stations
	baseIcon = me._buildIconBase("images/info-trans.png", new GSize(16,16), new GPoint(8,12), new GPoint(15,4), [0,0,16,0,16,16,0,16]);
	baseIcon.owned=false;
	icons["blueinfo"]	= me._buildIcon(baseIcon, "images/info-blue.png"  , null, "images/info-blue.gif"  , "images/info-blue.gif"  , null);
	icons["grayinfo"]	= me._buildIcon(baseIcon, "images/info-gray.png"  , null, "images/info-gray.gif"  , "images/info-gray.gif"  , null);
	icons["greeninfo"]	= me._buildIcon(baseIcon, "images/info-green.png" , null, "images/info-green.gif" , "images/info-green.gif" , null);
	icons["orangeinfo"]	= me._buildIcon(baseIcon, "images/info-orange.png", null, "images/info-orange.gif", "images/info-orange.gif", null);
	icons["redinfo"]	= me._buildIcon(baseIcon, "images/info-red.png"   , null, "images/info-red.gif"   , "images/info-red.gif"   , null);
	icons["yellowinfo"]	= me._buildIcon(baseIcon, "images/info-yellow.png", null, "images/info-yellow.gif", "images/info-yellow.gif", null);
	
	//create icons - owned ITS stations
	baseIcon = me._buildIconBase("images/info-trans.png", new GSize(20,20), new GPoint(10,15), new GPoint(18,5), [0,0,20,0,20,20,0,20]);
	baseIcon.owned=true;
	icons["bigblueinfo"]	= me._buildIcon(baseIcon, "images/info-blue.png"  , null, "images/info-blue.gif"  , "images/info-blue.gif"  , null);
	icons["biggrayinfo"]	= me._buildIcon(baseIcon, "images/info-gray.png"  , null, "images/info-gray.gif"  , "images/info-gray.gif"  , null);
	icons["biggreeninfo"]	= me._buildIcon(baseIcon, "images/info-green.png" , null, "images/info-green.gif" , "images/info-green.gif" , null);
	icons["bigorangeinfo"]	= me._buildIcon(baseIcon, "images/info-orange.png", null, "images/info-orange.gif", "images/info-orange.gif", null);
	icons["bigredinfo"]		= me._buildIcon(baseIcon, "images/info-red.png"   , null, "images/info-red.gif"   , "images/info-red.gif"   , null);
	icons["bigyellowinfo"]	= me._buildIcon(baseIcon, "images/info-yellow.png", null, "images/info-yellow.gif", "images/info-yellow.gif", null);
	
	//create icons - unowned closed road
	baseIcon = me._buildIconBase("images/info-trans.png", new GSize(16,16), new GPoint(8,12), new GPoint(15,4), [0,0,16,0,16,16,0,16]);
	baseIcon.owned=false;
	icons["X"]		= me._buildIcon(baseIcon, "images/x-red.png" , null, "images/x-red.gif" , "images/x-red.gif" , null);
	icons["grayX"]	= me._buildIcon(baseIcon, "images/x-gray.png", null, "images/x-gray.gif", "images/x-gray.gif", null);
	
	//create icons - owned closed road
	baseIcon = me._buildIconBase("images/info-trans.png", new GSize(20,20), new GPoint(10,15), new GPoint(18,5), [0,0,20,0,20,20,0,20]);
	baseIcon.owned=true;
	icons["bigX"]		= me._buildIcon(baseIcon, "images/x-red.png" , null, "images/x-red.gif" , "images/x-red.gif" , null);
	icons["biggrayX"]	= me._buildIcon(baseIcon, "images/x-gray.png", null, "images/x-gray.gif", "images/x-gray.gif", null);
	
	return icons;
};
/**
 * Function to create a baseIcon.
 */
iConeManager.prototype._buildIconBase = function(transparent, size, anchor, infoAnchor, imageMap){
	if(transparent!=null){
		var base = new GIcon();
		base.transparent = transparent;
		
		if(size!=null)
			base.iconSize = size;
		if(anchor!=null)
			base.iconAnchor = anchor;
		if(infoAnchor!=null)
			base.infoWindowAnchor = infoAnchor;
		if(imageMap!=null)
			base.imageMap = imageMap;
		
		return base;
	}
	return null;
};
/**
 * Function to create a single icon with specific images from a base icon with the correct size, imageMap and offsets.
 */
iConeManager.prototype._buildIcon = function(baseIcon, image, shadow, printImage, mozPrintImage, printShadow){
	if(baseIcon!=null && image!=null){
		var icon = new GIcon(baseIcon, image);
		
		icon.owned=baseIcon.owned;
		
		if(shadow!=null)
			icon.shadow = shadow;
		if(printImage!=null)
			icon.printImage = printImage;
		if(mozPrintImage!=null)
			icon.mozPrintImage = mozPrintImage;
		if(printShadow!=null)
			icone.printShadow = printShadow;
		
		return icon;
	}
	return null;
};

/**
 * Function to perform upon a change to the map's zoom... basically just forces the info window to refresh.
 */
iConeManager.prototype._onMapZoomEnd = function(oldZ, newZ){
	var me = this;
	me._currZoom=newZ;
	
	if(me._openInfoID!=null){
		var toOpen = me._infoWindows[me._openInfoID];
		var info = me._map.getInfoWindow();
		if(toOpen!=null && toOpen.minZoom<=me._currZoom && me._currZoom<=toOpen.maxZoom){
			if(info.isHidden()){
				var h = info.getContentContainers()[0].style.height;
				var w = info.getContentContainers()[0].style.width;
				var size = new GSize(w.substring(0,w.length-2),h.substring(0,h.length-2));
				info.reset(toOpen.loc, toOpen.tabs, size, toOpen.offset, info.getSelectedTab());
				info.show();
			}
		} else {
			info.hide();
		}
	}
};
/*
 * Function to perform upon a map click event.
 */
iConeManager.prototype._onMapClick = function(overlay, latLng, overlayLatLng){
	var me=this;
	
	if(me._rcMarker!=null){
		me._map.removeOverlay(me._rcMarker);
	}
	
	if(overlay!=null && overlay.id!=null){
		me.openInfo(overlay.id);
	} else {
		me._openInfoID=null;
	}
	
	var sel = document.getElementById("selected");
	if(sel!=null){
		if(overlay!=null){
			sel.value = true;
		} else {
			sel.value = false;
		}
	}
};
/**
 * Function to perform upon a map right-click event.
 */
iConeManager.prototype._onMapRightClick = function(pxPoint, src, overlay){
	var me = this;
	
	if(me._rcMarker!=null){
		me._map.removeOverlay(me._rcMarker);
	}
	
	var latlng;
	if(overlay!=null && overlay.getLatLng()!=null){
		latlng = overlay.getLatLng();
	} else {
		latlng = me._map.fromContainerPixelToLatLng(pxPoint);
	}
	
	if(document.getElementById("selectedLat")!=null && document.getElementById("selectedLng")!=null){
		document.getElementById("selectedLat").value = latlng.lat().toFixed(5);
		document.getElementById("selectedLng").value = latlng.lng().toFixed(5);
	}
	
	var txt = "<b>Selected Location:</b>";
	txt += "<br />Lat  = "+latlng.lat().toFixed(5);
	txt += "<br />Long = "+latlng.lng().toFixed(5);
	
	me._rcMarker = new GMarker(latlng, {icon:me._icons["locMarker"],zIndexProcess:function(marker,b){return 100;}});
	me._map.addOverlay(me._rcMarker);
	me._rcMarker.openInfoWindowHtml(txt);
	
	var sel = document.getElementById("selected");
	if(sel!=null){
		sel.value = true;
	}
};

/**
 * Functions to control the display of the loading messages when refreshCones is called.
 * set here to avoid residual loading messages when an update is cancelled for another update
 */
iConeManager.prototype._ShowLoadingCones = function(){
	var me=this;
	if(me._loadingCones==null){
		me._loadingCones=new LoadingControl();
		me._map.addControl(me._loadingCones);
	}
};
iConeManager.prototype._HideLoadingCones = function(){
	var me=this;
	if(me._loadingCones!=null){
		me._map.removeControl(me._loadingCones);
		me._loadingCones=null;
	}
};

/**
 * Functions to control the display of the loading messages when refreshHistory is called.
 * set here to avoid residual loading messages when an update is cancelled for another update
 */
iConeManager.prototype._ShowLoadingHist = function(){
	var me=this;
	if(me._loadingHist==null){
		me._loadingHist=new LoadingControl();
		me._map.addControl(me._loadingHist);
	}
};
iConeManager.prototype._HideLoadingHist = function(){
	var me=this;
	if(me._loadingHist!=null){
		me._map.removeControl(me._loadingHist);
		me._loadingHist=null;
	}
};


/**
 * Parses an xml string, returning a readable DOM object
 *
 * @param {String} xmlStr The xml string to parse
 * @param {String} root Optional root tag name to initialize the DOM object with.
 * @returns {DOM} The parsed xml string as a DOM object
 */
function getXML(xmlStr, root){
	if(xmlStr==null) return;
	
	var rtn = GXml.parse(xmlStr)
	
	if(root==null) return rtn;
	return rtn.getElementsByTagName(root)[0];
}
/**
 * Function to change the display format of the delivered SQL formatted time to a universally legible timestamp.
 * delivered SQL format = 'yyyy-MM-dd HH:mm:ss.ssss'
 * Universally legible format = 'MMM dd, yyyy HH:mm:ss.ssss'
 */
function formatDate(timestamp){
	if(timestamp==null) return "";
	var months = ["","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
	
	timestamp=timestamp.split(' ');
	timestamp[0]=timestamp[0].split('-');
	timestamp[0][1] = parseFloat(timestamp[0][1]);
	
	var rtn = months[timestamp[0][1]]+" "+timestamp[0][2]+", "+timestamp[0][0];
	rtn += " "+timestamp[1];
	
	return rtn;
}
/**
 * Function to create a popup window
 */
function popup(mylink, windowname, w, h, scroll, giveFocus){
	if (! window.focus)
		return true;
		
	var href;
	if (typeof(mylink) == 'string')
		href=mylink;
	else
		href=mylink.href;
	
	w = (w==null || typeof(w)!='number')?500:w;
	h = (h==null || typeof(h)!='number')?600:h;
	scroll = (scroll!=1 && scroll!=0)?1:scroll;
	
	var win = window.open(href, windowname, "width="+w+",height="+h+",scrollbars="+scroll+",resizable=1,location=1,status=0,menubar=0,toolbar=0");
	if(giveFocus!="false" && win!=null && win.focus){
		win.focus();
	}
	return false;
}
/**
 * Function to change the icon and publicVisibility settings of an iCone.
 */
function changeSettings(serial,startTime,deployment,visibility){
	var link = "editSettings.aspx?";
	link += "serial="+serial+"&";
	link += "start="+startTime+"&";
	link+="offset="+((new Date()).getTimezoneOffset()/-60)+"&";
	
	if(deployment!=null){
		deployment = deployment.toLowerCase();
		if(deployment=="construction"){
			link += "icon=0&";
		} else if (deployment=="survey"){
			link += "icon=1&";
		} else if (deployment=="closed"){
			link += "icon=2&";
		}
	}
	if(visibility!=null){
		visibility = visibility.toLowerCase();
		if(visibility=="public"){
			link += "visibility=1&";
		} else if(visibility=="private"){
			link += "visibility=0&";
		}
	}
	
	popup(link, "settings", 10, 10, 1, "false");

	setTimeout("icones.refreshCones();",500);
}
/**
 * Function to get the value of the selected radio button in a set.
 */
function getCheckedValue(radioObj){
	if(!radioObj)
		return "";
	var radioLength = radioObj.length;
	if(radioLength == undefined)
		if(radioObj.checked)
			return radioObj.value;
		else
			return "";
	for(var i = 0; i < radioLength; i++) {
		if(radioObj[i].checked) {
			return radioObj[i].value;
		}
	}
	return "";
}
/**
 * Helper function to change the display of a div tag.  Primarily used to show/hide history.
 */
function divDisplay(id,mainid){
	var current=document.getElementById(id).style.display;
	if (current=="none"){
		document.getElementById(id).style.display = 'block';
		document.getElementById(mainid).innerHTML='<img src="images/close.bmp" />';
	} else{
		document.getElementById(id).style.display = 'none';
		document.getElementById(mainid).innerHTML='<img src="images/expand.bmp" />';
	}
	current="";
}
/**
 * Wrapper Function for XMLHttpRequests, i.e. downloading pages.
 * @param {Callback} onload The function to execute when the readyState is 4, (responseText, status)
 */
function xhr(url, onload){
	var a=GXmlHttp.create();
	if(!a){
		alert('Oops.  There was an error initializing an XMLHttpRequest object for an asynchronous download.');
		return null;
	}
	a.onreadystatechange = function(){
		if(a.readyState==4){
			onload(a.responseText, a.status);
		}
	};
	a.open('get',url,true);
	a.send(null);
	return a;
}
/**
 * Function to handle setting the selected values in the config tab for an iCone.  Including whether or not the "private"
 * radio button is available.
 * @param {String} deployType The value of the selected item in the drop-down list of available icons.
 * @param {String} visibility The original setting for the public/private radio button
 * @param {Boolean} force Whether or not to force the selection of public when disableing private.
 */
function setConfig(deployType,visibility,force){
	if(force!=true) force=false;
	var dtDiv = document.getElementById("deployType");
	var privDiv = document.getElementById("private");
	var pubDiv = document.getElementById("public");
	
	if (dtDiv!=null && dtDiv.value!=deployType){
		dtDiv.value=deployType;
	}
	
	if (privDiv!=null && pubDiv!=null){
		if(deployType=="construction"){
			privDiv.disabled=true;
			if(force)	pubDiv.checked='checked';
			else {
				if(visibility=="private")
					privDiv.checked='checked';
				else
					pubDiv.checked='checked';
			}
		} else {
			privDiv.disabled=false;
			if(visibility=="private")
				privDiv.checked='checked';
			else
				pubDiv.checked='checked';
		}
	}
}
/**
 * Click a specified button, when hitting the enter key from within  a Input element.
 */
function keyPressed(event, btnID){
	if (typeof event == 'undefined'){
		event = window.event;
	}
	if(event.keyCode==13 && btnID!=null){
		document.getElementById(btnID).click();
	}
}
/**
 * Switch the display of an element, changing the button image as necissary, and optionally focusing on an Input element.
 */
function switchDisplay(divID, btnID, openImg, closedImg, focusID){
	var box = document.getElementById(divID);
	var btn = document.getElementById(btnID);
	if(box!=null){
		box.style.display = box.style.display!='none'?'none':'block';
		btn.src = box.style.display!='none'?openImg:closedImg;
	} else {
		btn.src.indexOf(openImg)==-1?openImg:closedImg;
	}
	if(focusID!=null){
		var toFocus = document.getElementById(focusID);
		if(toFocus.focus && toFocus.parentNode.style.display!='none'){
			toFocus.focus();
		}
	}
}
/**
 * Force the display of an element.  If if the element is hidden, click the controlling img.
 */
function showDisplay(divID, btnID){
	var box = document.getElementById(divID);
	if(box.style.display=='none'){
		var btn = document.getElementById(btnID);
		if(btn!=null && btn.onclick) btn.onclick();
	}
}
/**
 * Force the hiding of an element.  If if the element is shown, click the controlling img.
 */
function hideDisplay(divID, btnID){
	var box = document.getElementById(divID);
	if(box.style.display=='block'){
		var btn = document.getElementById(btnID);
		if(btn!=null && btn.onclick) btn.onclick();
	}
}

/**
 * A GControl that displays a "loading..." image onto the map.
 */
function LoadingControl(){
};
LoadingControl.prototype = new GControl();
LoadingControl.prototype.initialize = function(map){
	var container = document.createElement("div");
	var img = document.createElement("img");
	img.src="images/loading.png";
	container.appendChild(img);
	map.getContainer().appendChild(container);
	return container;
};
LoadingControl.prototype.getDefaultPosition = function(){
	return new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(25,30));
};
/**
 * A GControl that displays the "DISCLAIMER" link on the map.
 */
function disclaimerCtrl(){
};
disclaimerCtrl.prototype = new GControl(true, false);
disclaimerCtrl.prototype.initialize = function(map){
	var container = document.createElement("div");
	container.id="disclaimer";
	map.getContainer().appendChild(container);
	
	container.style.fontSize="11px";
	container.style.fontWeight="bold";
	container.style.color="#0040A0";
	container.style.cursor="pointer";
	
	container.innerHTML = "DISCLAIMER";
	container.onclick = this.onClickEvent
	
	return container;
};
disclaimerCtrl.prototype.getDefaultPosition = function() {
	return new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(5,15));
};
disclaimerCtrl.prototype.onClickEvent = function() {
	return popup("disclaimer.html", 'Disclaimer', 550, 425, 1, 'true');
};
/**
 * A GControl that displays the Legend on the map
 */
function legendCtrl(){
};
legendCtrl.prototype = new GControl(true, false);
legendCtrl.prototype.initialize = function(map){
	this.container = document.createElement("div");
	map.getContainer().appendChild(this.container);
	this.container.id="legend";
	this.container.style.width="100%";
	this.container.innerHTML = "<img src=\"images/HLegend-conditions.png\" />";
	return this.container;
};
legendCtrl.prototype.getDefaultPosition = function() {
	return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(0,15));
};
/**
 * A GControl that contains an emergency stop button
 */
function panicCtrl(){
};
panicCtrl.prototype = new GControl(true, false);
panicCtrl.prototype.initialize = function(map){
	var container = document.createElement("div");
	container.id = "CMSactive";
	map.getContainer().appendChild(container);
	
	container.style.width="100px";
	container.style.height="55px";
	container.style.border="2px solid black";
	container.style.color="black";
	container.style.fontWeight="bold";
	container.style.cursor="pointer";
	
	container.onclick = this.onClickEvent;
	
	container.style.backgroundColor="white";
	container.innerHTML = "MANAGE PROJECT PCMSs";
	return container;
};
panicCtrl.prototype.getDefaultPosition = function() {
	return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(8,40));
};
panicCtrl.prototype.onClickEvent = function(){
	var link="pcmsControl.aspx?tzOffset="+((new Date()).getTimezoneOffset()/-60);
	popup(link, "pcmsControl", 500, 600, 1, "true");
};
/**
 * A GControl that displays an img button inside of a new div element, that when clicked will call the
 *	switchDisplay function and resize the map.
 *
 * @constructor
 * @param {Object} opts The optional parameters for this object.
 *	{String} wrapID The id for the wrapper div
 *	{String} wrapClass The CSS class for the wrapper div style
 *	{String} btnIDThe id for the button
 *	{String} btnClass The CSS class for the button style
 *	{String} ctrlDiv The ID of the container to control
 *	{String} openImg Location of image to display when ctrlDiv is open, or does not exist
 *	{String} closeImg Location of image to display when ctrlDiv is closed
 *	{GControlAnchor} anchor The anchor constant for the location of this GControl
 *	{GSize} offset The offset from the anchor
 */
function btnCtrl(opts){
	this._opts = opts;
};
btnCtrl.prototype = new GControl(true, false);
btnCtrl.prototype.initialize = function(map){
	var opts = this._opts;

	var wrapper = document.createElement("div");
	map.getContainer().appendChild(wrapper);
	if(opts.wrapID!=null)		wrapper.id=opts.wrapID;
	if(opts.wrapClass!=null)	wrapper.className=opts.wrapClass;
	
	var btn = wrapper.appendChild(document.createElement("img"));
	btn.title="Expand/Close";
	btn.alt="Button Control Button";
	if(opts.btnID!=null)		btn.id=opts.btnID;
	if(opts.btnClass!=null)		btn.className=opts.btnClass;
	if(opts.ctrlDiv!=null && opts.btnID!=null && opts.openImg!=null && opts.openImg!=null){
		btn.onclick = function() {
			switchDisplay(opts.ctrlDiv, opts.btnID, opts.openImg, opts.closedImg);
			map.checkResize();
		};
	}
	
	var ctrlDiv = document.getElementById(opts.ctrlDiv)
	if (ctrlDiv!=null && ctrlDiv.style.display=="none"){
		btn.src = opts.closedImg;
	} else {
		btn.src = opts.openImg;
	}
	
	return wrapper;
};
btnCtrl.prototype.getDefaultPosition = function() {
	return new GControlPosition(this._opts.anchor, this._opts.offset);
};
/**
 * Control containing an entry box to quickly go to a specific map location.
 */
function gotoLocCtrl(){
}
gotoLocCtrl.prototype = new GControl(true, false);
gotoLocCtrl.prototype.initialize = function(map){
	var geocoder = new GClientGeocoder();

	var container = document.createElement("div");
	container.style.position="relative";
	container.style.height="16px";
	
	var expand = container.appendChild(document.createElement("img"));
	expand.id = "gotoLocShowHide";
	expand.className = "btn";
	expand.src = "images/doubleArrow-Left.png";
	expand.title = "Show/Hide Location Search";
	expand.alt = "Show/Hide Location Search";
	expand.style.position="absolute";
	expand.style.left="-17px";
	expand.style.top="3px";
	expand.onclick = function(){
		switchDisplay("gotoLocWrapper", "gotoLocShowHide", "images/doubleArrow-Right.png", "images/doubleArrow-Left.png","gotoLocEntry");
	};
	
	var wrapper = container.appendChild(document.createElement("span"));
	wrapper.id = "gotoLocWrapper";
	wrapper.style.display="none";
	
	var entry = document.createElement("input");
	entry.type="text";
	entry.id="gotoLocEntry";
	entry.size="30";
	entry.onkeydown = function(){ keyPressed(event, 'gotoLocBtn'); };
	
	var btn = document.createElement("input");
	btn.type="button";
	btn.id="gotoLocBtn";
	btn.value="Go To Location";
	btn.onclick=function (){
		geocoder.getLocations(entry.value, function(response){
			if(!response || response.Status.code!=200){
				alert("Unable to Geocode the address entered");
				return;
			}
			expand.onclick();
			
			var place = response.Placemark[0];
			var bounds = new GLatLngBounds(	new GLatLng(place.ExtendedData.LatLonBox.south, place.ExtendedData.LatLonBox.west),
											new GLatLng(place.ExtendedData.LatLonBox.north, place.ExtendedData.LatLonBox.east)
										);
			
			var zoom = map.getBoundsZoomLevel(bounds);
			panAndZoom(place.Point.coordinates[0], place.Point.coordinates[1], zoom);
		});
	};
	
	wrapper.appendChild(btn);
	wrapper.appendChild(entry);
	
	map.getContainer().appendChild(container);
	
	return container;
};
gotoLocCtrl.prototype.getDefaultPosition = function() {
	return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(150, 5));
};

