function SpatialFilter()
{
	var self = this;
	
	// properties
	this.Type; // Rectange, Polygon, Line, Buffer
	this.Points; // Points: -23.0,-12.0,12.0,23.0
	this.XmlReqFilter; // XMLHttpRequest object used to request the spatial filter queries
	this.Buffer = null;//buffer object
	this.LayerId;
	
	// methods
	this.getSpatialFilterResults = getSpatialFilterResults;
	this.getAdjoiningFeatures = getAdjoiningFeatures;
	this.processAdjoiningFeatures = processAdjoiningFeatures;
	this.processSpatialFilterResults = processSpatialFilterResults;
	this.getQueryBuilderResults = getQueryBuilderResults;
	this.multiSelection = multiSelection;
	
	function getSpatialFilterResults()
	{
		showLoading();		
		url = server + "FeatureService.asmx/GetFeatureShortReport?layers=" + getVisibleLayerString() + "&userGroupName=" + user.userGroupName;
		
		spatialFilter.XmlReqFilter = new TXmlHttp();
//alert(url);
		
		if(spatialFilter.XmlReqFilter)
		{
			spatialFilter.XmlReqFilter.onreadystatechange = processShortReport;
			spatialFilter.XmlReqFilter.open("GET", url, true); //async call
			spatialFilter.XmlReqFilter.send(null);
		}
	}
	
	function processSpatialFilterResults()
	{
		var envelopeList = new Array();
		var objectIds = new Array();
		
		if( spatialFilter.XmlReqFilter.readyState == 4 )
		{
			if( spatialFilter.XmlReqFilter.status == 200 )
			{
				// parse response and place data into html table
				var resultTable = document.getElementById("divResultsList");
				resultTable.innerHTML = "";
				
				var response = spatialFilter.XmlReqFilter.responseXML.documentElement;
				var features = response.getElementsByTagName('FEATURES');
				var featureID = "";
				var html = "";
				
				// get request specific top level values (response feature count, hasMore features)
				var count = features[0].attributes.getNamedItem('count').value;
				var hasMore = features[0].attributes.getNamedItem('hasmore').value;
				
				if( count == 0 )
					spnResultsInfo.innerHTML = "No Features Found";
				else if( count == 1 )
					spnResultsInfo.innerHTML = "1 Feature Found";
				else
					spnResultsInfo.innerHTML = count + " Features Found";
			
				// looks at FEATURES elements
							for( var i = 0; i < features.length; i++ )
			{
				// looks at FEATURE elements
				for( var x = 0; x < features[i].childNodes.length; x++ )
				{
					if( features[i].childNodes[x].nodeName == 'FEATURE' )
					{
						var fieldCount = 0;
						var minx = "", miny = "", maxx = "", maxy = "";
						
						var layer = features[i].childNodes[x].attributes.getNamedItem('layer').value;
						var layerHyperlink = features[i].childNodes[x].attributes.getNamedItem('hyperlink').value;	
						// get feature specific top level values (uniqueName, uniqueValue, primaryDisplay)
						var uniqueName = features[i].childNodes[x].attributes.getNamedItem('uniquename').value;
						var uniqueValue = features[i].childNodes[x].attributes.getNamedItem('uniquevalue').value;
						var pdisplay = features[i].childNodes[x].attributes.getNamedItem('pdisplay').value;
						
						objectIds.push(uniqueValue);
						
						// for parcels, need to add 1 to this value
						var totalFieldsInFeature = features[i].childNodes[x].attributes.getNamedItem('fields').value;
						
						for( var y = 0; y < features[i].childNodes[x].childNodes.length; y++ )
						{
							if( features[i].childNodes[x].childNodes[y].nodeName == 'ENVELOPE' )
							{
								// get envelope information
								minx = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('minx').value;
								miny = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('miny').value;
								maxx = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('maxx').value;
								maxy = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('maxy').value;
								
								// setup primary display field in HTML
								featureID = "feature" + x;
								className = "fieldPrimary";
								
								var objectIdHidden = document.getElementById("objectIdHidden");
								objectIdHidden.value = uniqueValue;
								var activeLayerHidden = document.getElementById("activeLayerHidden");
								activeLayerHidden.value = layer;
								var objectIdLayer = document.getElementById("objectIdLayer");
								objectIdLayer.value = layer;
								
								html = "<table style=\"width: 100%; padding: 5px 0px 0px 0px;\" id=\"tblSearchResults" + featureID +"\" cellspacing=\"0\" cellpadding=\"2\" style=\"margin-top:5px;\">";
								html += "<tr id=\"" + featureID + "\" class=\"" + className + "\">";
								html += "<td><img id=\"" + featureID + "img\" class=\"collapseImage\" src=\"images/plus.gif\" onmousedown=\"collapseFeatureData('" + featureID + "'," + totalFieldsInFeature + ");\" />";
								
								if( pdisplay != '' )
									html += layer + ": " + pdisplay + "</td>";
								else
									html += layer + ": " + uniqueValue + "</td>";
								
								html += "<td align=\"right\">";
								
								
								html += "<img class=\"featureImage\" src=\"images/feature_zoom_to.gif\" onmousedown=\"map.zoomToFeature('" + minx + "', '" + miny + "', '" + maxx + "', '" + maxy + "');\" alt=\"Zoom to Feature\" />";
								html += "<img class=\"featureImage\" src=\"images/feature_report.gif\" alt=\"Feature Details\" onmousedown=\"feature.getFeatureDetails('" + layer + "','" + uniqueValue + "');\"/>";
								if( layer == 'Parcels' )
									html += "<img class=\"featureImage\" src=\"images/adjoiners.gif\" onmousedown=\"spatialFilter.getAdjoiningFeatures('" + uniqueValue + "', 'feet', 1, 'Parcels', 'Parcels');\" alt=\"Get Adjoining Parcels\" />";
								
							//	html += "<img class=\"featureImage\" src=\"images/buffer.gif\" alt=\"Buffer Select\" onmousedown=\"activateTab('tabInformation');document.getElementById('trInformationInfo').style.display='none';document.getElementById('divBuffer').style.display='block';document.getElementById('divInformationList').style.display='none';document.getElementById('divInformationMessage').style.display='none';document.getElementById('divResultsList').style.display='none';\" />";
							//	html += "<a href=\"feature_csv.aspx?objectId=" + uniqueValue + "&layer=" + layer + "&reportType=Short Report&userGroupName=" + user.userGroupName + "\" target=\"_new\" border=\"0\"><img class=\"featureImage\" src=\"images/excel.gif\" alt=\"Export to Excel\" border=\"0\" /></a>";			
								html += "</td></tr>";
							}
							else if( features[i].childNodes[x].childNodes[y].nodeName == 'FIELDGROUP' )
							{
								var fieldGroupName = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('name').value;
								var fieldGroupHyperlink = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('hyperlink').value; 
								
								// looks at FIELD elements
								html += "<tbody id=\"" + featureID + "tbody\" style=\"display:none;\">";
								for( var z = 0; z < features[i].childNodes[x].childNodes[y].childNodes.length; z++ )
								{
									if( features[i].childNodes[x].childNodes[y].childNodes[z].nodeName == 'FIELD' )
									{
										var fieldName = features[i].childNodes[x].childNodes[y].childNodes[z].attributes.getNamedItem('name').value;
										var fieldAlias = features[i].childNodes[x].childNodes[y].childNodes[z].attributes.getNamedItem('alias').value;
										var fieldNameHyperlink = features[i].childNodes[x].childNodes[y].childNodes[z].attributes.getNamedItem('namehyperlink').value;
										var fieldValue = features[i].childNodes[x].childNodes[y].childNodes[z].attributes.getNamedItem('value').value;
										var fieldValueHyperlink = features[i].childNodes[x].childNodes[y].childNodes[z].attributes.getNamedItem('valuehyperlink').value;
										
										// add each field to the HTML
										className = (fieldCount % 2 == 1)?"Odd":"Even";
										featureID = "feature" + x + "field" + fieldCount;

										html += "<tr>";
										
										// add field name (alias)
										if( fieldNameHyperlink != "" )
										{
											html += "<td class=\"field" + className + "\">";
											html += "<a class=\"fieldLink\" href=\"" + fieldNameHyperlink + "\" target=\"_new\">";
											html += fieldAlias + "</a></td>";
										}
										else
											html += "<td class=\"field" + className + "\">" + fieldAlias + "</td>";
										
										// add field value
										if( fieldValue != null )
										{
											// check for hyperlink!
											if( fieldValueHyperlink != "" )
											{
												html += "<td class=\"fieldValue" + className + "\">";
												html += "<a class=\"fieldLink\" href=\"" + fieldValueHyperlink + "\" target=\"_new\">";
												html += fieldValue + "</a></td>";
											}
											else
												html += "<td class=\"fieldValue" + className + "\">" + fieldValue + "</td>";
										}
										else
											html += "<td></td>";
										
										fieldCount++;
									}
								}
							}
						}
						
						html += "</tbody></tr></table>";
						resultTable.innerHTML += html;
						
					}
				}
			}
								
								
			if(objectIds.length > 0)
			{
				var spanHtml = "<br/><span class=\"trInfo\" style=\"font-size:11px\">Export feature data to Excel </span><a href=\"feature_csv.aspx?objectId=";
				for( var n in objectIds)
				{
					spanHtml += objectIds[n] + ",";
				}

				spanHtml += "&layer=" + layer + "&reportType=Short Report&userGroupName=" + user.userGroupName + "\" target=\"_new\" border=\"0\"><img src=\"images/excel.gif\" alt=\"Export to Excel\" border=\"0\" /></a>";
				spnResultsInfo.innerHTML += spanHtml;
			}			
			
			activateTab("tabResults");
			trResultsInfo.style.display='block';
			trDetailsInfo.style.display='none';
			divResultsList.style.display='block';
			divDetailsList.style.display='none';
			subTabResultsList.className='subTabActive';
			subTabDetailsList.className='subTabNormal';
			document.getElementById('loading').style.visibility = 'hidden';
			
			// disable loading div
			loading.style.visibility = "hidden";
			
			if( hasMore == 'True' )
				alert("This search returned more than the number of features allowed.  Please refine your search for more detailed results.");
			}
		}
	}
	
	function getAdjoiningFeatures(objectId, units, distance, targetLayer, activeLayer)
	{
		var layer;
		showLoading();
		
		if( selectMode == 0 )
			draw.clearSelection(false);
			
		for( var i = 0; i < layerArray.length; i++ )
		{
			if( layerArray[i].Name == activeLayer )
			{
				layer = layerArray[i];
				layer.SpatialFilter = null;
				break;
			}	
		}
		
		var sFilter = new SpatialFilter();
		var buff = new Buffer();
		
		buff.ObjectId = objectId;
		buff.BufferUnits = units;
		buff.BufferDistance = distance;
		buff.BufferTarget = targetLayer;
		buff.ActiveLayer = activeLayer;
		
		sFilter.Buffer = buff;
		sFilter.Type = "Buffer";
		
		layer.SpatialFilter = sFilter;
		
		// send request to get new map image
		//map.getAdjoiningFeaturesMap(objectId);
		
		// send request to get adjoining feature data
		url = server + "FeatureService.asmx/GetBufferedFeatures?layerId=" + targetLayer + "&activeLayer=" + activeLayer + "&objectId=" + objectId + "&distance=" + distance + "&units=" + units + "&userGroupName=" + user.userGroupName;
		spatialFilter.XmlReqFilter = new TXmlHttp();
		
		if(spatialFilter.XmlReqFilter)
		{
			spatialFilter.XmlReqFilter.onreadystatechange = processAdjoiningFeatures;
			spatialFilter.XmlReqFilter.open("GET", url, true); //async call
			spatialFilter.XmlReqFilter.send(null);
		}
	}
	
	function processAdjoiningFeatures()
	{
		showLoading();
		var objectIds = new Array();
		var envelopeList = new Array();		
		
		if( spatialFilter.XmlReqFilter.readyState == 4 )
		{
			if( spatialFilter.XmlReqFilter.status == 200 )
			{
				// parse response and place data into html table
				var resultTable = document.getElementById("divResultsList");
				resultTable.innerHTML = "";
				
				var response = spatialFilter.XmlReqFilter.responseXML.documentElement;
				var features = response.getElementsByTagName('FEATURES');
				var featureID = "";
				var html = "";
				
				// get request specific top level values (layer, layerHyperlink, response feature count, hasMore features)
				var layer = features[0].attributes.getNamedItem('layer').value;
				var layerHyperlink = features[0].attributes.getNamedItem('hyperlink').value;
				var count = features[0].attributes.getNamedItem('count').value;
				var hasMore = features[0].attributes.getNamedItem('hasmore').value;
				
				if( count == 0 )
					spnResultsInfo.innerHTML = "No Features Found";
				else if( count == 1 )
					spnResultsInfo.innerHTML = "1 Feature Found";
				else
					spnResultsInfo.innerHTML = count + " Features Found";
				
				// looks at FEATURES elements
				for( var i = 0; i < features.length; i++ )
				{
					// looks at FEATURE elements
					for( var x = 0; x < features[i].childNodes.length; x++ )
					{
						if( features[i].childNodes[x].nodeName == 'FEATURE' )
						{
							var fieldCount = 0;
							var gpin = "";
							var minx = "", miny = "", maxx = "", maxy = "";
							
							// get feature specific top level values (uniqueName, uniqueValue, primaryDisplay)
							//var layer = features[i].childNodes[x].attributes.getNamedItem('layer').value;
							//var layer = "Parcels";
							//var layerHyperlink = features[i].childNodes[x].attributes.getNamedItem('hyperlink').value;
							//var layerHyperlink = "";
							var uniqueName = features[i].childNodes[x].attributes.getNamedItem('uniquename').value;
							var uniqueValue = features[i].childNodes[x].attributes.getNamedItem('uniquevalue').value;
							var pdisplay = features[i].childNodes[x].attributes.getNamedItem('pdisplay').value;
							
							objectIds.push(uniqueValue);
														
							// for parcels, need to add 1 to this value
							var totalFieldsInFeature = features[i].childNodes[x].attributes.getNamedItem('fields').value;
							
							for( var y = 0; y < features[i].childNodes[x].childNodes.length; y++ )
							{
								if( features[i].childNodes[x].childNodes[y].nodeName == 'ENVELOPE' )
								{					
									// get envelope information
									minx = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('minx').value;
									miny = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('miny').value;
									maxx = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('maxx').value;
									maxy = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('maxy').value;
									
									var envObj = new Envelope();
									envObj.minx = minx;
									envObj.miny = miny;
									envObj.maxx = maxx;
									envObj.maxy = maxy;
									envelopeList.push(envObj);
									
									
									// setup primary display field in HTML
									featureID = "feature" + x;
									className = "fieldPrimary";
									
									html = "<table width=\"100%\" cellspacing=\"0\" cellpadding=\"2\" style=\"margin-top:5px;\">";
									html += "<tr id=\"" + featureID + "\" class=\"" + className + "\">";
									html += "<td><img id=\"" + featureID + "img\" class=\"collapseimg\" src=\"images/plus.gif\" onmousedown=\"collapseFeatureData('" + featureID + "'," + totalFieldsInFeature + ");\" />";
									
									if( pdisplay != '' )
										html += layer + ": " + pdisplay + "</td>";
									else
										html += layer + ": " + uniqueValue + "</td>";
								
									html += "<td align=\"right\">";
									if( layer == 'Parcels' )
										html += "<img class=\"featureImage\" src=\"images/adjoiners.gif\" onmousedown=\"spatialFilter.getAdjoiningFeatures('" + uniqueValue + "', 'feet', 1, 'Parcels', 'Parcels');\" alt=\"Get Adjoining Parcels\" />";
										
									//html += "<a href=\"feature_csv.aspx?objectId=" + uniqueValue + "&layer=" + layer + "&reportType=Short Report&userGroupName=" + user.userGroupName + "\" target=\"_new\" border=\"0\"><img src=\"images/excel.gif\" alt=\"Export to Excel\" border=\"0\" /></a>";
									html += "<img class=\"featureImage\" src=\"images/feature_zoom_to.gif\" onmousedown=\"map.zoomToFeature('" + minx + "', '" + miny + "', '" + maxx + "', '" + maxy + "');\" alt=\"Zoom to Feature\" />";
									html += "<img class=\"featureImage\" src=\"images/feature_report.gif\" alt=\"Feature Details\" onmousedown=\"feature.getFeatureDetails('" + layer + "','" + uniqueValue + "');\"/>";
									//html += "<img class=\"featureImage\" src=\"images/buffer.gif\" alt=\"Buffer Select\" onmousedown=\"document.getElementById('objectIdHidden').value='" + uniqueValue + "';activateTab('tabInformation');document.getElementById('trInformationInfo').style.display='none';document.getElementById('divBuffer').style.display='block';document.getElementById('divInformationList').style.display='none';document.getElementById('divInformationMessage').style.display='none';document.getElementById('divResultsList').style.display='none';\" />";
									html += "</td></tr>";
								}
								else if( features[i].childNodes[x].childNodes[y].nodeName == 'FIELDGROUP' )
								{
									var fieldGroupName = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('name').value;
									var fieldGroupHyperlink = features[i].childNodes[x].childNodes[y].attributes.getNamedItem('hyperlink').value;
									html+= "<tbody id=\"" + featureID + "tbody\" style=\"display:none;\">";
									// looks at FIELD elements
									for( var z = 0; z < features[i].childNodes[x].childNodes[y].childNodes.length; z++ )
									{
										if( features[i].childNodes[x].childNodes[y].childNodes[z].nodeName == 'FIELD' )
										{
											var fieldName = features[i].childNodes[x].childNodes[y].childNodes[z].attributes.getNamedItem('name').value;
											var fieldAlias = features[i].childNodes[x].childNodes[y].childNodes[z].attributes.getNamedItem('alias').value;
											var fieldNameHyperlink = features[i].childNodes[x].childNodes[y].childNodes[z].attributes.getNamedItem('namehyperlink').value;
											var fieldValue = features[i].childNodes[x].childNodes[y].childNodes[z].attributes.getNamedItem('value').value;
											var fieldValueHyperlink = features[i].childNodes[x].childNodes[y].childNodes[z].attributes.getNamedItem('valuehyperlink').value;
											
											
											// add each field to the HTML
											className = (fieldCount % 2 == 1)?"Odd":"Even";
											featureID = "feature" + x + "field" + fieldCount;
											html += "<tr id=\"" + featureID + "\">";
											
											// add field name (alias)
											if( fieldNameHyperlink != "" )
											{
												html += "<td class=\"field" + className + "\">";
												html += "<a class=\"fieldLink\" href=\"" + fieldNameHyperlink + "\" target=\"_new\">";
												html += fieldAlias + "</a></td>";
											}
											else
												html += "<td class=\"field" + className + "\">" + fieldAlias + "</td>";
											
											// add field value
											if( fieldValue != null )
											{
												// check for hyperlink!
												if( fieldValueHyperlink != "" )
												{
													html += "<td class=\"fieldValue" + className + "\">";
													html += "<a class=\"fieldLink\" href=\"" + fieldValueHyperlink + "\" target=\"_new\">";
													html += fieldValue + "</a></td>";
												}
												else
													html += "<td class=\"fieldValue" + className + "\">" + fieldValue + "</a></td>";
											}
											else
												html += "<td></td>";
											
											fieldCount++;
										}
									}
								}
							}
							
							html += "</tbody></tr></table>";
							resultTable.innerHTML += html;
						}
					}
				}
				
				if(objectIds.length > 0)
				{
					var spanHtml = "<br/><span class=\"trInfo\" style=\"font-size:11px\">Export feature data to Excel </span><a href=\"feature_csv.aspx?objectId=";
					
					for( var n in objectIds)
					{
						spanHtml += objectIds[n] + ",";
					}
	
					spanHtml += "&layer=" + layer + "&reportType=Short Report&userGroupName=" + user.userGroupName + "\" target=\"_new\" border=\"0\"><img src=\"images/excel.gif\" alt=\"Export to Excel\" border=\"0\" /></a>";
					spnResultsInfo.innerHTML += spanHtml;
				}			
			
				// disable loading div
				loading.style.visibility = "hidden";
				
				activateTab("tabResults");
				trResultsInfo.style.display='block';
				trDetailsInfo.style.display='none';
				divResultsList.style.display='block';
				divDetailsList.style.display='none';
				subTabResultsList.className='subTabActive';
				subTabDetailsList.className='subTabNormal';
				
				if(envelopeList.length > 0)
				{
					var largestMinX;
					var largestMinY;
					var largestMaxX;
					var largestMaxY;

					for( var j = 0; j < envelopeList.length; j++ )
					{
						var env = envelopeList[j];
				
						if( largestMinX == null || env.minx < largestMinX )
							largestMinX = env.minx;
					
						if( largestMinY == null || env.miny < largestMinY )
							largestMinY = env.miny;
					
						if( largestMaxX == null || env.maxx > largestMaxX )
							largestMaxX = env.maxx;
							
						if( largestMaxY == null || env.maxy > largestMaxY )
							largestMaxY = env.maxy;
					}
					
					map.getMap("ZOOMIN", largestMinX, largestMinY, largestMaxX, largestMaxY, false);
				}
				//loading.style.visibility = 'false';
				
				if( hasMore == 'True' )
					alert("This search returned more than the number of features allowed.  Please refine your search for more detailed results.");
			}
		}
	}
	
	function getQueryBuilderResults(layerName, attributes, conditions)
	{
		showLoading();		
		url = server + "FindService.asmx/QueryFind?layer=" + layerName + "&attributes=" + attributes + "&conditions=" + conditions;
	
		spatialFilter.XmlReqFilter = new TXmlHttp();
		
		if(spatialFilter.XmlReqFilter)
		{
			showLoading();
			spatialFilter.XmlReqFilter.onreadystatechange = processQueryBuilder;
			spatialFilter.XmlReqFilter.open("GET", url, true); //async call
			spatialFilter.XmlReqFilter.send(null);
		}
	}
	
	function multiSelection(x, y, dist)
	{
		showLoading();
		var x = convertMapPoints(x, y).split(",")[0];
		var y = convertMapPoints(x, y).split(",")[1];
				
		url = server + "FeatureService.asmx/GetMultiSelect?x=" + x + "&y=" + y + "&distance=" + dist + "&userGroupName=" + user.userGroupName;
		
		spatialFilter.XmlReqFilter = new TXmlHttp();
			
		if(spatialFilter.XmlReqFilter)
		{
			
			if(spatialFilter.XmlReqFilter)
			{
				spatialFilter.XmlReqFilter.onreadystatechange = processSpatialFilterResults;
				spatialFilter.XmlReqFilter.open("GET", url, true); //async call
				spatialFilter.XmlReqFilter.send(null);
			}
		}
	}
}