// This function is used to create Ext JS Layout
function createLayout(){
	mapLayout = new Ext.Viewport({
		id: 'mapLayoutID',
		layout: 'border',
		renderTo: Ext.getBody(),
		items: layoutItems		
	});
}

//This function is associated with Google Maps initialization
function gmapLoad(){
	if (GBrowserIsCompatible()) {
		mapID = new GMap2(Ext.getCmp('mapPanel').body.dom);
		mapExtension = new esri.arcgis.gmaps.MapExtension(mapID); //for esri
		mapID.setCenter(new GLatLng(centerx, centery), initialLevel);
		mapID.addControl(mapDragZoom);  	
		mapID.addControl(new logoCopyRight(logoImage));	
		
		mapID.addMapType(VE_NORMAL_MAP);
		mapID.addMapType(VE_SATELLITE_MAP);
		mapID.addMapType(VE_HYBRID_MAP);
		mapID.addMapType(OSM_NORMAL_MAP);
		
		geocoderClient = new GClientGeocoder();

		GEvent.addListener(mapID,"maptypechanged", function() { 
			var tempMapType = mapID.getCurrentMapType();
			if ( tempMapType == VE_NORMAL_MAP || tempMapType == VE_SATELLITE_MAP || tempMapType == VE_HYBRID_MAP) {
				var imgElements = document.getElementsByTagName("img");
				for (i = 0; i < imgElements.length; i++ ) {
        			if (imgElements[i].src.search(/poweredby/) != -1){
						imgElements[i].src = 'img/poweredby.png';
					} 
    			}
			}
			else {
				var imgElements = document.getElementsByTagName("img");
				for (i = 0; i < imgElements.length; i++ ) {
        			if (imgElements[i].src.search(/poweredby/) != -1){
						imgElements[i].src = 'http://maps.google.com/intl/en_ALL/mapfiles/poweredby.png';
					} 
    			}				
				
			}
			
		}); 
		
		gmapNavControl =new GSmallMapControl();
		mapID.addControl(gmapNavControl);
		GEvent.addListener(mapID,"mousemove", function(point) {        	
			coords = "Lat : " + point.y.toFixed(6) + ", Lng : " + point.x.toFixed(6);
			coordinateBar.setStatus(coords);
        });
        
		Ext.getCmp('mapPanel').on("resize", checkGMapResize);
		
        featureTable_ = document.getElementById("featuretbody");
    	select("hand_b"); 
	}
}

//This function is added to recover DIV problems of Map container for IE.
function checkGMapResize(){
	mapID.checkResize();	
}

// This function changes the Google Maps / Virtual Earth and Open Street Map base maps
function changeBaseMap(btn){
	mapID.setMapType(btn.maptype);
}

// This function open/close the measurement tool
function shiftMeasure(param1) {
	if (param1 == 1) {
			removeMeasureLayers();
			Ext.get('measurementTool').setVisible(false);
	}
	else {			
		if (measureWindow.isVisible() == false) {
			mX = Ext.getCmp('mapPanel').getPosition();
			Ext.getCmp('measureWindowID').setPosition(mX[0] + 6, mX[1] + 6);
			Ext.get('measurementTool').setVisible(true); 
			measureWindow.setAnimateTarget(Ext.getCmp('tbarMeasureButton').getEl()); 
			measureWindow.show();
		}
		else { 
			removeMeasureLayers();
			measureWindow.hide();
		}
	}
}

//This function removes the lines/polygons drawn by measurement tool
function removeMeasureLayers(){
	for (i=0; i < measureLayers.length; i++){
		if (measureLayers[i][1] == 0) {
			mapID.removeOverlay(measureLayers[i][0]);
			measurelayerID--;
		}
	}
	
    var table = document.getElementById('featuretable'); 
    var rows = table.rows; 
    while(rows.length) 
        table.deleteRow(rows.length-1);
    lineCounter_ = 0;
	shapeCounter_ = 0;
	colorIndex_ = 0;    
}

//This function is used to create layer tree from dataTree.json 
function createLayerTree(){
	layerTree = new Ext.tree.TreePanel({
		renderTo:'treeViewAccordion',
		loader: layerTreeLoader,
		root: layerTreeRootNode
	});
	layerTree.expandAll();
	layerTree.on('checkchange', addRemoveLayer);
	layerTree.on('append', function(tree, parent, node, xindex) { layerTreeIndex = node.attributes.id; });
	layerTree.on('contextMenu', layerTreeContextHandler);
}	

//This function is a listener for Layer Tree Context Menu
function layerTreeContextHandler(node) {
	node.select();
	if (node.attributes.serviceType == 2 || node.attributes.serviceType == 3)
		layerTreeContextMenuAGS.show(node.ui.getAnchor());
	else
		layerTreeContextMenuOther.show(node.ui.getAnchor());
} 

//This function adds layer to map or removes layer from the map according to its layer type via layer tree checkboxes 
function addRemoveLayer (node,checked){ 
	layerID = node.attributes.id;
	layType = node.attributes.serviceType;
	if (checked == true) {
		if (layType == 1) { //tile service için		
			tileLayers[layerID] = new GTileLayer(copyrightColl, 0, 21); 
			tileLayers[layerID].getTileUrl = function(tile, zoom){
				return node.attributes.serviceUrl + zoom + '/' + tile.x + '/' + tile.y + '.png';
			};
			tileLayers[layerID].isPng = function(){
				return true;
			};
			tileLayers[layerID].getOpacity = function(){
				return (node.attributes.layerTp / 10);
			}
			
			mapLayers[layerID] = new Array(2);
			mapLayers[layerID][0] = new GTileLayerOverlay(tileLayers[layerID]);
			mapLayers[layerID][1] = 1; //tile layer
		}
		else if (layType == 2) { //ArcGIS Server Dynamic Service
			var urlText = node.attributes.serviceUrl;
			urlText.search(/MapServer/);
			var mapUrl = urlText.substr(0,urlText.search(/MapServer/)+9);
			var layID = urlText.substr(urlText.search(/MapServer/)+10,1);
			var imageParams = new esri.arcgis.gmaps.ImageParameters();
      		imageParams.layerIds = [layID];
			mapLayers[layerID] = new Array(2);
			mapLayers[layerID][0] = new esri.arcgis.gmaps.DynamicMapServiceLayer(mapUrl, imageParams, node.attributes.layerTp / 10, null);
			mapLayers[layerID][1] = 2; //dynamic layer			
		}
		else if (layType == 3) { //ArcGIS Server Tile Service
			var urlText = node.attributes.serviceUrl;
			urlText.search(/MapServer/);
			var mapUrl = urlText.substr(0,urlText.search(/MapServer/)+9);

			tileLayers[layerID] = new GTileLayer(copyrightColl, 0, 21); 
			tileLayers[layerID].getTileUrl = function(tile, zoom){
				return mapUrl + '/tile/' + zoom + '/' + tile.y + '/' + tile.x;
			};
			tileLayers[layerID].isPng = function(){
				return true;
			};
			tileLayers[layerID].getOpacity = function(){
				return (node.attributes.layerTp / 10);
			}
			
			mapLayers[layerID] = new Array(2);
			mapLayers[layerID][0] = new GTileLayerOverlay(tileLayers[layerID]);
			mapLayers[layerID][1] = 3; //Arcgis tile 				
		}		
		else if (layType == 4) { //wms tile layer			
			
			tileLayers[layerID] = new GTileLayer(copyrightColl, 0, 21); 
			tileLayers[layerID].myFormat = 'image/png';
			tileLayers[layerID].myBaseURL = node.attributes.serviceUrl;
			tileLayers[layerID].myVersion = '1.1.1';
			tileLayers[layerID].getTileUrl = CustomGetTileUrl;
			tileLayers[layerID].getOpacity = function(){
				return (node.attributes.layerTp / 10);
			}			
			
			mapLayers[layerID] = new Array(2);
			mapLayers[layerID][0] = new GTileLayerOverlay(tileLayers[layerID]);
			mapLayers[layerID][1] = 4; //wms tile layer
		}
		else if (layType == 5) { //kml-georss service için			
			mapLayers[layerID] = new Array(2);
			mapLayers[layerID][0] = new GGeoXml(node.attributes.serviceUrl);
			mapLayers[layerID][1] = 5; //kml-georss layer			
		}
		mapID.addOverlay(mapLayers[layerID][0]);
	}
	else {
		mapID.removeOverlay(mapLayers[layerID][0]);	
	} 
}

