var click = 0;
var dblClick = 0;

var backgroundClick = false;
var backgroundDblClick = false;

var rubberstarted = false;
var clickStart = 0;
var draggingStart = 0;

// co-ordinates of the starting point of the selection.
var startx = 0;
var starty = 0;
// co-ordinates of the ending point of the selection.
var endx = 0;
var endy = 0;
// offset of the layers : margin relative to the border of
// the frame. Is it computed with the top and left properties
// of the layer of the map : maplayer
var Xoffset = 0;
var Yoffset = 0;
var debug ="";

var browser = new Browser()
var dragObj = new Object();

dragObj.zIndex = 0;


/***************************
 *     Mouse functions     *
 ***************************/


function InvokeMapClick(elementId, controllerId, mapId, path, event)
{
	click = (new Date()).getTime();
	
	if (!event.ctrlKey)
	{
		clearSelectionIds(mapId);
		addSelectionId(mapId, elementId);
	}
	else
	{
		if (hasSelectionId(mapId, elementId))
			removeSelectionId(mapId, elementId);
		else
			addSelectionId(mapId, elementId);
	}
	
	UpdateMapElementsStyle(mapId, null);
	
	var selected = hasSelectionId(mapId, elementId);
	
	InvokeSelection((selected ? "_select" : "_unselect"), elementId, controllerId, (event.ctrlKey ? "true" : "false"), path);
	
	return false;
}

function InvokeMapDblClick(elementId, controllerId, mapId, path)
{
	dblClick = (new Date()).getTime();
	
	InvokeAction(mapId, path, '', controllerId, elementId);
}

function InvokeBackgroundClick(mapId, controllerId, path)
{
	if (backgroundClick == true)
	{
		backgroundClick = false;
		return;
	}
	
	backgroundClick = true;
	backgroundDblClick = false;

	var method = "callBackgroundFunction('" + mapId + "','" + controllerId + "','" + path + "')";

	setTimeout(method, 100);
}

function InvokeBackgroundDblCLick(mapId, controllerId, path)
{
	var dblClickTime = (new Date()).getTime() - dblClick;

	if (dblClickTime < 1000)
	{
		return;
	}
	
	backgroundDblClick = true;
	InvokeAction(mapId, path, '', controllerId, '');
}

function AreaDblClick(elementId, mapId, controllerId, path)
{
	backgroundDblClick = true;
	InvokeAction(mapId, path, '', controllerId, elementId);

	window.event.cancelBubble = true;
}

function callBackgroundFunction(mapId, controllerId, path)
{
	backgroundClick = false;
	
	if (!backgroundDblClick)
	{
		backgroundDblClick = false;
		
		var date = new Date();
		var time = date.getTime() - clickStart;
		var elementTime = date.getTime() - click;

		if (time > 500)
			return;

		if (elementTime < 200)
			return;

		clearSelectionIds(mapId);
		UpdateMapElementsStyle(mapId, null);
		InvokeSelection("_select", '', controllerId, "false", path);
	}
}

// Called when a contextual menu is performed on the map
function InvokeMapPopup(elementId, regionId, controllerId, htmlMapId, mapId, path, selectionPath, event)
{
	var selected = hasSelectionId(htmlMapId, elementId);
	
	// Try to select map region (for treemap layout only)
	try
	{
		var doc = window.document;
		var region = doc.getElementById(regionId);
		
		selected = (region.style.borderWidth.substring(0, 1) != '0' && region.style.borderWidth.substring(0, 1) != '');
		
		if (!selected)
			TreemapSelection(elementId, true);
	}
	catch (ex)
	{
	}

	if (!selected)
	{
		InvokeMapClick(elementId, controllerId, htmlMapId, selectionPath, event);
		
		// Send the popup demand
		var methodParam = ReplaceString(elementId, "\\", "\\\\");
		
		setTimeout("InvokePopup('" + mapId + "','" + methodParam + "','" + path + "','" +
			controllerId + "'," + event.ctrlKey + "," +
			event.clientX + "," + event.clientY + ")", 300);
	}
	else
		InvokePopup(mapId, elementId, path, controllerId, event.ctrlKey, event.clientX, event.clientY);
}

// Graphical select a node
// return true if changed
function selectMapNode(id)
{
	needUpdate = false;
	divObject = document.getElementById(id);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeSelectedImage')
		{
			divObject.className = 'nodeSelectedImage';
			needUpdate = true;
		}
	}
	
	// compute label id
	i = id.indexOf("_node");
	currentId = id.substring(0, i);
	
	var labelId = currentId +"_label";
	divObject = document.getElementById(labelId);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeSelectedLabel')
		{
			divObject.className = 'nodeSelectedLabel';
			needUpdate = true;
		}
	}
	
	labelId = currentId +"_leftLabel";
	divObject = document.getElementById(labelId);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeSelectedLabel')
		{
			divObject.className = 'nodeSelectedLabel';
			needUpdate = true;
		}
	}
	
	labelId = currentId +"_rightLabel";
	divObject = document.getElementById(labelId);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeSelectedLabel')
		{
			divObject.className = 'nodeSelectedLabel';
			needUpdate = true;
		}
	}
	
	labelId = currentId +"_topLabel";
	divObject = document.getElementById(labelId);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeSelectedLabel')
		{
			divObject.className = 'nodeSelectedLabel';
			needUpdate = true;
		}
	}
	
	labelId = currentId +"_bottomLabel";
	divObject = document.getElementById(labelId);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeSelectedLabel')
		{
			divObject.className = 'nodeSelectedLabel';
			needUpdate = true;
		}
	}

	return needUpdate;
}

