// $Revision
var MAP_SIZE_RATIO = 0.618034;
var CurrentMapMode;
var CurrentMapTool;
var MapTools = new Object();
var xycoord;
var vo;
var X0 = 0;
var Y0 = 0;
var X1 = 0;
var Y1 = 0;

var globalMapPanelContainerId = null;
var globalMapPanelContainer = null;
var globalMapPanelContainerWidth = -1;

var globalIsFullWidth = false;
var globalStartMapTimeout = null;
var DEFAULT_MAP_TOOL = "defaultmaptool";

function GetMap() {
	return getElement("mapimg_id");
}

function GetMapDiv() {
	return GetMap().parentNode;
}

function GetMapContainer() {
	return getElement("mapcontainer_id");
}

function GetMapPanel() {
	return getElement("mappanel_id");
}

function GetMapPanelBody() {
	return getElement("mappanel_id_map_body");
}

function GetBox() {
	return getElement("box_id");
}

function GetBoxInside() {
	return getElement("box_inside_id");
}

function GetVectorDiv() {
	return getElement("vector_div_id");
}

function GetStickyCursorDiv() {
	return getElement("sticky_cursor_div_id");
}

function GetStickyCursor() {
	return getElement("sticky_cursor_id");
}

function InitializeMapPanel(mapPanelContainerId) {
	if (mapPanelContainerId == null) {
		errorReporter.Report("Map.js", "InitializeMapPanel(): mapPanelContainerId is not set.");
		return;
	}
	globalMapPanelContainerId = mapPanelContainerId;
	globalMapPanelContainer = getElement(globalMapPanelContainerId);
	globalMapPanelContainerWidth = globalMapPanelContainer.offsetWidth;
}

function GetMapMargin() {
	if (CurrentMapMode == "Preview") {
		return 14;
	}
	switch (currentTextSize) {
		case "small":
			return 30;
		case "medium":
		default:
			return 34;
		case "large":
			return 40;
	}
}

function InitializeMap(mapWidth) {
	var mapPanel = GetMapPanel();
	if (mapPanel == null || !IsVisibleElement(mapPanel, false)) {
		return false;
	}
	var mapDiv = GetMapDiv();
	var vectorDiv = GetVectorDiv();
	var stickyCursorDiv = GetStickyCursorDiv();
	// set map size
	if (mapWidth == null || mapWidth <= 0) {
		var margin = GetMapMargin();
		// may be called before map panel has been rendered
		if (globalMapPanelContainerWidth > margin) {
			mapWidth = globalMapPanelContainerWidth - margin;
		} else {
			mapWidth = 0;
		}
	}
	var mapHeight = parseInt(mapWidth * MAP_SIZE_RATIO) - 1;
	var map = GetMap();
	if (mapWidth > 0) {
		if (map.style == null || map.style.width != mapWidth + "px") {
			map.style.width = mapWidth + "px";
			map.style.height = mapHeight + "px";
		}
		if (mapDiv.style == null || mapDiv.style.width != mapWidth + "px") {
			mapDiv.style.width = mapWidth + "px";
			mapDiv.style.height = mapHeight + "px";
		}
		if (vectorDiv != null && (vectorDiv.style == null || vectorDiv.style.width != mapWidth + "px")) {
			vectorDiv.style.width = mapWidth + "px";
			vectorDiv.style.height = mapHeight + "px";
		}
		if (stickyCursorDiv != null && (stickyCursorDiv.style == null || stickyCursorDiv.style.width != mapWidth + "px")) {
			stickyCursorDiv.style.width = mapWidth + "px";
			stickyCursorDiv.style.height = mapHeight + "px";
		}
	}
	AbsLeft(map);
	AbsTop(map);
	return mapWidth > 0;
}

function StartMap(mapMode) {
	CurrentMapMode = mapMode;
	if (InitialBusyMap()) {
		setTimeout("StartMap2(CurrentMapMode)", 0);
	}
}

function StartMap2(mapMode) {
	var map = GetMap();
	var url = new Url(LOADSCRIPT_URL);
	url.Append("command", "start_map");
	url.Append("mapmode", mapMode);
	url.Append("mapimg_width", map.offsetWidth);
	url.Append("mapdiv_width", map.parentNode.offsetWidth);
	url.Append("windowwidthpx", GetPageWidth());
	url.Append("windowheightpx", GetPageHeight());
	url.Append("screenwidthpx", window.screen.width);
	LoadScript(url.toString());
}

function InitialBusyMap(mapWidth) {
	var map = GetMap();
	if (map == null || !InitializeMap(mapWidth)) {
		return false;
	}
	// MapBusy doesn't work until map size has been set
	MapBusy(true);
	return true;
}

function UpdateAoiPanel()
{
	if (LOADSCRIPT_URL == null) {
		errorReporter.Report("Map.js", "UpdateAoiPanel(): LOADSCRIPT_URL is not set.");
		return;
	}
	// handler for getaoiprops zooms to AOI
	MapBusy(true);
	var url = new Url(LOADSCRIPT_URL);
	url.Append("command", "getaoiprops");
	LoadScript(url.toString());
}

var MAP_BUSY_BACKDROP_ID = "mapbusybackdropid";
var MAP_BUSY_BACKDROP_IMG_ID = "mapbusybackdropimgid";

function MapBusy(doBusy, message)
{
	var busyBackdrop = getElement(MAP_BUSY_BACKDROP_ID);
	if (busyBackdrop == null) {
		return;
	}
	var busyBackdropImg = getElement(MAP_BUSY_BACKDROP_IMG_ID);
	if (doBusy) {
	    if (cancelScripts != undefined) {
		    cancelScripts.Add("MapBusy(false)");
		}
		var container = busyBackdrop.offsetParent;
		if (container == null) {
			return;
		}
		busyBackdrop.style.width = container.offsetWidth + "px";
		if (isMozilla) {
			busyBackdrop.style.height = container.offsetHeight + Number(4) + "px";
		} else {
			busyBackdrop.style.height = container.offsetHeight + "px";
		}
		busyBackdropImg = getElement(MAP_BUSY_BACKDROP_IMG_ID);
		if (busyBackdropImg != null) {
			busyBackdropImg.style.width = busyBackdrop.style.width;
			busyBackdropImg.style.height = busyBackdrop.style.height;
		}
		busyBackdrop.style.visibility = "visible";
		SetBusyMessage(doBusy, message);
	} else {
		window.setTimeout("cancelScripts.RemoveAll()", 0);
		busyBackdrop.style.visibility = "hidden";
		if (globalBusyCounter == 0) {
			SetBusyMessage(doBusy, null);
		}
	}
}