//This function open/close the service window
function openCloseServiceWindow() {	
	if (serviceWindow.isVisible() == false) {
		mX = Ext.getCmp('mapPanel').getPosition();
		Ext.getCmp('serviceWindowID').setPosition(mX[0] + 260, mX[1] + 6);
		serviceWindow.setAnimateTarget(Ext.getCmp('tbarAddDataButton').getEl());
		serviceWindow.show();
	}
	else 
		serviceWindow.hide();
}

//This function adds the service to the layer tree, it does not add it to the map!
function addServiceToMap(){
	if (serviceNameTextbox.getValue() != '' && serviceUrlTextbox.getValue() != '' && serviceTypeCombobox.getValue()) {
		layerTreeIndex++;
		var tempText = {id: layerTreeIndex, text: serviceNameTextbox.getValue(), leaf: true, serviceUrl: serviceUrlTextbox.getValue(), serviceType: serviceTypeCombobox.getValue(), layerTp: 5, checked: false};
		var newNode = new Ext.tree.TreeNode(tempText);

		layerTree.getRootNode().appendChild(newNode);
		statusBar.setStatus('<b>Last action:</b> New service <i>'+ serviceNameTextbox.getValue() + '</i> is added to layer tree');		
		if (serviceTypeCombobox.getValue() == 2 || serviceTypeCombobox.getValue() == 3)
			prepareGridOptions(layerTreeIndex, serviceUrlTextbox.getValue());
		serviceWindow.hide();
		serviceFormPanel.getForm().reset();
	}  
}

//This function removes the layer from the tree, it also removes it from the map if the layer is checked.
function deleteLayerTreeNode(){
	var delNode = layerTree.selModel.selNode;
	statusBar.setStatus('<b>Last action:</b> Service <i>'+ delNode.attributes.text + '</i> is deleted.');
	if (delNode.attributes.checked == true) {
		addRemoveLayer(delNode, false);
	}
	layerTree.selModel.selNode.parentNode.removeChild(delNode);
}

function setLayerTransparency(){
	Ext.getCmp('layerSlider').setValue(layerTree.selModel.selNode.attributes.layerTp);
}

//This function opens the layer info window
function openLayerInfoWindow(){ 
	layerNameLabel.setValue(layerTree.selModel.selNode.attributes.text); 
	layerTypeLabel.setValue(serviceTypes.getAt(layerTree.selModel.selNode.attributes.serviceType-1).get('serviceType')); 
	layerUrlLabel.setValue(layerTree.selModel.selNode.attributes.serviceUrl);	
	layerInfoWindow.setAnimateTarget(Ext.get('animationPoint'));
	layerInfoWindow.show();
	setTimeout("setLayerTransparency();",1000);
	
	if (layerTree.selModel.selNode.attributes.serviceType == 2 || layerTree.selModel.selNode.attributes.serviceType == 3){			
		layerOptionsForm.setHeight(350);
		layerFieldDataStore.proxy.conn.url = proxyFile + '?' + layerTree.selModel.selNode.attributes.serviceUrl + '%3Ff=json';
		layerFieldDataStore.load();
		layerFieldGrid.show();
	}
}

//This function applies the new layer transparency value which can be taken from the layer info window.
function changeLayerOptions(){
	var selNode = layerTree.selModel.selNode;
	selNode.attributes.layerTp = Ext.getCmp('layerSlider').getValue();
	if (selNode.attributes.checked == true) {
		addRemoveLayer(selNode, false);
		addRemoveLayer(selNode, true);
	}
	layerFieldGrid.hide();
	layerInfoWindow.hide();
	layerOptionsForm.setHeight(170);
}

//This function applies the new Google Map options from "options" window.
function applyGmapSettings(){
	var navCmb = gmapNavCombobox.getValue();
	var scaleCmb = gmapScaleCombobox.getValue(); 
	var overviewCmb = gmapOverviewCombobox.getValue();
	var wheelZoomCmb = gmapWheelZoomCombobox.getValue();
	var contZoomCmb = gmapContZoomCombobox.getValue();
	
	if (navCmb == 'no'){
		mapID.removeControl(gmapNavControl);
	}
	else {
		mapID.removeControl(gmapNavControl);
		gmapNavControl = eval(navCmb); 
		mapID.addControl(gmapNavControl);
	}
	if (scaleCmb == 'no'){
		mapID.removeControl(gmapScaleControl);
	}
	else {
		mapID.removeControl(gmapScaleControl);
		gmapScaleControl = eval(scaleCmb); 
		mapID.addControl(gmapScaleControl);
	}	
	if (overviewCmb == 'no'){
		mapID.removeControl(gmapOverviewControl);
	}
	else {
		mapID.removeControl(gmapOverviewControl);
		gmapOverviewControl = eval(overviewCmb); 
		mapID.addControl(gmapOverviewControl);
	}	
	if (wheelZoomCmb == 'no'){
		mapID.disableScrollWheelZoom();
	}
	else {
		mapID.enableScrollWheelZoom();
	}		
	if (contZoomCmb == 'no'){
		mapID.disableContinuousZoom();
	}
	else {
		mapID.enableContinuousZoom();
	}
	configureWindow.hide();	
}