// Graphical unselect a node
// return true if changed
function unselectMapNode(id)
{
	needUpdate = false;
	divObject = document.getElementById(id);
	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeImage')
		{
			divObject.className = 'nodeImage';
			needUpdate = true;
		}
	}

	// compute label id
	i = id.indexOf("_node");
	currentId = id.substring(0, i);

	var labelId = currentId +"_label";
	divObject = document.getElementById(labelId);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeLabel')
		{
			divObject.className = 'nodeLabel';
			needUpdate = true;
		}
	}

	labelId = currentId +"_leftLabel";
	divObject = document.getElementById(labelId);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeLabel')
		{
			divObject.className = 'nodeLabel';
			needUpdate = true;
		}
	}

	labelId = currentId +"_rightLabel";
	divObject = document.getElementById(labelId);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeLabel')
		{
			divObject.className = 'nodeLabel';
			needUpdate = true;
		}
	}

	labelId = currentId +"_topLabel";
	divObject = document.getElementById(labelId);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeLabel')
		{
			divObject.className = 'nodeLabel';
			needUpdate = true;
		}
	}

	labelId = currentId +"_bottomLabel";
	divObject = document.getElementById(labelId);

	if ( (divObject != null) && (divObject != "undefined") )
	{
		if (divObject.className != 'nodeLabel')
		{
			divObject.className = 'nodeLabel';
			needUpdate = true;
		}
	}

	return needUpdate;
}

function UpdateMapElementsStyle(mapId, frameId)
{
	var ie= (navigator.appName == "Microsoft Internet Explorer")?1:0;
	var doc = document;

	if (frameId != null)
	{
		var frame = findTarget(null, frameId, null);
		
		if (frame != null)
			doc = frame.document;
	}
 
	var map = doc.getElementById(mapId);
	
	if ((map == null) || ((typeof map) == "undefined"))
		return;

	var divs = doc.getElementsByTagName('div');

	for (var i = 0; i < divs.length; i++)
	{
		divObject = divs[i];
		currentId = divObject.id;
		
		if ( (currentId == null) || (currentId == "undefined") || (currentId == ""))
			continue;

		if ((typeof id != "undefined") && (id != null) && (currentId == id) )
			continue;

		if (endsWith(currentId, "_node") )
		{
			var isSelected = hasSelectionId(mapId, divObject.getAttribute("nodeId"));
			
			if (isSelected)
				selectMapNode(currentId);
			else
				unselectMapNode(currentId);
		}
	}
}

// unselect all node except id
function unselectAllNodes(id)
{
	var needUpdate = false;
	var divs = document.getElementsByTagName('div');
	
	for (var i = 0; i < divs.length; i++)
	{
		divObject = divs[i];
		currentId = divObject.id;
		
		if ( (currentId == null) || (currentId == "undefined") || (currentId == ""))
			continue;

		if ((typeof id != "undefined") && (id != null) && (currentId == id) )
			continue;

		if ( endsWith(currentId, "_node") )
		{
			if (unselectMapNode(currentId))
				needUpdate = true;
		}
	}
	return needUpdate;
}

function unselectAll(url)
{
	date = new Date();
	time = date.getTime() - clickStart;

	if (time > 500)
		return;

	unselectAllNodes();
	InvokeMapSelection(url);
}


/***********************************
 *     Drag and drop functions     *
 ***********************************/

var dragStopCallback = null;

function dragStart(event, id, nodeId, mapId, controllerId, path)
{
  var el;
  var x, y;

  // If an element id was given, find it. Otherwise use the element being
  // clicked on.
  date = new Date();

  draggingStart = date.getTime();

  if (id)
  {
	  dragObj.nodeId = nodeId;
	  dragObj.elNode = document.getElementById(id);
  }

  // Get cursor position with respect to the page.
  if (browser.isIE)
  {
    x = window.event.clientX + document.documentElement.scrollLeft
      + document.body.scrollLeft;
    y = window.event.clientY + document.documentElement.scrollTop
      + document.body.scrollTop;
  }
  if (browser.isFirefox)
  {
    x = event.clientX + window.scrollX;
    y = event.clientY + window.scrollY;
    startx = x;
    starty = y;
  }
  else if (browser.isNS)
  {
    x = event.clientX + window.scrollX;
    y = event.clientY + window.scrollY;
  }

  // Save starting positions of cursor and element.
  dragObj.cursorStartX = x;
  dragObj.cursorStartY = y;

  if (dragObj.elNode != null)
  {
	dragObj.elNodeStartLeft  = parseInt(dragObj.elNode.style.left, 10);
  	dragObj.elNodeStartTop   = parseInt(dragObj.elNode.style.top,  10);
  	if (isNaN(dragObj.elNodeStartLeft))
  		dragObj.elNodeStartLeft = 0;
  	if (isNaN(dragObj.elNodeStartTop))
  		dragObj.elNodeStartTop  = 0;

  	// Update element's z-index.
  	dragObj.elNode.style.zIndex = ++dragObj.zIndex;
  }

  // Capture mousemove and mouseup events on the page.
	dragStopCallback = function()
	{
		dragStop(mapId, controllerId, path);
	}

  if (browser.isIE) {
    document.attachEvent("onmousemove", dragGo);
    document.attachEvent("onmouseup",   dragStopCallback);
    window.event.cancelBubble = true;
    window.event.returnValue = false;
  }
  if (browser.isNS) {
    document.addEventListener("mousemove", dragGo,   true);
    document.addEventListener("mouseup",   dragStopCallback, true);
    event.preventDefault();
  }
}