var EPSILON = 0;

function withinEpsilon(a, b) {
	return Math.abs(a - b) <= EPSILON;
}

// CoordArray object
// example:
//  var a = new CoordArray(xycoord);
//  var b = new CoordArray(0, 1, 2, 3);
function CoordArray() {
	this.a = new Array();
	this.length = 0;
	this.lastX = null;
	this.lastY = null;
	if (arguments.length == 1 && arguments[0].constructor == XYCoord) {
		// input is an XYCoord object, where XYCoord.x is an array of x coordinates and XYCoord.y is the
		// corresponding array of y coordinates.
		if (arguments[0].x.length != arguments[0].y.length) {
			throw new Error("CoordArray constructor: XYCoord with unequal x and y arrays");
		}
		for (var i = 0; i < arguments[0].x.length; i++) {
			this.AddPoint(arguments[0].x[i], arguments[0].y[i]);
		}
	} else {
		// input is a series of numbers, where arguments[2n] (arguments[0], arguments[2], arguments[4] etc.)
		// is an x coordinates, and arguments[2n + 1] (arguments[1], arguments[3], arguments[5] etc.) is the
		// corresponding y coordinate.
		for (var j = 0; j + 1 - 0 < arguments.length; j += 2 - 0) {
			this.AddPoint(arguments[j], arguments[j + 1 - 0]);
		}
	}
}

CoordArray.prototype.AddPoint = function(x, y) {
	if (arguments.length < 2) {
		throw new Error("CoordArray.AddPoint: two coordinates required.");
	}
	// don't add another point just like the last one
	if (this.lastX != null && this.lastY != null && withinEpsilon(this.lastX, x) && withinEpsilon(this.lastY, y)) {
		return false;
	}
	var c = new Array();
	c.push(x);
	this.lastX = x;
	c.push(y);
	this.lastY = y;
	this.a.push("[" + c.toString() + "]");
	this.length++;
	return true;
}

CoordArray.prototype.toString = function() {
	return "[" + this.a.toString() + "]"
}

function XYCoord() {
	this.x = new Array();
	this.y = new Array();
	this.length = 0;
	this.area = 0;
	this.lastX = null;
	this.lastY = null;
}

XYCoord.prototype.AddPoint = function(x, y) {
	if (arguments.length < 2) {
		throw new Error("XYCoord.AddPoint: two coordinates required.");
	}
	// don't add another point just like the last one
	if (this.lastX != null && this.lastY != null && withinEpsilon(this.lastX, x) && withinEpsilon(this.lastY, y)) {
		return false;
	}
	this.x.push(x);
	this.lastX = x;
	this.y.push(y);
	this.lastY = y;
	this.length++;
	return true
}

XYCoord.prototype.RemovePoint = function() {
	this.length--;
	this.x.length = this.y.length = this.length;
	this.lastX = this.x[this.length - 1];
	this.lastY = this.y[this.length - 1];
}

XYCoord.prototype.Area = function() {
	if (this.areaLength != this.length) {
		this.area = 0;
	}
	if (this.area == 0) {
		var area2 = 0;
		for (var i = 0; i < this.length - 1; i++) {
			area2 += (this.x[i] * this.y[i + 1] - this.x[i + 1] * this.y[i]);
		}
		this.area = area2 / 2;
		this.areaLength = this.length;
	}
	return this.area;
}

XYCoord.prototype.CentroidX = function() {
	var centroidX = 0;
	for (var i = 0; i < this.length - 1; i++) {
		centroidX += (this.x[i] + this.x[i + 1]) * (this.x[i] * this.y[i + 1] - this.x[i + 1] * this.y[i]);
	}
	return centroidX / (6 * this.Area());
}

XYCoord.prototype.CentroidY = function() {
	var centroidY = 0;
	for (var i = 0; i < this.length - 1; i++) {
		centroidY += (this.y[i] + this.y[i + 1]) * (this.x[i] * this.y[i + 1] - this.x[i + 1] * this.y[i]);
	}
	return centroidY / (6 * this.Area());
}

XYCoord.prototype.MinX = function() {
	var minX = this.x[0];
	for (var i = 1; i < this.length; i++) {
		if (this.x[i] < minX) {
			minX = this.x[i];
		}
	}
	return minX;
}

XYCoord.prototype.MaxX = function() {
	var maxX = this.x[0];
	for (var i = 1; i < this.length; i++) {
		if (this.x[i] > maxX) {
			maxX = this.x[i];
		}
	}
	return maxX;
}

XYCoord.prototype.MinY = function() {
	var minY = this.y[0];
	for (var i = 1; i < this.length; i++) {
		if (this.y[i] < minY) {
			minY = this.y[i];
		}
	}
	return minY;
}

XYCoord.prototype.MaxY = function() {
	var maxY = this.y[0];
	for (var i = 1; i < this.length; i++) {
		if (this.y[i] < maxY) {
			maxY = this.y[i];
		}
	}
	return maxY;
}

// MapTool object
function MapTool(command, buttonId, singleClickMode, cursor, action, setFunction, releaseFunction, busyFunction, busyMessage) {
	this.command = command;
	this.buttonId = buttonId;
	if (singleClickMode == null) {
		this.singleClickMode = null;
	} else {
		switch (singleClickMode) {
			case MapTool.SEND_ALL:
			case MapTool.SEND_ONE:
			case MapTool.SEND_NONE:
				this.singleClickMode = singleClickMode;
				break;
			default:
				throw new Error("MapTool: invalid singleClickMode " + singleClickMode);
				break;
		}
	}
	this.cursor = cursor;
	this.action = action;
	this.setFunction = setFunction;
	this.releaseFunction = releaseFunction;
	this.busyFunction = busyFunction;
	this.busyMessage = busyMessage;
}