//This function is used to identify the map objects and it is associated with the Identify button at top toolbar.
function doSelection(maxPoint,minPoint){
	shapeFieldStatus = true;
	var selectedNode = layerTree.selModel.selNode;
	if (selectedNode != null) {	
		var selID = selectedNode.attributes.id;
		lastIdentifiedLayerID = selID;
		if (selectedNode.attributes.serviceType == 2 || selectedNode.attributes.serviceType == 3) {
			statusBar.showBusy('Processing - Getting Selected Objects');
			geomText = minPoint.lng()+','+minPoint.lat()+','+maxPoint.lng()+','+maxPoint.lat();
			var queryUrl = proxyFile + '?' + selectedNode.attributes.serviceUrl + '/query%3Fgeometry=' + geomText
							+ '&geometryType=esriGeometryEnvelope&inSR=4326&spatialRel=esriSpatialRelIntersects&returnGeometry=true&outSR=4326&outFields=*&f=json';
			
			lastKMLUrl = selectedNode.attributes.serviceUrl + '/query?geometry=' + geomText + '&geometryType=esriGeometryEnvelope&inSR=4326&spatialRel=esriSpatialRelIntersects&returnGeometry=true&outSR=4326&outFields=*&f=kmz'; 
			prepareDataGrid (queryUrl,selectedNode.attributes.text, selID);						
		}
		else {
			Ext.Msg.alert('Alert','Layer must be an ArcGIS Server Layer');
		}
	}
	else {
		Ext.Msg.alert('Alert','Please select a layer from tree');
	}
}

//This function is a generic function that can be used for any ArcGIS Server REST API which returns map items in grid.
//It takes 3 parameters. queryUrl is the REST API url, nameLabelValue is the label of grid window. The last one
//is selID which refers to the selection in layer tree. This selID is used to get column model for each layer.
//Column model for each layer is created at the initialization of layer tree with prepareTreeGridOptions() and 
//at the creation of each layer via add service tool with prepareGridOptions()
function prepareDataGrid (queryUrl, nameLabelValue, selID){
	var attWindowlayerNameLabel = new Ext.form.TextField({id:'attWindowlayerNameID', name:'attWindowlayerNameName',fieldLabel: 'Layer Name', width:230, readOnly: true });
	attWindowlayerNameLabel.setValue(nameLabelValue);
	if (shapeFieldStatus == true)
		var attWindowOptionGridColumns =  new Ext.grid.ColumnModel(agsLayerColumns[selID]);
	else 
		var attWindowOptionGridColumns =  new Ext.grid.ColumnModel(agsLayerColumnsWS[selID]);
	if (shapeFieldStatus == true)
		var attWindowFieldDataReader = new Ext.data.JsonReader({fields: agsLayerFields[selID],root: 'features'});
	else
		var attWindowFieldDataReader = new Ext.data.JsonReader({fields: agsLayerFieldsWS[selID],root: 'features'});
	
	var attWindowFieldDataProxy = new Ext.data.HttpProxy({url: queryUrl });
	attWindowFieldDataStore = new Ext.data.Store({reader: attWindowFieldDataReader, proxy: attWindowFieldDataProxy, listeners:{load : function(){ 
			statusBar.clearStatus();
			statusBar.setStatus('Ready - Total Records Fetched : ' + this.getCount());
		}}	
	});
	attWindowFieldDataStore.load();	
	attWindowGrid = new Ext.grid.GridPanel({ cm: attWindowOptionGridColumns, ds: attWindowFieldDataStore, loadMask:true, height: 300, listeners:{rowclick:attGridRowClick}, tbar:[{text: 'Export as KML', cls: 'x-btn-text-icon', icon: 'img/gearth.gif', handler: function(){ window.open(lastKMLUrl,null,'left=20,top=20,width=600,height=500,toolbar=no,resizable=yes,scrollbars=yes'); } },{text: 'Clear Map', cls: 'x-btn-text-icon', icon: 'img/delicon.gif', handler: function(){ removeItemsFromMaps(); } },{text: 'Zoom to Selected', cls: 'x-btn-text-icon', icon: 'img/zoom-in.gif', handler: function(){ zoomToMapObject(); } }]});
	var attWindowForm = new Ext.form.FormPanel({ frame:true, width: 520, height: 340,
		defaults: {labelSeparator:':', hideLabel:false},
		items: [attWindowlayerNameLabel, attWindowGrid]
	});
		
	if (tempWindowItem != null) attributeWindow.remove(tempWindowItem, true);		
	tempWindowItem = attributeWindow.insert(0,attWindowForm);
	
	attributeWindow.setAnimateTarget(Ext.get('animationPoint'));
	//attributeWindow.setAnimateTarget(Ext.getCmp('tbarQueryButton')); 
	
	if (attributeWindow.isVisible()) {
		attributeWindow.doLayout();
		attributeWindow.focus();
	}
	else {
		attributeWindow.show();
		attributeWindow.focus();
	}	
}

//This function creates the variables for the layer properties to use them in other functions.
//Layer extent, Layer SRID, layer column model (with and without shapes), field model (with and without shapes)
//are created with this function.
function prepareGridOptions(sentlayerID, layerUrl){
	var sentlayerx = sentlayerID;
	var fieldAliases;
	var fieldArr = new Array();
	var colArr = new Array();
	var queryArr = new Array();
	var layerExtent;
	var extentArr = new Array();
	var fieldArrWS = new Array();
	var colArrWS = new Array();	
	statusBar.showBusy('Processing - Getting Layer Properties');
	Ext.Ajax.request({
		url: proxyFile + '?' + layerUrl + '%3Ff=json',
		success: function(result){		    			
			if(result.responseText != ''){
				var jsonData = Ext.util.JSON.decode(result.responseText);
				fieldAliases = jsonData.fields;
				layerExtent = jsonData.extent;
				esriGeomTypeArr[sentlayerx] = jsonData.geometryType;
			    var i = 0;
				
				for (var key in fieldAliases){	
					i++;
					if (fieldAliases[key].name === undefined) {} 
					else {
						if (fieldAliases[key].name != ''){
							fieldArr.push('attributes.' + fieldAliases[key].name);
							queryArr.push([fieldAliases[key].name]);
							colArr.push({
								header: fieldAliases[key].name,
								dataIndex: 'attributes.' + fieldAliases[key].name
							});

							var tmpField = fieldAliases[key].name.toString();
	                		if (tmpField.search(/shape/i) == -1){
	                			fieldArrWS.push('attributes.' + fieldAliases[key].name);
								colArrWS.push({
									header: fieldAliases[key].name,
									dataIndex: 'attributes.' + fieldAliases[key].name
								});
	                		}							
						}
					}
			    }	    
			   extentArr[0] = layerExtent.xmin;
			   extentArr[1] = layerExtent.ymin;
			   extentArr[2] = layerExtent.xmax;
			   extentArr[3] = layerExtent.ymax;
			   extentArr[4] = layerExtent.spatialReference.wkid;		   								
			}
			agsLayerFields[sentlayerx] = fieldArr;
			agsLayerColumns[sentlayerx] = colArr;
			agsQueryFields[sentlayerx] = queryArr;
			agsLayerExtents[sentlayerx] = extentArr;			
			agsLayerFieldsWS[sentlayerx] =  fieldArrWS; //without shapes
			agsLayerColumnsWS[sentlayerx] = colArrWS; //without shapes
			statusBar.clearStatus();
			statusBar.setStatus('Ready');
		},
		failure:function(result){
			console.log('There is a problem, please try again later!');
		}
		}); 
}