function dragGo(event) {

  var x, y;

  // Get cursor position with respect to the page.
  draggingStart -= 500;
  
  if (browser.isIE) {
    x = window.event.clientX + document.documentElement.scrollLeft
      + document.body.scrollLeft;
    y = window.event.clientY + document.documentElement.scrollTop
      + document.body.scrollTop;
  }
  if (browser.isNS) {
    x = event.clientX + window.scrollX;
    y = event.clientY + window.scrollY;
  }

  // Move drag element by the same amount the cursor has moved.

	if (dragObj.elNode != null)
	{
		dragObj.elNode.style.left = (dragObj.elNodeStartLeft + x - dragObj.cursorStartX) + "px";
		dragObj.elNode.style.top  = (dragObj.elNodeStartTop  + y - dragObj.cursorStartY) + "px";
	}

  if (browser.isIE) {
    window.event.cancelBubble = true;
    window.event.returnValue = false;
  }
  if (browser.isNS)
    event.preventDefault();
}

function dragStop(mapId, controllerId, path)
{
	// Stop capturing mousemove and mouseup events.
	if (browser.isIE)
	{
		document.detachEvent("onmousemove", dragGo);
		document.detachEvent("onmouseup",   dragStopCallback);
		dragStopCallback = null;
	}
	if (browser.isNS)
	{
		document.removeEventListener("mousemove", dragGo,   true);
		document.removeEventListener("mouseup",   dragStopCallback, true);
		dragStopCallback = null;
	}

	date = new Date();
	time = date.getTime() - draggingStart;

	if (time < 500 )
		return;

	if (dragObj.elNode != null)
	{
		x = parseInt(dragObj.elNode.style.left,10);
		y = parseInt(dragObj.elNode.style.top,10);
		id = ReplaceString(dragObj.nodeId,"\\","\\\\");
		
		SendAjaxRequestParams(_rootUrl + path, pageParam + '=' + mapId + '&' + sourceParam + '=moveElements' +
			'&' + controllerParam + '=' + controllerId +
			'&' + valueParam + '=' + id + '&' + indexParam + '=' + x + "|" + y, 'false');
	}
}


/***********************************
 *     Miscellaneous functions     *
 ***********************************/


function Browser()
{

  var ua, s, i;

  this.isIE    = false;
  this.isNS    = false;
  this.isFirefox = false;
  this.version = null;

  ua = navigator.userAgent;

  s = "MSIE";
  if ((i = ua.indexOf(s)) >= 0) {
    this.isIE = true;
    this.version = parseFloat(ua.substr(i + s.length));
    return;
  }


  s = "Firefox";
    if ((i = ua.indexOf(s)) >= 0) {
      this.isFirefox = true;
      this.isNS = true; // As long has everything is not migrated
      this.version = parseFloat(ua.substr(i + s.length));;
      return;
    }

  s = "Netscape6/";
  if ((i = ua.indexOf(s)) >= 0) {
    this.isNS = true;
    this.version = parseFloat(ua.substr(i + s.length));
    return;
  }

  // Treat any other "Gecko" browser as NS 6.1.

  s = "Gecko";
  if ((i = ua.indexOf(s)) >= 0) {
    this.isNS = true;
    this.version = 6.1;
    return;
  }
}

function getMapDocument()
{
	return window.document;
}

// return true if the given source string endsWith pattern
function endsWith(source, pattern)
{
	n = pattern.length;
	m = source.length;
	
	temp = source.substring(m-n);

	if (temp == pattern)
		return true;
	else
		return false;
}


/***********************************
 *     Management of tree maps     *
 ***********************************/


var mapWidth = 0;
var mapHeight = 0;
var mapDelta = 10;
var mapInitialized = false;

function mouseOverRegion(regionId, over, isSmallImage, x, y, width, height, borderWidth)
{
	var doc = getMapDocument();
	var newValue = (over ? 'visible' : 'hidden');
	var selectBorder = doc.getElementById("_select_border_up");

	selectBorder.style.visibility = newValue;

	if (over)
	{
		selectBorder.style.width = width;
		selectBorder.style.height = selectBorderWidth;
		selectBorder.style.left = x + "px";
		selectBorder.style.top = y + "px";
	}

	selectBorder = doc.getElementById("_select_border_right");
	selectBorder.style.visibility = newValue;

	if (over)
	{
		selectBorder.style.width = selectBorderWidth;
		selectBorder.style.height = height;
		selectBorder.style.left = (width - selectBorderWidth) + "px";
		selectBorder.style.top = "0px";
	}

	selectBorder = doc.getElementById("_select_border_down");
	selectBorder.style.visibility = newValue;

	if (over)
	{
		selectBorder.style.width = width;
		selectBorder.style.height = selectBorderWidth;
		selectBorder.style.left = (selectBorderWidth - width) + "px";
		selectBorder.style.top = (height - selectBorderWidth) + "px";
	}

	selectBorder = doc.getElementById("_select_border_left");
	selectBorder.style.visibility = newValue;

	if (over)
	{
		selectBorder.style.width = selectBorderWidth;
		selectBorder.style.height = height;
		selectBorder.style.left = "0px";
		selectBorder.style.top = (selectBorderWidth - height) + "px";
	}

	var tooltipId = (isSmallImage ? "_smallimage_tooltip" : "_tooltip");
	var regionTooltip = doc.getElementById(regionId + tooltipId);

	if (regionTooltip != null)
	{
		regionTooltip.style.visibility = newValue;
	}
}

function ReinitMap()
{
	mapWidth = 0;
	mapHeight = 0;
	mapDelta = 10;
	mapInitialized = false;
}

function InitResizeMap(frameName, pageId, bottomDivId, path)
{
	setTimeout("ResizeMap('" + frameName + "','" + pageId + "','" + bottomDivId + "','" + path + "','true')", 50);
}