MapTool.SEND_ALL = "send_all";
MapTool.SEND_ONE = "send_one";
MapTool.SEND_NONE = "send_none";

function AddMapTool(command, buttonId, singleClickMode, cursor, action, setFunction, releaseFunction, busyFunction, busyMessage) {
	var mapTool = new MapTool(command, buttonId, singleClickMode, cursor, action, setFunction, releaseFunction, busyFunction, busyMessage);
	MapTools[command] = mapTool;
	if (MapTools[DEFAULT_MAP_TOOL] == null) {
		MapTools[DEFAULT_MAP_TOOL] = mapTool;
	}
}

function SetZoomIn() {
	DoSetStyleClass(GetBox(), "zoom");
}

function ReleaseZoomIn() {
	HideBox();
}

function SetIdentify() {
	// display output panel
	var outputPanel = document.getElementById("outputpanelid");
	if (outputPanel != null) {
		var url = new Url(LOADSCRIPT_URL);
		url.Append("command", "new_identify");
		url.Append("mapmode", CurrentMapMode);
		LoadScript(url.toString());
	}
}

function ReleaseIdentify() {
	HideStickyCursorDiv();
}

function SetAOIRectangle() {
	DoSetStyleClass(GetBox(), "aoi");
}

function ReleaseAOIRectangle() {
	HideBox();
}

function SetAOIPolygon() {
	// display vector div
	lineWidth = 3;
	divColor = "#990033";
	xycoord = new XYCoord();
	var vectorDiv = GetVectorDiv();
	if (vo != null) {
		vo.clearObjects();
		vo.drawObjects();
	}
	vo = new vectorObjects(vectorDiv.id);
	PushOnMouseUp(PolygonClick, true);
	vectorDiv.style.display = "block";
}

function ReleaseAOIPolygon() {
	HideVectorDiv();
}

function SetMeasure() {
	// display vector div
	lineWidth = 2;
	divColor = "#00FF00";
	xycoord = new XYCoord();
	var vectorDiv = GetVectorDiv();
	if (vo != null) {
		vo.clearObjects();
		vo.drawObjects();
	}
	vo = new vectorObjects(vectorDiv.id);
	PushOnMouseDown(PolyLineClick, true);
	vectorDiv.style.display = "block";
	// Scroll output panel into view, if measure container is not already present.
	var outputPanel = getElement("outputpanelid");
	if (outputPanel != null) {
		var url = new Url(LOADSCRIPT_URL);
		url.Append("command", "newmeasurepanel");
		if (getElement("measurecontainerid") == null || !IsVisible("measurecontainerid", true)) {
			url.Append("doScroll", "true");
		}
		LoadScript(url.toString());
	}
}

function ReleaseMeasure() {
	HideVectorDiv();
	PopOnMouseDown(PolyLineClick);
	PopOnMouseMove(PolyLineMove);
	PopOnDblClick(PolyLineEnd);
	document.onkeyup = null;
}

function DoCommandIfEnabled(buttonId, command, event) {
	if (event == null) {
		event = window.event;
	}
	if (IsValidButton(event) && !IsLeftMouseButton(event)) {
		return Finish(event);
	}
	var span = getElement(unEscape(buttonId));
	if (span != null) {
		var button = new MapButton(span);
		if (button.state != MapButton.DISABLED) {
			MapBusy(true);
			var url = new Url(LOADSCRIPT_URL);
			url.Append("command", command);
		    url.Append("mapmode", CurrentMapMode);
			LoadScript(url.toString());
		}
	}
	return DoPropagate(false, event);
}

function SetMapTool(tool, doNotifyServer, event) {
	if (window.event) {
		event = window.event;
	}
	if (event != null && IsValidButton(event) && !IsLeftMouseButton(event)) {
		return Finish(event);
	}
	if (MapTools[tool] == null) {
		SetMapTool(MapTools[DEFAULT_MAP_TOOL].command, true);
		return;
	} 
	if (CurrentMapTool != null) {
		if (CurrentMapTool.releaseFunction != null) {
			CurrentMapTool.releaseFunction();
		}
	}
	CurrentMapTool = MapTools[tool];
	if (!UpDown(CurrentMapTool.buttonId, "tool", "mapleftspan_id", "mousedown")) {
	    if (CurrentMapTool.command != MapTools[DEFAULT_MAP_TOOL].command) {
		    SetMapTool(MapTools[DEFAULT_MAP_TOOL].command, true);
		}
		return;
	}
	if (doNotifyServer) {
		var url = new Url(LOADSCRIPT_URL);
		url.Append("command", "set_map_tool");
		url.Append("map_tool", CurrentMapTool.command);
        url.Append("mapmode", CurrentMapMode);
		LoadScript(url.toString());
	}
	if (CurrentMapTool.setFunction != null) {
		CurrentMapTool.setFunction();
	}
	var map = GetMap();
	var mapDiv = map.parentNode;
	map.style.cursor = CurrentMapTool.cursor;
	mapDiv.style.cursor = CurrentMapTool.cursor;
}

function SetLayout(layout, event) {
	if (event == null) {
		event = window.event;
	}
	if (event != null && IsValidButton(event) && !IsLeftMouseButton(event)) {
		return Finish(event);
	}
	var url = new Url(LOADSCRIPT_URL);
	url.Append("command", "expand");
	switch (layout) {
		case "layout_fullwidth":
			url.Append("doexpand", "true");
			break;
		case "layout_normal":
			url.Append("doexpand", "false");
			break;
		default:
			errorReporter.Report("Map.js", "SetLayout: Unknown layout \"" + layout + "\"");
			return;
			break;
	}
    url.Append("mapmode", CurrentMapMode);
	LoadScript(url.toString());
}