//This function called at the initialization of layer tree to create layer variables via prepareGridOptions() function.
function prepareTreeGridOptions(){
	layerTreeRootNode.eachChild(function (node, v) {
			var layType = node.attributes.serviceType;
			if (layType == 2 || layType == 3) {
				prepareGridOptions(node.attributes.id, node.attributes.serviceUrl);
			}
    	}, null, null);		
}

//This function listens the data grid for row click
function attGridRowClick(grid, row, e){
	if (shapeFieldStatus == true) {
		var layerType = esriGeomTypeArr[lastIdentifiedLayerID];	
		addItems2Map(layerType, attWindowFieldDataStore.data.items[row].json.geometry);
	}
	else {
		Ext.Msg.alert('Alert','Shape displaying is disabled, please try identify or query windows to see shapes on map!');
	}
	
}

//This function add selected item from data grid to map
function addItems2Map(layerType, xgeom){
	statusBar.showBusy('Processing - Adding Items to the Map');
	xPoints = new Array();
	
	if (layerType == 'esriGeometryPoint'){
		xPoints[0] = new GLatLng(xgeom.y,xgeom.x);
		addedMapItems[addItemsCount] = new GMarker(xPoints[0]);
		mapID.addOverlay(addedMapItems[addItemsCount]);
		addItemsCount++;
	}
	else if (layerType == 'esriGeometryPolyline'){
		var totalPaths = xgeom.paths.length;
		for (j=0; j < totalPaths; j++){
			var pathln = xgeom.paths[j].length;
			for (i=0; i < pathln; i++){
				xPoints[i] = new GLatLng(xgeom.paths[j][i][1],xgeom.paths[j][i][0]);
			}
			addedMapItems[addItemsCount] = new GPolyline(xPoints, "#ff0000", 5);
			mapID.addOverlay(addedMapItems[addItemsCount]);
			addItemsCount++;
		}
	}
	else if (layerType == 'esriGeometryPolygon'){
		var totalRings = xgeom.rings.length;
		for (j=0; j < totalRings; j++){
			var ringln = xgeom.rings[j].length;
			for (i=0; i < ringln; i++){
				xPoints[i] = new GLatLng(xgeom.rings[j][i][1],xgeom.rings[j][i][0]);		
			}
			addedMapItems[addItemsCount] = new GPolygon(xPoints, "#f33f00", 5, 1, "#ff0000", 0.2);
			mapID.addOverlay(addedMapItems[addItemsCount]);
			addItemsCount++;			
		}
	}
	else {
		Ext.Msg.alert('Error','Unknown Geometry Type');		
	}
	statusBar.clearStatus();
	statusBar.setStatus('Ready');
}

//This function removes the added items from the map.
function removeItemsFromMaps(){
	statusBar.showBusy('Processing - Removing Items from the Map');
	for (i=0; i < addItemsCount; i++){
		mapID.removeOverlay(addedMapItems[i]);	
	}
	addItemsCount = 0;
	statusBar.clearStatus();
	statusBar.setStatus('Ready');	
}

//This function zooms to selected item on the map.
function zoomToMapObject(){
	if (shapeFieldStatus == true) {
		var layerType = esriGeomTypeArr[lastIdentifiedLayerID];
		var row = attWindowGrid.getSelectionModel().last;
		xgeom = attWindowFieldDataStore.data.items[row].json.geometry;
		var center;
		var zoomLevel;
		var tempGeoArray = new Array();
		
		if (layerType == 'esriGeometryPoint'){
			center = new GLatLng(xgeom.y,xgeom.x);
			zoomLevel = 16;
		}
		else if (layerType == 'esriGeometryPolyline'){
			var pathln = xgeom.paths[0].length;
			for (i=0; i < pathln; i++){
				tempGeoArray[i] = new GLatLng(xgeom.paths[0][i][1],xgeom.paths[0][i][0]);
			}
			var tempGeo = new GPolyline(tempGeoArray, "#ff0000", 5);
			center = tempGeo.getBounds().getCenter();		
			zoomLevel = mapID.getBoundsZoomLevel(tempGeo.getBounds());
		}
		else if (layerType == 'esriGeometryPolygon'){
			var ringln = xgeom.rings[0].length;
			for (i=0; i < ringln; i++){
				tempGeoArray[i] = new GLatLng(xgeom.rings[0][i][1],xgeom.rings[0][i][0]);		
			}
			var tempGeo = new GPolygon(tempGeoArray, "#f33f00", 5, 1, "#ff0000", 0.2);
			center = tempGeo.getBounds().getCenter();		
			zoomLevel = mapID.getBoundsZoomLevel(tempGeo.getBounds());
		}
		else {
			Ext.Msg.alert('Error','Unknown Geometry Type');		
		}
		
		mapID.setCenter(center);
	   	mapID.setZoom(zoomLevel);			
	}
	else {
		Ext.Msg.alert('Alert','Shape displaying is disabled, please try identify or query windows to see shapes on map!');
	}
	
}

//This function opens/closes the query window.
function openCloseQueryWindow(){
	var selectedNode = layerTree.selModel.selNode;
	if (selectedNode != null) {	
		var selID = selectedNode.attributes.id;
		lastIdentifiedLayerID = selID;
		if (selectedNode.attributes.serviceType == 2 || selectedNode.attributes.serviceType == 3) {
		
			selectedLayerID = selectedNode.attributes.id;	
			var layerAttGridColumns =  new Ext.grid.ColumnModel([{header:'Field Name', dataIndex: 'value', width:310}]);						
						
			var layerAttGridStore = new Ext.data.SimpleStore({
				fields: ['value'],
				data: agsQueryFields[selectedLayerID]
			});	
				
			var layerAttGrid = new Ext.grid.GridPanel({
				cm: layerAttGridColumns,
				ds: layerAttGridStore,
				height: 130,
				listeners:{celldblclick:layerAttGridDblClick, cellclick:layerAttGridClick}
			});
		
			fieldValueGridPanel = new Ext.Panel({width:220, height: 140});
		
			var queryLayerForm = new Ext.FormPanel({
				frame: true,
				title: 'Select By Attributes',
				width: 350,
				items: [
				{
					xtype: 'textfield',
					id : 'queryLayerName',
					fieldLabel: 'Layer Name',
					name: 'title'
				},
				layerAttGrid,						
				{
			      layout : "column",
			      items : [{
			          width : 35,
					  items:[{xtype: 'button', text:'=', handler: function(){ queryWindowButtonHandler('='); }}, 
					  		 {xtype: 'button', text:'>', handler: function(){ queryWindowButtonHandler('>'); }},
							 {xtype: 'button', text:'<', handler: function(){ queryWindowButtonHandler('<'); }}
					  ]
			      },        {
			          width : 45,
					  items:[{xtype: 'button', text:'<>', handler: function(){ queryWindowButtonHandler('<>'); }}, 
					  		 {xtype: 'button', text:'>=', handler: function(){ queryWindowButtonHandler('>='); }},
							 {xtype: 'button', text:'<=', handler: function(){ queryWindowButtonHandler('<='); }}
					  ]
			      },        {
			          width : 45,
					  items:[{xtype: 'button', text:'Like', handler: function(){ queryWindowButtonHandler('LIKE'); }}, 
					  		 {xtype: 'button', text:'And', handler: function(){ queryWindowButtonHandler('AND'); }},
							 {xtype: 'button', text:'Or', handler: function(){ queryWindowButtonHandler('OR'); }}
					  ]
			      },        {
			          width : 210,
					  items: [fieldValueGridPanel,{xtype: 'button', text:'Get Values', handler: function(){ layerAttGridValuesUpdate(); }}]
			      }]						
				},										
				{
					xtype: 'textarea',
					id:'queryArea',
					name: 'description',
					hideLabel: true,
					labelSeparator: '',
					height: 100,
					anchor: '100%'
				}												
				],
				buttons: [{
					text: 'Query',
					handler: function(){
						doQuery(Ext.getCmp('queryArea').getValue());
					}
				}, {
					text: 'Reset',
					handler: function(){
						queryLayerForm.getForm().reset();
					}
					}
				 ]
				});
				
				Ext.getCmp('queryLayerName').setValue(selectedNode.attributes.text);				
				if (tempQueryWindowItem != null) queryWindow.remove(tempQueryWindowItem, true);		
				tempQueryWindowItem = queryWindow.insert(0,queryLayerForm);				
				queryWindow.setAnimateTarget(Ext.getCmp('tbarQueryButton').getEl());				
				if (queryWindow.isVisible()) {
					queryWindow.doLayout();
					queryWindow.focus();
				}
				else {
					queryWindow.show();
					queryWindow.focus();
				}							
		}
		else {
			Ext.Msg.alert('Alert','Layer must be an ArcGIS Server Layer');
		}
	}
	else {
		Ext.Msg.alert('Alert','Please select a layer from tree');
	}											
}