function ResizeMap(frameName, pageId, bottomDivId, path, initialization)
{
	if (mapInitialized && (initialization == 'true'))
		return;
	
	var parentIframes = this.document.getElementsByTagName('iframe');
	var frame = this.frames[frameName];
	var iframe = parentIframes[frameName];
	
	if (frame == null || frame.document == null || frame.document.body == null)
	{
		this.location.reload();
		return;
	}	
	
	// For performances reasons, only update url when size change significantly
	var  width = frame.document.body.clientWidth;
	var  height = frame.document.body.clientHeight;
	
	if ((mapWidth > width + mapDelta)
		|| (mapWidth < width - mapDelta)
		|| (mapHeight > height + mapDelta)
		|| (mapHeight < height - mapDelta))
	{
		mapWidth = width;
		mapHeight = height;

		iframe.style.height = 0;

		var totalHeight = this.document.body.clientHeight;
		var scrollHeight = this.document.body.scrollHeight;
		var messageDiv = this.document.getElementById(bottomDivId);
		var newHeight = totalHeight;
		
		if (messageDiv != null)
			newHeight = cmGetY(messageDiv) - cmGetY(iframe);
		else
			newHeight = totalHeight - cmGetY(iframe);

		iframe.style.height = newHeight - 2;
		
		if (initialization == 'true')
			mapInitialized = true;

		var  newUrl = _rootUrl + path;
		var  date = new Date();

		newUrl = newUrl + '?_reload=' + date.getTime() + '&_ajax=false' + '&_page=' + pageId +
			'&_frame=' + frame.name + cmGetWidth(iframe) + '*' + cmGetHeight(iframe);

		frame.location.href = newUrl;
	}
}


/****************************************
 *     Management of rubber banding     *
 ****************************************/


/**
 * Set or Unset the document has a rubberband listener.
 * doc is the reference to the document.
 **/
function setRubberBandListener(set, doc, mapId, controllerId, path)
{
	if (rubberstarted)
		return;
	
	if (set == true)
	{
		var stopRectangleCallback = function()
		{
			stopRectangle(mapId, controllerId, path);
		}
		
		doc.onmousemove = moveRectangle;
		doc.onmousedown = startRectangle;
		doc.onmouseup = stopRectangleCallback;
	}
	else if (set == false)
	{
		// the events are realeased !!
		if (navigator.appName=="Netscape")
		{
			doc.releaseEvents(Event.MOUSEMOVE);
			doc.releaseEvents(Event.MOUSEDOWN);
			doc.releaseEvents(Event.MOUSEUP);
		}
		doc.onmousemove = "";
		doc.onmousedown = "";
		doc.onmouseup = "";
	}
	else
		return true;
}

/**
 * This method defines the starting point of a rectangle for
 * the selection of an area over the map.
 * It is called when the mouse is pressed over the map.
 * doc : the reference of the document
 **/
function startRectangle(e)
{
	if (zoomMoving || viewerMoving || translatingViewer)
		return;
	
	date = new Date();
	clickStart = date.getTime();

	if (browser.isFirefox)
	{
		return;
	}
	if (!rubberstarted)
	{
		var doc = getMapDocument();
		rubberstarted = true;
		//debug = debug + "start : rubberstarted set to true\n";



		/* get the event co-ordinates */
		var mapwindow = window;


		if (e)
		{
			startx = e.layerX + document.body.scrollLeft;
			starty = e.layerY + document.body.scrollTop;
		}
		else
		{
			startx = mapwindow.event.x + document.body.scrollLeft;
			starty = mapwindow.event.y + document.body.scrollTop;
		}

		/* initialise the layer for the rubberband */
		if (document.layers)
		{
			// initialise variable for starting point.
			Xoffset = doc.layers["background"].left;
			Yoffset = doc.layers["background"].top;
			startx = startx + Xoffset;
			starty = starty + Yoffset;

			// initialise layers.
			doc.layers["rubberband"].moveTo(startx,starty);
			doc.layers["rubberband"].clip.width = 0;
			doc.layers["rubberband"].clip.height = 0;
			doc.layers["topborder"].moveTo(startx,starty);
			doc.layers["topborder"].clip.width = 0;
			doc.layers["bottomborder"].moveTo(startx,starty);
			doc.layers["bottomborder"].clip.width = 0;
			doc.layers["leftborder"].moveTo(startx,starty);
			doc.layers["leftborder"].clip.height = 0;
			doc.layers["rightborder"].moveTo(startx,starty);
			doc.layers["rightborder"].clip.height = 0;
		}
		else if (document.all)
		{
			// initialise variable for starting point.
			if (doc.all.background)
			{
				Xoffset = doc.all.background.offsetLeft;
				Yoffset = doc.all.background.offsetTop;
			}
			else
			{
				Xoffset = 0;
				Yoffset = 0;
			}
			startx = event.clientX + document.body.scrollLeft;
			starty = event.clientY + document.body.scrollTop;
			clientX = doc.body.clientTop;
			clientY = doc.body.clientLeft;

			clientWidth = doc.body.clientWidth;
			clientHeight = doc.body.clientHeight;

			if ( (startx < clientX + document.body.scrollLeft) || ( startx > (clientX + clientWidth + document.body.scrollLeft) ) )
			{
				rubberstarted = false;
				//alert("not in client");
				return;
			}

			if ( (starty < clientY + document.body.scrollTop) || ( starty > (clientY + clientHeight + document.body.scrollTop) ) )
			{
				rubberstarted = false;
				//alert("not in client");
				return;
			}


			if (doc.all.background)
				Yoffset = doc.all.background.offsetTop;


			// initialise layer.
			doc.all.rubberband.style.left = startx;
			doc.all.rubberband.style.top = starty;
			doc.all.rubberband.style.width = 0;
			doc.all.rubberband.style.height = 0;
		}
		else
		{
			// initialise variable for starting point.
			var maplayer = doc.getElementById("background");
			var rubberband = doc.getElementById("rubberband");
			if ((typeof mapLayer != "undefined")
				&& (typeof rubberband != "undefined"))
			{
				Xoffset = maplayer.offsetLeft;
				Yoffset = maplayer.offsetTop;
				startx = startx + Xoffset;
				starty = starty + Yoffset;

				// initialise layer.
				rubberband.style.left = startx + "px";
				rubberband.style.top = starty + "px";
				rubberband.style.width = 0 + "px";
				rubberband.style.height = 0 + "px";
			}
		}

		endx = startx;
		endy = starty;
		//debug = debug + "start : showRectangle\n";
		showRectangle();
	}
	return false; // very important, do not remove!
}