// MapButton object
function MapButton(span) {
	this.span = span;
	this.upId = this.span.id + "_up";
	this.downId = this.span.id + "_down";
	this.disabledId = this.span.id + "_disabled";
	this.currentImgId = (isIE) ? this.span.currentimg : this.span.getAttribute("currentimg");
	if  (this.currentImgId == this.upId) {
		this.state = MapButton.UP;
	} else if (this.currentImgId == this.downId) {
		this.state = MapButton.DOWN;
	} else if (this.currentImgId == this.disabledId) {
		this.state = MapButton.DISABLED;
	} else {
		// default state
		this.SetState(MapButton.UP);
	}
	this.mode = (isIE) ? this.span.mode : this.span.getAttribute("mode");
}

MapButton.UP = "up";
MapButton.DOWN = "down";
MapButton.DISABLED = "disabled";

MapButton.prototype.SetState = function(state) {
	switch (state) {
		case MapButton.UP:
			this.state = MapButton.UP;
			this.currentImgId = this.upId;
			if (isIE) {
				this.span.currentimg = this.upId;
			} else {
				this.span.setAttribute("currentimg", this.upId);
			}
			Display(this.upId, true);
			Display(this.downId, false);
			Display(this.disabledId, false);
			break;
		case MapButton.DOWN:
			this.state = MapButton.DOWN;
			this.currentImgId = this.downId;
			if (isIE) {
				this.span.currentimg = this.downId;
			} else {
				this.span.setAttribute("currentimg", this.downId);
			}
			Display(this.downId, true);
			Display(this.upId, false);
			Display(this.disabledId, false);
			break;
		case MapButton.DISABLED:
			this.state = MapButton.DISABLED;
			this.currentImgId = this.disabledId;
			if (isIE) {
				this.span.currentimg = this.disabledId;
			} else {
				this.span.setAttribute("currentimg", this.disabledId);
			}
			Display(this.disabledId, true);
			Display(this.upId, false);
			Display(this.downId, false);
			break;
	}
}

function EnableImgButton(id, doEnable) {
	id = unEscape(id);
	var span = getElement(id);
	if (span != null) {
		var button = new MapButton(span);
		if (doEnable) {
			button.SetState(MapButton.UP);
			if (button.mode == "tool" && CurrentMapTool.buttonId == id) {
				// retain this tool
				button.SetState(MapButton.DOWN);
			} else {
				button.SetState(MapButton.UP);
			}
		} else {
			button.SetState(MapButton.DISABLED);
			if (button.mode == "tool" && CurrentMapTool.buttonId == id) {
				// abandon this tool
				SetMapTool("default", true);
			}
		}
	}
}

function MouseUpDown(id, mode, groupId, event) {
	if (event == null) {
		event = window.event;
	}
	if (IsValidButton(event) && IsRightMouseButton(event)) {
		switch (event.type) {
			case "mousedown":
				return Finish(event);
			case "mouseup":
				return ContextMenu(event);
			default:
				return Finish(event);
		}
	}
	if (IsValidButton(event) && !IsLeftMouseButton(event)) {
		return Finish(event);
	}
	UpDown(id, mode, groupId, event.type);
	return Finish(event);
}

function UpDown(id, mode, groupId, type) {
	id = unEscape(id);
	var span = getElement(id);
	if (span == null) {
		return false;
	}
	var button = new MapButton(span);
	if (button.state == MapButton.DISABLED) {
		return false;
	}
	if (mode == "tool" && type == "mousedown") {
		button.SetState(MapButton.DOWN);
		groupId = unEscape(groupId);
		var group = getElement(groupId);
		if (group == null) {
			errorReporter.Report("Map.js", "UpDown: group '" + groupId + "' not found.");
			return false;
		}
		var otherButtons = GetDescendentsByTagNameAndClassName(group, "span", "mapbutton");
		for (var i = 0; i < otherButtons.length; i++) {
			var otherSpan = otherButtons[i];
			var otherId = otherSpan.id;
			if (otherId == id) {
				continue;
			}
			var otherSpan = getElement(otherId);
			var otherButton = new MapButton(otherSpan);
			if (otherButton.state == MapButton.DISABLED) {
				continue;
			}
			if (otherButton.mode == "tool") {
				otherButton.SetState(MapButton.UP);
			}
		}
	} else if (mode == "command") {
		if (type == "mousedown") {
			button.SetState(MapButton.DOWN);
			// in case we don't get the mouseup event
			window.setTimeout("UpDown('" + id + "','command',null,'mouseup')", 750);
		} else if (type == "mouseup") {
			button.SetState(MapButton.UP);
		}
	}
	return true;
} 

function HideBox() {
	var box = GetBox();
	if (box != null) {
		box.style.display = "none";
	}
}

function HideVectorDiv() {
	var vectorDiv = GetVectorDiv();
	if (vectorDiv != null) {
		vectorDiv.innerHTML = null;
		vectorDiv.style.display = "none";
	}
}

function HideStickyCursorDiv() {
	var stickyCursorDiv = GetStickyCursorDiv();
	if (stickyCursorDiv != null) {
		stickyCursorDiv.style.display = "none";
	}
}

function MapAction(event)
{
	if (event == null) {
		event = window.event;
	}
	// if not left button, don't go on.
	if (IsValidButton(event) && !IsLeftMouseButton(event)) {
		return Finish(event);
	}
	if (CurrentMapTool != null && CurrentMapTool.action != null) {
		CurrentMapTool.action(event);
	}
	return Finish(event);
}

function ActionZoomOut(event) {
	if (event == null) {
		event = window.event;
	}
	var map = GetMap();
	var coords = new CoordArray(RelX(map, event), RelY(map, event));
	var url = new Url(LOADSCRIPT_URL);
	url.Append("command", "zoom_out");
	url.Append("mapmode", CurrentMapMode);
	url.Append("coordinate_array", coords.toString());
	MapBusy(true);
	LoadScript(url.toString());
	return Finish(event);
}

function ActionIdentify(event) {
	if (event == null) {
		event = window.event;
	}
	var map = GetMap();
	var x = RelX(map, event);
	var y = RelY(map, event);
	var coords = new CoordArray(x, y);
	DisplayStickyCursor(x, y);
	var url = new Url(LOADSCRIPT_URL);
	url.Append("command", "identify");
	url.Append("mapmode", CurrentMapMode);
	url.Append("coordinate_array", coords.toString());
	MapBusy(true);
	LoadScript(url.toString());
	return Finish(event);
}