//This function gets value of query buttons and adds its content to the query box.
function queryWindowButtonHandler(btnText){
	var queryText = Ext.getCmp('queryArea').getValue(); 
	if (queryText == '') queryText = btnText;
	else queryText = queryText + '' + btnText;
	Ext.getCmp('queryArea').setValue(queryText);
}

//This function gets the selected field in query window to get values later.
function layerAttGridClick( xgrid, xrowIndex, xcolumnIndex, xe ){		
	selectedFieldColumn = agsQueryFields[layerTree.selModel.selNode.attributes.id][xrowIndex];
} 

//This function gets value of field and adds its content to the query box.			
function layerAttGridDblClick( xgrid, xrowIndex, xcolumnIndex, xe ){	
	var queryText = Ext.getCmp('queryArea').getValue(); 
	if (queryText == '') queryText = agsQueryFields[layerTree.selModel.selNode.attributes.id][xrowIndex];
	else queryText = queryText + '' + agsQueryFields[layerTree.selModel.selNode.attributes.id][xrowIndex];
	Ext.getCmp('queryArea').setValue(queryText);
} 

//This function gets the value of selected field and adds its content to the query box.
function fieldValueGridDblClick( xgrid, xrowIndex, xcolumnIndex, xe ){
	if (selectedFieldColumn != '') {
		var tempVarText = 'fieldValueGridStore.data.items[xrowIndex].json.' + 'attributes.' + selectedFieldColumn;
		var queryText = Ext.getCmp('queryArea').getValue();
		if (queryText == '') 
			queryText = eval(tempVarText);
		else 
			queryText = queryText + '' + eval(tempVarText);
		Ext.getCmp('queryArea').setValue(queryText);
	}
} 

//This function gets the values of selected field. This function also has a bottleneck due to ArcGIS Server default row limit. (500)
//Due to this limit, it is not possible to get all values or filter the unique ones.	
function layerAttGridValuesUpdate(){
	if (selectedFieldColumn != '') {
		statusBar.showBusy('Processing - Getting Field Values');		
		var attUrl = proxyFile + '?' + layerTree.selModel.selNode.attributes.serviceUrl + '/query%3Fgeometry=-180,-90,180,90&geometryType=esriGeometryEnvelope&returnGeometry=false&outFields=' + selectedFieldColumn + '&inSR=4326&f=json';
		var fieldValueGridColumns = new Ext.grid.ColumnModel([{
			header: 'Field Value - ' + selectedFieldColumn,
			dataIndex: 'attributes.' + selectedFieldColumn,
			width: 180
		}]);
		var fieldValueGridReader = new Ext.data.JsonReader({
			fields: ['attributes.' + selectedFieldColumn],
			root: 'features'
		});
		var fieldValueGridProxy = new Ext.data.HttpProxy({
			url: attUrl
		});
		fieldValueGridStore = new Ext.data.Store({
			reader: fieldValueGridReader,
			proxy: fieldValueGridProxy,
			listeners: {
				load: function(){
					statusBar.clearStatus();
					statusBar.setStatus('Ready');
				}
			}
		});
		
		fieldValueGridStore.load();
		
		fieldValueGrid = new Ext.grid.GridPanel({
			cm: fieldValueGridColumns,
			ds: fieldValueGridStore,
			width: 210,
			height: 130,
			listeners: {
				celldblclick: fieldValueGridDblClick
			}
		});
		
		if (tempPanelItem != null) 
			fieldValueGridPanel.remove(tempPanelItem, true);
		
		tempPanelItem = fieldValueGridPanel.insert(0, fieldValueGrid);
		fieldValueGridPanel.doLayout();
	}
	else {
		Ext.Msg.alert('Warning','Please select a column from the grid above');
	}
}		

//This function does the query which gets its values from query window.
function doQuery(queryText){
	shapeFieldStatus = true;
	var encodedUrlPart = urlencode(queryText);
	var queryUrl = proxyFile + '?' + layerTree.selModel.selNode.attributes.serviceUrl + '/query%3FreturnGeometry=true&outFields=*&f=json&outSR=4326&where=' + encodedUrlPart;		
	lastKMLUrl = layerTree.selModel.selNode.attributes.serviceUrl + '/query?returnGeometry=true&outFields=*&f=kmz&outSR=4326&where=' + encodedUrlPart; 
	prepareDataGrid (queryUrl,layerTree.selModel.selNode.attributes.text, layerTree.selModel.selNode.attributes.id);						
}