/**
 * This method draws a rectangle for the selection of an area over the map.
 * It is drawn each time the user moves the mouse while pressed over the map.
 **/
function moveRectangle(e)
{
	var  mapwindow = window;


	if (rubberstarted)
	{
		/* get the event co-ordinates */
		if (e)
		{
			endx = e.pageX + document.body.scrollLeft;
			endy = e.pageY + document.body.scrollTop;
		}
		else
		{
			endx = mapwindow.event.clientX + document.body.scrollLeft;
			endy = mapwindow.event.clientY + document.body.scrollTop;
		}

		clipRectangle(endx,endy);
		return false;
	}
	else
	{
		// The event is routed in order to let the tooltip
		// function going on.
		if (document.layers)
		{
			var doc = getMapDocument();
			doc.routeEvent(e);
		}
		return true;
	}
}

/**
 * This method stops drawing the rectangle and capture
 * the coordinates of the upper left and bottom right corners.
 **/
function stopRectangle(mapId, controllerId, path)
{
	if (rubberstarted)
	{
		corner1x = Math.min(startx, endx)-Xoffset;
		corner1y = Math.min(starty, endy)-Yoffset;
		corner2x = Math.max(startx, endx)-Xoffset;
		corner2y = Math.max(starty, endy)-Yoffset;

		rubberstarted = false;
		hideRectangle();

		date = new Date();
		time =  date.getTime() - clickStart;

		if (time < 200)
		{
			return;
		}

		corner1x = corner1x;
		corner2x = corner2x;
		corner1y = corner1y;
		corner2y = corner2y;

		select(corner1x ,corner1y ,corner2x, corner2y, mapId, controllerId, path);
	}
	
	return true;
}

/**
 * This method defines the new position, width and heigth of the
 * layers that defines the rectangle.
 **/
function clipRectangle(x,y)
{
	var doc = getMapDocument();
	var posx = Math.min(x, startx);
	var posy = Math.min(y, starty);
	var w = Math.abs(x-startx);
	var h = Math.abs(y-starty);
	if (document.layers)
	{
		var pos2x = Math.max(x, startx);
		var pos2y = Math.max(y, starty);
		doc.layers["rubberband"].moveTo(posx, posy);
		doc.layers["rubberband"].clip.width = w;
		doc.layers["rubberband"].clip.height = h;
		doc.layers["topborder"].moveTo(posx, posy);
		doc.layers["topborder"].clip.width = w;

		doc.layers["bottomborder"].moveTo(posx, pos2y);
		doc.layers["bottomborder"].clip.width = w;

		doc.layers["leftborder"].moveTo(posx,posy);
		doc.layers["leftborder"].clip.height = h;

		doc.layers["rightborder"].moveTo(pos2x,posy);
		doc.layers["rightborder"].clip.height = h;
	}
	else if (!doc.getElementById)
	{
		doc.all.rubberband.style.width = w;
		doc.all.rubberband.style.height = h;
		doc.all.rubberband.style.left = posx + document.body.scrollLeft;
		doc.all.rubberband.style.top = posy + document.body.scrollTop;
	}
	else
	{
		var rubberband = doc.getElementById("rubberband");
		rubberband.style.width = w + "px";
		rubberband.style.height = h + "px";
		rubberband.style.left = posx + "px";
		rubberband.style.top = posy + "px";
	}
}

/**
 * This method make the rectangle visible.
 **/
function showRectangle()
{
	// debug = debug + "*** Showing\n";
	var doc = getMapDocument();
	if (document.layers)
	{
		doc.layers["rubberband"].visibility = "show";
		doc.layers["topborder"].visibility = "show";
		doc.layers["bottomborder"].visibility = "show";
		doc.layers["leftborder"].visibility = "show";
		doc.layers["rightborder"].visibility = "show";
	}
	else if (!doc.getElementById)
	{
		doc.all.rubberband.style.visibility = "visible";
	}
	else
	{
		var rubberband = doc.getElementById("rubberband");
		rubberband.style.visibility = "visible";
	}
}

function hideRectangle()
{
	var doc = getMapDocument();
	if (document.layers)
	{
		doc.layers["rubberband"].visibility = "show";
		doc.layers["topborder"].visibility = "show";
		doc.layers["bottomborder"].visibility = "show";
		doc.layers["leftborder"].visibility = "show";
		doc.layers["rightborder"].visibility = "show";
	}
	else if (!doc.getElementById)
	{
		doc.all.rubberband.style.visibility = "hidden";
	}
	else
	{
		var rubberband = doc.getElementById("rubberband");
		rubberband.style.visibility = "hidden";
	}
}

