var g_bPlaceShape = false;
var pickedPoint = new Array(); //records the spatial query polygon, or measuring area polygon
var pickedPointNum = 0;
var g_nMaxPoints = 100;

var bShowOverviewMap = true;

var g_strPhotoOpacity = "0.6";
var g_strGeotiffOpacity = "0.6";

var g_aryWindows = new Array();

// menu options
var MENU_DOC_SEARCH = 0;
var MENU_PARCEL_SEARCH = 1;
var MENU_GEODETIC_VIEW = 2;
var MENU_GET_VIEW = 3;
var MENU_MEASURE = 4;
var MENU_MAP_ARCHIVE = 5;
var MENU_HELP = 6;
var MENU_SHOPPING_CART = 7;
var MENU_DOWNLOAD = 8;
var MENU_ECOMMERCE = 9;

// spatial search shapes
var RectangleShape = null;
var CircleShape = null;
var CircleRadius = 0;
var PolygonShape = null;
var bPolygonShapeBegin = true;
var closeShapeCircle = null;
var PolygonShapeSX;
var PolygonShapeSY;

// measuring
var shpMeaLine = null;
var aryMeaPointObjs = new Array();		// store measuring point objects
var g_nLastMeaPointX = 0;
var g_nLastMeaPointY = 0;
var g_nMeaPointCount = 0;
var g_nLastTotalDistance = 0;
var g_nTotalDistance = 0;
var g_nLastTotalArea = 0;
var g_nTotalArea = 0;
var g_strResultPanelID = "ResultPanel";		// measuring result panel
var g_strLastAreaUnit = "ft";

var nDrawGeodetic = 0;
var g_strGeodeticIsVertical = "horizontal";

var g_bFill = true;

var g_strGeometryType = 'rectangle';
var g_strSpatialMode = 'o';		// overlap

var g_strImageID = null;
var g_aryOrigin = new Array();
var g_aryMultiplier = new Array();
var g_arySize = new Array();

var g_strHiliteParcelID = null;
var g_strParcelLayerID = "parcel";

function escapeSpecialChar4SQLServer(strValue)
{
	strResult = strValue;
	strResult = strResult.replace(/\\/g, "\\\\");
	strResult = strResult.replace(/%/g, "\\%");
	strResult = strResult.replace(/_/g, "\\_");
	strResult = strResult.replace(/\[/g, "\\[");
	strResult = strResult.replace(/\]/g, "\\]");
	return strResult;
}

function ParcelSearch(form)
{
	var strLastName = form.txtLastName ? trim(form.txtLastName.value) : "";
	var strAPN = form.txtAPN ? trim(form.txtAPN.value) : "";
//	var strAddress = form.txtAddress ? trim(form.txtAddress.value) : "";
//	var strCity = form.txtCity ? trim(form.txtCity.value) : "";
//	var strZip = form.txtZip ? trim(form.txtZip.value) : "";

	if (!(strLastName || strAPN/* || strAddress || strCity || strZip*/))
	{
		alert("Please input search value.");
		return;
	}

	var queryStr = "";
	queryStr += "txtLastName=" + escape(strLastName);
	queryStr += "&txtAPN=" + escape(strAPN);
//	queryStr += "&txtAddress=" + escape(strAddress);
//	queryStr += "&txtCity=" + escape(strCity);
//	queryStr += "&txtZip=" + escape(strZip);
	
	top.openSearchingWin();

	var win = window.open(pagePath + "/ParcelSearch.aspx?" + queryStr, "ParcelSearch", "width=800,height=600,scrollbars=1,resizable=1,status=1");
	win.focus();
	AddWindow(win);
}

function ClearParcelSearchFields(form)
{
	if (form.txtFirstName) form.txtFirstName.value = "";
	if (form.txtLastName) form.txtLastName.value = "";
	if (form.txtAPN) form.txtAPN.value = "";
	if (form.txtAddressNo) form.txtAddressNo.value = "";
	if (form.txtAddress) form.txtAddress.value = "";
	if (form.txtCity) form.txtCity.value = "";
	if (form.txtZip) form.txtZip.value = "";
}