//This function zooms to extents of ArcGIS layers.
function zoom2AGSLayer(){
	var geomServer = esriGeometryService;
	var selectedNode = layerTree.selModel.selNode;
	var tempCoords;
	if (selectedNode != null) {	
		var selID = selectedNode.attributes.id;
		if (selectedNode.attributes.serviceType == 2 || selectedNode.attributes.serviceType == 3) {			
			statusBar.showBusy('Processing - Zooming to Selected Layer');
			var swrid = agsLayerExtents[selID][4];
			var geoText = '{\"x\":' +  agsLayerExtents[selID][0] + ',\"y\":' + agsLayerExtents[selID][1] + '},' + 
						  '{\"x\":' +  agsLayerExtents[selID][2] + ',\"y\":' + agsLayerExtents[selID][3] + '}';
			
			var projectionUrl = proxyFile + '?' + geomServer + '/project%3FinSR=' + swrid + '&outSR=4326&f=json&geometries={\"geometryType\":\"esriGeometryPoint\",\"geometries\":[' + geoText + ']}';			
									  
			Ext.Ajax.request({
				url: projectionUrl,
				success: function(result){		    			
					if(result.responseText != ''){
						var jsonData = Ext.util.JSON.decode(result.responseText);
						tempCoords = jsonData.geometries;						
						var pointsw = new GLatLng(tempCoords[0].y,tempCoords[0].x);
						var pointne = new GLatLng(tempCoords[1].y,tempCoords[1].x);
						var layerBound = new GLatLngBounds(pointsw,pointne);						
						mapID.setCenter(layerBound.getCenter());
		   				mapID.setZoom(mapID.getBoundsZoomLevel(layerBound));				   								
					}
					statusBar.clearStatus();
					statusBar.setStatus('Ready');
				},
				failure:function(result){
					console.log('There is a problem, please try again later!');
				}
			}); 			
		}
		else {
			Ext.Msg.alert('Alert','Layer must be an ArcGIS Server Layer');
		}
	}
	else {
		Ext.Msg.alert('Alert','Please select a layer from tree');
	}	
	
}

//This function gets the attribute table of selected layer, but the full list cannot be taken from the server
//due to ArcGIS Server's default limitation (500 rows). This function is experimental because loading 500+ rows
//in a data grid make your browser slow. 
function getLayerAttributeTable(){
	shapeFieldStatus = false;
	var geomServer = esriGeometryService;
	var selectedNode = layerTree.selModel.selNode;
	if (selectedNode != null) {	
		var selID = selectedNode.attributes.id;
		if (selectedNode.attributes.serviceType == 2 || selectedNode.attributes.serviceType == 3) {
	        statusBar.showBusy('Processing - Getting Attribute');
			var fieldLength = agsQueryFields[selID].length;
	        var fields = '';
	        for (i=0; i < fieldLength; i++){
	                var tmpField = agsQueryFields[selID][i].toString();
	                if (tmpField.search(/shape/i) == -1){
	                	if (fields == '') fields = agsQueryFields[selID][i];
	                	else fields = fields + ',' + agsQueryFields[selID][i];
	                }
	        }			
			
			var geoText = 'geometry=' + agsLayerExtents[selID][0] + ',' + agsLayerExtents[selID][1] + ',' + agsLayerExtents[selID][2] + ',' + agsLayerExtents[selID][3] + '&geometryType=esriGeometryEnvelope';	
			var queryUrl = proxyFile + '?' + selectedNode.attributes.serviceUrl + '/query%3F' + geoText + '&returnGeometry=false&outFields=' + fields + '&f=json&outSR=4326';			
			lastKMLUrl = selectedNode.attributes.serviceUrl + '/query?' + geoText + '&returnGeometry=true&outFields=*&f=kmz&outSR=4326'; 
			prepareDataGrid (queryUrl,layerTree.selModel.selNode.attributes.text, selID);						
		}
		else {
			Ext.Msg.alert('Alert','Layer must be an ArcGIS Server Layer');
		}
	}
	else {
		Ext.Msg.alert('Alert','Please select a layer from tree');
	}	
}

//This function enables Google Street View
function getStreetView(){	
	if (mapID.getZoom() > 14){
		if (streetViewStatus == false){
			panoramaOptions = { latlng:mapID.getCenter() };
			streetViewWindow.setAnimateTarget(Ext.getCmp('tbarSVButton').getEl());
			streetViewWindow.show();		
			streetViewPano = new GStreetviewPanorama(streetViewWindow.body.dom, panoramaOptions);
			GEvent.addListener(streetViewPano, 'yawchanged', onStreetViewPanoYawChanged);
			GEvent.addListener(streetViewPano, 'initialized', onStreetViewPanoInitialized);
			GEvent.addListener(streetViewPano, 'error', onStreetViewPanoError);
			streetViewOverlay = new GStreetviewOverlay();
			mapID.addOverlay(streetViewOverlay);
			streetViewYaw = 90;
			streetViewLocation = mapID.getCenter();
			setStPanoMarker();	
			streetViewStatus =  true;
		}
		else {	
		}				
	}
	else {
		Ext.Msg.alert('Alert','Your zoom level is ' + mapID.getZoom() + '. <br>You should zoom to minimum level 15 to get Street View!');
	}
}

//This function is a listener for Street View to detect yaw changes.
function onStreetViewPanoYawChanged(stYaw){
	streetViewYaw = stYaw;
	setStPanoMarker();
}

//This function is a listener for Street View to detect errors.
function onStreetViewPanoError(errorCode){	
	if (errorCode ==600){
		Ext.Msg.alert('Alert','No Street View Panorama available at this location!');
		streetViewWindow.hide();
	}
}

//This function is a listener for Street View to detect marker dragend action.
function onStMarkerDragEnd(lastLocation){
	streetViewPano.setLocationAndPOV(lastLocation, {});
	streetViewLocation = lastLocation;
}

//This function is a listener for Street View to detect view changes.
function onStreetViewPanoInitialized(location) {
	streetViewLocation = location.latlng;
	streetViewYaw = location.pov.yaw;
	setStPanoMarker();
}

//This function is a listener for Street View to detect window hide.
function onStreetViewWindowHide(){
	streetViewPano.remove();
	mapID.removeOverlay(streetViewOverlay);
	mapID.removeOverlay(stMarker);
	stMarker = null;
	streetViewStatus = false;
}

//This function is used for Street View to sync marker in map according to Street View motions.
function setStPanoMarker(){
	streetViewYaw = wrapAngle(streetViewYaw);
	var stImageNum = Math.round(streetViewYaw / 22.5) % 16;
	var stImageUrl = 'http://maps.google.com/intl/en_us/mapfiles/cb/man_arrow-' + stImageNum + ".png";
	
	if (stMarker == null) {
		stIcon = new GIcon(G_DEFAULT_ICON);
		stIcon.iconSize = new GSize(49, 52);	
		stIcon.image = stImageUrl;
		stIcon.transparent = "http://maps.google.com/intl/en_us/mapfiles/cb/man-pick.png";
		stIcon.imageMap = [26, 13, 30, 14, 32, 28, 27, 28, 28, 36, 18, 35, 18, 27, 16, 26, 16, 20, 16, 14, 19, 13, 22, 8];
		stIcon.iconSize = new GSize(49, 52);
		stIcon.iconAnchor = new GPoint(25, 35); 
		stIcon.infoWindowAnchor = new GPoint(25, 5);	
		stMarker = new GMarker(streetViewLocation, {draggable: true, icon: stIcon});
		mapID.addOverlay(stMarker);
		mapID.panTo(streetViewLocation);
		GEvent.addListener(stMarker, 'dragend', onStMarkerDragEnd);	
	}
	else {
		stMarker.setImage(stImageUrl);
		stMarker.setLatLng(streetViewLocation);
		mapID.panTo(streetViewLocation);
	}	
}