function select(startX, startY, endX, endY, mapId, controllerId, path)
{
	clearSelectionIds(mapId);
	unselectAllNodes();

	for (var i = 0; i < document.all.length; i++)
	{
		var divObject = document.all[i];

		currentId = divObject.id;
		
		if ( (currentId == null) || (currentId == "undefined") )
			continue;

		if (endsWith(currentId, "_node"))
		{
			var x = 0, y = 0;
			var obj = divObject;

			do
			{
				x += obj.offsetLeft;
				y += obj.offsetTop;
				obj = obj.offsetParent;
			}
			while (obj);
			
			if ((startX <= x ) && (x <= endX) && (startY <= y) && (y <= endY))
			{
				n = currentId.indexOf("_node");
				nodeId = currentId.substring(0, n);
				addSelectionId(mapId, divObject.getAttribute("nodeId"));
				selectMapNode(currentId);
			}
		}
	}
	
	// Call InvokeSelection
	var selectedIds = getSelectionIds(mapId);

	InvokeSelection("_select", selectedIds, controllerId, "false", path);
}


/**************************************
 *     Management of zoom widgets     *
 **************************************/


var viewerXPos = null;
var viewerYPos = null;
var viewerMoving = false;
var zoomYPos = null;
var zoomMoving = false;
var translatingViewer = false;
var currentScale = new Array();

function switchMapWidgetState(actionId, path, mapId, toolDivId, controller)
{
	backgroundDblClick = true;

	var viewerDiv = this.document.getElementById(toolDivId);
	var open = (viewerDiv.style.display == 'none');

	if ((controller != null) && (controller != '') && (typeof controller != "undefined"))
		SendAjaxRequestParams(_rootUrl + path, pageParam + '=' + mapId + '&' + sourceParam + '=' + actionId +
			'&' + valueParam + '=' + open + '&' + controllerParam + '=' + controller, 'false');
}

function setMapWidgetState(open, toolDivId, switchImgId, image, tooltip)
{
	var viewerDiv = this.document.getElementById(toolDivId);
	var viewerSwitchImg = this.document.getElementById(switchImgId);

	if (open)
		viewerDiv.style.display = 'block';
	else
		viewerDiv.style.display = 'none';

	if (viewerSwitchImg != null)
	{
		viewerSwitchImg.src = image;
		SetImageTooltip(switchImgId, tooltip);
	}
}

function setMapZoomScale(scale, path, mapId, mapZoomId, xTranslation, yTranslation, controller)
{
	backgroundDblClick = true;

	var parentFrame = findTargetByContent(null, mapZoomId);
	
	if (parentFrame == null)
		return;

	var mapZoomDiv = parentFrame.document.getElementById(mapZoomId);
	var scaleDiv = parentFrame.document.getElementById(mapZoomId + '_scale' + scale);

	if ((scaleDiv == null) || (typeof scaleDiv == "undefined"))
		return;

	var zoomCursorDiv = parentFrame.document.getElementById(mapZoomId + '_cursor');
	var zoomCursorMovingDiv = parentFrame.document.getElementById(mapZoomId + '_cursor_moving');
	var x = cmGetXAt(scaleDiv, mapZoomDiv);
	var y = cmGetYAt(scaleDiv, mapZoomDiv);

	zoomCursorDiv.style.left = x + 1;
	zoomCursorDiv.style.top = y + 1;
	zoomCursorDiv.style.visibility = "visible";
	parentFrame.currentScale[mapId] = scale;
	zoomCursorMovingDiv.style.visibility = "hidden";
	
	if ((mapId != null) && (mapId != ''))
	{
		var params = pageParam + '=' + mapId + '&' + sourceParam + '=setMapZoomScale' +
			'&' + valueParam + '=' + scale;
		
		if ((xTranslation != null) && (typeof xTranslation != "undefined")
				&& (yTranslation != null) && (typeof yTranslation != "undefined"))
			params += '_' + xTranslation + '_' + yTranslation;
		
		if ((typeof controller != "undefined") && (controller != null) && (controller != ''))
			params += '&' + controllerParam + '=' + controller;

		SendAjaxRequestParams(_rootUrl + path, params, 'false');
	}
}

function prepareMovingZoom(evt, mapId, mapZoomId)
{
	var zoomDiv = this.document.getElementById(mapZoomId + '_cursor');
	var zoomCursorMovingDiv = this.document.getElementById(mapZoomId + '_cursor_moving');
	var mapDiv = this.document.getElementById(mapId);

	zoomCursorMovingDiv.style.left = cmGetXAt(zoomDiv, mapDiv);
	zoomCursorMovingDiv.style.top = cmGetYAt(zoomDiv, mapDiv);
	zoomCursorMovingDiv.style.width = cmGetWidth(zoomDiv);
	zoomCursorMovingDiv.style.height = cmGetHeight(zoomDiv);
	zoomCursorMovingDiv.style.visibility = "visible";
}

function startMovingZoom(mapId, mapZoomId)
{
	var mapDiv = this.document.getElementById(mapId);
	var zoomCursorMovingDiv = this.document.getElementById(mapZoomId + '_cursor_moving');

	zoomCursorMovingDiv.style.left = "0px";
	zoomCursorMovingDiv.style.top = "0px";
	zoomCursorMovingDiv.style.width = cmGetWidth(mapDiv);
	zoomCursorMovingDiv.style.height = cmGetHeight(mapDiv);
	zoomMoving = true;
}