function SelectDocType()
{
	var url = pagePath + "/SelectDocType.html";
	var win = window.open(url, "SelectDocType", "width=300,height=510,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function UpdateDocTypeArray(aryFlags)
{
	for (var i = 0; i < gaDocType.length; i++)
		gaDocType[i].bSelected = aryFlags[i];
}

function prepareShape(oSVGRoot)
{
	// reset it each time the map is refreshed because we don't keep the old shape
	pickedPointNum = 0;

	var shapeLayer = oSVGRoot.getElementById(SEARCH_SHAPE_ID);
	RectangleShape = _newRectangle( oSVGRoot,0, 0 ,"1","1","red",3,"red",0.5);
	RectangleShape.getStyle().setProperty("display", "none");
	shapeLayer.appendChild(RectangleShape);
	
	CircleShape = _newcircle( oSVGRoot,0, 0 ,"1","red","red",0.5);
	CircleShape.getStyle().setProperty("display", "none");
	shapeLayer.appendChild(CircleShape);
	
	PolygonShape = _newpath(oSVGRoot,0,0,0.5);
	PolygonShape.getStyle().setProperty("display", "none");
	shapeLayer.appendChild(PolygonShape);

	closeShapeCircle = _newcircle( oSVGRoot,0, 0 ,3,"black","black",1);
	closeShapeCircle.getStyle().setProperty("display", "none");
	shapeLayer.appendChild(closeShapeCircle);
	
	// measuring shape
	shpMeaLine = _newpolyline(oSVGRoot, "red", 1, "red", 0.5);
	shpMeaLine.getStyle().setProperty("display", "none");
	shapeLayer.appendChild(shpMeaLine);

	ZoomInBox = _newrect(SVGDocument, 0, 0, 0, 0, "red", 1);
	with (ZoomInBox.getStyle())
	{	
		setProperty("stroke-dasharray", "4 2");	
		setProperty("display",   "none");
	}
	shapeLayer.appendChild(ZoomInBox);
}

function PlaceShape()
{
	if (!bFullyloaded)
	{
		alert("Map is still loading. Please try later.");
		return;
	}
	
	// clear measuring shapes
	ClearMeasuringShapes();
	RestartMeasuring();

	// clear searching shapes
	DeleteShape();
	g_bPlaceShape = true;
}

function DeleteShape()
{
	RectangleShape.getStyle().setProperty("display", "none");
	CircleShape.getStyle().setProperty("display", "none");
	PolygonShape.getStyle().setProperty("display", "none");
	closeShapeCircle.getStyle().setProperty("display", "none");

	g_bPlaceShape = false;
	bPolygonShapeBegin = true;
	pickedPoint = new Array();
	pickedPointNum = 0;
}

function closeToEnd(MouseX,MouseY,PolygonShapeSX,PolygonShapeSY)
{
    var bReturn;
	with (Math){
	if(abs(MouseX-PolygonShapeSX)<=4 && abs(MouseY-PolygonShapeSY)<=4 )
	{
		bPolygonShapeBegin = true;
		bReturn =  true;
	}
	else
		bReturn =  false; 
	}
	return (bReturn);
}

function ViewParcel(nMSLink, nXLow, nXHigh, nYLow, nYHigh)
{
	vCenterLong = (nXLow + nXHigh) * 0.5;
	vCenterLat = (nYLow + nYHigh) * 0.5;
	var currentW = Math.abs(vMapWidth / mul_x);
	var currentH = Math.abs(vMapHeight / mul_y);
	var newW = 2 * Math.abs(nXHigh - nXLow);
	var newH = 2 * Math.abs(nYHigh - nYLow);
	var factor = Math.max(newW / currentW, newH / currentH);
	var scale = Math.round(vScale * factor);
	if (scale > g_nMaxViewParcelScale)
		scale = g_nMaxViewParcelScale;
	else if (scale < g_nMinViewParcelScale)
		scale = g_nMinViewParcelScale;
	vScale = scale;
	
	g_strHiliteParcelID = "" + nMSLink;
	var vSVGImage = getSvgURL(SVG_IMAGE_URL, SVG_TEMPLATE, vMapWidth, vMapHeight, vCenterLong, vCenterLat, vScale, g_strVisibleLayers);
    
	RefreshSVG(parent.MainMapFrame.document.MapImageID, vSVGImage);
	window.focus();
}

function SearchDocByShape()
{
	var strDocTypes = "";
	for (var i = 0; i < gaDocType.length; i++)
	{
		if (gaDocType[i].bSelected)
		{
			if (strDocTypes == "")
				strDocTypes = gaDocType[i].DocName;
			else
				strDocTypes += ";" + gaDocType[i].DocName;
		}
	}

	if (strDocTypes == "")
	{
		alert("Please choose at least one document type to search.");
		SelectDocType();
		return;
	}
	
	if (pickedPoint.length < 1)
	{
		alert("Please draw a shape to search.");
		return;
	}
	
	var nGeometryType = 0;
	var strGeoValue = "";
	if (g_strGeometryType.match(/rectangle/i) || g_strGeometryType.match(/polygon/i))
	{
		nGeometryType = 1;		// polygon
		
		for (var i = 0; i < pickedPoint.length; i++)
		{
			if (i != 0)
				strGeoValue += ";"

			strGeoValue += pickedPoint[i].x + "," + pickedPoint[i].y;
		}
	}
	else if (g_strGeometryType.match(/circle/i))
	{
		nGeometryType = 2;		// circle

		strGeoValue = pickedPoint[0].x + "," + pickedPoint[0].y + ";" + (Math.round((CircleRadius * 10)) / 10);
	}
	else
	{
		alert("Invalid shape type: " + g_strGeometryType);
		return;
	}

	var url = pagePath + "/SearchDocByShape.aspx?documentTypes=" + escape(strDocTypes) + "&geometryValue=" + escape(strGeoValue) + "&geometryType=" + escape("" + nGeometryType) + "&spatialOperator=" + escape(g_strSpatialMode);

	top.openSearchingWin();

	var win = window.open(url, "SearchDocByShape", "width=800,height=600,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function ShowTextInResultPanel(panelID, strText, /*for area unit*/bSuperscript)
{
	var panel = SVGDocument.getDocumentElement().getElementById(panelID);
	if (!panel)
		return;

	var text = panel.getElementsByTagName("text").item(0);
	text.getFirstChild().setNodeValue(strText)
	var border = panel.getElementsByTagName("rect").item(0);
	border.setAttribute("width", 10 + text.getComputedTextLength());

	if (bSuperscript)
		panel.getElementsByTagName("tspan").item(0).getStyle().setProperty("display", "inline");
	else
		panel.getElementsByTagName("tspan").item(0).getStyle().setProperty("display", "none");

	panel.getStyle().setProperty("display", "inline");
}

function ShowCoordinate(x, y)
{
	var strText = "";
	if (bUseMeter)
		strText = "X: " + Math.round(x * 10 / FOOT_PER_METER) / 10 + "   Y: " + Math.round(y * 10 / FOOT_PER_METER) / 10;
	else
		strText = "X: " + Math.round(x * 10) / 10 + "   Y: " + Math.round(y * 10) / 10;

	ShowTextInResultPanel(g_strResultPanelID, strText);
}

function trim(strInput)
{
	if (strInput == null)
		return null;

	strInput = strInput.replace(/^\s*/, "");
	strInput = strInput.replace(/\s*$/, "");
	
	return strInput;
}

function GeodeticShowDetail(txtHorizontalSurvey, txtHorizontalQuad, txtHorizontalStation, txtHorizontalOrder)
{
	txtHorizontalSurvey = txtHorizontalSurvey ? trim(txtHorizontalSurvey) : "";
	txtHorizontalQuad = txtHorizontalQuad ? trim(txtHorizontalQuad) : "";
	txtHorizontalStation = txtHorizontalStation ? trim(txtHorizontalStation) : "";
	txtHorizontalOrder = txtHorizontalOrder ? trim(txtHorizontalOrder) : "";

	if (!(txtHorizontalSurvey || txtHorizontalQuad || txtHorizontalStation || txtHorizontalOrder))
	{
		alert("Please input search value.");
		return;
	}

	var txtVerticalStation = "";
	var txtVerticalQuad = "";
	if (g_strGeodeticIsVertical.toLowerCase() == "vertical")		// vertical
	{
		txtVerticalStation = txtHorizontalSurvey;
		txtVerticalQuad = txtHorizontalQuad;
	}
	
	var queryStr = "txtVerticalStation=" + escape(txtVerticalStation);
	queryStr += "&txtVerticalQuad=" + escape(txtVerticalQuad);
	queryStr += "&txtHorizontalSurvey=" + escape(txtHorizontalSurvey);
	queryStr += "&txtHorizontalQuad=" + escape(txtHorizontalQuad);
	queryStr += "&txtHorizontalStation=" + escape(txtHorizontalStation);
	queryStr += "&txtHorizontalOrder=" + escape(txtHorizontalOrder);
	queryStr += "&method=0"; 
	queryStr += "&txtIsVertical=" + escape(g_strGeodeticIsVertical);	
	top.openSearchingWin();
	var win = window.open(pagePath + "/GeodeticView.aspx?" + queryStr, "GeodeticView", "width=800,height=600,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function GeodeticShowPhoto(strControlPointN, strViewRadius)
{
	if (strControlPointN != null && strControlPointN.length > 0) strControlPointN = trim(strControlPointN);
	if (strViewRadius != null && strViewRadius.length > 0) strViewRadius = trim(strViewRadius);
	if (strControlPointN == null || strControlPointN.length < 1)
	{
		alert("Input Control Point.");
		return "";
	}

	if (strViewRadius == null || strViewRadius.length < 1)
	{
		var factor1 = 2 * mul_x / vMapWidth;
		var factor2 = 2 * mul_y / vMapHeight;
		with (Math) 
		{
			var factor = max(abs(factor1), abs(factor2));
			var nRadius = 1. / factor;
		}
		strViewRadius = nRadius.toString();
	}
	else {
		if (bUseMeter)
			strViewRadius = (strViewRadius * FOOT_PER_METER).toString();
		else
			strViewRadius = strViewRadius.toString();
	}
	
	var queryStr = "txtControlPointN=" + escape(strControlPointN);
	queryStr += "&txtViewRadius=" + escape(strViewRadius);
	queryStr += "&method=1";
	top.openSearchingWin();
	var win = window.open(pagePath + "/GeodeticView.aspx?" + queryStr, "GeodeticView", "width=800,height=600,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function GeodeticShowMonumentRecord(strControlPointN, strViewRadius)
{
	if (strControlPointN != null && strControlPointN.length > 0) strControlPointN = trim(strControlPointN);
	if (strViewRadius != null && strViewRadius.length > 0) strViewRadius = trim(strViewRadius);
	if (strControlPointN == null || strControlPointN.length < 1)
	{
		alert("Input Control Point.");
		return "";
	}

	if (strViewRadius == null || strViewRadius.length < 1)
	{
		var factor1 = 2 * mul_x / vMapWidth;
		var factor2 = 2 * mul_y / vMapHeight;
		with (Math) 
		{
			var factor = max(abs(factor1), abs(factor2));
			var nRadius = 1. / factor;
		}
		strViewRadius = nRadius.toString();
	}
	else {
		if (bUseMeter)
			strViewRadius = (strViewRadius * FOOT_PER_METER).toString();
		else
			strViewRadius = strViewRadius.toString();
	}

	var queryStr = "txtControlPointN=" + escape(strControlPointN);
	queryStr += "&txtViewRadius=" + escape(strViewRadius);
	queryStr += "&method=2";
	top.openSearchingWin();
	var win = window.open(pagePath + "/GeodeticView.aspx?" + queryStr, "GeodeticView", "width=800,height=600,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function GeodeticShowDetailReport(strControlPointN, strIsVertical)
{
	if (strControlPointN != null && strControlPointN.length > 0) strControlPointN = trim(strControlPointN);
	if (strIsVertical != null && strIsVertical.length > 0) strIsVertical = trim(strIsVertical);
	if (strControlPointN == null || strControlPointN.length < 1)
	{
		alert("Input Control Point.");
		return "";
	}

	var queryStr = "txtControlPointN=" + escape(strControlPointN);
	queryStr += "&txtIsVertical=" + escape(strIsVertical);
	var win = window.open(pagePath + "/GeodeticDetail.aspx?" + queryStr, "GeodeticDetail", "width=800,height=600,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function GeodeticShowDetailPhoto(strControlPointN, strIsVertical)
{
	if (strControlPointN != null && strControlPointN.length > 0) strControlPointN = trim(strControlPointN);
	if (strIsVertical != null && strIsVertical.length > 0) strIsVertical = trim(strIsVertical);
	if (strControlPointN == null || strControlPointN.length < 1)
	{
		alert("Input Control Point.");
		return "";
	}

	var queryStr = "txtControlPointN=" + escape(strControlPointN);
	queryStr += "&txtIsVertical=" + escape(strIsVertical);
	var win = window.open(pagePath + "/GeodeticImage.aspx?" + queryStr, "GeodeticImage", "width=400,height=400,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function cbDrawViewMap(strResponseXML, args)
{
	var xmlDoc = g_objSVGUtils.parseXML(strResponseXML);
	if (!xmlDoc)
	{
		alert("Error in cbDrawViewMap.");		
		return;
	}

	var nodes = xmlDoc.getElementsByTagName("x");
	if (nodes == null || nodes.length < 1)
	{
		nodes = xmlDoc.getElementsByTagName("text");
		if (nodes != null) {
			var errorMsg = nodes.item(0).firstChild.nodeValue;
			alert(errorMsg);
		}
		else
			alert("Failed to locate the position.");
		delete xmlDoc;
		return "";
	}
	var strX = nodes.item(0).firstChild.nodeValue;

	nodes = xmlDoc.getElementsByTagName("y");
	if (nodes == null || nodes.length < 1)
	{
		alert("Missing Y tag.");
		delete xmlDoc;
		return "";
	}
	var strY = nodes.item(0).firstChild.nodeValue;

	var bKeepCurrentScale = true;
	var width, height;
	nodes = xmlDoc.getElementsByTagName("w");
	if (nodes != null && nodes.length > 0)
	{
		bKeepCurrentScale = false;

		width = nodes.item(0).firstChild.nodeValue;
		
		nodes = xmlDoc.getElementsByTagName("h");
		if (nodes != null && nodes.length > 0)
			height = nodes.item(0).firstChild.nodeValue;
		else
			bKeepCurrentScale = true;
	}

	if (!bKeepCurrentScale) 
	{	
		var factor1 = width * mul_x / vMapWidth;
		var factor2 = height * mul_y / vMapHeight;
		with (Math)
		{
			vScale = ceil(vScale * max(abs(factor1), abs(factor2)));
		}
	}

	vCenterLong = 1 * strX;
	vCenterLat = 1 * strY;
	var vSVGImage = getSvgURL(SVG_IMAGE_URL, SVG_TEMPLATE, vMapWidth, vMapHeight, vCenterLong, vCenterLat, vScale, g_strVisibleLayers);
	RefreshSVG(top.MainMapFrame.document.MapImageID, vSVGImage);
}

function DrawViewMap(strGetViewURL)
{
	if (!g_objSVGUtils.getResponse(strGetViewURL, cbDrawViewMap))
		alert("Error in sending request to get image specs.");
}

function isDigit(c)
{
  return "0123456789.".indexOf(c) == -1 ? 0 : 1
}

function GetViewByPageNumber(txtGVPage)
{
	txtGVPage = "" + txtGVPage;		// force it to be string
	if (txtGVPage != null && txtGVPage.length > 0) txtGVPage = trim(txtGVPage);
	if (txtGVPage == null || txtGVPage.length < 1)
	{
		alert("Please enter a page number.");
		return "";
	}

/*2002.7.29
	if (txtGVGrid == null || txtGVGrid.length < 1)
	{
		alert("Input Grid.");
		return "";
	}
*/	

	var queryStr = "&fppage=" + txtGVPage;

	var url = pagePath + "/GetView.aspx?t=" + SVG_TEMPLATE + "&h=" + vMapHeight + "&w=" + vMapWidth + "&hg=" + g_strVisibleLayers + queryStr;
	DrawViewMap(url);
}

function GetViewByCity(nCityIndex)
{
	var queryStr = "&fcCity=" + g_aryCities[nCityIndex].strObjID;

	var url = pagePath + "/GetView.aspx?t=" + SVG_TEMPLATE + "&h=" + vMapHeight + "&w=" + vMapWidth + "&hg=" + g_strVisibleLayers + queryStr;
	DrawViewMap(url);
}

function GetViewByIntersection(txtGVStreet1,txtGVStreet2,txtGVInterZip)
{
	txtGVStreet1 = txtGVStreet1 ? trim(txtGVStreet1) : "";
	txtGVStreet2 = txtGVStreet2 ? trim(txtGVStreet2) : "";
	txtGVInterZip = txtGVInterZip ? trim(txtGVInterZip) : "";
			
	if (txtGVStreet1.length < 1)
	{
		alert("Please enter a #1 Street Name.");
		return "";
	}

	if (txtGVStreet2.length < 1)
	{
		alert("Please enter a #2 Street Name.");
		return "";
	}

	var queryStr = "&fss1=" + escape(txtGVStreet1) + "&fss2=" + escape(txtGVStreet2) + "&fsZip=" + escape(txtGVInterZip);

	var url = pagePath + "/AddressSearch.aspx?t=" + SVG_TEMPLATE + "&h=" + vMapHeight + "&w=" + vMapWidth + "&hg=" + g_strVisibleLayers + queryStr;

	var win = window.open(url, "AddressSearch", "width=500,height=500,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function GetViewByCoordinate(txtGVCoordinateX,txtGVCoordinateY,txtGVRadius, nGeodeticCenter)
{
	if (txtGVCoordinateX != null && txtGVCoordinateX.length > 0) txtGVCoordinateX = trim(txtGVCoordinateX);
	if (txtGVCoordinateY != null && txtGVCoordinateY.length > 0) txtGVCoordinateY = trim(txtGVCoordinateY);
	if (txtGVRadius != null && txtGVRadius.length > 0) txtGVRadius = trim(txtGVRadius);

	if (txtGVCoordinateX == "") 
	{
		alert("Please enter an X Coordinate.");
		return;
	}
	if (isNaN(1 * txtGVCoordinateX))
	{
		alert("Please enter a number for the X Coordinate.");
		return;
	}

	if (txtGVCoordinateY == "") 
	{
		alert("Please enter a Y Coordinate.");
		return;
	}
	if (isNaN(1 * txtGVCoordinateY))
	{
		alert("Please enter a number for the Y Coordinate.");
		return;
	}

	if (txtGVRadius != null && txtGVRadius.length > 0)
	{
		if (isNaN(1 * txtGVRadius))
		{
			alert("Please enter a number for the Radius. Eg: 500.");
			return;
		}
		if (bUseMeter)
			txtGVRadius = (txtGVRadius * FOOT_PER_METER).toString();
		else
			txtGVRadius = txtGVRadius.toString();
		var factor1 = 2 * txtGVRadius * mul_x / vMapWidth;
		var factor2 = 2 * txtGVRadius * mul_y / vMapHeight;
		with (Math)
		{
			vScale = ceil(vScale * max(abs(factor1), abs(factor2)));
			if (vScale < MIN_SCALE)
			{
				alert("Specified radius is too short. Minimum scale is used.");
				vScale = MIN_SCALE;
			}
			else if (vScale > MAX_SCALE)
			{
				alert("Specified radius is too large. Maximum scale is used.");
				vScale = MAX_SCALE;
			}
		}
	}

	if (bUseMeter) {
		vCenterLong = 1 * txtGVCoordinateX * FOOT_PER_METER;
		vCenterLat = 1 * txtGVCoordinateY * FOOT_PER_METER;
	}
	else {
		vCenterLong = 1 * txtGVCoordinateX;
		vCenterLat = 1 * txtGVCoordinateY;
	}
	
	nDrawGeodetic = nGeodeticCenter;

	var vSVGImage = getSvgURL(SVG_IMAGE_URL, SVG_TEMPLATE, vMapWidth, vMapHeight, vCenterLong, vCenterLat, vScale, g_strVisibleLayers);
	RefreshSVG(top.MainMapFrame.document.MapImageID, vSVGImage);
	window.focus();
}

function GetViewByTownshipRange(txtGVStation,txtGVTownship,txtGVRange)
{
	if (txtGVStation != null && txtGVStation.length > 0) txtGVStation = trim(txtGVStation);
	if (txtGVTownship != null && txtGVTownship.length > 0) txtGVTownship = trim(txtGVTownship);
	if (txtGVRange != null && txtGVRange.length > 0) txtGVRange = trim(txtGVRange);

	if (txtGVStation == "" && txtGVTownship == "" && txtGVRange == "") 
	{
		alert("Please enter a search criteria.");
		return;
	}

	var queryStr = "&txtGVStation=" + escape(txtGVStation) + "&txtGVTownship=" + escape(txtGVTownship) + "&txtGVRange=" + escape(txtGVRange);

	var url = pagePath + "/MonumentSearch.aspx?t=" + SVG_TEMPLATE + "&h=" + vMapHeight + "&w=" + vMapWidth + "&hg=" + g_strVisibleLayers + queryStr;
	var win = window.open(url, "MonumentSearch", "width=500,height=500,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function GetViewByAddress(txtAddrNum,txtAddrName,txtAddrZip)
{
	if (txtAddrNum != null && txtAddrNum.length > 0) txtAddrNum = trim(txtAddrNum);
	if (txtAddrName != null && txtAddrName.length > 0) txtAddrName = trim(txtAddrName);
	if (txtAddrZip != null && txtAddrZip.length > 0) txtAddrZip = trim(txtAddrZip);

	if (txtAddrName == "") 
	{
		alert("Please input Street Name.");
		return;
	}
	else if  (txtAddrNum != "") {
		txtAddrName = txtAddrNum + " " + txtAddrName;
	}

	var queryStr = "&fss1=" + escape(txtAddrName) + "&fss2=&fsZip=" + escape(txtAddrZip);

	var url = pagePath + "/AddressSearch.aspx?t=" + SVG_TEMPLATE + "&h=" + vMapHeight + "&w=" + vMapWidth + "&hg=" + g_strVisibleLayers + queryStr;
	var win = window.open(url, "AddressSearch", "width=500,height=500,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function MapArchiveDetail(method)
{
	var queryStr = "method=" + escape(method);
	var win = window.open(pagePath + "/MapArchive.aspx?" + queryStr, "MapArchive", "width=800,height=600,scrollbars=1,resizable=1");
	win.focus();
	AddWindow(win);
}

function RestartMeasuring()
{
	// reset variables
	g_nMeaPointCount = 0;
	g_nTotalDistance = 0;
	g_nTotalArea = 0
}

function ClearMeasuringShapes()
{
	if (aryMeaPointObjs.length)
	{
		for (var i = 0; i < aryMeaPointObjs.length; i++)
		{
			aryMeaPointObjs[i][0].getStyle().setProperty("display", "none");
			aryMeaPointObjs[i][1].getStyle().setProperty("display", "none");
		}
	}

	shpMeaLine.getStyle().setProperty("display", "none");
		
	// reset variables
	g_nMeaPointCount = 0;
	g_nTotalDistance = 0;
	g_nTotalArea = 0
	
	aryMeaPointObjs = new Array();
	
	// clear searching shape
	DeleteShape();
	pickedPoint = new Array();
	pickedPointNum = 0;
}

function GenerateDistanceText(dblDistance)
{
	var strText = "";
	var strUnit = "";
	if (bUseMeter) {
		strUnit = "m";
		if (dblDistance >= 1000.0)
		{
			strUnit = "km";
			dblDistance /= 1000.0
		}
	}
	else {
		strUnit = "ft";
		if (dblDistance >= 5279.79)
		{
			strUnit = "mi";
			dblDistance /= 5279.79
		}
	}
		
	if (dblDistance > 100)
		dblDistance = Math.round(dblDistance);
	else
		dblDistance = Math.round(dblDistance * 100) / 100.0;	// keep 2 decimal digits
	
	return "Distance: " + FormatNumber(dblDistance) + " " + strUnit;
}

function AddMeaDisPoint(sx, sy, nLong, nLat)
{
	if (g_nMeaPointCount == 0)		// first point
	{
		ClearMeasuringShapes();
		
		shpMeaLine.setAttribute("points", sx + "," + sy);
		shpMeaLine.getStyle().setProperty("display", "inline");
		shpMeaLine.getStyle().setProperty("fill", "none");
	}
	else
	{
		var params = shpMeaLine.getAttribute("points");
		shpMeaLine.setAttribute("points", params + " " + sx + "," + sy);
	}

	g_nMeaPointCount++;
	
	// display point and line on map
	var shapeLayer = SVGDocument.getElementById(SEARCH_SHAPE_ID);
	var circle = _newcircle(SVGDocument, 0, 0, 3, "black", "black", 1);
	var text = SVGDocument.createTextNode(g_nMeaPointCount);
	var textNode = SVGDocument.createElement("text");
	textNode.setAttribute("x", 5);
	textNode.setAttribute("y", 15);
	textNode.getStyle().setProperty("stroke", "blue");
	textNode.getStyle().setProperty("fill", "blue");
	textNode.appendChild(text);
/*
	var group = SVGDocument.createElement("g");
	group.setAttribute("transform", "translate(" + sx + "," + sy + ")");
	group.appendChild(circle);
	group.appendChild(textNode);
	shapeLayer.appendChild(group);
*/
//******************
	circle.setAttribute("transform", "translate(" + sx + "," + sy + ")");
	textNode.setAttribute("transform", "translate(" + sx + "," + sy + ")");
	shapeLayer.appendChild(circle);
	shapeLayer.appendChild(textNode);
//******************
	aryMeaPointObjs[aryMeaPointObjs.length] = [circle, textNode];
	
	// display point info
	var nDistance = 0;
	var strText = "0";
	if (g_nMeaPointCount != 1)	// not first point
	{
		var wDeltaX = (sx - g_nLastMeaPointX) / mul_x;
		var wDeltaY = (sy - g_nLastMeaPointY) / mul_y;
		nDistance = Math.sqrt(wDeltaX * wDeltaX + wDeltaY * wDeltaY);
		if (bUseMeter)
			nDistance = nDistance / FOOT_PER_METER;
		
		g_nLastTotalDistance = g_nTotalDistance;
		g_nTotalDistance += nDistance;
	}

	strText = GenerateDistanceText(g_nTotalDistance);

    g_nLastMeaPointX = sx;
    g_nLastMeaPointY = sy;
    
   	ShowTextInResultPanel(g_strResultPanelID, strText);
}

function AddMeaAreaPoint(sx, sy, nLong, nLat)
{
	if (g_nMeaPointCount == 0)		// first point
	{
		ClearMeasuringShapes();
		
		shpMeaLine.setAttribute("points", sx + "," + sy);
		shpMeaLine.getStyle().setProperty("display", "inline");
		shpMeaLine.getStyle().setProperty("fill", "red");
		
		// add first point
		pickedPoint[pickedPoint.length] = new PointCoor(nLong, nLat);
		// add last point the same as first point
		pickedPoint[pickedPoint.length] = pickedPoint[0];
	}
	else
	{
		var newPoint = new PointCoor(sx, sy);
		if (IsMeaAreaShapeSelfCross(newPoint))
		{
			alert("Line segments should not cross each other.");
			return;
		}

		var params = shpMeaLine.getAttribute("points");
		shpMeaLine.setAttribute("points", params + " " + sx + "," + sy);

		// move down the last point, which is always the same as the first point
		pickedPoint[pickedPoint.length] = pickedPoint[0];
		// add the new point
		pickedPoint[pickedPoint.length - 2] = new PointCoor(nLong, nLat);
	}

	g_nMeaPointCount++;
	
	// display point and line on map
	var shapeLayer = SVGDocument.getElementById(SEARCH_SHAPE_ID);
	var circle = _newcircle(SVGDocument, 0, 0, 3, "black", "black", 1);
	var text = SVGDocument.createTextNode(g_nMeaPointCount);
	var textNode = SVGDocument.createElement("text");
	textNode.setAttribute("x", 5);
	textNode.setAttribute("y", 15);
	textNode.getStyle().setProperty("stroke", "blue");
	textNode.getStyle().setProperty("fill", "blue");
	textNode.appendChild(text);
/*
	var group = SVGDocument.createElement("g");
	group.setAttribute("transform", "translate(" + sx + "," + sy + ")");
	group.appendChild(circle);
	group.appendChild(textNode);
	shapeLayer.appendChild(group);
*/
//******************
	circle.setAttribute("transform", "translate(" + sx + "," + sy + ")");
	textNode.setAttribute("transform", "translate(" + sx + "," + sy + ")");
	shapeLayer.appendChild(circle);
	shapeLayer.appendChild(textNode);
//******************
	aryMeaPointObjs[aryMeaPointObjs.length] = [circle, textNode];
	
	// display point info
	var nArea = 0;
	var bSuperscript = false;
	if (g_nMeaPointCount > 2)	 // after the 3rd point
	{
		nArea = CalculateArea(pickedPoint);
		if (bUseMeter)
			nArea = nArea / (FOOT_PER_METER * FOOT_PER_METER);
	}
	
	g_nLastTotalArea = g_nTotalArea;
	g_strLastAreaUnit = AREA_UNIT;
	g_nTotalArea = nArea;

	if (bUseMeter) {
		if (g_nTotalArea < 1000000) {
			AREA_UNIT = "m";
			bSuperscript = true;
		}
		else {
			AREA_UNIT = "km";
			bSuperscript = true;
			g_nTotalArea /= 1000000.0;
		}
	}
	else {
		if (g_nTotalArea < 43559.8641) {
			AREA_UNIT = "ft";
			bSuperscript = true;
		}
		else if (g_nTotalArea < 27878313.024) {
			AREA_UNIT = "acres";
			g_nTotalArea /= 43559.8641;
		}
		else {
			AREA_UNIT = "mi";
			bSuperscript = true;
			g_nTotalArea /= 27878313.024;
		}
	}
	// round the total area
	var dblArea = 0.0;
	if (g_nTotalArea < 100)
		dblArea = Math.round(g_nTotalArea * 100.0) / 100.0;		// keep 2 digits after decimal point
	else
		dblArea = Math.round(g_nTotalArea);

	var strText = "Area: " + FormatNumber(dblArea)+ " " + AREA_UNIT;

   	ShowTextInResultPanel(g_strResultPanelID, strText, bSuperscript);
}

function RemoveLastMeaPoint()
{
	// remove the last point on map
	aryMeaPointObjs[aryMeaPointObjs.length - 1][0].getStyle().setProperty("display", "none");
	aryMeaPointObjs[aryMeaPointObjs.length - 1][1].getStyle().setProperty("display", "none");
	var params = shpMeaLine.getAttribute("points");
	params = params.substring(0, params.lastIndexOf(" "));
	shpMeaLine.setAttribute("points", params);
	
	var strText = "";
	if (vTool == MEASURE_DISTANCE)		// measure distance
	{
		// restore total distance
		g_nTotalDistance = g_nLastTotalDistance;

		strText = GenerateDistanceText(g_nTotalDistance);

	   	ShowTextInResultPanel(g_strResultPanelID, strText);
	}
	else if (vTool == MEASURE_AREA)		// measure area
	{
		// restore total area
		g_nTotalArea = g_nLastTotalArea;

		AREA_UNIT = g_strLastAreaUnit;

		var bSuperscript = false;
		if (bUseMeter)
		{
		   if (AREA_UNIT == "m" || AREA_UNIT == "km")
			   bSuperscript = true;
		}
		else
		{
		   if (AREA_UNIT == "ft" || AREA_UNIT == "mi")
			   bSuperscript = true;
		}
		// round the total area
		g_nTotalArea = Math.round(g_nTotalArea * 10.0) / 10.0;
		strText = "Area: " + FormatNumber(g_nTotalArea) + " " + AREA_UNIT;

   		ShowTextInResultPanel(g_strResultPanelID, strText, bSuperscript);
	}

	g_nMeaPointCount--;
}

function FormatNumber(dblNum)
{
	var tmpStr = String(dblNum);
	var dotPos = tmpStr.indexOf(".");
	var front = tmpStr;
	var tail = "";
	if (dotPos > 0) {
		front = tmpStr.substr(0,dotPos);
		tail = tmpStr.substr(dotPos,tmpStr.length-dotPos);
	}
	var numComma = Math.floor((front.length-1)/3);
	var rtnStr = tail;
	for (var i = 0; i < numComma; i++)
		rtnStr = ","+front.substr(front.length-(i+1)*3, 3)+rtnStr;
	rtnStr = front.substr(0, front.length-numComma*3)+rtnStr;
		
	return rtnStr;
}

function CalculateArea(aryPoints)
{
	var nArea = 0;

	if (aryPoints.length < 3 + 1)	// +1 because the last point is always added as the same as the first one.
		return 0;
	
	for (var i = 0; i < aryPoints.length - 1; i++)
	{
		nArea += aryPoints[i].x * aryPoints[i + 1].y - aryPoints[i + 1].x * aryPoints[i].y;
	}
	nArea = nArea * 0.5;
	
	return Math.abs(nArea);
}

function ShowGeoPage(strImageID)
{
	g_strImageID = strImageID;
	if (strImageID == null || strImageID == "")
		return;

	if (g_bFill) g_bFill = false;

	// get image spec
	var url = pagePath + "/TiffSpec.aspx?t=tiff&s=DocumentumImageA&i=" + strImageID;
	if (document.layers)	// Netscape
		setTimeout("g_objSVGUtils.getResponse('" + url + "', cbShowGeoPage)", 1000);
	else
	{
		if (!g_objSVGUtils.getResponse(url, cbShowGeoPage))
			alert("Error in sending request to get image specs.");
	}
}

function cbShowGeoPage(strResponseXML, args)
{
	var xmlDoc = g_objSVGUtils.parseXML(strResponseXML);
	if (!xmlDoc)
	{
		alert("Error in getting image clip specs.");		
		return;
	}

	EleOrigin = xmlDoc.getElementsByTagName("origin").item(0);
    if(EleOrigin == null)
	{
		alert("Error in getting image origin.");
	    delete xmlDoc;
		return;
	}

    g_aryOrigin[0] = EleOrigin.getAttribute("x")*1.0;
    g_aryOrigin[1] = EleOrigin.getAttribute("y")*1.0;

    EleMul = xmlDoc.getElementsByTagName("scale").item(0);
    if(EleMul == null)
	{
		alert("Error in getting image multiplier.");		
	    delete xmlDoc;
		return;
	}

    g_aryMultiplier[0] = EleMul.getAttribute("x")*1.0;
    g_aryMultiplier[1] = EleMul.getAttribute("y")*1.0;
	
    EleSize = xmlDoc.getElementsByTagName("size").item(0);
    if(EleSize == null)
	{
		alert("Error in getting image clip size.");		
	    delete xmlDoc;
		return;
	}

    g_arySize[0] = EleSize.getAttribute("x")*1.0;
    g_arySize[1] = EleSize.getAttribute("y")*1.0;

    if (g_aryMultiplier[1] > 0)	// origin is bottom-left corner
    {
		// move the origin to top-left corner and change the multiplier to negative
		g_aryOrigin[1] += g_arySize[1] * g_aryMultiplier[1];
		g_aryMultiplier[1] *= -1;
	}

    delete xmlDoc;
    
	// re-center map
	vCenterLong = g_aryOrigin[0] + g_arySize[0] * g_aryMultiplier[0] * 0.5;
	vCenterLat = g_aryOrigin[1] + g_arySize[1] * g_aryMultiplier[1] * 0.5;
	
	var factor1 = g_arySize[0] * g_aryMultiplier[0] * mul_x / vMapWidth;
	var factor2 = g_arySize[1] * g_aryMultiplier[1] * mul_y / vMapHeight;
	vScale = Math.ceil(vScale * Math.max(factor1, factor2));
	
	var vSVGImage = getSvgURL(SVG_IMAGE_URL, SVG_TEMPLATE, vMapWidth, vMapHeight, vCenterLong, vCenterLat, vScale, g_strVisibleLayers);
	RefreshSVG(top.MainMapFrame.document.MapImageID, vSVGImage);

	window.focus();
}

function ViewDoc(strDocID)
{
	var win = window.open(pagePath + "/SVGDocView.aspx?docID=" + escape(strDocID), "DocumentViewer", "width=800,height=600,scrollbars=1,resizable=1,status=1");
	win.focus();
	AddWindow(win);
}

function HiliteParcel(svgRoot)
{
	if (g_strHiliteParcelID == null)
		return;

	var parcelLayer = svgRoot.getElementById(g_strParcelLayerID);
	if (parcelLayer == null)
		return;
	var parcels = parcelLayer.getElementsByTagName("path");
	if (parcels == null)
		return;
	
	var parcel = null;
	for (var i = 0; i < parcels.length; i++)
	{
		parcel = parcels.item(i);
		if (parcel.getAttribute("id") == g_strHiliteParcelID)
			break;
	}
	if (i >= parcels.length)		// cannot find parcel
	{
		g_strHiliteParcelID = null;
		return;
	}

	parcel.getStyle().setProperty("fill", HIGHLIGHT_COLOR);
}

function GetCityList()
{
	var strCityList = "";
	for (var i = 0; i < g_aryCities.length; i++)
	{
		var strCityName = g_aryCities[i].strName;
		var strCityOption = "<option value=\"" + i + "\">" + strCityName + "</option>";
		
		strCityList += strCityOption;
	}
	
	return strCityList;
}

function GetTownshipList()
{
	var strTownshipList = "";
	for (var i = 0; i < g_aryTownships.length; i++)
	{
		var strTownshipName = g_aryTownships[i].name;
		var strTownshipOption = "<option value=\"" + strTownshipName + "\">" + strTownshipName + "</option>";
		
		strTownshipList += strTownshipOption;
	}
	
	return strTownshipList;
}

function GetRangeList()
{
	var strRangeList = "";
	for (var i = 0; i < g_aryRanges.length; i++)
	{
		var strRangeName = g_aryRanges[i].name;
		var strRangeOption = "<option value=\"" + strRangeName + "\">" + strRangeName + "</option>";
		
		strRangeList += strRangeOption;
	}
	
	return strRangeList;
}

function AddWindow(win)
{
	var nWinIndex = 0;
	for (nWinIndex = 0; nWinIndex < g_aryWindows.length; nWinIndex++)
	{
		if (!g_aryWindows[nWinIndex] || g_aryWindows[nWinIndex].closed || g_aryWindows[nWinIndex] == win)	// not occupied, or closed, or already in the array.
			break;
	}
	
	g_aryWindows[nWinIndex] = win;
}

function CloseAllWindows()
{
	for (var nWinIndex = 0; nWinIndex < g_aryWindows.length; nWinIndex++)
	{
		if (g_aryWindows[nWinIndex] && !g_aryWindows[nWinIndex].closed)
			g_aryWindows[nWinIndex].close();
	}
}

function DownloadSave(strDocid, objWin)
{
	var queryStr = pagePath + "/DownloadWait.aspx?strDocid=" + escape(strDocid);
	if (!objWin || !objWin.document)
		objWin = top;

	var win = objWin.open(queryStr, "DownloadWait", "width=700,height=500,scrollbars=1,resizable=1,status=1");
	win.focus();
	AddWindow(win);
}

function help()
{
	var url = pagePath + "/Help/index.html";
	if (document.all)		// IE
		window.showModelessDialog(url, "helpWin", "dialogLeft:10;dialogTop:10;dialogWidth:700px;dialogHeight:600px;resizable:yes;status:no;help:no");
	else
	{
		var openWinown = window.open(url, "helpWin", 'height=600,width=700,scrollbars=1,resizable=1,status=1');
		openWinown.focus();
	}
}

function Callback(fnCallback, cbArgs)
{
	this.fnCallback = fnCallback;
	this.cbArgs = cbArgs;
}

Callback.prototype.operationComplete = function(status)
{
	this.fnCallback(status.success ? status.content : null, this.cbArgs);
}

function SVGUtils(objSVGViewer)
{
	this.objSVGViewer = objSVGViewer;
}

SVGUtils.prototype.getResponse = function(strURL, fnCallback, cbArgs)
{
	if (!this.objSVGViewer)
		return false;

	if (!strURL)
		return false;

	if (!this.objSVGViewer.getWindow())
		return false;

	var objCallback = new Callback(fnCallback, cbArgs);
	this.objSVGViewer.getWindow().getURL(strURL, objCallback);

	return true;
}

SVGUtils.prototype.parseXML = function(strXML)
{
	if (!this.objSVGViewer)
		return null;

	if (!strXML)
		return null;

	if (!this.objSVGViewer.getWindow())
		return null;

	// remove "xmlns" attribute if there is any
	var nStartIndex = strXML.indexOf(" xmlns=\"");
	if (nStartIndex != -1)
	{
		var nEndIndex = strXML.indexOf("\"", nStartIndex + 8);
		strXML = strXML.substring(0, nStartIndex) + strXML.substring(nEndIndex + 1);
	}
	
	return this.objSVGViewer.getWindow().parseXML(strXML);
}

function IsMeaAreaShapeSelfCross(newPoint)
{
	var strPoints = trim(shpMeaLine.getAttribute("points"));
	var aryPoints = strPoints.split(" ");	// x1,y1 x2,y2 ...
	
	if (aryPoints.length > 2)	//	at least 3 existing points
	{
		for (var i = 0; i < aryPoints.length - 2; i++)		// check whether the new segment intersects with any existing segment
		{
			var aryCoords1 = aryPoints[i].split(",");
			var aryCoords2 = aryPoints[i + 1].split(",");
			var aryCoordsN = aryPoints[aryPoints.length - 1].split(",");
			if (SegmentsIntersect(new PointCoor(1 * trim(aryCoords1[0]), 1 * trim(aryCoords1[1])), new PointCoor(1 * trim(aryCoords2[0]), 1 * trim(aryCoords2[1])), new PointCoor(1 * trim(aryCoordsN[0]), 1 * trim(aryCoordsN[1])), newPoint))
				return true;
		}

		for (var i = 1; i < aryPoints.length - 1; i++)	// check whether the closing segment(between first point and new point) intersects with any existing segment
		{
			var aryCoords1 = aryPoints[i].split(",");
			var aryCoords2 = aryPoints[i + 1].split(",");
			var aryCoordsN = aryPoints[0].split(",");
			if (SegmentsIntersect(new PointCoor(1 * trim(aryCoords1[0]), 1 * trim(aryCoords1[1])), new PointCoor(1 * trim(aryCoords2[0]), 1 * trim(aryCoords2[1])), new PointCoor(1 * trim(aryCoordsN[0]), 1 * trim(aryCoordsN[1])), newPoint))
				return true;
		}
	}
	
	return false;
}

function IsSearchShapeSelfCross(newPoint)
{
	var strPoints = trim(PolygonShape.getAttribute("d").split("L")[1]);
	var aryPoints = strPoints.split(" ");	// x1 y1 x2 y2 ...
	
	if (aryPoints.length / 2 > 2)	//	at least 3 existing points
	{
		for (var i = 0; i < aryPoints.length - 4; i = i + 2)
		{
			if (SegmentsIntersect(new PointCoor(aryPoints[i], aryPoints[i + 1]), new PointCoor(aryPoints[i + 2], aryPoints[i + 3]), new PointCoor(aryPoints[aryPoints.length - 2], aryPoints[aryPoints.length - 1]), newPoint))
				return true;
		}
	}
	
	return false;
}

function SegmentsIntersect(p1, p2, q1, q2)	// segment 1 -- p1, p2; segment 2 -- q1, q2
{
	if (BoundingBoxIntersect(p1, p2, q1, q2))
	{
		if ((((p1.x - q1.x) * (q2.y - q1.y) - (q2.x - q1.x) * (p1.y - q1.y)) * ((p2.x - q1.x) * (q2.y - q1.y) - (q2.x - q1.x) * (p2.y - q1.y))) < 0 && (((q1.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (q1.y - p1.y)) * ((q2.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (q2.y - p1.y))) < 0)
		{
			return true;
		}
	}

	return false;
}

function BoundingBoxIntersect(p1, p2, q1, q2)
{
	with (Math)
	{
		if (min(p1.x, p2.x) >= max(q1.x, q2.x))
			return false;

		if (max(p1.x, p2.x) <= min(q1.x, q2.x))
			return false;

		if (min(p1.y, p2.y) >= max(q1.y, q2.y))
			return false;

		if (max(p1.y, p2.y) <= min(q1.y, q2.y))
			return false;
	}
	
	return true;
}