//This function is a helper function to use in setStPanoMarker() function.
function wrapAngle (angle) {
	if (angle >= 360) {
		angle -= 360;
	} else if (angle < 0) {
		angle += 360;
	}
	return angle;
}

//This function is used to open or close the geocoding window.
function openCloseGeocodeWindow() {
	geocodeWindow.setAnimateTarget(Ext.get('animationPoint'));
	geocodeWindow.show();	
}

//This function is used to find addresses.
function findAddress(){
	addressTextFound = new Array();
	if (addressMarker != null)
		mapID.removeOverlay(addressMarker);
		geocoderClient.getLocations(addressField.getValue(), function (result){
		if (result.Status.code == G_GEO_SUCCESS) {
            for (i=0; i < result.Placemark.length; i++) {           
				addressPointFound[i] = result.Placemark[i].Point.coordinates;				
				addressTextFound.push([i+1, result.Placemark[i].address]);				
			}
			var geocodeGridColumns =  new Ext.grid.ColumnModel([{header:'ID', dataIndex: 'id', width:30},{header:'Address', dataIndex: 'value', width:310}]);											
			var geocodeGridStore = new Ext.data.SimpleStore({
				fields: ['id','value'],
				data: addressTextFound
			});					
			var geocodeGrid = new Ext.grid.GridPanel({
				cm: geocodeGridColumns,
				ds: geocodeGridStore,
				height: 130,
				listeners:{cellclick:geocodeGridClick}
			});				
			if (tempGeocodePanel != null){ 
				addressGridPanel.remove(tempGeocodePanel, true);
			}
			tempGeocodePanel = addressGridPanel.insert(0,geocodeGrid);	
			addressGridPanel.doLayout();		
		}
		else {
			var reason = "Code "+result.Status.code;
			if (geocodeReasons[result.Status.code]) {
                reason = geocodeReasons[result.Status.code]
			}
			Ext.Msg.alert('Alert','Could not find <i>\"' + addressField.getValue() + '\"</i><br>' + reason );  //alert('Could not find "'+search+ '" ' + reason);
			if (tempGeocodePanel != null){ 
				addressGridPanel.remove(tempGeocodePanel, true);
			}
		}
	});
}

//This function is used to catch the click on address results data grid.
function geocodeGridClick(xgrid, xrowIndex, xcolumnIndex, xe){
	if (addressMarker != null)
		mapID.removeOverlay(addressMarker);
	var point = new GLatLng(addressPointFound[xrowIndex][1],addressPointFound[xrowIndex][0]);
	mapID.setCenter(point,14); 
	addressMarker = new GMarker(point);
	mapID.addOverlay(addressMarker);
}

//This function is used to enable or disable the reverse geocoding tool.
function openCloseRevGeocodeWindow(){
	if(revGeoCodeStatus == false) {
		if(altitudeListener != null) openCloseAltitudeWindow();
		revGeoCodeListener = GEvent.addListener(mapID, "click", getAddress);
		revGeoCodeStatus = true;
		statusBar.clearStatus();
		statusBar.setStatus('Reverse Geocoding is enabled, please double click on its tree node to disable!');
		Ext.Msg.alert('Alert','Reverse geocoding is enabled, please click on map to get address. To disable, please double click on its name in toolbox tree!');
	}
	else {		
		GEvent.removeListener(revGeoCodeListener);
		revGeoCodeListener = null;
		revGeoCodeStatus = false;
		if (addressMarker != null)
			mapID.removeOverlay(addressMarker);
		statusBar.clearStatus();
		statusBar.setStatus('Last Action : Reverse Geocoding is disabled!');
	}
}

//This function gets the address for reverse geocoding.
function getAddress(overlay, latlng) {
  if (latlng != null) {
    address = latlng;
    geocoderClient.getLocations(latlng, showRevGeocodeResult);
  }
}

//This function is used to show result of reverse geocoding on the map.
function showRevGeocodeResult(response) {
	if (addressMarker != null)
		mapID.removeOverlay(addressMarker);
	if (!response || response.Status.code != 200) {
		Ext.Msg.alert('Alert','There is a problem with reverse geocoding!');
	} else {
		place = response.Placemark[0];
	    point = new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
	    addressMarker = new GMarker(point);
	    mapID.addOverlay(addressMarker);
	    addressMarker.openInfoWindowHtml(
	        '<span style=\'font-family:verdana; font-size:12px\'><b>Click Coordinates :</b>' + response.name + '<br/>' + 
	        '<b>Address Coordinates :</b>' + place.Point.coordinates[1] + "," + place.Point.coordinates[0] + '<br>' +
	        '<b>Address :</b>' + place.address + '<br>' +
	        '<b>Accuracy :</b>' + place.AddressDetails.Accuracy + '<br>' +
	        '<b>Country code :</b> ' + place.AddressDetails.Country.CountryNameCode + '</span>');
	  }
}

//This function shows the bookmark windows to get name of bookmark
function openBookmarkWindow(){
	Ext.Msg.prompt('Bookmarks', 'Give a name to bookmark :', function(btn, btnText){
	    if (btn == 'ok'){
			bookmarkTreeIndex++;
			var tempText = {id: bookmarkTreeIndex, text: btnText, leaf: true, lat: mapID.getCenter().lat(), lng:mapID.getCenter().lng(), zoom:mapID.getZoom()};
			var newNode = new Ext.tree.TreeNode(tempText);
			bookmarkTree.getRootNode().appendChild(newNode);			
	    }
	});
}

//This function creates the bookmark tree.
function createBookmarkTree(){
	bookmarkTree = new Ext.tree.TreePanel({
		renderTo:'bookmarkPanel',
		loader:bookmarkTreeLoader,
		root: bookmarkTreeRootNode
	});
	bookmarkTree.expandAll();
	bookmarkTree.on('append', function(tree, parent, node, xindex) { bookmarkTreeIndex = node.attributes.id; });
	bookmarkTree.on('contextMenu', bookmarkTreeContextHandler);
	bookmarkTree.on('click', go2bookmark);
}	

//This function is a listener for context menu of Bookmark Tree.
function bookmarkTreeContextHandler(node) {
	node.select();
	bookmarkTreeContextMenu.show(node.ui.getAnchor());
} 

//This function deletes selected bookmark from its tree.
function deleteBookmarkTreeNode () {
	var delNode = bookmarkTree.selModel.selNode;
	statusBar.setStatus('<b>Last action:</b> Bookmark <i>'+ delNode.attributes.text + '</i> is deleted.');
	bookmarkTree.selModel.selNode.parentNode.removeChild(delNode);	
}

//This function zooms to selected bookmark.
function go2bookmark(){
	var selectedNode = bookmarkTree.selModel.selNode;
	if (selectedNode != null) {	
		var xid = selectedNode.attributes.id;
		mapID.setCenter(new GLatLng(selectedNode.attributes.lat,selectedNode.attributes.lng),selectedNode.attributes.zoom);
	}
}