function ActionDataStatus(event) {
	if (event == null) {
		event = window.event;
	}
	var map = GetMap();
	var x = RelX(map, event);
	var y = RelY(map, event);
	var coords = new CoordArray(x, y);
	DisplayStickyCursor(x, y);
	var url = new Url(LOADSCRIPT_URL);
	url.Append("command", "data_status");
	url.Append("mapmode", CurrentMapMode);
	url.Append("coordinate_array", coords.toString());
	MapBusy(true);
	LoadScript(url.toString());
	return Finish(event);
}

function DisplayStickyCursor(x, y) {
	var stickyCursor = GetStickyCursor();
	var stickyCursorDiv = GetStickyCursorDiv();
	// until it is visible, it has no height or width
	stickyCursorDiv.style.display = "";
	var leftDisplacement = parseInt(stickyCursor.offsetWidth / 2);
	var topDisplacement = parseInt(stickyCursor.offsetHeight / 2);
	stickyCursor.style.left = x - leftDisplacement + "px";
	stickyCursor.style.top = y - topDisplacement + "px";
}

function RefreshMap(event) {
	if (event == null) {
		event = window.event;
	}
	var url = new Url(LOADSCRIPT_URL);
	url.Append("command", CurrentMapTool.command);
	url.Append("mapmode", CurrentMapMode);
	MapBusy(true);
	LoadScript(url.toString());
	return Finish(event);
}

function RectangleDown(event) {
	if (event == null) {
		event = window.event;
	}
	var map = GetMap();	
	X0 = RelX(map, event);
	Y0 = RelY(map, event);
	DrawBox(map, event);
	PushOnMouseMove(RectangleMove); 
	PushOnMouseUp(RectangleUp);
	document.onkeyup = RectangleAbort;
	return Finish(event);
}

function RectangleAbort(event) {
	if (event == null) {
		event = window.event;
	}
	switch (event.keyCode) {
		// Escape
		case 27:
			PopOnMouseMove(RectangleMove);
			PopOnMouseUp(RectangleUp);
			document.onkeyup = null;
			HideBox();
			break;
	}
	return Finish(event);	
}

function RectangleMove(event) {
	if (event == null) {
		event = window.event;
	}	
	if (isIE) {
		// catch mouse up event outside the map
		if (event.button == 0) {
			// return RectangleUp(event);
			return Finish(event);
		}
	}
	var map = GetMap();
	DrawBox(map, event);
	return Finish(event);
}

function RectangleUp(event) {
	if (event == null) {
		event = window.event;
	}
	PopOnMouseMove(RectangleMove);
	PopOnMouseUp(RectangleUp);
	
	var map = GetMap();
	var box = GetBox();
 	var coords;
	X1 = RelX(map, event);
	Y1 = RelY(map, event);
	var width = parseInt(map.style.width);
	var height = parseInt(map.style.height);
	var url = new Url(LOADSCRIPT_URL);
			
	switch (CurrentMapTool.singleClickMode) {
		case MapTool.SEND_NONE:
			coords = new CoordArray(X0, Y0);
			if (coords.AddPoint(Math.min(X1, width - 1), Math.min(Y1, height - 1))) {
				url.Append("command", CurrentMapTool.command);
				url.Append("mapmode", CurrentMapMode);
				url.Append("coordinate_array", coords.toString());
				if (CurrentMapTool.busyFunction != null) {
					CurrentMapTool.busyFunction(true, CurrentMapTool.busyMessage);
				}
				LoadScript(url.toString());
				DrawBox(map, event);
			} else {
				HideBox();
			}
			break;
		case MapTool.SEND_ONE:
		case MapTool.SEND_ALL:
		default:
			coords = new CoordArray(X0, Y0);
			coords.AddPoint(Math.min(X1, width - 1), Math.min(Y1, height - 1));
			url.Append("command", CurrentMapTool.command);
			url.Append("mapmode", CurrentMapMode);
			url.Append("coordinate_array", coords.toString());
			if (CurrentMapTool.busyFunction != null) {
				CurrentMapTool.busyFunction(true);
			}
			LoadScript(url.toString());
			DrawBox(map, event);
			break;
	}
	return Finish(event);
}

function DrawBox(map, event) {
	X1 = RelX(map, event);
	Y1 = RelY(map, event);
	var mapWidth = parseInt(map.style.width);
	var mapHeight = parseInt(map.style.height);
	var box = GetBox();
	var boxBorderWidth = parseInt(box.style.borderWidth);
	var boxInside = GetBoxInside();
	
	var left = Math.max(Math.min(X1, X0), 0);
	box.style.left = Math.min(left, mapWidth - 2 * boxBorderWidth) + "px";
	var top = Math.max(Math.min(Y1, Y0), 0);
	box.style.top = Math.min(top, mapHeight - 2 * boxBorderWidth) + "px";
	var width = Math.max(Math.abs(X1 - X0) - 2 * boxBorderWidth, 0);
	box.style.width = width + "px";
	var height = Math.max(Math.abs(Y1 - Y0) - 2 * boxBorderWidth, 0);
	box.style.height = height + "px";

	boxInside.style.left = left + Number(boxBorderWidth) + "px";
	boxInside.style.top = top + Number(boxBorderWidth) + "px";
	boxInside.style.width = box.style.width;
	boxInside.style.height = box.style.height;
	
	box.style.display = "";
	// window.top.status = "left = " + left + " top = " + top + " width = " + width + " height = " + height;
	// window.top.status = "X0 = " + X0 + " Y0 = " + Y0 + " X1 = " + X1 + " Y1 = " + Y1;
}

function PolyLineAbort(event) {
	if (event == null) {
		event = window.event;
	}
	switch (event.keyCode) {
		// Escape
		case 27:
			PopOnMouseMove(PolyLineMove);
			PopOnDblClick(PolyLineEnd);
			document.onkeyup = null;
			SetMeasure();
			break;
	}
	return Finish(event);	
}

