// aimsCustom.js
/*
*  JavaScript template file for ArcIMS HTML Viewer
*		dependent on aimsXML.js, ArcIMSparam.js, aimsCommon.js, aimsMap.js,
*		aimsLayers.js, aimsDHTML.js
*		aimsClick.js, aimsNavigation.js,
*/

// global variables
	aimsCustomPresent=true;
	// change these to send XML response to custom function.
	// use numbers >= 1000 and match in useCustomFunction()
	// defaults are defined in aimsXML.js and use standard functions
	
	// xml response mode for selection
	selectXMLMode = 6;
	// xml response mode for identify
	identifyXMLMode = 7;
	// xml response mode for query
	queryXMLMode = 8;
	// xml response mode for find
	findXMLMode = 14;
	// xml response mode hyperlink
	hyperlinkXMLMode = 15;




// custom function for handling clicks 
// 		flow redirected here when
//		toolMode set to >=1000
function customMapTool(e) {
	if (toolMode == 1001) {
			// insert code here
			return false;
		
	}
	else if (toolMode == 1002) {
			// insert code here

	}
	else if (toolMode==redlineToolMode) {
		// BB: custom mode for redlining
		makeRedliningItem(e)
	}

}

// send  XML response to custom function
//		flow  redirected here when
//		XMLMode >=1000
function useCustomFunction(theReply) {
	if (XMLMode==1001) {
		if (getBufferedData) {
                    getBufferAttributeData(theReply);
                }
                var theXYs = getEnvelopeXYs(theReply, 0); 
				
				//alert ("The XYS");
				//alert (theXYs);
				
                if (theXYs.length>0){
                         eLeft = theXYs[0];
      	             eBottom = theXYs[1];
	                   eRight = theXYs[2];
	                   eTop = theXYs[3];
					   
					   //alert (eLeft);
					   
					   
                         sendMapXML();
                }
                else alert("No features found");
		
	} else if (XMLMode==1002) {
		// insert code here
	} else {
		alert(msgList[55] + XMLMode + msgList[56]);
	}
	hideLayer("LoadData");
	//aimsBufferPresent=false;
}

// add custom stuff to Map XML request. . . between selection and geocode
function addCustomToMap1(){
	var customString = "";
	return customString;
}

// add custom stuff to Map XML request. . . between clickpoints and copyright
function addCustomToMap2(){

	// BB: add redline to the map
	var customString = addRedlineToMap();
	
	return customString;
}

// add custom stuff to Map XML request. . . under modeOnMap
function addCustomToMap3(){
	var customString = "";
	return customString;
}

// add custom stuff to Map XML request. . . on top of everything
function addCustomToMap4(){
	var customString = "";
	
	return customString;
}

// extract layers to download
function extractIt() {
	hideLayer("measureBox");
	alert(msgList[51]);
}

/*
 *  BB: Custom code for redlining functionality
 */
 
var useRedlining = true;

// Whether to show complete polygon when 3+ points clicked
//	(if false, only shows line until "Finished" button clicked)
var completePolygon = true;
 
// current redline settings (updated in redlining form)
var redliningMode = "point";
var redliningColor = "0,0,0";	// point/line/polygon (outline) color
var redliningSize = "5";	// point/line width, or polygon outline width, or text height
var redliningStyle = "circle"; // point marker type, or line type, or polygon fill type, or font style
var redliningOutline = "0,0,0";	// outline color (fill color for polygon)
var redliningUseOutline = false;	// use outline (fill for polygons)
var redliningFont = "Arial";	// text font
var redliningText = "";

// whether redlining object is being drawn or is done (used for lines/polygons)
var redlineFinished = true;

var redlineWin = null;
var redlineToolMode = 1022;

// array that will hold redlining objects
var redlineArray = new Array();

// "function" that defines a redlining object - stores all information about each redline item
function redlineObject (mode, color, size, style, outline, useOutline, font, text, coords) {
	this.mode = mode;
	this.color = color;
	this.size = size;
	this.style = style;
	this.outline = outline;
	this.useOutline = (useOutline.toString().toLowerCase() == "true") ? true : false;
	this.font = font;
	this.text = text;
	this.coords = coords;
}

function createRedliningObject (mode, color, size, style, outline, useOutline, font, text, coords) {
	var newObj = new redlineObject (mode, color, size, style, outline, useOutline, font, text, coords);
	return newObj;
}