function moveZoom(evt, mapId, mapZoomId)
{
	var zoomCursorDiv = this.document.getElementById(mapZoomId + '_cursor');

	if (!zoomMoving)
	{
		zoomYPos = evt.clientY;

		return;
	}

	if (document.getElementById && !(document.all))
	{
		// Firefox
		// Nothing to do
	}
	else if(document.all)
	{
		// IE
		evt = event;
	}

	if (zoomYPos == null)
	{
		zoomYPos = evt.clientY;
	}

	var diffY = evt.clientY - zoomYPos;
	var newY = parseInt(zoomCursorDiv.style.top) + diffY;
	var mapZoomDiv = this.document.getElementById(mapZoomId);
	var mapDiv = this.document.getElementById(mapId);
	var zoomScaleDiv = this.document.getElementById(mapZoomId + '_scale');
	var yTotal = cmGetYAt(mapZoomDiv, mapDiv) + newY;
	var yMin = cmGetYAt(zoomScaleDiv, mapDiv);
	var yMax = yMin + cmGetHeight(zoomScaleDiv);

	if (yTotal < yMin + 1)
	{
		newY = yMin - cmGetYAt(mapZoomDiv, mapDiv) + 1;
		zoomCursorDiv.style.top = newY + "px";
		return;
	}

	if (yTotal > yMax - 8)
	{
		newY = yMax - cmGetYAt(mapZoomDiv, mapDiv) - 8;
		zoomCursorDiv.style.top = newY + "px";
		return;
	}

	zoomYPos = evt.clientY;
	zoomCursorDiv.style.top = newY + "px";
}

function endMovingZoom(path, mapId, mapZoomId, minScale, controller)
{
	var zoomDiv = this.document.getElementById(mapZoomId);
	var zoomCursorDiv = this.document.getElementById(mapZoomId + '_cursor');
	var zoomCursorMovingDiv = this.document.getElementById(mapZoomId + '_cursor_moving');
	var zoomCursorY = cmGetYAt(zoomCursorDiv, zoomDiv);
	var scale = minScale;
	var scaleDiv = null;

	while (zoomMoving
		&& ((scaleDiv = document.getElementById(mapZoomId + '_scale' + scale)) != null)
		&& (typeof scaleDiv != "undefined"))
	{
		if (cmGetYAt(scaleDiv, zoomDiv) < zoomCursorY - (-4))
		{
			setMapZoomScale(scale, path, mapId, mapZoomId, controller);
			break;
		}

		scale++;
	}

	zoomCursorMovingDiv.style.visibility = "hidden";
	zoomYPos = null;
	zoomMoving = false;
}

function prepareMovingViewer(mapDivId, mapViewerDivId, mapViewerTranslateId, mapViewerMovingId)
{
	var viewerDiv = this.document.getElementById(mapViewerDivId);
	var viewerTranslateDiv = this.document.getElementById(mapViewerTranslateId);
	var viewerMovingDiv = this.document.getElementById(mapViewerMovingId);
	var mapDiv = this.document.getElementById(mapDivId);

	viewerMovingDiv.style.left = cmGetXAt(viewerDiv, mapDiv);
	viewerMovingDiv.style.top = cmGetYAt(viewerDiv, mapDiv);
	viewerMovingDiv.style.width = cmGetWidth(viewerDiv);
	viewerMovingDiv.style.height = cmGetHeight(viewerDiv);
	viewerMovingDiv.style.visibility = "visible";
	viewerTranslateDiv.style.left = cmGetXAt(viewerDiv, mapDiv) + 5;
	viewerTranslateDiv.style.top = cmGetYAt(viewerDiv, mapDiv) + 5;
	viewerTranslateDiv.style.width = cmGetWidth(viewerDiv) - 10;
	viewerTranslateDiv.style.height = cmGetHeight(viewerDiv) - 10;
	viewerTranslateDiv.style.visibility = "visible";
}

function startMovingViewer(mapDivId, mapViewerTranslateId, mapViewerMovingId)
{
	var mapDiv = this.document.getElementById(mapDivId);
	var viewerTranslateDiv = this.document.getElementById(mapViewerTranslateId);
	var viewerMovingDiv = this.document.getElementById(mapViewerMovingId);

	viewerTranslateDiv.style.visibility = "hidden";
	viewerMovingDiv.style.left = "0px";
	viewerMovingDiv.style.top = "0px";
	viewerMovingDiv.style.width = cmGetWidth(mapDiv);
	viewerMovingDiv.style.height = cmGetHeight(mapDiv);
	viewerMoving = true;
}

function moveViewer(evt, mapDivId, mapViewerDivId, mapViewerImgId, mapViewerSwitchId)
{
	var viewerDiv = this.document.getElementById(mapViewerDivId);
	var mapDiv = this.document.getElementById(mapDivId);
	var viewerImgDiv = this.document.getElementById(mapViewerImgId);
	var viewerSwitchDiv = this.document.getElementById(mapViewerSwitchId);

	if (!viewerMoving)
	{
		viewerXPos = evt.clientX;
		viewerYPos = evt.clientY;

		return;
	}

	if (document.getElementById && !(document.all))
	{
		// Firefox
		// Nothing to do
	}
	else if(document.all)
	{
		// IE
		evt = event;
	}

	if (viewerXPos == null)
	{
		viewerXPos = evt.clientX;
		viewerYPos = evt.clientY;
	}

	var diffX = evt.clientX - viewerXPos;
	var diffY = evt.clientY - viewerYPos;
	var newX = parseInt(viewerDiv.style.left) + diffX;
	var newY = parseInt(viewerDiv.style.top) + diffY;
	var yTotal = cmGetYAt(viewerDiv, mapDiv) + newY;
	var xMax = cmGetWidth(mapDiv) - cmGetWidth(viewerImgDiv);
	var yMax = cmGetHeight(mapDiv) - cmGetHeight(viewerImgDiv);
	var setXPos = true;
	var setYPos = true;

	if (newX < 2)
	{
		newX = 2;
		setXPos = false;
	}

	if (newY < 2)
	{
		newY = 2;
		setYPos = false;
	}

	if (newX > xMax - 5)
	{
		newX = (xMax - 5);
		setXPos = false;
	}

	if (newY > yMax - 5)
	{
		newY = (yMax - 5);
		setYPos = false;
	}

	if (setXPos)
		viewerXPos = evt.clientX;

	if (setYPos)
		viewerYPos = evt.clientY;

	viewerDiv.style.left = newX + "px";
	viewerDiv.style.top = newY + "px";
	viewerSwitchDiv.style.left = (newX + 2) + "px";
	viewerSwitchDiv.style.top = (newY + 2) + "px";
}