function PolyLineClick(event) {
	if (event == null) {
		event = window.event;
	}
	if (!IsInMap(event)) {
		// pass on the event
		return true;
	}
	if (xycoord.length == 0) {
		SetMeasure();
		PushOnMouseMove(PolyLineMove, true);
		PushOnDblClick(PolyLineEnd, true);
		document.onkeyup = PolyLineAbort;
	}
	var map = GetMap();
	var x = RelX(map, event);
	var y = RelY(map, event);
	if (xycoord.AddPoint(x, y)) {
		// user added a distinct point
		if (xycoord.length > 1) {
			vo.clearObjects();	
			vo.polyline(xycoord.x, xycoord.y);
			command = "vo.drawObjects()";
			window.setTimeout(command, 0);
			var vectorDiv = GetVectorDiv();
			vectorDiv.style.display = "";
			if (IsCtrl(event)) {
				// user pressed CTRL: finish
				return PolyLineEnd(event);
			}
			var coords = new CoordArray(xycoord);
			var url = new Url(LOADSCRIPT_URL);
			// annoying hack here
			url.Append("command", "measuresegment");
			url.Append("mapmode", CurrentMapMode);
			url.Append("coordinate_array", coords.toString());
			url.Append("scrolltop", GetScrollTop());
			if (CurrentMapTool.busyFunction != null) {
				CurrentMapTool.busyFunction(true, CurrentMapTool.busyMessage);
			}
			LoadScript(url.toString());
		}
	} else if (xycoord.length > 1) {
		// user double clicked, slowly: finish
		return PolyLineEnd(event);
	}
	return Finish(event);
}

function PolyLineMove(event) {
	if (event == null) {
		event = window.event;
	}
	var map = GetMap();
	var vectorDiv = GetVectorDiv();
	var x = RelX(map, event);
	var y = RelY(map, event);
	// window.top.status = "x = " + x + " y = " + y + " xycoord.length = " + xycoord.length;
	if (xycoord.length == 1) {
		vo.clearObjects();
		vo.line(xycoord.lastX, xycoord.lastY, x, y);
		command = "vo.drawObjects()";
		window.setTimeout(command, 0);
		vectorDiv.style.display = "";
	} else if (xycoord.length > 1) {
		var xTmp = new Array();
		var yTmp = new Array();
		for (var i = 0; i < xycoord.length; i++) {
			xTmp.push(xycoord.x[i]);
			yTmp.push(xycoord.y[i]);
		}
		xTmp.push(x);
		yTmp.push(y);
		vo.clearObjects();
		vo.polyline(xTmp, yTmp);
		command = "vo.drawObjects()";
		window.setTimeout(command, 0);
		vectorDiv.style.display = "";
	}
	return Finish(event);
}

function PolyLineEnd(event) {
	if (event == null) {
		event = window.event;
	}
	if (event.type == "dblclick") {
		if (IsInMap(event)) {
			var map = GetMap();
			var vectorDiv = GetVectorDiv();
			var x = RelX(map, event);
			var y = RelY(map, event);
			// if this point has not already been added in the single click handler, add it now
			if (xycoord.AddPoint(x, y)) {
				if (xycoord.length > 1) {
					// this rarely happens
					vo.clearObjects();	
					vo.polyline(xycoord.x, xycoord.y);
					vo.drawObjects();
				}
			}
		}
	}
	if (xycoord.length > 1) {
		PopOnMouseMove(PolyLineMove);
		PopOnDblClick(PolyLineEnd);	
		var coords = new CoordArray(xycoord);
		var url = new Url(LOADSCRIPT_URL);
		url.Append("command", CurrentMapTool.command);
		url.Append("mapmode", CurrentMapMode);
		url.Append("coordinate_array", coords.toString());
		if (CurrentMapTool.busyFunction != null) {
			CurrentMapTool.busyFunction(true, CurrentMapTool.busyMessage);
		}
		LoadScript(url.toString());
		xycoord = new XYCoord();
	}
	return Finish(event);
}

function PanDown(event) {
	if (event == null) {
		event = window.event;
	}
	
	var map = GetMap();	
	X0 = RelX(map, event);
	Y0 = RelY(map, event);
	
	PushOnMouseMove(PanMove); 
	PushOnMouseUp(PanUp);
	
	return Finish(event);
}

function PanMove(event) {
	if (event == null) {
		event = window.event;
	}	
	if (isIE) {
		// catch mouse up event outside the map
		if (event.button == 0) {
			PanUp(event);
			return Finish(event);
		}
	} else if ((typeof(event.originalTarget) != "undefined") && (event.originalTarget != null)) {
		if (event.target != event.originalTarget) {
			PanUp(event);
			return Finish(event);
		}
	}
	var map = GetMap();
	MoveMap(map, event);
	return Finish(event);
}

function PanUp(event) {
	if (event == null) {
		event = window.event;
	}
	PopOnMouseMove(PanMove);
	PopOnMouseUp(PanUp);

	var map = GetMap();
 	var coords;
	X1 = RelX(map, event);
	Y1 = RelY(map, event);
	var width = parseInt(map.style.width);
	var height = parseInt(map.style.height);
	var url = new Url(LOADSCRIPT_URL);
			
	switch (CurrentMapTool.singleClickMode) {
		case MapTool.SEND_NONE:
		case MapTool.SEND_ONE:
		case MapTool.SEND_ALL:
		default:
			coords = new CoordArray(X0, Y0);
			if (coords.AddPoint(Math.min(X1, width), Math.min(Y1, height))) {
				url.Append("command", CurrentMapTool.command);
				url.Append("mapmode", CurrentMapMode);
				url.Append("coordinate_array", coords.toString());
				MapBusy(true);
				LoadScript(url.toString());
			}
			break;
	}
	return Finish(event);
}

function MoveMap(map, event) {
	X1 = RelX(map, event);
	Y1 = RelY(map, event);

	var xMove = X1 - X0;
	var yMove = Y1 - Y0;
	var cTop, cRight, cBottom, cLeft;

	// move
	map.style.left = xMove + "px";
	map.style.top = yMove + "px";
	
	// clip
	cLeft = -xMove;
	cTop = -yMove;
	cRight = map.offsetWidth;
	cBottom = map.offsetHeight;
	if (xMove > 0) {
		cLeft = 0;
		cRight = map.offsetWidth - xMove;
	}
	if (yMove > 0) {
		cTop = 0;
		cBottom = map.offsetHeight - yMove;
	}
	map.style.clip = "rect(" + cTop + "px " + cRight + "px " + cBottom + "px " + cLeft + "px)";
}