// Display redlining form to user, and set current tool to redlining
function customRedliningForm() {
	redlineForm = appDir + "RedliningForm.htm";
	//redlineForm = "RedliningForm.htm";
	if (useTextFrame) {
//	    parent.TitleRightFrame.t_Data.src="Images/Data_04.gif";
//	    parent.TitleRightFrame.t_Map_Layers.src="Images/Map_Layers_01.gif";
//        parent.TitleRightFrame.t_Legend.src="Images/Legend_01.gif";
		parent.TextFrame.document.location = redlineForm;
		redlineWin = parent.TextFrame;
	} else {
		redlineWin = open(redlineForm,"RedliningFormWindow","width=300,height=500,scrollbars=no,resizable=yes");
	}
	
	toolMode = 1022;	// custom redline mode - directs map clicks back to aimsCustom.js
	panning=false;
	zooming=false;
	selectBox=false;
	shapeSelectBuffer = false;
	
	hideLayer("measureBox");
	modeBlurb = "Redlining";
	
	geocodeAppMode = "route";
	
	setCursor("theTop", "crosshair"); //fix
	//alert("here");
	modeName=modeBlurb;
	
	// refresh mode display
	if (useModeFrame) {
		writeModeFrame(modeBlurb);
	} else if ((drawFloatingMode) && (modeLayerOn)) {
		writeModeLayers(modeBlurb);
	} else if ((modeRefreshMap) && (drawModeOnMap)) {
		sendMapXML();
	}
}

function makeRedliningItem(e) {
    
	// start new redline item unless one already started
	if (redlineFinished)
		beginRedliningItem(e);
	else
		continueRedliningItem(e);
}

function beginRedliningItem(e) {
	// User clicked on map: place redlining item, or start it if line/polygon
	
	// changing focus to mapframe fixes values in the redlining form
	// (otherwise doesn't grab values where cursor is)
	
	//if right click do nothing
	if (event.button == 2)
	    return;
	
	if (redlineWin != null)
		window.focus();
	
	// check inputs
	var inputOk = true;
	if (redliningMode == "text" && redliningText == "") {
		alert("Please enter some text in the text box before clicking on the map");
		inputOk = false;
	}
	if (isNaN(parseInt(redliningSize))) {
		alert("Size needs to be an integer number");
		inputOk = false;
	}
	
	if (inputOk) {
	
		if (redliningMode == "line" || redliningMode == "polygon") {
			redlineFinished = false;
			resetClick();
			// turn on "Finish" button
			if (redlineWin != null && redlineWin.document.redliningForm != null && redliningMode == "polygon")
				redlineWin.setFinishSpanVisibility(true);
			if (use_jsgraphics)
		    {
		        activateRubberband(e);
		    }
		}
		else
		{
		    // convert pixel location to map coordinates
		    getMapXY(mouseX,mouseY);
		}
		
		var redlineCoords = mapX + coordsDelimiter + mapY;
		// create the redline object and add it to the array
		var newRedlineObj = new redlineObject(redliningMode, redliningColor, redliningSize, redliningStyle, redliningOutline, redliningUseOutline, redliningFont, redliningText, redlineCoords);
		redlineArray[redlineArray.length] = newRedlineObj;
		
		// add item to the user's form
		if (redlineWin != null && redlineWin.document.redliningForm != null) {
			var redList = redlineWin.document.redliningForm.redliningObjects;		
			var newOptText = (redList.length+1).toString() + ") " + newRedlineObj.mode;
			// createElement used for IE bug--when form in separate window, IE doesn't allow transfering an option to it
			var newOption = redlineWin.document.createElement("option");
			newOption.value = newOptText;			
			newOptText = newOptText.toUpperCase();
			newOption.text = newOptText;
			redList.options[redList.length] = newOption;
		}
		
		// refresh map to show redline object(s) - writeXML() calls addCustomToMap above
		if ( (redliningMode == "text") || (redliningMode == "point") )
		{
		    finishRedliningObject(true);
	        resetClick();
		    sendMapXML();
		}
	
	}
}

function continueRedliningItem(e) {
	// User is continuing previous line/polygon -- just add coords to the object
	if(redliningMode == "polygon")
	{
	    //left button click - draw another vertex
	    if(event.button == 1)
	    {
	        activateRubberband(e);
	    }
	    else if (event.button == 2) //close the polygon
	    {
	        //finishRedliningObject(true);
	        redlineFinished = true;
	        resetPolyline();
	        deactivateRubberband();
	        closePolyline();
	        sendMapXML();
	        return; //dont save the last clicked coordinate just exit the function
	    }
	        
	}
	else if(redliningMode == "line")
	{
	    getMapXY(mouseX, mouseY);
	    finishRedliningObject(true);
	    resetClick();
	}
	    
	var rCoords = pairsDelimiter + mapX + coordsDelimiter + mapY;
	var currentItem = redlineArray[redlineArray.length-1];
	currentItem.coords += rCoords;
	if(redliningMode == "line")
	{
	    sendMapXML();
	}
}