function endMovingViewer(mapDivId, mapViewerDivId, mapViewerTranslateId, mapViewerMovingId, path, mapId, controller)
{
	var viewerDiv = this.document.getElementById(mapViewerDivId);

	prepareMovingViewer(mapDivId, mapViewerDivId, mapViewerTranslateId, mapViewerMovingId);
	viewerXPos = null;
	viewerYPos = null;
	
	var viewerX = viewerDiv.style.left;
	var viewerY = viewerDiv.style.top;

	if (viewerMoving && (controller != null) && (controller != '') && (typeof controller != "undefined"))
		SendAjaxRequestParams(_rootUrl + path, pageParam + '=' + mapId + '&' + sourceParam + '=moveViewer' +
			'&' + valueParam + '=' + viewerX + "_" + viewerY + '&' + controllerParam + '=' + controller, 'false');

	viewerMoving = false;
}

function translateViewer(evt, path, mapId, mapViewerDivId, controller)
{
	translatingViewer = true;
	
	if (document.getElementById && !(document.all))
	{
		// Firefox
		// Nothing to do
	}
	else if(document.all)
	{
		// IE
		evt = event;
	}

	var viewerDiv = this.document.getElementById(mapViewerDivId);
	var x = evt.clientX - cmGetX(viewerDiv);
	var y = evt.clientY - cmGetY(viewerDiv);
	
	SendAjaxRequestParams(_rootUrl + path, pageParam + '=' + mapId + '&' + sourceParam + '=translateViewer' +
		'&' + valueParam + '=' + x + "_" + y + '&' + controllerParam + '=' + controller, 'false');
	
	setTimeout("translatingViewer = false;", 500);
}

function translateMap(path, direction, mapId, backgroundImagesId, emptyImagePath, controller)
{
	backgroundDblClick = true;

	if (direction != "CENTER")
	{
		var i = 0;
		var j = 0;
		var stop = false;
		var images = new Array();

		for (i = 0; !stop; i++)
		{
			for (j = 0; !stop; j++)
			{
				var imgId = backgroundImagesId + "_" + i + "_" + j + "_background_image";
				var backgroundImage = this.document.getElementById(imgId);

				if (backgroundImage == null)
				{
					if (j == 0)
						stop = true;
					else
						break;
				}
				else
				{
					if (images[i] == null)
						images[i] = new Array();

					images[i][j] = backgroundImage;
				}
			}
		}
		
		var iOffset = (direction == "NORTH" ? -1 : 1);
		var iStart = (direction == "NORTH" ? images.length - 1 : 0);
		var nextImageIOffset = ((direction == "NORTH") || (direction == "SOUTH") ? iOffset : 0);

		for (i = iStart; (i + nextImageIOffset) >= 0 && (i + nextImageIOffset) < images.length; i += iOffset)
		{
			var jOffset = (direction == "WEST" ? -1 : 1);
			var jStart = (direction == "WEST" ? images[i].length - 1 : 0);
			var nextImageJOffset = ((direction == "NORTH") || (direction == "SOUTH") ? 0 : jOffset);

			for (j = jStart; (j + nextImageJOffset) >= 0 && (j + nextImageJOffset) < images[i].length; j += jOffset)
			{
				var backgroundImage = images[i][j];
				var nextBackgroundImage = images[i + nextImageIOffset][j + nextImageJOffset];

				backgroundImage.src = nextBackgroundImage.src;
				// Uncomment next line to switch images that must reloaded with en empty image
				// until new images are loaded.
				//nextBackgroundImage.src = emptyImagePath;
			}
		}
	}
	
	SendAjaxRequestParams(_rootUrl + path, pageParam + '=' + mapId + '&' + sourceParam + '=translateMap' +
		'&' + valueParam + '=' + direction + '&' + controllerParam + '=' + controller, 'false');
}

function addFirefoxWheelEvent(path, mapDivId, mapZoomId, mapId, controller)
{
	var parentFrame = findTargetByContent(null, mapDivId);

	if (parentFrame == null)
		return;

	var mapZoomDiv = parentFrame.document.getElementById(mapDivId);

	var firefoxWheelMoved = function(event)
	{
		parentFrame.wheelMoved(event, path, mapDivId, mapZoomId, mapId, controller);
	}
	
	mapZoomDiv.addEventListener('DOMMouseScroll', firefoxWheelMoved, false);
}

function wheelMoved(event, path, mapDivId, mapZoomId, mapId, controller)
{
	var zoomIn = true;

	if (event.wheelDelta)
		zoomIn = (event.wheelDelta > 0);
	else if (event.detail)
		zoomIn = (event.detail < 0);

	var mapDiv = this.document.getElementById(mapDivId);
	var x = event.clientX - cmGetX(mapDiv);
	var y = event.clientY - cmGetY(mapDiv);

	if (zoomIn)
		setMapZoomScale(currentScale[mapId] + 1, path, mapId, mapZoomId, x, y, controller);
	else
		setMapZoomScale(currentScale[mapId] - 1, path, mapId, mapZoomId, x, y, controller);
	
	if (browser.isIE)
	{
		window.event.cancelBubble = true;
		window.event.returnValue = false;
	}
	else if (browser.isNS)
		event.preventDefault();
}