function PolygonAbort(event) {
	if (event == null) {
		event = window.event;
	}
	switch (event.keyCode) {
		// Escape
		case 27:
			PopOnMouseMove(PolygonMove);
			PopOnDblClick(PolygonEnd);
			document.onkeyup = null;
			SetAOIPolygon();
			break;
/*
		// Backspace
		case 8:
			switch (xycoord.length) {
				case 0:
					break;
				case 1:
					PopOnMouseMove(PolygonMove);
					PopOnDblClick(PolygonEnd);
					document.onkeyup = null;
					SetAOIPolygon();
					break;
				case 2:
					xycoord.RemovePoint();
					vo.clearObjects();	
					vo.polyline(xycoord.x, xycoord.y);
					vo.drawObjects();
					break;
				default:
					xycoord.RemovePoint();
					vo.clearObjects();	
					vo.polygon(xycoord.x, xycoord.y);
					vo.drawObjects();
			}
			break;
*/
	}
	return Finish(event);	
}

function PolygonClick(event) {
	if (event == null) {
		event = window.event;
	}
	if (!IsInMap(event)) {
		// pass on the event
		return true;
	}
	var map = GetMap();
	var vectorDiv = GetVectorDiv();
	if (xycoord.length == 0) {
		PushOnMouseMove(PolygonMove);
		PushOnDblClick(PolygonEnd);
		document.onkeyup = PolygonAbort;
	}
	var x = RelX(map, event);
	var y = RelY(map, event);
	if (xycoord.AddPoint(x, y)) {
		// user added a distinct point
		if (xycoord.length > 1) {
			vo.clearObjects();	
			if (xycoord.length > 2) {
				vo.polygon(xycoord.x, xycoord.y);
				if (IsCtrl(event)) {
					// user pressed CTRL: finish
					return PolygonEnd(event);
				}
			} else {
				vo.polyline(xycoord.x, xycoord.y);
			}
			command = "vo.drawObjects()";
			window.setTimeout(command, 0);
		}
	} else if (xycoord.length > 2) {
		// user double clicked, slowly: finish
		return PolygonEnd(event);
	}
	return Finish(event);
}

function PolygonMove(event) {
	if (event == null) {
		event = window.event;
	}
	var map = GetMap();
	var x = RelX(map, event);
	var y = RelY(map, event);
	var command;
	if (xycoord.length == 1) {
		vo.clearObjects();
		vo.line(xycoord.lastX, xycoord.lastY, x, y);
		command = "vo.drawObjects()";
		window.setTimeout(command, 0);
	} else if (xycoord.length > 1) {
		var xTmp = new Array();
		var yTmp = new Array();
		for (var i = 0; i < xycoord.length; i++) {
			xTmp.push(xycoord.x[i]);
			yTmp.push(xycoord.y[i]);
		}
		xTmp.push(x);
		yTmp.push(y);
		vo.clearObjects();
		vo.polygon(xTmp, yTmp);
		command = "vo.drawObjects()";
		window.setTimeout(command, 0);
	}
	return Finish(event);
}

function PolygonEnd(event) {
	if (event == null) {
		event = window.event;
	}
	if (event.type == "dblclick") {
		if (IsInMap(event)) {
			var map = GetMap();
			var vectorDiv = GetVectorDiv();
			var x = RelX(map, event);
			var y = RelY(map, event);
			// if this point has not already been added in the single click handler, add it now
			if (xycoord.AddPoint(x, y)) {
				if (xycoord.length > 1) {
					// this rarely happens
					vo.clearObjects();	
					if (xycoord.length > 2) {
						vo.polygon(xycoord.x, xycoord.y);
					} else {
						vo.polyline(xycoord.x, xycoord.y);
					}
					command = "vo.drawObjects()";
					window.setTimeout(command, 0);
				}
			}
		}
	}
	if (xycoord.length > 2) {
		PopOnMouseUp(PolygonClick);
		PopOnMouseMove(PolygonMove);
		PopOnDblClick(PolygonEnd);	
		var coords = new CoordArray(xycoord);
		var url = new Url(LOADSCRIPT_URL);
		url.Append("command", CurrentMapTool.command);
		url.Append("mapmode", CurrentMapMode);
		url.Append("coordinate_array", coords.toString());
		if (CurrentMapTool.busyFunction != null) {
			CurrentMapTool.busyFunction(true, CurrentMapTool.busyMessage);
		}
		LoadScript(url.toString());
	}
	return Finish(event);
}

// Report event location relative to element. For debug purposes only!
function ReportXY(msg, element, doAppend, event) {
	if (event == null) {
		event = window.event;
	}
	try {
		var s = (msg == null) ? "" : (msg + " ");
		s += "X = " + RelX(element, event);
		s += " Y = " + RelY(element, event);
		if (doAppend) {
			if (window.top.status.length > 0) {
				s = " " + s;
			}
			window.top.status += s;
		} else {
			window.top.status = s;
		}
	}
	catch (e) {
		alert("Map.js: ReportXY: " + e.name + ": " + e.message);
	}
}

function IsInMap(event) {
	var map = GetMap();
	if (map == null) {
		return false;
	}
	if (Dialogs.isInDialog(event)) {
		return false;
	}
	if (IsInBib(event)) {
		return false;
	}
	var width = map.offsetWidth;
	var height = map.offsetHeight;
	var X = EventX(map, event);
	var Y = EventY(map, event);
	return (X >= 0 && X <= width && Y >= 0 && Y <= height);
}

// Return X location of event with respect to map.
function RelX(map, event) {
	var width = map.offsetWidth;
	if (width == 0) {
		width = parseInt(map.style.width);
	}
	var X = EventX(map, event);
	if (X < 0) {
		return 0;
	}
	if (X >= width) {
		return width;
	}
	return X;
}