function updateItemInProgress(redlineForm) {
	if (!redlineFinished) {
		// user changed properties of a line/polygon after first map click
		var currentItem = redlineArray[redlineArray.length-1];
		currentItem.color = redliningColor;
		currentItem.size = redliningSize;
		currentItem.outline = redliningOutline;
		currentItem.useOutline = redliningUseOutline;
		currentItem.style = redliningStyle;
		// (font/text not used by line/polygon)
	}
}

function finishRedliningObject(drawMap) {
	redlineFinished = true;
	deactivateRubberband();
	closePolyline();
	var currentItem = redlineArray[redlineArray.length-1];
	//if (!completePolygon && drawMap=="true" && currentItem.mode=="polygon")
	if (drawMap=="true" && currentItem.mode=="polygon")
		sendMapXML();
}

function removeRedliningItem(deleteIndex) {
	// called by redline form to remove a redline object
	
	// move remaining items up in the array, overwriting the deleted item
	for (var i=deleteIndex; i<redlineArray.length; i++) {
		redlineArray[i] = redlineArray[i+1]
	}
	redlineArray.length -= 1;
}

function removeAllRedliningItems() {
	redlineArray.length = 0;
	sendMapXML();
}
function endredlinining()
{
    //finishRedliningObject(true);
    redlineFinished = true;
    resetPolyline();
    deactivateRubberband();
    closePolyline();
    sendMapXML();
    return; //dont save the last clicked coordinate just exit the function
}
// called during map refresh by writeXML/addCustomToMap2 - adds redline objects to map
function addRedlineToMap() {
	var redlineText = "";
	if (redlineArray.length > 0) {
		redlineText = '<LAYER type="acetate" name="Redlining" >';
		
		for (var i=0; i<redlineArray.length; i++) {
			var rObj = redlineArray[i];
			// for line/polygon, find number of points
			var arrLoc = rObj.coords.split(pairsDelimiter);
			
			redlineText += '<OBJECT units="database">';
			switch (rObj.mode) {
				case "point":
					redlineText += makePoint(rObj.coords, rObj.color, rObj.style, rObj.size, rObj.outline, rObj.useOutline);
					break;
				case "line":
					if (arrLoc.length > 1) {
						redlineText += makeLine(rObj.coords, rObj.color, rObj.style, rObj.size);
					}
					else {
						// only one point in line so far -- just show point
						redlineText += makePoint(rObj.coords, rObj.color, "circle", "3", "", false);
					}
					break;
				case "polygon":
					// if 3+ points, draw polygon; otherwise draw line/point
					if (arrLoc.length > 2 && (completePolygon || redlineFinished)) {
						redlineText += '<POLYGON coords="' + rObj.coords + '" >';
						redlineText += '<SIMPLEPOLYGONSYMBOL boundarywidth="' + rObj.size + '" boundarycolor="' + rObj.color + '"'
						if (rObj.useOutline)
							redlineText += ' filltype="' + rObj.style + '" fillcolor="' + rObj.outline + '" ';
						else
							redlineText += ' filltransparency="0.0" ';	// note this may change to 1.0 at ArcIMS 9.2
						redlineText += ' />';
						redlineText += '</POLYGON>';
					}
					else if (arrLoc.length >= 2) {
						redlineText += makeLine(rObj.coords, rObj.color, "solid", "1");
					}
					else {
						redlineText += makePoint(rObj.coords, rObj.color, "circle", "3", "", false);
					}
					break;
				case "text":
					redlineText += '<TEXT coords="' + rObj.coords + '" label="' + makeXMLsafe(rObj.text) + '" >';
					redlineText += '<TEXTMARKERSYMBOL font="' + rObj.font + '" fontcolor="' + rObj.color + '" ';
					redlineText += ' fontsize="' + rObj.size + '" fontstyle="' + rObj.style + '"';
					if (rObj.useOutline)
						redlineText += ' outline="' + rObj.outline + '"';
					redlineText += ' />';
					redlineText += '</TEXT>';
					break;
			}
			redlineText += '</OBJECT>';
		}
		
		redlineText += '</LAYER>\n';
	}
	//alert(redlineText);
	return redlineText;
}