//This function creates the toolbox tree.
function createToolboxTree(){
	toolboxTree = new Ext.tree.TreePanel({
		renderTo:'toolboxPanel',
		loader: toolboxTreeLoader,
		root: toolboxTreeRootNode
	});	
	toolboxTree.expandAll();
	toolboxTree.on('append', function(tree, parent, node, xindex) { toolboxTreeIndex = node.attributes.id; });
	toolboxTree.on('contextMenu', toolboxTreeContextHandler);
	toolboxTree.on('dblclick', runTool);
}	

//This function is a listener for context menu of Toolbox Tree.
function toolboxTreeContextHandler(node) {
	node.select();
	toolboxTreeContextMenu.show(node.ui.getAnchor());
} 

//This function runs the selected tool.
function runTool(){
	var selectedNode = toolboxTree.selModel.selNode;
	if (selectedNode != null) {	
		eval(selectedNode.attributes.toolbox);		
	}
}

//This function is used to go given coordinates (used for go2XY)
function gotoCoordinates(){
	mapID.panTo(new GLatLng(go2xyLatLabel.getValue(),go2xyLngLabel.getValue()));	
}

//This function shows the go2XY window.
function startgo2xy(){
	go2xyWindow.setAnimateTarget(Ext.get('animationPoint'));
	go2xyWindow.show();	
}

//This function is used to enable or disable the get altitude tool.
function openCloseAltitudeWindow(){
	if(altitudeStatus == false) {
		if (revGeoCodeListener != null){
			openCloseRevGeocodeWindow();
		}
		altitudeListener = GEvent.addListener(mapID, "click", getAltitude);
		altitudeStatus = true;
		statusBar.clearStatus();
		statusBar.setStatus('Altitude Toolbox is enabled, please double click on its tree node to disable!');
		Ext.Msg.alert('Alert','Altitude Toolbox is enabled, please click on map to get address. To disable, please double click on its name in toolbox tree!');
	}
	else {
		GEvent.removeListener(altitudeListener);
		altitudeListener = null;
		altitudeStatus = false;
		if (addressMarker != null)
			mapID.removeOverlay(addressMarker);
		statusBar.clearStatus();
		statusBar.setStatus('Last Action : Altitude Toolbox is disabled!');
	}
}

//This function gets the altitude of selected point.
function getAltitude(overlay,point){
	if (point) { 	
		if (addressMarker != null)
			mapID.removeOverlay(addressMarker);
			var altUrl = proxyFile + '?http://gisdata.usgs.gov/xmlwebservices2/elevation_service.asmx/getElevation%3FX_Value=' + point.lng() + '&Y_Value=' + point.lat() + '&Elevation_Units=METERS&Source_Layer=-1&Elevation_Only=true';   
			GDownloadUrl(altUrl, function(data) {
			var doc = GXml.parse(data);
			var altitude = parseInt(GXml.value(doc));
	    	addressMarker = new GMarker(point);
	    	mapID.addOverlay(addressMarker);
			addressMarker.openInfoWindowHtml('<span style=\'font-family:verdana; font-size:12px\'><b>Altitude : </b>' + altitude + ' metres</span>');
		});
	}	
}

//This function is added to encode Unicode characters for URL actions.
function urlencode( str ) { 
    // URL-encodes string  
    // 
    // version: 905.3122
    // discuss at: http://phpjs.org/functions/urlencode
    // +   original by: Philip Peterson
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: AJ
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: travc
    // +      input by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Lars Fischer
    // %          note 1: info on what encoding functions to use from: http://xkr.us/articles/javascript/encode-compare/
    // *     example 1: urlencode('Kevin van Zonneveld!');
    // *     returns 1: 'Kevin+van+Zonneveld%21'
    // *     example 2: urlencode('http://kevin.vanzonneveld.net/');
    // *     returns 2: 'http%3A%2F%2Fkevin.vanzonneveld.net%2F'
    // *     example 3: urlencode('http://www.google.nl/search?q=php.js&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a');
    // *     returns 3: 'http%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3Dphp.js%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dcom.ubuntu%3Aen-US%3Aunofficial%26client%3Dfirefox-a'
                             
    var histogram = {}, unicodeStr='', hexEscStr='';
    var ret = (str+'').toString();
    
    var replacer = function(search, replace, str) {
        var tmp_arr = [];
        tmp_arr = str.split(search);
        return tmp_arr.join(replace);
    };
    
    // The histogram is identical to the one in urldecode.
    histogram["'"]   = '%27';
    histogram['(']   = '%28';
    histogram[')']   = '%29';
    histogram['*']   = '%2A';
    histogram['~']   = '%7E';
    histogram['!']   = '%21';
    histogram['%20'] = '+';
    histogram['\u00DC'] = '%DC';
    histogram['\u00FC'] = '%FC';
    histogram['\u00C4'] = '%D4';
    histogram['\u00E4'] = '%E4';
    histogram['\u00D6'] = '%D6';
    histogram['\u00F6'] = '%F6';
    histogram['\u00DF'] = '%DF';
    histogram['\u20AC'] = '%80';
    histogram['\u0081'] = '%81';
    histogram['\u201A'] = '%82';
    histogram['\u0192'] = '%83';
    histogram['\u201E'] = '%84';
    histogram['\u2026'] = '%85';
    histogram['\u2020'] = '%86';
    histogram['\u2021'] = '%87';
    histogram['\u02C6'] = '%88';
    histogram['\u2030'] = '%89';
    histogram['\u0160'] = '%8A';
    histogram['\u2039'] = '%8B';
    histogram['\u0152'] = '%8C';
    histogram['\u008D'] = '%8D';
    histogram['\u017D'] = '%8E';
    histogram['\u008F'] = '%8F';
    histogram['\u0090'] = '%90';
    histogram['\u2018'] = '%91';
    histogram['\u2019'] = '%92';
    histogram['\u201C'] = '%93';
    histogram['\u201D'] = '%94';
    histogram['\u2022'] = '%95';
    histogram['\u2013'] = '%96';
    histogram['\u2014'] = '%97';
    histogram['\u02DC'] = '%98';
    histogram['\u2122'] = '%99';
    histogram['\u0161'] = '%9A';
    histogram['\u203A'] = '%9B';
    histogram['\u0153'] = '%9C';
    histogram['\u009D'] = '%9D';
    histogram['\u017E'] = '%9E';
    histogram['\u0178'] = '%9F';
    
    // Begin with encodeURIComponent, which most resembles PHP's encoding functions
    ret = encodeURIComponent(ret);

    for (unicodeStr in histogram) {
        hexEscStr = histogram[unicodeStr];
        ret = replacer(unicodeStr, hexEscStr, ret); // Custom replace. No regexing
    }
    
    // Uppercase for full PHP compatibility
    return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2) {
        return "%"+m2.toUpperCase();
    });
}

function TileToQuadKey ( x, y, zoom){
    var quad = "";
    for (var i = zoom; i > 0; i--){
        var mask = 1 << (i - 1);
        var cell = 0;
        if ((x & mask) != 0)
            cell++;
        if ((y & mask) != 0)
            cell += 2;
        quad += cell;
    }
    return quad;
}
