function ComponentMap(id, formID, mapCanvasID, minX, minY, maxX, maxY, panFactor, zoomFactor, zoomBoxColour, zoomBoxOpacity,
                      markerSize, panMode, drawLibObj, componentManagerObj, browserObj, geometryObj, loadSplashDelay, drawMenuLocation, shapeValidation) {
    
    ComponentMap.prototype.setExtent = function(minX, minY, maxX, maxY) {
        this.minX = minX;
        this.minY = minY;
        this.maxX = maxX;
        this.maxY = maxY;
        this.distanceX = this.maxX - this.minX;
        this.distanceY = this.maxY - this.minY;
        this.centerX = this.minX + (this.distanceX / 2);
        this.centerY = this.minY + (this.distanceY / 2);
    }
    
    ComponentMap.prototype.resizeMapEventHandler = function() {        
        clearTimeout(this.mapObj.resizeTimer);
        this.mapObj.resizeTimer = setTimeout(this.mapObj.id + '.resizeMap();', 500);
    }
    
    ComponentMap.prototype.resizeMap = function() {
               
        //Map canvas span tag.
        this.mapCanvasObj.style.display = "none";
        var styleObj = this.mapCanvasObj.style;
        
        var origHeight = this.browserObj.getPixelValue(this.mapCanvasObj.style.height);
        var origWidth = this.browserObj.getPixelValue(this.mapCanvasObj.style.width);
        
        //This checks that map canvas is not inside another element.
        if (this.mapCanvasObj.parentNode.id == this.formObj.id) {
            styleObj.height = this.browserObj.getClientHeight() - this.mapCanvasObj.offsetTop - this.resizePadding + "px";
            styleObj.width = this.browserObj.getClientWidth() - this.mapCanvasObj.offsetLeft - this.resizePadding + "px";
        }
        else {
        
            //Do nothing if no height can be found.
            if (this.mapCanvasObj.parentNode.offsetHeight == 0) {
                this.maptype = this.MAP_TYPE_RESIZE;
                this.sendMapRequst(true);
                this.mapCanvasObj.style.display = "";
                return;
            }
            
            //For first resize neeed to move the map canvas to allow for padding.
            //NOTE done when not inside element.
            if (!this.firstResizeDone) {
                styleObj.left = this.browserObj.getPixelValue(styleObj.left) + this.resizePadding + "px";
                styleObj.top = this.browserObj.getPixelValue(styleObj.top) + this.resizePadding + "px";
            }
            styleObj.height = this.mapCanvasObj.parentNode.offsetHeight  - this.resizePadding * 2 + "px";
            styleObj.width = this.mapCanvasObj.parentNode.offsetWidth  - this.resizePadding * 2 + "px";
        }
        this.mapCanvasObj.style.display = "";
        var docWidthChange = this.browserObj.getPixelValue(styleObj.width) - origWidth;
        var docHeightChange = this.browserObj.getPixelValue(styleObj.height) - origHeight;
        
        
        styleObj = this.mapCanvasDivObj.style;
        styleObj.height = this.mapCanvasObj.style.height;
        styleObj.width = this.mapCanvasObj.style.width;
        
        styleObj = this.glassTop.style;
        styleObj.height = this.browserObj.getPixelValue(styleObj.height) + docHeightChange + "px";
        styleObj.width = this.browserObj.getPixelValue(styleObj.width) + docWidthChange + "px";
        var glassTopChild = this.glassTop.firstChild;
        if ((glassTopChild != null) && (glassTopChild.tagName.toLowerCase() == "table")) {
            styleObj = glassTopChild.style;
            styleObj.width = this.browserObj.getPixelValue(styleObj.width) + docWidthChange + "px";
            styleObj.height = this.browserObj.getPixelValue(styleObj.height) + docHeightChange + "px";
        }

        //Map Image has parent div tag.
        styleObj = this.mapImage.parentNode.style;
        styleObj.height = this.browserObj.getPixelValue(styleObj.height) + docHeightChange + "px";
        styleObj.width = this.browserObj.getPixelValue(styleObj.width) + docWidthChange + "px";
        var barderWidth = this.browserObj.getPixelValue(this.mapImage.parentNode.style.left);
        this.mapImage.height = this.browserObj.getPixelValue(this.mapCanvasObj.style.height) - (barderWidth * 2);
        this.mapImage.width = this.browserObj.getPixelValue(this.mapCanvasObj.style.width) - (barderWidth * 2);
        
        this.pageWidth = this.mapImage.width - 1;
        this.pageHeight = this.mapImage.height - 1;
        
        this.currentClientWidth = this.currentClientWidth + docWidthChange;
        this.currentClientHeight = this.currentClientHeight + docHeightChange;
        this.firstResizeDone = true;
        this.maptype = this.MAP_TYPE_RESIZE;
        this.sendMapRequst(true);
        this.positionDrawMenu();
    }
    
    ComponentMap.prototype.moveExtent = function(minX, maxY) {
        var distanceX = this.minX - minX;
        var distanceY = this.maxY - maxY;
        this.minX = this.minX + distanceX;
        this.minY = this.minY + distanceY;
        this.maxX = this.maxX + distanceX;
        this.maxY = this.maxY + distanceY;
        this.distanceX = this.maxX - this.minX;
        this.distanceY = this.maxY - this.minY;
    }
    
    ComponentMap.prototype.setStartImage = function(minX, minY, maxX, maxY, imageURL, scale, metersPerPixel, scaleFactor) {
        this.setExtent(minX, minY, maxX, maxY);
        this.componentManagerObj.setStatus((this.minX + (this.distanceX / 2)), (this.minY + (this.distanceY / 2)));
        if (scale) {
            this.scale = scale;
            this.scaleFactor = scaleFactor;
            this.componentManagerObj.setScale(scale, this.scaleFactor);
        }
        this.mapImage.src = imageURL;
        this.metersPerPixel = metersPerPixel;
        
        if (this.maxDistanceX == 0 || this.maxDistanceY == 0) {
            this.maxDistanceX = this.distanceX;
            this.maxDistanceY = this.distanceY;
        }
        this.componentManagerObj.setOverviewLocation(minX, minY, maxX, maxY);
    }
    
    ComponentMap.prototype.moveMapImage = function(pageOffsetX, pageOffsetY, totalSteps, step, panDirection) {
        
        if (!step) {
            step = 0;
        }
        if (!panDirection) {
            panDirection = "";
        }

        var offsetXStep = pageOffsetX / totalSteps;
        var offsetYStep = pageOffsetY / totalSteps;
        
        this.mapImage.style.left = offsetXStep * (step + 1) + "px";
        this.mapImage.style.top = offsetYStep * (step + 1) + "px";
        
        step++;
        if (step < totalSteps) {
            setTimeout(this.id + ".moveMapImage(" + pageOffsetX + ", " + pageOffsetY + ", " + totalSteps + ", " + step + ", '" + panDirection + "');", 5);
        }
        else {
            if (panDirection.length > 0) {
                this.sendPanRequest(panDirection);
            }
        }
    }
    
    ComponentMap.prototype.panDirection = function(e) {
        
        this.mapObj.clearRectangleCoords();
        var pageOffsetX = this.mapObj.mapImage.width * this.mapObj.panFactor;
        var pageOffsetY = this.mapObj.mapImage.height * this.mapObj.panFactor;
        
        //Move the map image
        switch (this.direction) {
            case this.mapObj.PAN_N: {
                pageOffsetX = 0;
            break;
            }
            case this.mapObj.PAN_E: {
                pageOffsetX = -pageOffsetX;
                pageOffsetY = 0;
            break;
            }
            case this.mapObj.PAN_W: {
                pageOffsetY = 0;
            break;
            }
            case this.mapObj.PAN_S: {
                pageOffsetX = 0;
                pageOffsetY = -pageOffsetY;
            break;
            }
            case this.mapObj.PAN_NE: {
                pageOffsetX = -pageOffsetX;
            break;
            }
            case this.mapObj.PAN_NW: {
            break;
            }
            case this.mapObj.PAN_SE: {
                pageOffsetX = -pageOffsetX;
                pageOffsetY = -pageOffsetY;            
            break;
            }
            case this.mapObj.PAN_SW: {
                pageOffsetY = -pageOffsetY;
            break;
            }
        }
        this.mapObj.resetDrawingTools(true);
        this.mapObj.moveMapImage(pageOffsetX, pageOffsetY, (this.mapObj.panFactor * 10), 0, this.direction);
    }

    ComponentMap.prototype.setPanEvents = function() {
    
        this.setDrawMenu(true, false);
        this.glassTop.style.cursor = "move";
		this.glassTop.onmousedown = this.panMouseDown;
		this.glassTop.onmousemove = this.panMouseMove;
		this.glassTop.onmouseup = this.panMouseUp;
		this.glassTop.onmouseout = this.panMouseUp;
    }
    
    ComponentMap.prototype.setPanButtonEvents = function() {
        
        if (this.panN != null) {
            this.panN.mapObj = this;
            this.panN.direction = this.PAN_N;
            this.panN.onmousedown = this.panDirection;
        }
        if (this.panE != null) {
            this.panE.mapObj = this;
            this.panE.direction = this.PAN_E;
            this.panE.onmousedown = this.panDirection;
        }
        if (this.panW != null) {
            this.panW.mapObj = this;
            this.panW.direction = this.PAN_W;
            this.panW.onmousedown = this.panDirection;
        }
        if (this.panS != null) {
            this.panS.mapObj = this;
            this.panS.direction = this.PAN_S;
            this.panS.onmousedown = this.panDirection;
        }
        if (this.panNE != null) {
            this.panNE.mapObj = this;
            this.panNE.direction = this.PAN_NE;
            this.panNE.onmousedown = this.panDirection;
        }
        if (this.panNW != null) {
            this.panNW.mapObj = this;
            this.panNW.direction = this.PAN_NW;
            this.panNW.onmousedown = this.panDirection;
        }
        if (this.panSE != null) {
            this.panSE.mapObj = this;
            this.panSE.direction = this.PAN_SE;
            this.panSE.onmousedown = this.panDirection;
        }
        if (this.panSW != null) {
            this.panSW.mapObj = this;
            this.panSW.direction = this.PAN_SW;
            this.panSW.onmousedown = this.panDirection;
        }
    }
    
    ComponentMap.prototype.setDrawButtonEvents = function() {
    
        this.cancelObj.mapObj = this;
        this.cancelObj.onmousedown = this.deleteLastShape;
        this.submitObj.mapObj = this;
        this.submitObj.onmousedown = this.submitShapesClick;
        this.addShapeObj.mapObj = this;
        this.addShapeObj.onmousedown = this.drawAddShape;
    }
    
    ComponentMap.prototype.setDrawRectangleEvents = function(singleShape) {
        
        this.setDrawMenu(singleShape, false);
        this.glassTop.onmousedown = this.drawRectangleMouseDown;
		this.glassTop.onmousemove = this.drawRectangleMouseMove;
		this.glassTop.onmouseup = this.drawRectangleMouseUp;
		this.glassTop.onmouseout = this.drawRectangleMouseUp;
		this.componentManagerObj.setMeasureMode(this.componentManagerObj.MEASURE_AREA);
    }
    
    ComponentMap.prototype.setDrawPolyLineEvents = function() {
        
        this.setDrawMenu(false, true);
        this.glassTop.onmousedown = this.drawPolyLineMouseDown;
		this.glassTop.onmousemove = this.drawShapeMouseMove;
		this.glassTop.onmouseup = this.drawShapeMouseMove;
		this.glassTop.onmouseout = this.drawShapeMouseOut;
		this.componentManagerObj.setMeasureMode(this.componentManagerObj.MEASURE_DISTANCE);
    }
    
    ComponentMap.prototype.setDrawPolyonEvents = function() {
        
        this.setDrawMenu(false, true);
        this.glassTop.onmousedown = this.drawPolygonMouseDown;
		this.glassTop.onmousemove = this.drawShapeMouseMove;
		this.glassTop.onmouseup = this.drawShapeMouseMove;
		this.glassTop.onmouseout = this.drawShapeMouseOut;
		this.componentManagerObj.setMeasureMode(this.componentManagerObj.MEASURE_AREA);
    }
    
    ComponentMap.prototype.setPointClickEvents = function() {
        
        this.setDrawMenu(true, false);
        this.glassTop.onmousedown = this.pointClickMouseDown;
		this.glassTop.onmousemove = this.drawShapeMouseMove;
		this.glassTop.onmouseup = this.drawShapeMouseMove;
		this.glassTop.onmouseout = this.drawShapeMouseOut;
    }
    
    ComponentMap.prototype.setDrawCircleEvents = function(singleShape) {
        
        this.setDrawMenu(singleShape, false);
        this.glassTop.onmousedown = this.drawCircleMouseDown;
		this.glassTop.onmousemove = this.drawCircleMouseMove;
		this.glassTop.onmouseup = this.drawCircleMouseUp;
		this.glassTop.onmouseout = this.drawCircleMouseUp;
		this.componentManagerObj.setMeasureMode(this.componentManagerObj.MEASURE_AREA);
    }
    
    ComponentMap.prototype.setDrawPointEvents = function() {
        
        this.setDrawMenu(false, false);
        this.glassTop.onmousedown = this.drawPointMouseDown;
		this.glassTop.onmousemove = this.drawShapeMouseMove;
		this.glassTop.onmouseup = this.drawShapeMouseMove;
		this.glassTop.onmouseout = this.drawShapeMouseMove;
    }
    
    ComponentMap.prototype.setDrawMenu = function(singleShape, addShape) {
        
        this.singleShape = false;
        
        if (singleShape) {
            this.singleShape = singleShape;
        }
        
        this.resetDrawingTools();
        
        if (!this.singleShape) {
            this.drawMenuObj.style.display = "";
        }
        if (addShape) {
            this.addShapeObj.style.display = "";
        }
        
        this.positionDrawMenu();
        
        this.glassTop.style.cursor = "crosshair";
    }
    
    ComponentMap.prototype.positionDrawMenu = function() {
    
        if (this.drawMenuObj == null) {
            return;
        }
        if (this.drawMenuObj.style.display == "") {
            var left = this.browserObj.getPixelValue(this.glassTop.style.left);
            var top = this.browserObj.getPixelValue(this.glassTop.style.top);
            switch(this.drawMenuLocation) {
                case "TOPLEFT":
                    this.drawMenuObj.style.left = left + "px";
                    this.drawMenuObj.style.top = top + "px";
                break;
                case "TOPRIGHT":
                    this.drawMenuObj.style.top = top + "px";
                    this.drawMenuObj.style.left = (left + this.glassTop.offsetWidth - this.drawMenuObj.offsetWidth) + "px"
                break;
                case "BOTTOMLEFT":
                    this.drawMenuObj.style.top = (top + this.glassTop.offsetHeight - this.drawMenuObj.offsetHeight) + "px";
                    this.drawMenuObj.style.left = left + "px";
                break;
                case "BOTTOMRIGHT":
                    this.drawMenuObj.style.top = (top + this.glassTop.offsetHeight - this.drawMenuObj.offsetHeight) + "px";
                    this.drawMenuObj.style.left = (left + this.glassTop.offsetWidth - this.drawMenuObj.offsetWidth) + "px"
                break;
            }
        }
    }
    
    ComponentMap.prototype.deleteLastShape = function() {
        
        var length = this.mapObj.shapeCollection.length;
        
        if (length > 0) {
            if (!this.mapObj.shapeCollection[this.mapObj.shapeIndex]) {
                --this.mapObj.shapeIndex;
            }
            this.mapObj.drawLibObj.deleteShape(this.mapObj.shapeCollection[this.mapObj.shapeIndex]);
            this.mapObj.shapeCollection.pop();
            
            if (this.mapObj.nodeCollection && this.mapObj.nodeCollection.length > 0) {
                var nodeList = this.mapObj.nodeCollection[this.mapObj.shapeIndex];
                if (nodeList) {
                    length = nodeList.length;
                    for (var j=0; j<length; j++) {
                        this.mapObj.drawLibObj.deleteShape(nodeList[j]);
                    }
                    this.mapObj.nodeCollection.pop();
                }
            }
            this.mapObj.shapeIndex = this.mapObj.shapeCollection.length - 1;
            if (this.mapObj.shapeIndex < 0) {
                this.mapObj.shapeIndex = 0;
            }
        }
        this.mapObj.removeShapeFromState();
    }
    
    ComponentMap.prototype.resetDrawingToolsViaButton = function() {
        this.mapObj.resetDrawingTools(true);
    }
    
    ComponentMap.prototype.resetDrawingTools = function(keepState) {
        
        if (this.drawMenuObj && !keepState) {
            this.drawMenuObj.style.display = "none";
            this.addShapeObj.style.display = "none";
        }
        
        var shape;
        var collectionLength = 0;
        var length = 0;
        var nodeList;
        
        if (this.shapeCollection) {
            length = this.shapeCollection.length;
            for (var i=0; i<length; i++) {
                this.drawLibObj.deleteShape(this.shapeCollection[i]);
            }
        }
        this.shapeCollection = new Array();
        
        if (this.nodeCollection) {
            collectionLength = this.nodeCollection.length;
            for (var i=0; i<collectionLength; i++) {
                nodeList = this.nodeCollection[i];
                length = nodeList.length;
                for (var j=0; j<length; j++) {
                    this.drawLibObj.deleteShape(nodeList[j]);
                }
            }
        }
        this.nodeCollection = new Array(); 
        
        this.drawing = false;
        this.shapeIndex = 0;
        this.componentManagerObj.setMeasureInformation(0, 0, 0, 0);
        
        if (this.shapeStateObj) {
            this.shapeStateObj.value = "";
        }
    }
    
    ComponentMap.prototype.submitShapesClick = function() {
    
        this.mapObj.submitShapes();
    }
    
    ComponentMap.prototype.submitShapes = function() {
        
        //Check all shapes are valid
        var length = this.shapeCollection.length;
        var shape;
        var isValid = true;
        
        for (var i=0; i<length; i++) {
            shape = this.shapeCollection[i];
            isValid = this.validateShape(shape, "Error with shape " + (i + 1) + ":");
            if (!isValid) {
                break;
            }
        }
        
        if (isValid) {
            this.sendMapRequst();
        }
    }
    
    ComponentMap.prototype.validateShape = function(shape, messagePrefix) {
        
        var isValid = true;
        if (!messagePrefix) {
            messagePrefix = "";
        }
        
        switch (shape.typeShape) {
            case this.SHAPE_TYPE_POLYGON:
                if (shape.coordList.length < 3) {
                    alert(messagePrefix + " Polygon requires at least 3 points.");
                    isValid = false;
                }
                else if (this.shapeValidation == this.SHAPE_VALIDATION_ONSUBMIT) {
                    isValid = this.geometryObj.isSimplePolygon(shape.clientClicks);
                    if (!isValid) {
                        alert(messagePrefix + " Polygon is not a simple polygon.");
                    }
                }
            break;
            case this.SHAPE_TYPE_POLYLINE:
                if (shape.coordList.length < 2) {
                    alert(messagePrefix + " Line requires at least 2 points.");
                    isValid = false;
                }
            break
        }
        
        return isValid;
    }
    
    ComponentMap.prototype.clearRectangleCoords = function() {
        
        this.drawLibObj.deleteShape(document.getElementById(this.mapCanvasID + "_askRectangleCoords"));
    }
    
    ComponentMap.prototype.addRectangleCoords = function(coords) {
        
        if (!coords) {
            return;
        }
        
        var x;
        var y;
        var currentCood;
        var width = this.markerSize;
        var height = this.markerSize;
        
        var container = document.createElement('div');
        this.glassTop.appendChild(container);
        container.id = this.mapCanvasID + "_askRectangleCoords";
        container.style.position = 'absolute';
        container.style.zIndex = -2;
		
        for (var i=coords.length - 1; i>=0; i--) {
            currentCood = coords[i];
            x = this.getPageX(currentCood[0]) - (width / 2);
            y = this.getPageY(currentCood[1]) - (height / 2);
            this.drawLibObj.addMarker(container, "snap", x, y, width, height, -2, 1,"black", "green", 1);
        }
    }
    
    ComponentMap.prototype.addRectangle = function(parentObj, rectangleId, x, y, width, height, center, borderColor, fillColor, opacity, zIndex) {
        
		var borderColor = borderColor;
		var fillColor = fillColor;
		var opacity = opacity;
		var rectangleIndex = -1;
		
		if (!borderColor) borderColor = this.zoomBoxColour;
		if (!fillColor) fillColor = this.zoomBoxColour;
		if (!opacity) opacity = this.zoomBoxOpacity;
		if (!rectangleIndex) rectangleIndex = zIndex;
		
		if (center) {
		    x = x - width / 2;
		    y = y - height / 2;
		}		
		
		var rectangleObj = this.drawLibObj.addRectangle(parentObj, rectangleId, x, y, width, height, rectangleIndex, 1, borderColor, fillColor, opacity);

		rectangleObj.startX = x;
		rectangleObj.startY = y;
		this.drawing = true;
		
		return rectangleObj;
    }
    
    ComponentMap.prototype.addRectangleEvent = function(e, rectangleId, width, height, center, borderColor, fillColor, opacity) {
        
        var x = this.browserObj.getMousePositionX(this.glassTop, e);
		var y = this.browserObj.getMousePositionY(this.glassTop, e);
		var shape = this.addRectangle(this.glassTop, rectangleId, x, y, width, height, center, borderColor, fillColor, opacity);		
		shape.coordList = new Array();
		shape.coordList[0] = new Array(this.getMapX(x), this.getMapY(y));
		return shape;
    }
    
    ComponentMap.prototype.resizeRectangle = function(e, rectangleObj) {
        
        var x = this.browserObj.getMousePositionX(this.glassTop, e);
		var y = this.browserObj.getMousePositionY(this.glassTop, e);
        
        if (this.drawing) {
		    if (rectangleObj != null) {
		        this.drawLibObj.resizeShape(rectangleObj, rectangleObj.startX, rectangleObj.startY, x, y);
		    }
		}
		
		this.setStatus(x, y);
    }
    
    ComponentMap.prototype.stopRectangle = function(rectangleObj) {
    
        if (this.drawing) {
            if (rectangleObj) {
                this.drawLibObj.deleteShape(rectangleObj);
            }
	        this.drawing = false;
	    }
    }
    
    ComponentMap.prototype.panMouseDown = function(e) {
    
		var x = this.mapObj.browserObj.getMousePositionX(this, e);
		var y = this.mapObj.browserObj.getMousePositionY(this, e);
		this.mapObj.mapImage.startX = x;
		this.mapObj.mapImage.startY = y;
		
		shape = document.createElement("div"); //This is a dummy shape for holding click points
		this.mapObj.glassTop.appendChild(shape);
		shape.coordList = new Array();
		shape.coordList[0] = new Array(this.mapObj.getMapX(x), this.mapObj.getMapY(y));
		this.mapObj.shapeCollection[this.mapObj.shapeIndex] = shape;
		this.mapObj.paning = true;
    }
    
    ComponentMap.prototype.panMouseMove = function(e) {
        
        var x = this.mapObj.browserObj.getMousePositionX(this, e);
		var y = this.mapObj.browserObj.getMousePositionY(this, e);
		
        if (this.mapObj.paning) {
            if (this.mapObj.panMode == this.mapObj.PAN_MODE_DRAG || this.mapObj.panMode == this.mapObj.PAN_MODE_COMBINED) {
		        this.mapObj.mapImage.style.left = (x - this.mapObj.mapImage.startX) + "px";
		        this.mapObj.mapImage.style.top = (y - this.mapObj.mapImage.startY) + "px";
		        x = this.mapObj.mapImage.startX;
		        y = this.mapObj.mapImage.startY;
		    }
		}
		this.mapObj.setStatus(x, y);
    }
    
    ComponentMap.prototype.panMouseUp = function(e) {
        
        if (this.mapObj.paning) {
            
            var x = this.mapObj.browserObj.getMousePositionX(this, e);
		    var y = this.mapObj.browserObj.getMousePositionY(this, e);
		    var mapX = this.mapObj.getMapX(x);
		    var mapY = this.mapObj.getMapY(y);
		    var shape = this.mapObj.shapeCollection[this.mapObj.shapeIndex];
		    
            shape.coordList[1] = new Array(mapX, mapY);
		    
		    var hasNotMoved = ((shape.coordList[0][0] == shape.coordList[1][0]) & (shape.coordList[0][1] == shape.coordList[1][1]));
            
            var sendRequest = true;
            if (hasNotMoved && (this.mapObj.panMode == this.mapObj.PAN_MODE_POINT || this.mapObj.panMode == this.mapObj.PAN_MODE_COMBINED)) 
            {
                x = (this.mapObj.pageWidth / 2) - this.mapObj.browserObj.getMousePositionX(this, e);
                y = (this.mapObj.pageHeight / 2) - this.mapObj.browserObj.getMousePositionY(this, e);
                this.mapObj.moveMapImage(x, y, 5);
            }
            
            this.mapObj.submitShapes();
            this.mapObj.paning = false;
        }
        this.mapObj.resetDrawingTools();
    }
    
    ComponentMap.prototype.drawRectangleMouseDown = function(e) {
        var index = this.mapObj.shapeCollection.length;
        var object = this.mapObj.addRectangleEvent(e, "shapeRectangle" + index, 0, 0);
        this.mapObj.shapeCollection[index] = object;
        this.mapObj.shapeIndex = index;
    }
    
    ComponentMap.prototype.drawRectangleMouseMove = function(e) {
        
        if (this.mapObj.drawing) {
            var shape = this.mapObj.shapeCollection[this.mapObj.shapeCollection.length - 1];
            this.mapObj.resizeRectangle(e, shape);
            this.mapObj.setRectangleInfo(shape);
        }
        var mouseX = this.mapObj.browserObj.getMousePositionX(this, e);
		var mouseY = this.mapObj.browserObj.getMousePositionY(this, e);
        this.mapObj.setStatus(mouseX, mouseY);
    }
    
    ComponentMap.prototype.drawRectangleMouseUp = function(e) {
    
        if (this.mapObj.drawing) {
	        this.mapObj.stopRectangle();
            var x = this.mapObj.browserObj.getMousePositionX(this, e);
		    var y = this.mapObj.browserObj.getMousePositionY(this, e);
	        var shape = this.mapObj.shapeCollection[this.mapObj.shapeCollection.length - 1];
	        shape.typeShape = this.mapObj.SHAPE_TYPE_ENVELOPE;
            shape.coordList[1] = new Array(this.mapObj.getMapX(x), this.mapObj.getMapY(y)); 
            this.mapObj.setShapeState(shape);
            
            if (this.mapObj.singleShape) {
                this.mapObj.submitShapes();
            }
	    }
    }
    
    ComponentMap.prototype.setRectangleInfo = function(shape) {
    
        var x = this.browserObj.getPixelValue(shape.style.left);
        var y = this.browserObj.getPixelValue(shape.style.top);
        var width = this.browserObj.getPixelValue(shape.style.width);
        var height = this.browserObj.getPixelValue(shape.style.height);
        
        var minX = x;
        var minY = y - height;
        var maxX = x + width;
        var maxY = y;
        
        if (this.geometryObj) {
            var segment = this.geometryObj.getLineLength(new Array(new Array(minX, minY), new Array(minX, maxY)));
            var total =  this.geometryObj.getRectanglePerimeter(minX, minY, maxX, maxY);
            var area = Math.abs(this.geometryObj.getRectangleArea(minX, minY, maxX, maxY));
            var perimeter = total;
            
            segment = segment * this.metersPerPixel;
            total = total * this.metersPerPixel;
            area = area * Math.pow(this.metersPerPixel, 2);
            perimeter = perimeter * this.metersPerPixel;
            
            this.componentManagerObj.setMeasureInformation(segment, total, area, perimeter);
        }
    }
    
    ComponentMap.prototype.setCircleInfo = function(shape) {
    
        var y = this.getPageX(shape.coordList[1][0]);
        var x = this.getPageY(shape.coordList[1][1]);
        var centerX = this.getPageX(shape.coordList[0][0]);
        var centerY = this.getPageY(shape.coordList[0][1]);
        var radius = Math.sqrt(Math.pow(Math.abs(x - centerX), 2) + Math.pow(Math.abs(y - centerY), 2));
		
		var segment = this.geometryObj.getCircleCircumference(radius) * this.metersPerPixel;
        var total = segment;
        var area = this.geometryObj.getCircleArea(radius) * Math.pow(this.metersPerPixel, 2);
        var perimeter = segment;
        
        this.componentManagerObj.setMeasureInformation(segment, total, area, perimeter);
    }
            
    //Generic actions for mouse down event when drawing the shape.
    ComponentMap.prototype.drawShapeMouseDown = function(e, shapeFunction, shapeId, typeShape) {
    
        var x = this.browserObj.getMousePositionX(this.glassTop, e);
		var y = this.browserObj.getMousePositionY(this.glassTop, e);
        var shape = this.shapeCollection[this.shapeIndex];
        var coordList = new Array();
        var clientClicks = new Array();
        var rightMouseClick = this.browserObj.isRightMouseClick(e);
        
        if (shape && shape.coordList) {
            coordList = shape.coordList;
        }
        
        if (shape && shape.clientClicks) {
            clientClicks = shape.clientClicks;
            
            var length = shape.clientClicks.length;
            var minX = 0;
            var minY = 0;
            var maxX = 0;
            var maxY = 0;
            var clickX;
            var clickY;
            
            for (var i=0; i<length; i++) {
                clickX = clientClicks[i][0];
                clickY = clientClicks[i][1];
                minX = clickX - this.markerSize;
                minY = clickY - this.markerSize;
                maxX = clickX + this.markerSize;
                maxY = clickY + this.markerSize;
                
                if (this.geometryObj.isInEnvelope(x, y, minX, minY, maxX, maxY)) {
                    //Delete node if right mouse click
                    this.glassTop.currentNode = document.getElementById("Node:" + shape.id.split(":")[1] + ":" + i);
                    var nodeList = this.nodeCollection[this.shapeIndex];
                    var removedClientClick = clientClicks[i];
                    var removedCoord = coordList[i];
                    var removedNode = nodeList[i];
                    var adjustNodeIds = true;
                    if (rightMouseClick) {
                        this.drawLibObj.deleteShape(this.glassTop.currentNode);
                        if (i==0) {
                            clientClicks.shift();
                            coordList.shift();
                            nodeList.shift();
                        }
                        else if (i == length - 1) {
                            clientClicks.pop();
                            coordList.pop();
                            nodeList.pop();
                        }
                        else {
                            clientClicks = clientClicks.slice(0, i).concat(clientClicks.slice(i + 1));
                            coordList = coordList.slice(0, i).concat(coordList.slice(i + 1));
                            nodeList = nodeList.slice(0, i).concat(nodeList.slice(i + 1));
                        }
                        
                        if ((this.shapeValidation == this.SHAPE_VALIDATION_ONCREATION) && (typeShape == this.SHAPE_TYPE_POLYGON)) {
                            if (!this.geometryObj.isSimplePolygon(clientClicks)) {
                                this.drawLibObj.deleteShape(shape);
                                eval("shape = this.drawLibObj." + shapeFunction + "(this.glassTop, '" + shapeId + ":' + this.shapeIndex, this.zoomBoxColour, 1, clientClicks, -2)");
                                alert("Cannot delete point as only simple polygons are supported.");
                                clientClicks = clientClicks.slice(0, i).concat(new Array(removedClientClick)).concat(clientClicks.slice(i));
                                coordList = coordList.slice(0, i).concat(new Array(removedCoord)).concat(coordList.slice(i));
                                removedNode = this.addRectangle(this.glassTop, "Node:" + this.shapeIndex + ":" + i, removedClientClick[0], removedClientClick[1], this.markerSize, this.markerSize, true, "black", this.zoomBoxColour, 1);
                                nodeList = nodeList.slice(0, i).concat(new Array(removedNode)).concat(nodeList.slice(i));
                                adjustNodeIds = false;
                            }
                        }
                        
                        if (adjustNodeIds) {
                            this.adjustNodeIds(i - 1, "-1");
                        }
                        shape.coordList = coordList;
                        shape.clientClicks = clientClicks;
                        this.nodeCollection[this.shapeIndex] = nodeList;
                        break;
                    }
                    else {
                        this.setNodeMoveEvents();
                        return;
                    }
                }
            }
        }
        
        
        if (!rightMouseClick) {
        
            var clickPoint = new Array(x, y);
            var coord = new Array(this.getMapX(x), this.getMapY(y));
            var nodeIndex = 0;
            //Check to see if is on line, if so then add node there.
            var addition = this.markerSize / 2;
            var x1 = x - addition;
            var y1 = y - addition;
            var x2 = x + addition;
            var y2 = y + addition;
            
            var interSectionIndex = this.geometryObj.getIntersectionIndex(clientClicks, x1, y1, x2, y2);
            
            if (interSectionIndex == -1) {
                interSectionIndex = this.geometryObj.getIntersectionIndex(clientClicks, x2, y1, x1, y2);
            }
            
            if (interSectionIndex > -1) {
                clientClicks = new Array().concat(clientClicks.slice(0, interSectionIndex + 1), new Array(clickPoint), clientClicks.slice(interSectionIndex + 1));
                coordList = new Array().concat(coordList.slice(0, interSectionIndex + 1), new Array(coord), coordList.slice(interSectionIndex + 1));
                nodeIndex = interSectionIndex + 1;
            }
            else {
                clientClicks.push(clickPoint);
                
                if ((this.shapeValidation == this.SHAPE_VALIDATION_ONCREATION) && (typeShape == this.SHAPE_TYPE_POLYGON)) {
                    if (!this.geometryObj.isSimplePolygon(clientClicks)) {
                        alert("Cannot add point as only simple polygons are supported.");
                        clientClicks.pop();
                        return;
                    }
                }
                nodeIndex = coordList.length;
                coordList[nodeIndex] = coord;
            }
            
            //Snap the point
            if (this.componentManagerObj.useSnap()) {
                coord = this.componentManagerObj.snapPoint(coord);
                coordList[nodeIndex] = coord;
                clickPoint[0] = this.getPageX(coord[0]);
                clickPoint[1] = this.getPageY(coord[1]);
            }
            
            var node = this.addRectangle(this.glassTop, "Node:" + this.shapeIndex + ":" + nodeIndex, clickPoint[0], clickPoint[1], this.markerSize, this.markerSize, true, "black", this.zoomBoxColour, 1);
            
            if (interSectionIndex > -1) {
                this.adjustNodeIds(interSectionIndex, "+1");
                var nodeList = this.nodeCollection[this.shapeIndex];
                var lastNodes = nodeList.slice(interSectionIndex + 1);
                this.nodeCollection[this.shapeIndex] = new Array().concat(nodeList.slice(0, interSectionIndex + 1), node, lastNodes);
            }
            else {
                if (!this.nodeCollection[this.shapeIndex]) {
                    this.nodeCollection[this.shapeIndex] = new Array();
                }
                this.nodeCollection[this.shapeIndex].push(node);
            }
        }
        
        this.drawLibObj.deleteShape(shape);
        if (shapeFunction) {
            eval("shape = this.drawLibObj." + shapeFunction + "(this.glassTop, '" + shapeId + ":' + this.shapeIndex, this.zoomBoxColour, 1, clientClicks, -2)");
        }
        else{
            shape = document.createElement("div");
            shape.id = shapeId + ":" + this.shapeIndex;
            this.glassTop.appendChild(shape); //This is a dummy shape for just displaying points.
        }
        shape.clientClicks = clientClicks;
        shape.coordList = coordList;
        shape.typeShape = typeShape;
	    shape.shapeFunction = shapeFunction;
        this.shapeCollection[this.shapeIndex] = shape;
        this.shapeInfo(shape);
        this.setShapeState(shape);
    }
    
    ComponentMap.prototype.adjustNodeIds = function(index, adjustValue) {

        var nodeList = this.nodeCollection[this.shapeIndex];
        var lastNodes = nodeList.slice(index + 1);
        var lastNodesLenght = lastNodes.length;
        var nodeId;
        //Adjust the nodeIds
        for (var j=0; j<lastNodesLenght; j++) {
            nodeId = lastNodes[j].id.split(":");
            nodeId[2] = eval("parseInt(nodeId[2])" + adjustValue);
            lastNodes[j].id = nodeId.join(":");
        }
    }
    
    ComponentMap.prototype.setShapeState = function(shape) {
        
        if (!this.shapeStateObj) {
            return;
        }
        var currentShapes = this.shapeStateObj.value.split("#");
        var coodList = shape.coordList;
        var shapeState = "";
        var length = coodList.length;
        for (var i=0; i<length; i++) {
            shapeState += coodList[i][0] + " " + coodList[i][1] + ",";
        }
        currentShapes[this.shapeIndex] = shapeState;
        this.shapeStateObj.value = currentShapes.join("#");
    }
    
    ComponentMap.prototype.removeShapeFromState = function(shape) {
        
        if (!this.shapeStateObj) {
            return;
        }
        var currentShapes = this.shapeStateObj.value.split("#");
        currentShapes.pop();
        this.shapeStateObj.value = currentShapes.join("#");
    }
    
    ComponentMap.prototype.shapeInfo = function(shape) {
        
        if (!shape) {
            shape = this.shapeCollection[this.shapeIndex];
        }
        if (!shape) {
            return;
        }
        
        if (shape.typeShape == this.SHAPE_TYPE_ENVELOPE) {
            this.setRectangleInfo(shape);
            return;
        }
        
        if (shape.typeShape == this.SHAPE_TYPE_CIRCLE) {
            this.setCircleInfo(shape);
            return;
        }
        
        var mode = this.componentManagerObj.getMeasureMode();
        var segment = 0;
        var total = 0;
        var area = 0;
        var perimeter = 0;
        var clientClicks = shape.clientClicks;
        
        switch (mode) {
            case this.componentManagerObj.MEASURE_DISTANCE: {
                segment = this.geometryObj.getLineLength(new Array(clientClicks[clientClicks.length - 2], clientClicks[clientClicks.length - 1])) * this.metersPerPixel;
                total = this.geometryObj.getLineLength(clientClicks) * this.metersPerPixel;
                break;
            }
            case this.componentManagerObj.MEASURE_AREA: {
                
                var clientCoirdinates = new Array();
                var length = clientClicks.length;
                for (var i = 0; i<length; i++){
                    clientCoirdinates[i] = new Array(clientClicks[i][0], (this.pageHeight - clientClicks[i][1]));
                }
                area = Math.abs(this.geometryObj.getPolygonArea(clientCoirdinates)) * Math.pow(this.metersPerPixel, 2);
                perimeter = this.geometryObj.getPolygonPerimeter(clientCoirdinates) * this.metersPerPixel;
                break;
            }
        }
        
        this.componentManagerObj.setMeasureInformation(segment, total, area, perimeter);
    }
    
    ComponentMap.prototype.reshapeShape = function(node, x, y) {
    
        var nodeIdArray = node.id.split(":");
        var shapeIndex = nodeIdArray[1];
        var nodeIndexIndex = nodeIdArray[2];
        var shape = this.shapeCollection[shapeIndex];
        var clientClicks = shape.clientClicks;
        var id = shape.id;
        var shapeFunction = shape.shapeFunction;
        var coordList = shape.coordList;
        var typeShape = shape.typeShape;
        coordList[nodeIndexIndex] = new Array(this.getMapX(x), this.getMapY(y));
        clientClicks[nodeIndexIndex] = new Array(x, y);
        if (shapeFunction) {
            shape = this.drawLibObj.reshapeShape(shape, clientClicks);
        }
        shape.coordList = coordList;
        shape.clientClicks = clientClicks;
        shape.shapeFunction = shapeFunction;
        shape.typeShape = typeShape;
        this.shapeCollection[shapeIndex] = shape;
        this.shapeInfo(shape);
    }
    
    ComponentMap.prototype.setNodeMoveEvents = function() {
        
        this.glassTop.currentMouseMove = this.glassTop.onmousemove;
        this.glassTop.currentMouseUp = this.glassTop.onmouseup;
        this.glassTop.currentMouseOut = this.glassTop.onmouseout;
        this.glassTop.onmousemove = this.nodeMouseMove;
        this.glassTop.onmouseup = this.nodeMouseUp;
        this.glassTop.onmouseout = this.nodeMouseUp;
    }
    
    ComponentMap.prototype.nodeMouseMove = function(e) {
        
        var x = this.mapObj.browserObj.getMousePositionX(this, e);
        var y = this.mapObj.browserObj.getMousePositionY(this, e);
        
        this.mapObj.moveNode(this.currentNode, x, y);
        this.mapObj.drawSnapCircle(x, y);
        this.mapObj.setStatus(x, y);
    }
    
    ComponentMap.prototype.moveNode = function(node, x, y) {
    
        var addition = (this.markerSize / 2);
        var distanceX = node.startX - x + addition;
		var distanceY = node.startY - y + addition;
		var newX = node.startX - distanceX;
		var newY = node.startY - distanceY;
        node.style.left = newX + "px";
        node.style.top = newY + "px";
        
        this.reshapeShape(node, newX + addition, newY + addition);
    }
    
    ComponentMap.prototype.nodeMouseUp = function(e) {
        
        this.onmousemove = eval(this.currentMouseMove);
        this.onmouseup = eval(this.currentMouseUp);
        this.onmouseout = eval(this.currentMouseOut);
        
        var node = this.currentNode;
        var nodeIdArray = node.id.split(":");
        var shapeIndex = nodeIdArray[1];
        var nodeIndex = nodeIdArray[2];
        var shape = this.mapObj.shapeCollection[shapeIndex];
        var addition = this.mapObj.markerSize / 2;

        if ((this.mapObj.shapeValidation == this.mapObj.SHAPE_VALIDATION_ONCREATION) && (shape.typeShape == this.mapObj.SHAPE_TYPE_POLYGON)) {
            if (!this.mapObj.geometryObj.isSimplePolygon(shape.clientClicks)) {
                alert("Cannot move point as only simple polygons are supported.");
                this.mapObj.reshapeShape(this.currentNode, this.currentNode.startX + addition, this.currentNode.startY + addition);
                this.currentNode.style.left = this.currentNode.startX  + "px";
                this.currentNode.style.top = this.currentNode.startY + "px";
                return;
            }
        }
        
        //Snap the point
        if (this.mapObj.componentManagerObj.useSnap()) {
            coord = shape.coordList[nodeIndex];
            coord = this.mapObj.componentManagerObj.snapPoint(coord);
            var x = this.mapObj.getPageX(coord[0]);
            var y = this.mapObj.getPageY(coord[1]);
            this.mapObj.moveNode(this.currentNode, x, y)
        }
        
        this.mapObj.setShapeState(shape);
        
        this.currentNode.startX = this.mapObj.browserObj.getMousePositionX(this, e) - addition;
        this.currentNode.startY = this.mapObj.browserObj.getMousePositionY(this, e) - addition;
    }
    
    ComponentMap.prototype.drawPolyLineMouseDown = function(e) {
  
        this.mapObj.drawShapeMouseDown(e, "addPolyLine", "polyLine", this.mapObj.SHAPE_TYPE_POLYLINE);
    }
    
    ComponentMap.prototype.drawShapeMouseMove = function(e) {
        
        var x = this.mapObj.browserObj.getMousePositionX(this.mapObj.glassTop, e);
		var y = this.mapObj.browserObj.getMousePositionY(this.mapObj.glassTop, e);
		
        this.mapObj.drawSnapCircle(x, y);
		this.mapObj.setStatus(x, y);
    }
    
    ComponentMap.prototype.drawShapeMouseOut = function(e) {
        this.mapObj.deleteSnapCircle();
    }
    
    ComponentMap.prototype.drawPolygonMouseDown = function(e) {
        
        this.mapObj.drawShapeMouseDown(e, "addPolygon", "polygon", this.mapObj.SHAPE_TYPE_POLYGON);
    }
    
    ComponentMap.prototype.drawPointMouseDown = function(e) {
        
        this.mapObj.drawShapeMouseDown(e, null, "point", this.mapObj.SHAPE_TYPE_POINT);
    }
    
    ComponentMap.prototype.drawAddShape = function(e) {
        
        var shape = this.mapObj.shapeCollection[this.mapObj.shapeIndex];
        
        if (shape) {
            if (this.mapObj.validateShape(shape, "Error with shape " + (this.mapObj.shapeIndex + 1) + ":")) {
                this.mapObj.shapeIndex++;
            }
        }
    }
    
    ComponentMap.prototype.pointClickMouseDown = function(e) {
        
        this.mapObj.addCircleEvent(e);
        this.mapObj.sendMapRequst();
    }
    
    ComponentMap.prototype.drawCircleMouseDown = function(e) {
        
        this.mapObj.addCircleEvent(e);
        this.mapObj.drawing = true;
    }
    
    ComponentMap.prototype.drawCircleMouseMove = function(e) {
        
        var x = this.mapObj.browserObj.getMousePositionX(this.mapObj.glassTop, e);
		var y = this.mapObj.browserObj.getMousePositionY(this.mapObj.glassTop, e);
        if (this.mapObj.drawing) {
		    var mapX = this.mapObj.getMapX(x);
            var mapY = this.mapObj.getMapY(y);
            var shape = this.mapObj.shapeCollection[this.mapObj.shapeIndex];
            var centerX = this.mapObj.getPageX(shape.coordList[0][0]);
            var centerY = this.mapObj.getPageY(shape.coordList[0][1]);
            var radius = Math.sqrt(Math.pow(Math.abs(x - centerX), 2) + Math.pow(Math.abs(y - centerY), 2));
    		var coordList = shape.coordList;
    		coordList[1] = new Array(mapX, mapY);
    		this.mapObj.drawLibObj.deleteShape(shape);
    		
    		shape = this.mapObj.drawLibObj.addCircle(this.mapObj.glassTop, id, centerX, centerY, radius, this.mapObj.zoomBoxColour, 1, -1);
    		this.mapObj.shapeCollection[this.mapObj.shapeIndex] = shape;
    		shape.coordList = coordList;
    		shape.typeShape = this.mapObj.SHAPE_TYPE_CIRCLE;
    		this.mapObj.setCircleInfo(shape);
        }
        this.mapObj.setStatus(x, y);
    }
    
    ComponentMap.prototype.drawCircleMouseUp = function(e) {
        
        if (this.mapObj.drawing) {
            this.mapObj.drawing = false;
            if (this.mapObj.singleShape) {
                this.mapObj.submitShapes();
            }
            var shape = this.mapObj.shapeCollection[this.mapObj.shapeCollection.length - 1];
            this.mapObj.setShapeState(shape);
        }
    }
    
    ComponentMap.prototype.addCircleEvent = function(e) {
        
        var x = this.browserObj.getMousePositionX(this.glassTop, e);
		var y = this.browserObj.getMousePositionY(this.glassTop, e);
		var id = "circle" + this.shapeCollection.length;
		var mapX = this.getMapX(x);
        var mapY = this.getMapY(y);
        var coord = new Array(mapX, mapY);
        
        if (this.componentManagerObj.useSnap()) {
            coord = this.componentManagerObj.snapPoint(coord);
            x = this.getPageX(coord[0]);
            y = this.getPageY(coord[1]);
        }
        
        var shape = this.drawLibObj.addCircle(this.glassTop, id, x, y, 1, this.zoomBoxColour, 1, -1);
        
        this.shapeCollection[this.shapeCollection.length] = shape;
        this.shapeIndex = this.shapeCollection.length - 1;
        shape.typeShape = this.SHAPE_TYPE_CIRCLE;
        shape.coordList = new Array();
        shape.coordList[0] = coord;
    }
    
    ComponentMap.prototype.drawSnapCircle = function(x, y) {
        
        if (!this.componentManagerObj.useSnap()) {
            return;
        }
        
        var distance = this.componentManagerObj.getSnapDistance(this.minY + (this.distanceY / 2));
        
        if (distance && (distance > 0)) {
            var radius = Math.round(this.getPageDistance(distance));
            if (!this.snapCircle || (this.browserObj.getPixelValue(this.snapCircle.style.width) / 2 != radius)) {
                this.deleteSnapCircle();
                this.snapCircle = this.drawLibObj.addCircle(this.glassTop, this.snapCircleId, x, y, radius, "black", 1, -1)
            }
            else {
                this.drawLibObj.moveShape(this.snapCircle, x, y, true);
            }
        }
    }
    
    ComponentMap.prototype.deleteSnapCircle = function(e) {
    
        this.drawLibObj.deleteShape(this.snapCircle);
        this.snapCircle = null;
    }
    
    ComponentMap.prototype.setStatus = function(x, y) {

        this.componentManagerObj.setStatus(this.getMapX(x), this.getMapY(y));
    }
    
    ComponentMap.prototype.zoomByStep = function(step) {
        
        var factor = step * this.zoomFactor;
        this.zoomByFactor(factor);
    }
    
    ComponentMap.prototype.zoomByFactor = function(factor) {
        
        if (factor == 0) {
            factor = 1;
        }
        var xHalfDist = this.maxDistanceX / (factor * 2);
        var yHalfDist = this.maxDistanceY / (factor * 2);
        
        this.setExtent((this.centerX - xHalfDist), (this.centerY - yHalfDist), (this.centerX + xHalfDist), (this.centerY + yHalfDist));
        this.sendMapRequst();
    }
    
    ComponentMap.prototype.getMapX = function(pixelX) {
    
		    return this.minX + (((pixelX) / this.pageWidth) * this.distanceX);
    }

    ComponentMap.prototype.getMapY = function(pixelY) {
    
            return this.maxY - (((pixelY) / this.pageHeight) * this.distanceY);
    }
    
    ComponentMap.prototype.getPageX = function(mapX) {
    
		    var pixelSizeX = this.distanceX / this.pageWidth;
		    return Math.round((mapX - this.minX) / pixelSizeX); //=  * mouseX + this.minX;
    }

    ComponentMap.prototype.getPageY = function(mapY) {
    
		    var pixelSizeY = this.distanceY / this.pageHeight;
		    return Math.round(this.pageHeight - ((mapY - this.minY) / pixelSizeY));
    }
    
    ComponentMap.prototype.getPageDistance = function(mapDistance) {
    
        return mapDistance / this.metersPerPixel;
    }
    
    ComponentMap.prototype.setDrawMode = function(drawMode) {
        
        if (drawMode) {
            drawMode = drawMode.toLowerCase();
            
            //Dont do anything if draw mode already set.
            if (drawMode == this.drawMode.toLowerCase()) {
                return;
            }
            
            if (drawMode == "envelope") {
                this.setDrawRectangleEvents(true);
            }
            if (drawMode == "multienvelope") {
                this.setDrawRectangleEvents();
            }
            else if (drawMode == "polyline") {
                this.setDrawPolyLineEvents();
            }
            else if (drawMode == "polygon") {
                this.setDrawPolyonEvents();
            }
            else if (drawMode == "circle") {
                this.setDrawCircleEvents(true);
            }
            else if (drawMode == "multicircle") {
                this.setDrawCircleEvents();
            }
            else if (drawMode == "pointclick") {
                this.setPointClickEvents();
            }
            else if (drawMode == "multipoint") {
                this.setDrawPointEvents();
            }
            else if (drawMode == "panmap") {
                this.setPanEvents();
            }
            this.drawMode = drawMode;
        }
        
    }
    
    ComponentMap.prototype.setShape = function(shapes) {
        
        var length = shapes.length;
        this.shapeCollection = new Array();
        this.nodeCollection = new Array();
        this.shapeIndex = -1;
        var shape;
        
        for (var i=0; i<length; i++) {
            
            switch (this.drawMode) {
                case "envelope":
                    shape = this.setShapeInfo(shapes[i]);
                    this.loadSimpleShape(shape, this.SHAPE_TYPE_ENVELOPE);
                    break;
                case "multienvelope":
                    shape = this.setShapeInfo(shapes[i]);
                    this.loadSimpleShape(shape, this.SHAPE_TYPE_ENVELOPE);
                    break;
                case "polyline":
                    shape = this.setShapeInfo(shapes[i], true);
                    this.loadShape(shape,  "polyLine", this.SHAPE_TYPE_POLYLINE, "addPolyLine");
                    break;
                case "polygon":
                    shape = this.setShapeInfo(shapes[i], true);
                    this.loadShape(shape,  "polygon", this.SHAPE_TYPE_POLYGON, "addPolygon");
                    break;
                case "circle":
                    shape = this.setShapeInfo(shapes[i]);
                    this.loadSimpleShape(shape,  this.SHAPE_TYPE_CIRCLE);
                    break;
                case "multicircle":
                    shape = this.setShapeInfo(shapes[i]);
                    this.loadSimpleShape(shape,  this.SHAPE_TYPE_CIRCLE);
                    break;
                case "multipoint":
                    shape = this.setShapeInfo(shapes[i], true);
                    this.loadSimpleShape(shape,  this.SHAPE_TYPE_POINT);
                    break;
            }
        }
    }
    
    ComponentMap.prototype.setShapeInfo = function(coords, addNodes) {
        
        var shape = new Object();
        var coordList = new Array();
        var clientClicks = new Array();
        var length = coords.length;
        var currentCoord;
        var nodeList = new Array();
        this.shapeIndex++;
	    
        for (var i=0; i<length; i++) {
            currentCoord = coords[i];
            coordList.push(currentCoord);
            clientClicks[i] = new Array(this.getPageX(currentCoord[0]), this.getPageY(currentCoord[1]));
            if (addNodes) {
                nodeList[i] = this.addRectangle(this.glassTop, "Node:" + this.shapeIndex + ":" + i, clientClicks[i][0], clientClicks[i][1], this.markerSize, this.markerSize, true, "black", this.zoomBoxColour, 1);
            }
        }
        shape.clientClicks = clientClicks;
        shape.coordList = coordList;
        this.nodeCollection.push(nodeList);
        return shape;
    }
    
    ComponentMap.prototype.loadShape = function(shape, shapeId, shapeType, shapeFunction) {
        
        var clientClicks = shape.clientClicks;
        eval("loadedShape = this.drawLibObj." + shapeFunction + "(this.glassTop, '" + shapeId + ":' + this.shapeIndex, this.zoomBoxColour, 1, clientClicks, -2)");
        loadedShape.typeShape = shapeType;
        loadedShape.coordList = shape.coordList;
        loadedShape.clientClicks = shape.clientClicks;
        loadedShape.shapeFunction = shapeFunction;
        this.shapeCollection.push(loadedShape);
        this.shapeIndex = this.shapeCollection.length - 1;
        this.setShapeState(loadedShape);
    }
    
    ComponentMap.prototype.loadSimpleShape = function(shape, type) {
        
        var clientClicks = shape.clientClicks;
        var loadedShape;
        
        switch (type) {
            case this.SHAPE_TYPE_ENVELOPE:
                var x = clientClicks[0][0];
                var y = clientClicks[0][1]; 
                var width = Math.abs(x - clientClicks[1][0]);
                var height = Math.abs(y - clientClicks[1][1]);
                
                if (x > clientClicks[1][0]) {
                    x = clientClicks[1][0];
                }
                if (y > clientClicks[1][1]) {
                    y = clientClicks[1][1];
                }
                
                loadedShape = this.addRectangle(this.glassTop, "shapeRectangle" + this.shapeIndex, x, y, width, height);		
                loadedShape.typeShape = this.SHAPE_TYPE_ENVELOPE;
                break;
            case this.SHAPE_TYPE_CIRCLE:
                var centerX = this.getPageX(shape.coordList[0][0]);
                var centerY = this.getPageY(shape.coordList[0][1]);
                var radius = Math.sqrt(Math.pow(Math.abs(clientClicks[1][0] - clientClicks[0][0]), 2) + Math.pow(Math.abs(clientClicks[1][1] - clientClicks[0][1]), 2));
    		    loadedShape = this.drawLibObj.addCircle(this.glassTop, id, centerX, centerY, radius, this.zoomBoxColour, 1, -1);
                loadedShape.typeShape = this.SHAPE_TYPE_CIRCLE;
                break;
            case this.SHAPE_TYPE_POINT:
                loadedShape = document.createElement("div");
                loadedShape.id = "points:" + this.shapeIndex;
                this.glassTop.appendChild(loadedShape);
                loadedShape.typeShape = this.SHAPE_TYPE_POINT;
                loadedShape.shapeFunction = null;
                break;
        }
        
        loadedShape.coordList = shape.coordList;
        loadedShape.clientClicks = shape.clientClicks;
        this.shapeCollection.push(loadedShape);
        this.shapeIndex = this.shapeCollection.length - 1;
        this.setShapeState(loadedShape);
        this.drawing = false;
    }

    
    //Start up image arg required to indicate that map request was automatically sent on
    //startup and not by the user.
    ComponentMap.prototype.sendMapRequst = function(startup) {
        this.componentManagerObj.sendMapRequest(this, startup); //Need to pass this as could be overview.
    }
    
    ComponentMap.prototype.sendPanRequest = function(panDirection) {
        this.componentManagerObj.sendPanRequest(panDirection);
    }
    
    ComponentMap.prototype.disable = function() {
        
        this.glassTop.currentMouseDown = this.glassTop.onmousedown;
        this.glassTop.currentMouseMove = this.glassTop.onmousemove;
        this.glassTop.currentMouseUp = this.glassTop.onmouseup;
        this.glassTop.currentMouseOut = this.glassTop.onmouseout;
        this.glassTop.onmousemove = null;
        this.glassTop.onmouseup = null;
        this.glassTop.onmouseout = null;
    }
    
    ComponentMap.prototype.enable = function() {
        
        if (this.glassTop.onmousedown == null) {
            this.glassTop.onmousedown = eval(this.glassTop.currentMouseDown);
        }
        if (this.glassTop.onmousemove == null) {
            this.glassTop.onmousemove = eval(this.glassTop.currentMouseMove);
        }
        if (this.glassTop.onmouseup == null) {
            this.glassTop.onmouseup = eval(this.glassTop.currentMouseUp);
        }
        if (this.glassTop.onmouseout == null) {
            this.glassTop.onmouseout = eval(this.glassTop.currentMouseOut);
        }
    }
    
    ComponentMap.prototype.setDefaultMapType = function() {
        this.maptype = this.MAP_TYPE_MAIN;
    }
    
    ComponentMap.prototype.init = function() {
        //Initialisation calls
        this.componentManagerObj.mapObj = this;
        this.glassTop.mapObj = this;
        this.setPanButtonEvents();
        this.setDrawButtonEvents();
        this.setExtent(minX, minY, maxX, maxY);
        this.mapCanvasObj.onselectstart = new Function ('return false');
        this.mapCanvasObj.oncontextmenu = new Function ('return false');
        this.drawMenuLocation = drawMenuLocation.toUpperCase();
        this.shapeValidation = shapeValidation.toUpperCase();
    }
    
    //Properties
    this.browserObj = browserObj;
    this.geometryObj = geometryObj;
    this.formObj = document.getElementById(formID); //DotNet Form.
    this.mapCanvasObj = document.getElementById(mapCanvasID);
    this.mapCanvasDivObj = document.getElementById(mapCanvasID + "_askMapCanvas");
    this.glassTop = document.getElementById(mapCanvasID + "_askGlassTop");
    this.mapImage = document.getElementById(mapCanvasID + "_askMapImage");
    this.loadSpash = document.getElementById(mapCanvasID + "_askLoadSplash");
    this.panN = document.getElementById(mapCanvasID + "_askPanN");
    this.panE = document.getElementById(mapCanvasID + "_askPanE");
    this.panW = document.getElementById(mapCanvasID + "_askPanW");
    this.panS = document.getElementById(mapCanvasID + "_askPanS");
    this.panNE = document.getElementById(mapCanvasID + "_askPanNE");
    this.panNW = document.getElementById(mapCanvasID + "_askPanNW");
    this.panSE = document.getElementById(mapCanvasID + "_askPanSE");
    this.panSW = document.getElementById(mapCanvasID + "_askPanSW");
    this.drawMenuObj = document.getElementById(mapCanvasID + "_askDrawMenu");
    this.submitObj = document.getElementById(mapCanvasID + "_askDrawSubmit");
    this.cancelObj = document.getElementById(mapCanvasID + "_askDrawCancel");
    this.addShapeObj = document.getElementById(mapCanvasID + "_askAddShape");
    this.shapeStateObj = document.getElementById(mapCanvasID + "_askShapeState");
    this.drawLibObj = drawLibObj;
    this.zoomBoxColour = zoomBoxColour;
    this.zoomBoxOpacity = zoomBoxOpacity;
    this.markerSize = markerSize;
    this.componentManagerObj = componentManagerObj;
    
    this.singleShape = false;
    this.drawing = false;
    this.paning = false;
    
    this.id = id;
    this.mapCanvasID = mapCanvasID;
    this.maptype = this.MAP_TYPE_MAIN;
    this.minX = 0;
    this.minY = 0;
    this.maxX = 0;
    this.maxY = 0;
    this.metersPerPixel;
    this.distanceX = 0;
    this.distanceY = 0;
    this.centerX = 0;
    this.centerY = 0;
    this.maxDistanceX = 0;
    this.maxDistanceY = 0;
    this.scale = 0;
    this.scaleFactor = 0;
    this.pageWidth = this.mapImage.width - 1;
    this.pageHeight = this.mapImage.height - 1;
    this.panFactor = panFactor;
    this.panMode = panMode;
    this.zoomFactor = zoomFactor;
    this.drawMode = "";
    this.currentClientWidth = browserObj.getClientWidth();
    this.currentClientHeight = browserObj.getClientHeight();
    this.resizePadding = 0;
    this.firstResizeDone = false;
    
    this.loadSplashDelay = loadSplashDelay;
    this.shapeCollection;
    this.nodeCollection;
    this.shapeIndex = 0;
    
    this.snapCircle;
    this.snapCircleId = "snapCircle";
    
    this.drawMenuLocation;
    this.shapeValidation = this.SHAPE_VALIDATION_ONCREATION;
    
    this.PAN_N = "north";
    this.PAN_E = "east";
    this.PAN_W = "west";
    this.PAN_S = "south";
    this.PAN_NE = "northEast";
    this.PAN_NW = "northWest";
    this.PAN_SE = "southEast";
    this.PAN_SW = "southWest";
    
    this.PAN_MODE_DRAG = "DragOffset";
    this.PAN_MODE_POINT = "PointReCenter";
    this.PAN_MODE_COMBINED = "Combined";
    
    this.SHAPE_TYPE_POINT = "POINT";
    this.SHAPE_TYPE_POLYLINE = "POLYLINE";
    this.SHAPE_TYPE_POLYGON = "POLYGON";
    this.SHAPE_TYPE_CIRCLE = "CIRCLE";
    this.SHAPE_TYPE_ENVELOPE = "ENVELOPE";
    
    this.SHAPE_VALIDATION_NEVER = "NEVER";
    this.SHAPE_VALIDATION_ONCREATION = "ONCREATION";
    this.SHAPE_VALIDATION_ONSUBMIT = "ONSUBMIT";

    
    this.MAP_TYPE_MAIN = "main";
    this.MAP_TYPE_RESIZE = "resize";
    
    this.init();
}