function makePoint (coords, color, type, width, outline, useOutline) {
	
	var ptStr = '<POINT coords="' + coords + '">';
	ptStr += '<SIMPLEMARKERSYMBOL type="' + type + '" color="' + color + '"';
	ptStr += ' width="' + width + '"';
	if (useOutline)
		ptStr += ' outline="' + outline + '"';
	ptStr += ' />';
	ptStr += '</POINT>';
	return ptStr;
}

function makeLine (coords, color, type, width) {

	var lineStr = '<LINE coords="' + coords + '" >';
	lineStr += '<SIMPLELINESYMBOL type="' + type + '" color="' + color + '" ';
	lineStr += ' width="' + width + '" />';
	lineStr += '</LINE>';
	return lineStr;
}

// BB: End custom redlining code






// Code to convert from map units to decimal degrees.
// Code based on asp code from Gerry Daumiller, Montana State Library 8-23-02 email. ASP code on web at http://nris.state.mt.us/gis/projection/projection.html.  Translated to javascript by Jeff Miller, Jefferson County, WA.

// The formulae this program is based on are from "Map Projections,
// A Working Manual" by John P. Snyder, U.S. GeoLogical Survey
// Professional Paper 1395, 1987, pages 295-298

// Set up the coordinate system parameters.  Need to edit these based on state plane zone.  This for WA North and US Survey Feet.

function convertSP(uX,uY) {
	

	
a = 20925604.48;   		//major radius of ellipsoid, map units (NAD 83)



ec = 0.08181905782;  		//eccentriTown of ellipsoid (NAD 83)





angRad = 0.01745329252;  	//number of radians in a degree
pi4 = Math.PI / 4;  		//Pi / 4
p0 = 41.000000 * angRad; 	 	//latitude of origin
p1 = 41.716667 * angRad;  		//latitude of first standard parallel
p2 = 42.683333 * angRad;  	//latitude of second standard parallel
m0 = -71.5 * angRad;  	//central meridian
x0 = 656166.666667; 		//False easting of central meridian, map units

// Calculate the coordinate system constants.
with (Math) {
m1 = cos(p1) / sqrt(1 - (pow(ec,2)) * pow(sin(p1),2));  
m2 = cos(p2) / sqrt(1 - (pow(ec,2)) * pow(sin(p2),2));
t0 = tan(pi4 - (p0 / 2));
t1 = tan(pi4 - (p1 / 2));
t2 = tan(pi4 - (p2 / 2));
t0 = t0 / pow(((1 - (ec * (sin(p0)))) / (1 + (ec * (sin(p0))))),ec/2);  
t1 = t1 / pow(((1 - (ec * (sin(p1)))) / (1 + (ec * (sin(p1))))),ec/2);
t2 = t2 / pow(((1 - (ec * (sin(p2)))) / (1 + (ec * (sin(p2))))),ec/2);
n = log(m1 / m2) / log(t1 / t2);
f = m1 / (n * pow(t1,n)); 
rho0 = a * f * pow(t0,n);

// Convert the coordinate to Latitude/Longitude.

// Calculate the Longitude.
uX = uX - x0;
pi2 = pi4 * 2;

rho = sqrt(pow(uX,2) + pow((rho0 - uY),2));  
theta = atan(uX / (rho0 - uY));
txy = pow((rho / (a * f)),(1 / n));
lon = (theta / n) + m0;
uX = uX + x0;

						// Estimate the Latitude
						lat0 = pi2 - (2 * atan(txy));					
						
						// Substitute the estimate into the iterative calculation that
						// converges on the correct Latitude value.
						part1 = (1 - (ec * sin(lat0))) / (1 + (ec * sin(lat0)));
						lat1 = pi2 - (2 * atan(txy * pow(part1,(ec/2))));
						
						while ((abs(lat1 - lat0)) > 0.000000002) {
						  lat0 = lat1;
						  part1 = (1 - (ec * sin(lat0))) / (1 + (ec * sin(lat0)));
						  lat1 = pi2 - (2 * atan(txy * pow(part1,(ec/2))));
						  }

// Convert from radians to degrees.
Lat = lat1 / angRad;
Lon = lon / angRad;

//alert ("Lat" + Lat);
//alert ("Lon" + Lon);

return Lon + "|" + Lat;

}
}
//End of Code for converting map units to decimal degrees.