// Return Y location of event with respect to map.
function RelY(map, event) {
	var height = map.offsetHeight;
	if (height == 0) {
		height = parseInt(map.style.height);
	}	
	var Y = EventY(map, event);
	if (Y < 0) {
		return 0;
	}
	if (Y >= height) {
		return height;
	}
	return Y;
}

function EventX(map, event) {
	var left = AbsLeft(map);
	if (isIE) {
        var eventX = event.clientX + document.documentElement.scrollLeft - left;
		if (ieVersion >= 7) {
			return eventX - 1
		} else {
			if (currentTextSize == "large") {
				return eventX + 20;
			} else {
				return eventX;
			}
		}
	} else {
		return event.pageX - left;
	}
}

function EventY(map, event) {
	var top = AbsTop(map);
	if (isIE) {
		var eventY = event.clientY + document.documentElement.scrollTop - top;
		return (ieVersion >= 7) ? eventY - 1 : eventY;	
	} else {
		return event.pageY - top;
	}
}

function findPos(obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft
		curtop = obj.offsetTop
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
	}
	return [curleft,curtop];
}

// Calculate Y location of (top of) element with respect to the screen.
function AbsTop(element, doForce) {
	var abstop = element.getAttribute("abstop");
	if (abstop == null || doForce) {
		abstop = element.offsetTop;
		for (var parent = element.offsetParent; parent != null; parent = parent.offsetParent) {
			abstop += parent.offsetTop;
			var style = GetComputedStyle(parent);
			if (style.borderTopStyle != "none") {
				var borderTopWidth = parseInt(style.borderTopWidth);
				if (!isNaN(borderTopWidth)) {
					abstop += borderTopWidth;
				}
			}
		}
		if (!doForce) {
			element.setAttribute("abstop", abstop);
		}
	}
	return Number(abstop);
}

// Calculate X location of (left side of) element with respect to the screen.
function AbsLeft(element, doForce) {
	var absleft = element.getAttribute("absleft");
	if (absleft == null || doForce) {
		absleft = element.offsetLeft;
		for (var parent = element.offsetParent; parent != null; parent = parent.offsetParent) {
			absleft += parent.offsetLeft;
			var style = GetComputedStyle(parent);
			if (style.borderLeftStyle != "none") {
				var borderLeftWidth = parseInt(style.borderLeftWidth);
				if (!isNaN(borderLeftWidth)) {
					absleft += borderLeftWidth;
				}
			}
		}
		if (!doForce) {
			element.setAttribute("absleft", absleft);
		}
	}
	return Number(absleft);
}

var ScaleBGWidth = Number(260);
var EDGE_WIDTH = Number(2);
var MARGIN_WIDTH = Number(10);
var PPI_MIN = Number(40);
var PPI_MAX = Number(350);
var DragX0;
var ClickX0;
var W0;
function GetScale() {
	var scale = getElement("scaleimg_id");
	var scaleBG = getElement("scalebg_id");
	ScaleBGWidth = scaleBG.offsetWidth;
	return scale;
}
function GetDefaultMsg() {
	return getElement("default_calibration_id");
}
function GetPressOKMsg() {
	return getElement("press_ok_id");
}
function GetPPIInput() {
	return getElement("pixelsperinch_id");
}
function GetPPIVisible() {
	return getElement("pixelsperinch_visible_id");
}
function GetScreenWidthInput() {
	return getElement("screenwidth_id");
}
// click scale background to establish right endpoint of "one inch" image
function ScaleClick(event) {
	if (event == null) {
		event = window.event;
	}
	var X = Number(event.clientX);
	var scale = GetScale();
	ClickX0 = AbsLeft(scale, true);
	var width = X - ClickX0;
	SetScaleWidth(width);
	return Finish(event);
}
// drag "one inch" image to resize it
function ScaleDown(event) {
	if (event == null) {
		event = window.event;
	}
	DragX0 = Number(event.clientX);
	var scale = GetScale();	
	W0 = parseInt(scale.width);
	PushOnMouseMove(ScaleMove); 
	PushOnMouseUp(ScaleUp);
	return Finish(event);
}
function ScaleMove(event) {
	if (event == null) {
		event = window.event;
	}	
	if (isIE) {
		// catch mouse up event outside the map
		if (event.button == 0) {
			ScaleUp(event);
			return Finish(event);
		}
	} else if ((typeof(event.originalTarget) != "undefined") && (event.originalTarget != null)) {
		if (event.target != event.originalTarget) {
			ScaleUp(event);
			return Finish(event);
		}
	}
	var width = GetDragWidth(event);
	SetScaleWidth(width);
	return Finish(event);
}
function ScaleUp(event) {
	if (event == null) {
		event = window.event;
	}
	PopOnMouseMove(ScaleMove);
	PopOnMouseUp(ScaleUp);
	var width = GetDragWidth(event);
	if (width == W0) {
		return ScaleClick(event);
	}
	SetScaleWidth(width);
	return Finish(event);
}
function GetDragWidth(event) {
	var width = Number(W0 + event.clientX - DragX0);
	width = Math.min(PPI_MAX, width);
	width = Math.min(ScaleBGWidth - (2 * EDGE_WIDTH) - (2 * MARGIN_WIDTH), width);
	width = Math.max(PPI_MIN, width);
	return width;
}
function SetScaleWidth(width) {
	width = Math.min(PPI_MAX, width);
	width = Math.min(ScaleBGWidth - (2 * EDGE_WIDTH) - (2 * MARGIN_WIDTH), width);
	width = Math.max(PPI_MIN, width);
	var scale = GetScale();
	scale.width = width;
	scale.style.width = width + "px";
	var ppiVisible = GetPPIVisible();
	ppiVisible.innerHTML = width;
	var defaultMsg = GetDefaultMsg();
	defaultMsg.style.visibility = "hidden";
	var pressOKMsg = GetPressOKMsg();
	pressOKMsg.style.display = "";
	var ppiInput = GetPPIInput();
	ppiInput.value = width;
	AdjustBibShadow("calibrationbibid", true);
}
function SetScreenWidthInput() {
	var screenWidthInput = GetScreenWidthInput();
	screenWidthInput.value = window.screen.width;
}