//var MapAPI = new MapApiController;
/**
 * Global Constants
 */

// Map Control Constants
var SD_MAP_CONTROL_EMPTY = 0;
var SD_MAP_CONTROL_SMALL = 1;
var SD_MAP_CONTROL_MEDIUM = 2;
var SD_MAP_CONTROL_COMPLETE = 3;
var SD_MAP_CONTROL_ZOOM = 4;
var SD_MAP_CONTROL_TINY = 5;
var GLOBALS = new Array();
GLOBALS['poweredby'] = true;

// API  class
function SDMapSG(elm_id,elm_obj)
{
	this.x = 0;
	this.y = 0;	
	this.elm_id = elm_id;
	this.elm_obj = document.getElementById(elm_id);
  this.markers = new Array();
	this.line = new Array();
	this.line_color = new Array();
	this.a = 6378137;
	this.b = 6356752.3142;
	this.k0 = 0.9996;
	this.method = 0;
	this.MapAPI = new MapApiController;
	
	/**
	 * map control style, there are 4 styles:
	 * - no map control
	 * - small map control (default)
	 * - medium map control
	 * - complete map control
	 */
	this.mapControl = new SmallMapControl;
	
	this.useLatLong = function(method) {
		this.method = method;
	};
	
	this.usePoweredBy = function(status) {
		GLOBALS['poweredby'] = status;
	}
		
	this.setCenter = function (x,y) {		
		if (this.method == 1)
		{
			var vertex = this.GeoToUTM(y,x,48);
			this.x = vertex[0];
			this.y = vertex[1];
			this.MapAPI.mapClient.setCenterVertex(new Vertex(vertex[0],vertex[1]));
		}
		else 
		{
			this.x = x;
			this.y = y;
			this.MapAPI.mapClient.setCenterVertex(new Vertex(x,y));
		}
	};
	
	this.getX = function()
	{
		return this.x;
	};
	
	this.getY = function()
	{
		return this.y;
	};	
	
	this.setLevel = function(level){
		level = level - 1;
	//	if (level < 2) level = 2;
		this.MapAPI.mapClient.levelIndex = level;
	};
	
	this.setSize = function(w,h) {
		this.elm_obj.style.cssText = 'width:'+w+'px;height:'+h+'px;display:inline;float:left;position:relative;overflow:hidden;';
	};
  
  this.addMarker = function(marker) {
	if (this.method == 1)
	{
		var xy = this.GeoToUTM(marker.y,marker.x,48);	
		marker.x = xy[0];
		marker.y = xy[1];
	}
    this.markers.push(marker);
  };
  
  this.addLine = function (arr_vertex, color) {
	  var n = arr_vertex.length, vertex =new Array(), temp;

	  for(var i=0;i<n;i+=2)
	  {
		  if (this.method == 1)
		  {		  
			xy = this.GeoToUTM(y,x,48);
			arr_vertex[i] = xy[0];
			arr_vertex[i+1] = xy[1];
		  } 
		  temp = new Vertex(arr_vertex[i],arr_vertex[i+1]);
		  vertex.push(temp);
	  }
	  this.line.push(vertex);
	  this.line_color.push(color == undefined ? '' : color);	 
  };
  
  this.disableDragging = function() {
    this.MapAPI.enableDragging(false);
  };
  
  this.showThumbnail = function() {
    this.MapAPI.showThumbnail(true);
  };
  
  this.setMapControl = function(map_control) {
  	switch (map_control)
  	{
		case SD_MAP_CONTROL_TINY :
		  this.mapControl = new TinyMapControl;
		  break;
		  
  		case SD_MAP_CONTROL_SMALL:
  		  this.mapControl = new SmallMapControl;
  		  break;
  		  
  		case SD_MAP_CONTROL_MEDIUM:
  		  this.mapControl = new MediumMapControl;
  		  break;
  		  
  		case SD_MAP_CONTROL_COMPLETE:
  		  this.mapControl = new CompleteMapControl;
  		  break;
  		  
  		case SD_MAP_CONTROL_ZOOM:
  		  this.mapControl = new ZoomMapControl;
  		  break;
  		  
  		default:  // SD_MAP_CONTROL_EMPTY
  		  this.mapControl = null; 
  	}
  };
	
	this.draw = function (){   
		this.MapAPI.init(this.elm_id, getBaseUrl()+'/dragmap/xg/');
		for (var i = 0; i < this.markers.length; i++)
		{
		  var ico = this.MapAPI.mapDraw.addMarker(this.markers[i]);
		  this.markers[i].size = ico.size;
		  this.markers[i].mapClient = ico.mapClient;
		  if (this.markers[i].id)
		  {
			  ico.obj.id = this.markers[i].id;
		  }
		}	 
	
		if (!this.x || !this.y) this.setCenter(365292.630777,144934.832246);
		
		this.MapAPI.addControl(this.mapControl);
		this.MapAPI.setMapSource("SG");
				
		if ( this.line.length)
		{
			for (var i = 0; i < this.line.length; i++)
			{					
				//MapAPI.mapDraw.renderLine(this.line[i],this.line_color[i]);		
				this.MapAPI.mapDraw.addLine(this.line[i],this.line_color[i]);		
			}		
		}
		 
		 this.MapAPI.mapDraw.updatePanel();
	};
  
  this.addMarkerBubble = function(icon, myHtml, option) {
    VEvent.addListener(icon, 'click', function() {
      icon.openInfoWindowHtml(myHtml, option);
    });
  };
  
   this.GeoToUTM = function(latitude,longitude,longitude_zone)
	{						
		var n = (this.a - this.b) / (this.a + this.b);		
		var sin_1 = Math.PI / (180.0 * 60.0 * 60.0);
		var e = Math.sqrt(1.0 - Math.pow(this.b / this.a, 2));
		var e_2 = Math.pow(e, 2) / (1.0 - Math.pow(e, 2));	
		latitude = latitude * Math.PI / 180;
		var nu = this.a / Math.sqrt(1 - Math.pow(e * Math.sin(latitude), 2));
		
		if (!longitude_zone) longitude_zone = 31 + parseInt((Math.floor(longitude / 6)));		
		var longitude_zone_cm = parseInt((6 * longitude_zone) - 183);
		var delta_long = (longitude - longitude_zone_cm);
		var p = delta_long * 3600.0 / 10000.0;
		var Ax = this.a * (1 - n + (5 / 4) * Math.pow(n, 2) * (1 - n) + (81 / 64) * Math.pow(n, 4) * (1 - n));
		var Bx = (3 * this.a * n / 2) * (1 - n - (7 / 8) * Math.pow(n, 2) * (1 - n) + (55 / 64) * Math.pow(n, 4));
		var Cx = (15 * this.a * Math.pow(n, 2) / 16) * (1 - n + (3 / 4) * Math.pow(n, 2) * (1 - n));
		var Dx = (35 * this.a * Math.pow(n, 3) / 48) * (1 - n + (11 / 16) * Math.pow(n, 2));
		var Ex = (315 * this.a * Math.pow(n, 4) / 51) * (1 - n);
		var calMerArcLL = (Ax * latitude) - (Bx * Math.sin(2 * latitude)) + (Cx * Math.sin(4 * latitude)) - (Dx * Math.sin(6 * latitude)) + (Ex * Math.sin(8 * latitude));
		var K1 = calMerArcLL * this.k0;
		var K2 = this.k0 * (100000000) * Math.pow(sin_1, 2) * nu * Math.sin(latitude) * Math.cos(latitude) / 2;
		var K3 = (this.k0 * (10000000000000000) * Math.pow(sin_1, 4) * nu * Math.sin(latitude) * Math.pow(Math.sin(latitude), 3) / 24) * ((5 - Math.pow(Math.tan(latitude), 2) + 9 * e_2 * Math.pow(Math.cos(latitude), 2) + 4 * Math.pow(e_2, 2) * Math.pow(Math.cos(latitude), 4)));
		var K4 = this.k0 * 10000 * sin_1 * nu * Math.cos(latitude);
		var K5 = (this.k0 * (1000000000000) * Math.pow(sin_1, 3) * nu * Math.pow(Math.cos(latitude), 3) / 6) * (1 - Math.pow(Math.tan(latitude), 2) + e_2 * Math.pow(Math.cos(latitude), 2));
		var A6 = (Math.pow(p * sin_1, 6) *
			 nu * Math.sin(latitude) *
			 Math.pow(Math.cos(latitude), 5)
			 / 720) * (61 - 58 *
			 Math.pow(Math.tan(latitude), 2) +
			 Math.pow(Math.tan(latitude), 4) +
			 270 * e_2 *
			 Math.pow(Math.cos(latitude), 2) -
			 330 * e_2 *
			 Math.pow(Math.sin(latitude), 2)) *
			 this.k0 * Math.pow(10, 24);
		var y = K1 + (K2 * Math.pow(p, 2)) + (K3 * Math.pow(p, 4)) + (A6 * Math.pow(p, 6));
		if (y < 0)
			y = y + 10000000;
		var x = (K4 * p) + (K5 * Math.pow(p, 3)) + 500000;
		return Array(x,y);
	}
  
};

function moveStarPosition(mapclient,pos,MapAPI)
{
		var vertex = mapclient.screenToVertex(pos);
		
		var offset_x = 0, offset_y = 0;
		
		if (document.getElementById("last_pos"))
		{
			document.getElementById("last_pos").innerHTML = (vertex.x + offset_x) +","+ (vertex.y + offset_y);
		};
		
		var obj_icon = MapAPI.mapDraw.panelIcon, n = obj_icon.icons.length;
		for(var i =0; i< n; i++)
		{		
			if (obj_icon.icons[i].move == true)
			{					
				obj_icon.icons[i].obj.style.display = 'block';
				obj_icon.icons[i].x = vertex.x;
				obj_icon.icons[i].y = vertex.y;
				obj_icon.icons[i].obj.style.left = pos.x-(parseInt(obj_icon.icons[i].obj.style.width)/2) + "px";
				obj_icon.icons[i].obj.style.top = pos.y-(parseInt(obj_icon.icons[i].obj.style.height)/2) + "px";
			};
		}
};

// engine sd map engine
function IeFix(url) {
	if (document.namespaces && document.namespaces.add) {
		try { 
			document.execCommand('BackgroundImageCache', false, true); 
		} catch(e) {};
		
    /*var cssStr = "img, body { behavior: url(" + url + "iepngfix.htc); }";
		var style = document.createElement("style");
		style.setAttribute("type", "text/css");
		
		if(style.styleSheet){// IE
			style.styleSheet.cssText = cssStr;
		} else {// w3c
			var cssText = doc.createTextNode(cssStr);
			style.appendChild(cssText);
		}		
		document.getElementsByTagName("head")[0].appendChild(style);*/
	}
};

function LineSegment(a, b) {
	this.p0 = a;
	this.p1 = b;
	
	this.distance = function(p) {
    	return this.distancePointLine(p, this.p0, this.p1);
	};
			
	this.distancePtoP = function(a, b) {
    	var dx = a.x - b.x;
        var dy = a.y - b.y;
        return Math.sqrt(dx * dx + dy * dy);
	};
	
	this.distancePointLine = function(p, A, B) {
		if (A.x == B.x && A.y == B.y)
			return this.distancePtoP(p, A);// p.Distance(A);

        // otherwise use comp.graphics.algorithms Frequently Asked Questions method
        /*(1)     	      AC dot AB
                    r =   ---------
                          ||AB||^2
     
                    r has the following meaning:
                    r=0 Point = A
                    r=1 Point = B
                    r<0 Point is on the backward extension of AB
                    r>1 Point is on the forward extension of AB
                    0<r<1 Point is interior to AB
        */
        var r = ((p.x - A.x) * (B.x - A.x) + (p.y - A.y) * (B.y - A.y))
                    /
                    ((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y));

        if (r <= 0.0) return this.distancePtoP(p, A);//p.Distance(A);
        if (r >= 1.0) return this.distancePtoP(p, B);//p.Distance(B);

        /*(2)
                        (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
                    s = -----------------------------
                                    Curve^2

                    Then the distance from C to Point = |s|*Curve.
        */

        var s = ((A.y - p.y) * (B.x - A.x) - (A.x - p.x) * (B.y - A.y))
                    /
                    ((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y));

        return Math.abs(s) * Math.sqrt(((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y)));
	};
};

function DPSimplifier(pts, tol) {
	this.pts = pts;
	this.usePt = [];
	this.seg = new LineSegment();
	this.distanceTolerance = tol;
	
	this.simplify = function() {
        for (var i = 0; i < this.pts.length; i++)
            this.usePt[i] = true;

        this.simplifySection(0, this.pts.length - 1);
        var coordList = new Array();
        for (var i = 0; i < this.pts.length; i++)
            if (this.usePt[i])
                coordList.push(this.pts[i]);
        return coordList;		
	},
	
    this.simplifySection = function (i, j) {
        if ((i + 1) == j)
        	return;
		
		this.seg.p0 = this.pts[i];
        this.seg.p1 = this.pts[j];
        var maxDistance = -1.0, maxIndex = i;
        
        for (var k = i + 1; k < j; k++)
        {
            var distance = this.seg.distance(this.pts[k]);
            if (distance > maxDistance)
            {
                maxDistance = distance;
                maxIndex = k;
            }
        }
        if (maxDistance <= this.distanceTolerance)
            for (var k = i + 1; k < j; k++)
                this.usePt[k] = false;
        else
        {
            this.simplifySection(i, maxIndex);
            this.simplifySection(maxIndex, j);
        }
    };
};
function DrawingCanvasSVGT(parent, width, height)
{
  if (!parent) {
  	throw new Error("No canvas parent!");
  }

  if (!width) {
    width  = parent.clientWidth;
  }
  if (!height) {
  	height = parent.clientHeight;
  }

  this.parent        = parent;
  this.width         = width;
  this.height        = height;
  this._bgColor      = "none";
  this._lineWidth    = 2;
  this._lineColor    = "#000";
  this._dotColor 	 = "#000";
  this._dotMode 	 = false;
  this._isDrawing    = false;
  this._currentShape = null;
  this._points       = "";
  this._dummyDot     = null;
  this._stack        = [];
  this._stackSize    = 0;
  this._opacity 	 = 0.45;

  var svg = document.createElementNS(this._XMLNS_SVG, "svg");
  svg.setAttribute("width", width);
  svg.setAttribute("height", height);
  svg.setAttribute("overflow", "visible");

  var rect = document.createElementNS(this._XMLNS_SVG, "rect");
  rect.setAttribute("width", width);
  rect.setAttribute("height", height);
  rect.setAttribute("fill", this._bgColor);
  svg.appendChild(rect);

  var container = document.createElementNS("http://www.w3.org/1999/xhtml",
                                          "div");
  container.setAttribute("style", "width: "  + width  + "px; " +
                                  "height: " + height + "px; ");
  container.appendChild(svg);

  parent.appendChild(container);

  this.container = container;
  this._svgRoot  = svg;
  this._bg       = rect;
};

DrawingCanvasSVGT.prototype = {
  _XMLNS_SVG: "http://www.w3.org/2000/svg",
  arrows:Array(),
  
  setPosX: function(left) {
  	/*
	this.container.style.left = left + "px";
  	this.container.style.top = top + "px";
  	*/
  	this._svgRoot.style.position = "absolute";
  	this._svgRoot.style.zIndex = 1000;
  	this._svgRoot.style.left = left + "px";
  },
  
  setPosY: function(top) {
  	this._svgRoot.style.position = "absolute";
  	this._svgRoot.style.zIndex = 1000;
  	this._svgRoot.style.top = top + "px";  	
  },
  
  setViewBox: function(left, top, width, height) {
  	var vb = left + " " + top + " " + width + " " + height; 
  	this._svgRoot.setAttribute("viewBox", vb);
  },
  
  setSize: function(width, height) {
  	//this.container.style.width = width + "px";
  	//this.container.style.height = height + "px";
  	this._svgRoot.setAttribute("width", width);
  	this._svgRoot.setAttribute("height", height);
	this._bg.setAttribute("width", width);
  	this._bg.setAttribute("height", height);  	
  	this.width = width;
  	this.height = height;
  },

  setBgColor: function (color) {
    this._bgColor = (color == "transparent") ? "none" : color;
    this._refresh();
  },

  setLineColor: function (color) {
  	if (color == undefined) {
  		return;
  	}
    this._lineColor = color;
  },
  
  setOpacity: function(opacity) {
  	this._opacity = opacity;
  },

  setLineWidth: function (width) {
    this._lineWidth = Number(width) || 0;
  },
  
  createGeofence: function(x, y, r, lbl, fs) {
  	this.createCircle(x, y, r, true);
    this.createArrow(x, y, r);
    this.createText(x, y, r, lbl, fs);
  },
  
  createCircle: function(x, y, r, geofence) {
    var dotColor = this._lineColor;
    if (this._dotMode == true || geofence == true) {
    	dotColor = this._dotColor;
	    var dot = document.createElementNS(this._XMLNS_SVG, "circle");
	    dot.setAttribute("cx", x);
	    dot.setAttribute("cy", y);
	    dot.setAttribute("r", r);
	    if (geofence == true) {
	    	dot.setAttribute("stroke", "black");
    		dot.setAttribute("stroke-width", 2);
    		dot.setAttribute("fill", "none");	    	
	    } else {
	    	dot.setAttribute("fill", dotColor);
	    }       
	  	this._svgRoot.appendChild(dot);
	    this._pushStack(dot);    	
    } 	
  },
  
  createFullArrow: function(pos0, pos1, pos2, color) {	
    var arrow = document.createElementNS(this._XMLNS_SVG, "polyline");
    arrow.setAttribute("fill", color);
    arrow.setAttribute("stroke", color);
    arrow.setAttribute("stroke-width", 2);
    arrow.setAttribute("stroke-linecap", "round");
    arrow.setAttribute("stroke-linejoin", "round");
    var points = pos1.x + "," + pos1.y + " "
    	+ pos0.x + "," + pos0.y + " "
    	+ pos2.x + "," + pos2.y;
    arrow.setAttribute("points", points);
	this.arrows.push(arrow);
    this._svgRoot.appendChild(arrow);
  },
  
  clearFullArrow: function(){
	  var n = this.arrows.length;
	  for(var i=0;i<n;i++)
	  {
		   this._svgRoot.removeChild(this.arrows[i]);
	  }
	  this.arrows = Array();
  },
  
  createArrow: function(x, y, r) {
    var arr = document.createElementNS(this._XMLNS_SVG, "polyline");
    var points = (x+r-5)+","+(y-5)+" "+(x+r)+","+y+" "
    	+x+","+y+" "+(x+r)+","+y+" "+(x+r-5)+","+(y+5);
    arr.setAttribute("fill", "none");
    arr.setAttribute("stroke", "red");
    arr.setAttribute("stroke-width", 5);
    arr.setAttribute("stroke-linecap", "round");
    arr.setAttribute("stroke-linejoin", "round");
    arr.setAttribute("points", points);
    this._svgRoot.appendChild(arr);
    this._pushStack(arr);
  },
  
  createText: function(x, y, r, l, fs) {
  	var tex = document.createElementNS(this._XMLNS_SVG, "text");
  	tex.setAttribute("x", x);
  	tex.setAttribute("y", y-5);
  	tex.setAttribute("fill", "red");
  	tex.setAttribute("stroke-linejoin", "bevel");
  	tex.setAttribute("font-size", fs);
  	tex.appendChild(document.createTextNode((l/1000)+" km"));
    this._svgRoot.appendChild(tex);
    this._pushStack(tex);  	
  },

  startLine: function (x, y) {	 
    if (this._isDrawing) {
      this.endLine();
    }
    this._isDrawing = true;
	this.createCircle(x, y, this._lineWidth / 2);
    this._points   = x + "," + y;

    var polyline = document.createElementNS(this._XMLNS_SVG, "polyline");
    polyline.setAttribute("fill", "none");
    polyline.setAttribute("stroke", this._lineColor);
    polyline.setAttribute("stroke-width", this._lineWidth);
    polyline.setAttribute("stroke-linecap", "round");
    polyline.setAttribute("stroke-linejoin", "round");
    polyline.setAttribute("opacity", this._opacity);
    polyline.setAttribute("points", this._points);
    this._svgRoot.appendChild(polyline);
    this._currentShape = polyline;	
  },

  endLine: function () {
    if (!this._isDrawing) {
    	return;
    }

    if (this._dummyDot) {
      this._svgRoot.removeChild(this._currentShape);
      this._pushStack(this._dummyDot);
      this._dummyDot = null;
    } else {
      this._pushStack(this._currentShape);
    }
    this._isDrawing    = false;
    this._currentShape = null;
    this._points       = "";
  },

  lineTo: function (x, y) {
    if (!this._isDrawing) {
    	return;
    }
    if (this._dummyDot) {
      this._svgRoot.removeChild(this._dummyDot);
      this._dummyDot = null;
    }

	this.createCircle(x, y, this._lineWidth / 2);
    this._points += " " + x + "," + y;
    this._currentShape.setAttribute("points", this._points);
  },

  undo: function () {
    if (this._isDrawing) {
      this.endLine();
    }
    if (this._stackSize <= 0) {
      return false;
	}
    this._svgRoot.removeChild(this._stack[--this._stackSize]);
    this._refresh();
    return true;
  },

  redo: function () {
    if (this._isDrawing) {
      this.endLine();
    }
    if (this._stackSize >= this._stack.length) {
      return false;
	}
    this._svgRoot.appendChild(this._stack[this._stackSize++]);
    this._refresh();
    return true;
  },

  clearShape: function () {
    if (this._isDrawing){
    	this.endLine();
    }
    if (this._stack.length > 1) {
	   	this._svgRoot.removeChild(this._stack[this._stack.length-1]);
	    this._refresh();
	   	this._stack.length = this._stack.length - 1;
	   	this._stackSize    = this._stackSize - 1;   	
    }
  },

  clear: function () {
    if (this._isDrawing) {
      this.endLine();
	}
    for (var i = this._stackSize; i--;) {
      if (this._stack[i]!=undefined) this._svgRoot.removeChild(this._stack[i]);
    }
    this._refresh();
    this._stack.length = 0;
    this._stackSize    = 0;
  },

  getX: function () {
    var box = this.container;
    var x   = box.offsetLeft;
    while ((box = box.offsetParent)) {
      x += box.offsetLeft;
	}
    return x;
  },

  getY: function () {
    var box = this.container;
    var y   = box.offsetTop;
    while ((box = box.offsetParent)) {
      y += box.offsetTop;
	}
    return y;
  },

  _pushStack: function (shape) {
    if (this._stackSize + 1 < this._stack.length) {
      this._stack.length = this._stackSize + 1;
    }
    this._stack[this._stackSize++] = shape;
  },

  _refresh: function () {
    this._bg.setAttribute("fill", this._bgColor);
  }
};

function DrawingCanvasCanvas(parent, width, height)
{
  if (!parent) {
  	throw new Error("No canvas parent!");
  }

  if (!width) {
  	width  = parent.clientWidth;
  }
  if (!height) {
  	height = parent.clientHeight;
  }

  this.parent        = parent;
  this.width         = width;
  this.height        = height;
  this._bgColor      = "transparent";
  this._lineWidth    = 2;
  this._lineColor    = "#000";
  this._dotColor 	 = "#000";
  this._dotMode 	 = false;
  this._isDrawing    = false;
  this._opacity 	 = 0.45;

  this._points       = null;
  this._stack        = [];
  this._stackSize    = 0;

  var canvas = document.createElement("canvas");
  canvas.setAttribute("id", "DCCanvas" + (new Date()).getTime() +
                            ++arguments.callee._count);
  canvas.setAttribute("width", width);
  canvas.setAttribute("height", height);

  var container = document.createElement("div");
  container.setAttribute("style", "width: "  + width  + "px; " +
                                  "height: " + height + "px; ");
  container.appendChild(canvas);
  parent.appendChild(container);

  var context = canvas.getContext("2d");
  context.lineCap  = "round";
  context.lineJoin = "round";

  this.container = container;
  this._context  = context;
  this._canvas   = canvas;
};

DrawingCanvasCanvas._count = 0;

DrawingCanvasCanvas.prototype = {
  setBgColor: function (color) {
    this._bgColor = color;
    this._refresh();
  },
  
  setPos:function(left, top) {
  	this.container.style.left = left + "px";
  	this.container.style.top = top + "px";
  },
  
  setSize: function(width, height) {
  	this.container.style.width = width + "px";
  	this.container.style.height = height + "px";
	this._canvas.setAttribute("width", width);
  	this._canvas.setAttribute("height", height);
  	this.width = width;
  	this.height = height;  	
  },  

  setLineColor: function (color) {
  	if (color == undefined) {
  		return;
  	} 	
    this._lineColor = color;
  },

  setLineWidth: function (width) {
    this._lineWidth = Number(width) || 0;
  },
  
  setOpacity: function (opacity) {
  	this._opacity = opacity;
  },

  startLine: function (x, y) {	  
    if (this._isDrawing) {
      this.endLine();
    }
    this._isDrawing = true;

    this._context.strokeStyle = this._lineColor;
    this._context.fillStyle   = this._lineColor;
    this._context.lineWidth   = this._lineWidth;

    this._context.arc(x, y, this._lineWidth / 2, 0, 2 * Math.PI, true);
    this._context.fill();

    this._points           = [x, y];
    this._currentX         = x;
    this._currentY         = y;
    this._currentLineColor = this._lineColor;
    this._currentLineWidth = this._lineWidth;
  },

  endLine: function () {
    if (!this._isDrawing) {
    	return;
    }

    this._isDrawing = false;
    this._pushStack(this._points,
                    this._currentLineColor, this._currentLineWidth);
    this._points    = null;
  },

  lineTo: function (x, y) {
    if (!this._isDrawing) {
    	return;
    }

    this._context.moveTo(this._currentX, this._currentY);
    this._context.lineTo(x, y);
    this._context.stroke();

    this._points.push(x, y);
    this._currentX = x;
    this._currentY = y;
  },

  undo: function () {
    if (this._isDrawing) {
      this.endLine();
    }
    if (this._stackSize <= 0) {
      return false;
    }

    --this._stackSize;
    this._refresh();
    return true;
  },

  redo: function () {
    if (this._isDrawing) {
      this.endLine();
    }
    if (this._stackSize >= this._stack.length) {
      return false;
    }

    ++this._stackSize;
    this._refresh();
    return true;
  },
  
  clearShape: function () {
    if (this._isDrawing) {
      this.endLine();
	}
	if (this._stack.length > 1) {
		this._stack[this._stack.length-1] = undefined;
   		this._refresh();
	}		
  },
  
  clear: function () {
    if (this._isDrawing) {
      this.endLine();
    }

    this._stack.length = 0;
    this._stackSize    = 0;
    this._refresh();
  },

  getX: function () {
    var box = this.container;
    var x   = box.offsetLeft;
    while ((box = box.offsetParent)) {
      x += box.offsetLeft;
	};
    return x;
  },

  getY: function () {
    var box = this.container;
    var y   = box.offsetTop;
    while ((box = box.offsetParent)) {
      y += box.offsetTop;
	};
    return y;
  },

  _pushStack: function (points, lineColor, lineWidth) {
    if (this._stackSize + 1 < this._stack.length) {
      this._stack.length = this._stackSize + 1;
    }
    this._stack[this._stackSize++] = {
      type:      (points.length == 2) ? "dot" : "polyline",
      points:    points,
      lineColor: lineColor,
      lineWidth: lineWidth
    }
  },

  _refresh: function () {
    if (this._bgColor == "transparent") {
      this._context.clearRect(0, 0, this.width, this.height);
    } else {
      this._context.fillStyle = this._bgColor;
      this._context.fillRect(0, 0, this.width, this.height);
    }

    for (var i = 0; i < this._stackSize; i++) {
      var shape = this._stack[i];
      if (shape.type == "dot") {
        this._context.fillStyle = shape.lineColor;
        this._context.arc(shape.points[0], shape.points[1],
                          shape.lineWidth / 2, 0, this._MATH_2PI, true);
        this._context.fill();
      } else {
        this._context.strokeStyle = shape.lineColor;
        this._context.lineWidth   = shape.lineWidth;
        this._context.moveTo(shape.points[0], shape.points[1]);
        for (var j = 2, n = shape.points.length; j < n; j += 2)
          this._context.lineTo(shape.points[j], shape.points[j + 1]);
        this._context.stroke();
      }
    }
  }
};


function DrawingCanvasCSSP(parent, width, height)
{
  if (!parent) {
  	throw new Error("No canvas parent!");
  }

  if (!width) {
    width  = parent.clientWidth;
  }
  if (!height) {
  	height = parent.clientHeight;
  }

  this.parent         = parent;
  this.width          = width;
  this.height         = height;
  this._bgColor       = "transparent";
  this._lineWidth     = 2;
  this._lineColor     = "#000";
  this._dotColor 	 = "#000";
  this._dotMode 	 = false;
  this._isDrawing     = false;
  this._currentLayer  = null;
  this._stack         = [];
  this._stackSize     = 0;
  this._opacity 	  = 0.45;

  this._dotStyle         = "";
  this._currentLineWidth = 0;
  this._dotOffset        = 0;
  this._dotX             = 0;
  this._dotY             = 0;

  var container = document.createElement("div");
  var containerStyle = "background-color: " + this._bgColor + "; " +
                       "position: relative; " +
                       "width: "  + width  + "px; " +
                       "height: " + height + "px; " +
                       "overflow: hidden; ";
  if (this._useCssText) {
    container.style.cssText = containerStyle;
  } else {
    container.setAttribute("style", containerStyle);
  }

  parent.appendChild(container);
  this.container = container;
};

DrawingCanvasCSSP.prototype = {
  _useCssText: document.documentElement.getAttribute("style") ==
               document.documentElement.style,

  setPos:function(left, top) {
  	this.container.style.left = left + "px";
  	this.container.style.top = top + "px";
  },

  setSize: function(width, height) {
  	this.container.style.width = width + "px";
  	this.container.style.height = height + "px";
  	this.width = width;
  	this.height = height;  	  	
  },

  setBgColor: function (color) {
    this.container.style.backgroundColor = this._bgColor = color;
  },

  setLineColor: function (color) {
  	if (color == undefined) {
  		return;
  	}  	
    this._lineColor = color;
  },

  setLineWidth: function (width) {
    this._lineWidth = Number(width) || 0;
  },

  startLine: function (x, y) {
    if (this._isDrawing) {
      this.endLine();
    }
    this._isDrawing = true;

    x = Math.round(x);
    y = Math.round(y);

    var currentLineWidth = this._lineWidth;
    this._dotStyle       = "background-color: " + this._lineColor + "; " +
                           "position: absolute; " +
                           "overflow: hidden; ";
    this._dotOffset      = Math.floor(currentLineWidth / 2);
    this._dotX           = x - this._dotOffset;
    this._dotY           = y - this._dotOffset;

    var layer    = document.createElement("div");
    var dot      = document.createElement("div");
    var dotStyle = this._dotStyle +
                   "width: "  + currentLineWidth + "px; " +
                   "height: " + currentLineWidth + "px; " +
                   "left: "   + this._dotX       + "px; " +
                   "top: "    + this._dotY       + "px; ";
    if (this._useCssText) {
      dot.style.cssText   = dotStyle;
    } else {
      dot.setAttribute("style", dotStyle);
    }
    layer.appendChild(dot);
    this.container.appendChild(layer);
    this._currentLineWidth = currentLineWidth;
    this._currentLayer     = layer;
  },

  endLine: function () {
    if (!this._isDrawing) {
    	return;
    }

    this._isDrawing        = false;
    this._pushStack(this._currentLayer);
    this._currentLineWidth = 0;
    this._currentLayer     = null;
  },

  lineTo: function (x, y) {
    if (!this._isDrawing) {
    	return;
    }

    x = Math.round(x);
    y = Math.round(y);

    var currentX = this._dotX;
    var currentY = this._dotY;
    var endX     = x - this._dotOffset;
    var endY     = y - this._dotOffset;
    var dirX     = (currentX < endX) ? 1 : -1;
    var dirY     = (currentY < endY) ? 1 : -1;
    var dx       = (dirX == 1) ? endX - currentX : currentX - endX;
    var dy       = (dirY == 1) ? endY - currentY : currentY - endY;
    var error, errorIncrement, errorCorrection;

    if (dx == 0 && dy == 0) {
      return;
    }
    var fragment       = document.createDocumentFragment();
    var dotStyleCommon = this._dotStyle;
    var useCssText     = this._useCssText;
    var lineWidth      = this._currentLineWidth;
    var lineLength     = lineWidth;

    if (dx >= dy) {
      var left, dot, dotStyle;
      var isPositiveDir = (dirX == 1);
      error             = -dx;
      errorIncrement    = dy << 1;
      errorCorrection   = dx << 1;
      for (var i = 0; i < dx; ++i) {
        error += errorIncrement;
        if (error >= 0) {
          left     = isPositiveDir ? currentX - lineLength + lineWidth
                                   : currentX;
          dot      = document.createElement("div");
          dotStyle = dotStyleCommon +
                     "width: "  + lineLength + "px; " +
                     "height: " + lineWidth  + "px; " +
                     "left: "   + left       + "px; " +
                     "top: "    + currentY   + "px; ";
          if (useCssText) {
            dot.style.cssText = dotStyle;
          } else {
            dot.setAttribute("style", dotStyle);
          }
          fragment.appendChild(dot);

          currentY   += dirY;
          error      -= errorCorrection;
          lineLength = lineWidth;
        } else {
          ++lineLength;
        }
        currentX += dirX;
      }
      left     = isPositiveDir ? endX - lineLength + lineWidth : endX;
      dot      = document.createElement("div");
      dotStyle = dotStyleCommon +
                 "width: "  + lineLength + "px; " +
                 "height: " + lineWidth  + "px; " +
                 "left: "   + left       + "px; " +
                 "top: "    + endY       + "px; ";
      if (useCssText) {
        dot.style.cssText = dotStyle;
      } else {
        dot.setAttribute("style", dotStyle);
      }
      fragment.appendChild(dot);
    } else { 
      var top, dot, dotStyle;
      var isPositiveDir = (dirY == 1);
      error             = -dy;
      errorIncrement    = dx << 1;
      errorCorrection   = dy << 1;
      for (var i = 0; i < dy; ++i) {
        error += errorIncrement;
        if (error >= 0) {
          top      = isPositiveDir ? currentY - lineLength + lineWidth
                                   : currentY;
          dot      = document.createElement("div");
          dotStyle = dotStyleCommon +
                     "width: "  + lineWidth  + "px; " +
                     "height: " + lineLength + "px; " +
                     "left: "   + currentX   + "px; " +
                     "top: "    + top        + "px; ";
          if (useCssText) {
            dot.style.cssText = dotStyle;
          } else {
            dot.setAttribute("style", dotStyle);
          }
          fragment.appendChild(dot);

          currentX   += dirX;
          error      -= errorCorrection;
          lineLength = lineWidth;
        } else {
          ++lineLength;
        }
        currentY += dirY;
      }
      top      = isPositiveDir ? endY - lineLength + lineWidth : endY;
      dot      = document.createElement("div");
      dotStyle = dotStyleCommon +
                 "width: "  + lineWidth  + "px; " +
                 "height: " + lineLength + "px; " +
                 "left: "   + endX       + "px; " +
                 "top: "    + top        + "px; ";
      if (useCssText) {
        dot.style.cssText = dotStyle;
      } else {
        dot.setAttribute("style", dotStyle);
      }
      fragment.appendChild(dot);
    }

    this._currentLayer.appendChild(fragment);
    this._dotX = endX;
    this._dotY = endY;
  },

  undo: function () {
    if (this._isDrawing){
      this.endLine();
    }
    if (this._stackSize <= 0) {
      return false;
    }

    this.container.removeChild(this._stack[--this._stackSize]);
    return true;
  },

  redo: function () {
    if (this._isDrawing) {
      this.endLine();
    }
    if (this._stackSize >= this._stack.length) {
      return false;
    }

    this.container.appendChild(this._stack[this._stackSize++]);
    return true;
  },

  clearShape: function () {
    if (this._isDrawing){
      this.endLine();
    }
    
    if (this._stack.length > 1) {
	   	this.container.removeChild(this._stack[this._stack.length-1]);
	    this._stack.length = this._stack.length - 1;
	   	this._stackSize    = this._stackSize - 1;
    }
  },

  clear: function () {
    if (this._isDrawing) {
      this.endLine();
    };

    for (var i = this._stackSize; i--;) {
      this.container.removeChild(this._stack[i]);
    };
    this._stack.length = 0;
    this._stackSize    = 0;
  },

  _htmlIsRoot: (typeof document.compatMode == "string") &&
               (document.compatMode == "CSS1Compat"),

  getX: function () {
    var box = this.container;
    var x = box.offsetLeft;
    while ((box = box.offsetParent)){
      x += box.offsetLeft;
    }

    if (this._useCssText){
      x += (this._htmlIsRoot ? document.documentElement
                             : document.body).clientLeft;
	}
    return x;
  },

  getY: function () {
    var box = this.container;
    var y = box.offsetTop;
    while ((box = box.offsetParent)) {
      y += box.offsetTop;
    }

    if (this._useCssText) {
      y += (this._htmlIsRoot ? document.documentElement
                             : document.body).clientTop;
	}
    return y;
  },

  _pushStack: function (layer) {
    if (this._stackSize + 1 < this._stack.length) {
      this._stack.length = this._stackSize + 1;
    }
    this._stack[this._stackSize++] = layer;
  }
};

function DrawingCanvasVML(parent, width, height)
{
  if (!document.namespaces) throw new Error("Not supported!");
  if (!document.namespaces.v) {
    document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
    document.createStyleSheet().addRule("v\\:*","behavior: url(#default#VML);");
  }
  if (!parent) throw new Error("No canvas parent!");

  if (!width)  width  = parent.clientWidth;
  if (!height) height = parent.clientHeight;

  this.parent        = parent;
  this.width         = width;
  this.height        = height;
  this._bgColor      = "none";
  this._lineWidth    = 2;
  this._lineColor    = "#000";
  this._isDrawing    = false;
  this._currentShape = null;
  this._dummyDot     = null;
  this._points       = "";
  this._stack        = [];
  this._stackSize    = 0;
  this._opacity 	 = 0.45;

  var container = document.createElement("div");
  container.style.cssText = "position: relative; text-align:left; " +
                            "width: "  + width  + "px; " +
                            "height: " + height + "px; ";
  parent.appendChild(container);
  this.container = container;
}

DrawingCanvasVML.prototype = {
  arrows:Array(),
  setBgColor: function (color) {
    this.container.style.backgroundColor = this._bgColor = color;
  },
  setSize: function(width, height) {
  	this.container.style.width = width + "px";
  	this.container.style.height = height + "px";
  	this.width = width;
  	this.height = height;  	  	
  },
	
  setViewBox: function(left, top, width, height) {
  	this.container.setAttribute("coordorigin", left + " " + top);
  	this.container.setAttribute("coordsize", parseInt(width + this._lineWidth * 2) 
  	+ "," + parseInt(height + this._lineWidth * 2));
  },
	
  setPosX: function(left) {
  	this.container.style.left = left + "px";  	
  },  
  
  setPosY: function(top) {
	this.container.style.top = top + "px";  	
  },

	// ismail
	updatePosition: function() {
		this.container.style.top = -parseInt(this.parent.style.top) + 'px';
		this.container.style.left = -parseInt(this.parent.style.left) + 'px';
	},
	
	// ismail
	panByOffset: function(offsetX, offsetY) {
		// do nothing
	},
	
  setLineColor: function (color) {
    this._lineColor = color;
  },
  
  setOpacity: function (opacity) {
  	this._opacity = opacity;
  },

  setLineWidth: function (width) {
    this._lineWidth = Number(width) || 0;
  },
  
  createGeofence: function(x, y, r, l) {
  	this.createCircle(x, y, r);
  	this.createArrow(x, y, r);
  	this.createText(x, y, r, l);
  },
  
  createCircle: function(x, y, r) {
  	r = Math.round(r);
    var dot  = document.createElement("v:oval");
    dot.strokeweight = 2;
    var w = r*2; 
    dot.style.cssText = "position: absolute; " +
                        "width: "  + w + "px; " +
                        "height: " + w + "px; " +
                        "left: " + (x-r) + "px; " +
                        "top: "  + (y-r) + "px; ";
	dot.innerHTML = "<v:fill on='false' />";                        
    this.container.appendChild(dot);    
    this._currentShape = dot;
    this._pushStack(this._currentShape);
  },
  
	// ismail
	// copied from sd_map_sg
	createFullArrow: function(pos0, pos1, pos2, color) {
		var arrow = document.createElement("v:polyline");
		arrow.filled = true;
		arrow.fillcolor = color;
		arrow.strokecolor = color;
		//arrow.strokeweight = "2px";
		var points = pos1.x + "," + pos1.y + " "
			+ pos0.x + "," + pos0.y + " "
			+ pos2.x + "," + pos2.y;
		arrow.points = points;
		
		//var stroke = document.createElement("v:stroke");
		//stroke.endcap = "round";
		//stroke.opacity = this._opacity;	
		//arrow.appendChild(stroke);
		this.arrows.push(arrow);
		this.container.appendChild(arrow);
	},
	
	// ismail
	// copied from sd_map_sg
	clearFullArrow: function(){
		var n = this.arrows.length;
		for(var i=0;i<n;i++)
		{
			this.container.removeChild(this.arrows[i]);
		}
		this.arrows = Array();
	},
	
  createArrow: function(x, y, r) {
    var arr = document.createElement("v:polyline");
    arr.filled       = false;
    arr.strokecolor  = "black";
    arr.strokeweight = 2;
    arr.points       = (x+r-5)+","+(y-5)+" "+(x+r)+","+y+" "
    	+x+","+y+" "+(x+r)+","+y+" "+(x+r-5)+","+(y+5);
    this.container.appendChild(arr);    
    this._currentShape = arr;
    this._pushStack(this._currentShape);
  },
  
  createText: function(x, y, r, l) {   
    var lin = document.createElement("v:line");
    lin.from = x+" "+(y-10); lin.to = (x+r)+" "+(y-11);
    lin.innerHTML = "<v:fill on='True' color='red'/>"
    	+ "<v:path textpathok='True'/>"
    	+ "<v:textpath on='True' string='"+(l/1000)+" km"
    	+ "' style='font:normal normal normal 12pt Arial'/>";
  	this.container.appendChild(lin);
    this._currentShape = lin;
    this._pushStack(this._currentShape);    	
  },
	
  startLine: function (x, y) {
    if (this._isDrawing)
      this.endLine();
    this._isDrawing = true;

    var dot  = document.createElement("v:oval");
    var size = this._lineWidth
    dot.fillcolor     = this._lineColor;
    dot.strokecolor   = this._lineColor;
    //dot.stroked       = false;
    dot.style.cssText = "position: absolute; " +
                        "width: "  + size + "px; " +
                        "height: " + size + "px; " +
                        "left: " + (x - size / 2) + "px; " +
                        "top: "  + (y - size / 2) + "px; ";
    this.container.appendChild(dot);

    this._dummyDot = dot;
    /*this._points   = x + "," + y;

    var polyline = document.createElement("v:polyline");
    polyline.filled       = false;
    polyline.strokecolor  = this._lineColor;
    polyline.strokeweight = this._lineWidth;
    polyline.points       = this._points;*/
		this._points = "m" + Math.round(x) + "," + Math.round(y) + " l";
		var polyline = document.createElement("v:shape");
		polyline.style.position = 'absolute';
		polyline.style.width = '1px';
		polyline.style.height = '1px';
		polyline.coordsize = "1,1";
    polyline.filled       = false;
    polyline.strokecolor  = this._lineColor;
    polyline.strokeweight = this._lineWidth;
		polyline.unselectable = "on";
		polyline.path = this._points;
    var stroke = document.createElement("v:stroke");
    stroke.endcap = "round";
    stroke.opacity = this._opacity;
    polyline.appendChild(stroke);
    this.container.appendChild(polyline);
    this._currentShape = polyline;
  },

  endLine: function () {
    if (!this._isDrawing) return;

		this._points += "e";
		this._currentShape.path = this._points;
    if (this._dummyDot) {
      this.container.removeChild(this._currentShape);
      this._pushStack(this._dummyDot);
      this._dummyDot = null;
    } else {
      this._pushStack(this._currentShape);
    }
    this._isDrawing    = false;
    this._currentShape = null;
    this._points       = "";
  },

  lineTo: function (x, y) {
    if (!this._isDrawing) return;
    if (this._dummyDot) {
      this.container.removeChild(this._dummyDot);
      this._dummyDot = null;
    }

    this._points +=  Math.round(x) + "," + Math.round(y) + " ";
    //this._currentShape.points.value = this._points;
		this._currentShape.path = this._points;
  },

  undo: function () {
    if (this._isDrawing)
      this.endLine();
    if (this._stackSize <= 0)
      return false;

    this._stack[--this._stackSize].style.visibility = "hidden";
    return true;
  },

  redo: function () {
    if (this._isDrawing)
      this.endLine();
    if (this._stackSize >= this._stack.length)
      return false;

    this._stack[this._stackSize++].style.visibility = "visible";
    return true;
  },

  clearShape: function () {
    if (this._isDrawing)
      this.endLine();
    
    if (this._stack.length > 1) {
	   	this.container.removeChild(this._stack[this._stack.length-1]);
	    this._stack.length = this._stack.length - 1;
	    this._stackSize    = this._stackSize - 1;
    }
  },

  clear: function () {
    if (this._isDrawing)
      this.endLine();

    for (var i = this._stack.length; i--;) {
      if (this._stack[i]!=undefined) this.container.removeChild(this._stack[i]);
    }
    this._stack.length = 0;
    this._stackSize    = 0;
  },

  _htmlIsRoot: (typeof document.compatMode == "string") &&
               (document.compatMode == "CSS1Compat"),

  getX: function () {
    var box = this.container;
    var x   = box.offsetLeft;
    while ((box = box.offsetParent))
      x += box.offsetLeft;

    x += (this._htmlIsRoot ? document.documentElement
                           : document.body).clientLeft;
    return x;
  },

  getY: function () {
    var box = this.container;
    var y   = box.offsetTop;
    while ((box = box.offsetParent))
      y += box.offsetTop;

    y += (this._htmlIsRoot ? document.documentElement
                           : document.body).clientTop;
    return y;
  },

  _pushStack: function (shape) {
    var stackLength = this._stack.length;
    if (this._stackSize < stackLength) {
      for (var i = this._stackSize; i < stackLength; i++)
        this.container.removeChild(this._stack[i]);
      this._stack.length = this._stackSize + 1;
    }
    this._stack[this._stackSize++] = shape;
  }
};

function DrawingCanvas()
{
  var backend = "CSSP";
  if (document.namespaces && document.namespaces.add) {
    backend = "VML";
  }
  try {
    if (document.createElement("canvas").getContext) {
      backend = "Canvas";
    };
  } catch (e) {}
  if (document.createElementNS) {
	var svgFeature = "http://www.w3.org/TR/SVG11/feature#";
    if (document.implementation && 
		(document.implementation.hasFeature("org.w3c.svg", "1.0") ||
        document.implementation.hasFeature(svgFeature + "SVG", "1.1") ||
        document.implementation.hasFeature(svgFeature + "BasicStructure", "1.1") )) {
    	backend = "SVGT";
    }
    if (window.opera) {
      var ua    = navigator.userAgent;
      var index = ua.indexOf("Opera");
      if (index >= 0 && parseInt(ua.substring(index + 6)) >= 8) {
        backend = "SVGT";
      };
    };    
  };
  switch (backend) {
    case "SVGT":   DrawingCanvas = DrawingCanvasSVGT;   break;
    case "Canvas": DrawingCanvas = DrawingCanvasCanvas; break;
    case "CSSP":   DrawingCanvas = DrawingCanvasCSSP;   break;
    case "VML":    DrawingCanvas = DrawingCanvasVML;    break;
  };
  DrawingCanvas.backend = backend;
  DrawingCanvas.prototype.constructor = DrawingCanvas;
};

DrawingCanvas();

function Point(x, y) {
    this.x = x;
    this.y = y;
};

function Vertex(x, y) {
    this.x = x;
    this.y = y;
};

function GLatLng(x,y) {
	this.x = x;
	this.y = y;
};

function getHttpObject() {
	var xmlHttp;
	try {
		xmlHttp = new XMLHttpRequest();		
	} catch (e) {
		try {
			xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');				
		} catch (e) {
			try {
				xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");	
			} catch (e) {
				alert("Your browser does not support AJAX!");
				return false;
			};
		};
	};
	return xmlHttp;
};

function Ajax(url, callback) {

    var req = getHttpObject();
    req.onreadystatechange = processRequest;
        
    function processRequest () {
    	if (req.readyState == 4) {
    		if (req.status == 200) {
    			if (callback) {
    				callback(req);
    			}
    		}
    	}
    };

    this.doGet = function() {
    	req.open("GET", url, true);
    	req.send(null);
    };
    
    this.doPost = function(body, xmlMode) {
    	req.open("POST", url, true);
		req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		req.setRequestHeader("Content-length", body.length);    	
    	if (xmlMode == true || xmlMode != undefined) {
    		req.setRequestHeader("Content-Type", "text/xml");
		}   	
    	req.send(body);
    };
};


function Rectangle(left, top_, right, bottom) {
    this.left = left;
    this.top = top_;
    this.right = right;
    this.bottom = bottom;
    
    this.setWidth = function(value) {
    	this.right = this.left + value;
    };
    
    this.setHeight = function(value) {
    	this.bottom = this.top + value;
    };
    
    this.offset = function(x, y) {
    	this.left = this.left + x;
    	this.top = this.top + y;
    	this.right = this.right + x;
    	this.bottom = this.bottom + y;
    };
    
    this.width = function() {
    	return Math.abs(this.right - this.left);	    	
    };
    
    this.height = function() {
    	return Math.abs(this.bottom - this.top);
    };
};

function DElement(el, id, _left, _top, _w, _h, _pos, _zIndex, _src, _color, overflow) {
	var cons = document.createElement(el);
	if (id != undefined && id != '') { cons.id = id; };
	if (_left != undefined && _left != '') { cons.style.left = _left; };
	if (_top != undefined && _top != '') { cons.style.top = _top; };
	if (_w != undefined && _w != '') { cons.style.width = _w; };
	if (_h != undefined && _h != '') { cons.style.height = _h; };
	if (_pos != undefined && _pos != '') { cons.style.position = _pos; };
	if (_src != undefined && _src != '') { cons.src = _src; };
	if (_zIndex != undefined && _zIndex != '') { cons.style.zIndex = _zIndex; };	
	if (_color != undefined && _color != '') { cons.style.backgroundColor = _color; };
	if (overflow != undefined && overflow == true) { cons.style.overflow = "hidden"; };
	return cons;
};

function MDiv(id, _left, _top, _w, _h, _pos, _zIndex, _color, overflow) {
	return new DElement("div", id, _left, _top, _w, _h, _pos, _zIndex, '', _color, overflow);
};

function MImg(id, _src, _left, _top, _w, _h, _pos, _zIndex, overflow) {
	var img = new DElement("img", id, _left, _top, _w, _h, _pos, _zIndex, _src, overflow);
  img.border = '0';
  return img;
};

function MSpan(value) {
	var span = new DElement("span");
	span.innerHTML = value;
	return span;
};

function MapTile(row, col, img, div) {
	this.row = row;
	this.col = col;
	this.img = img;
	this.div = div;
};
function OffsetPoint(pt, x, y) {
    var result = new Point();
    result.x = pt.x + x;
    result.y = pt.y + y;
    return result;
};

function getTopLeft(obj) {
	if (obj == undefined) {
		return {x:0, y:0};
	}
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft;
		curtop = obj.offsetTop;
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		};
	};
	return {x: curleft, y: curtop};
};

function getCursorPos(e, obj) {
	var _alt = getTopLeft(obj);
	var currX, currY, _x, _y;
	currX = (!document.all) ? e.pageX : (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
	currX -= _alt.x;
	currY = (!document.all) ? e.pageY : (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
	currY -= _alt.y;
	if(document.all) {		
		_x = event.clientX;
		_y = event.clientY;
	}else {
		_x = e.clientX;
		_y = e.clientY;
	};
	return {x: currX, y: currY, vx: _x, vy: _y};
};

function ViewportInfo() {
    this.width = 0;
    this.height = 0;
    this.centerVertex = new Vertex(0, 0);
    this.imgUrl = '';
    this.currentLvToHighLvPercentage = 0;    
};

function Quadtree(mapClient) {
	this.mapClient = mapClient;	
};


function MapSource(pathUrl, mapName) {
    this.mapTitle = '';
    this.mapCode = '';
    this.mapYear = '';
    this.mapZone = '';
    this.isSouth = '';
    this.isCassini = '';
    this.mapScales = [];
    this.pathUrl = pathUrl;
    this.name = mapName;
	
	
  this.loadVar = function(xmlDom) {
    if (BrowserDetect.browser == 'Explorer')
    {
      var doc = new ActiveXObject("Microsoft.XMLDOM");
      doc.async = "false";
      doc.loadXML(xmlDom);
    }
    else
    {
      var parser = new DOMParser();
      var doc = parser.parseFromString(xmlDom, "text/xml");
    }
    
    var root = doc.getElementsByTagName('MAPCONFIG')[0];
    this.mapTitle = root.getElementsByTagName('TITLE')[0].firstChild.nodeValue;
    this.mapYear = root.getElementsByTagName('YEAR')[0].firstChild.nodeValue;
    this.mapCode = root.getElementsByTagName('MAPCODE')[0].firstChild.nodeValue;
    this.mapZone = root.getElementsByTagName('MAPZONE')[0].firstChild.nodeValue;
    this.isSouth = root.getElementsByTagName('ISSOUTH')[0].firstChild.nodeValue;
    this.isCassini = root.getElementsByTagName('CASSINI')[0].firstChild.nodeValue;
    var scales = root.getElementsByTagName('SCALE');

		for (i=0;i<scales.length;i++)
		{
		  	
		  	var attlist = scales.item(i).attributes;
		  	var scale = new MapScale();
		  
	  		if (attlist.getNamedItem("DISABLED").nodeValue != "True") 
	  		{		  		
		  		scale.mapWidth = parseInt(attlist.getNamedItem("WIDTH").nodeValue); 
		  		scale.mapHeight = parseInt(attlist.getNamedItem("HEIGHT").nodeValue);
		  		scale.maxCol = parseInt(attlist.getNamedItem("MAXCOL").nodeValue);
		  		scale.maxRow = parseInt(attlist.getNamedItem("MAXROW").nodeValue);
		  		scale.minLon = parseFloat(attlist.getNamedItem("MINLONG").nodeValue);  
		  		scale.maxLon = parseFloat(attlist.getNamedItem("MAXLONG").nodeValue);
		  		scale.maxLat = parseFloat(attlist.getNamedItem("MAXLAT").nodeValue);
		  		scale._name = attlist.getNamedItem("LEVELCODE").nodeValue;
		  		/*if (attlist.getNamedItem("USERSCALING").nodeValue == "True") {
					scale._scaleValue = parseFloat(attlist.getNamedItem("USERSCALE").nodeValue);
		  		}*/
		  		this.mapScales.push(scale);
	  		};
		};		
  };
	
    this.loadFromXml = function(xmlDom) {
    	this.mapTitle = xmlDom.getElementsByTagName('TITLE').item(0).firstChild.nodeValue;
    	this.mapCode = xmlDom.getElementsByTagName('MAPCODE').item(0).firstChild.nodeValue;
    	this.mapYear = xmlDom.getElementsByTagName('YEAR').item(0).firstChild.nodeValue;
    	this.mapZone = xmlDom.getElementsByTagName('MAPZONE').item(0).firstChild.nodeValue;
    	this.mapScales = [];
    	
    	var scales = xmlDom.getElementsByTagName('SCALE');

		for (i=0;i<scales.length;i++)
		{
		  	
		  	var attlist = scales.item(i).attributes;
		  	var scale = new MapScale();
		  
	  		if (attlist.getNamedItem("DISABLED").nodeValue != "True") 
	  		{		  		
		  		scale.mapWidth = parseInt(attlist.getNamedItem("WIDTH").nodeValue); 
		  		scale.mapHeight = parseInt(attlist.getNamedItem("HEIGHT").nodeValue);
		  		scale.maxCol = parseInt(attlist.getNamedItem("MAXCOL").nodeValue);
		  		scale.maxRow = parseInt(attlist.getNamedItem("MAXROW").nodeValue);
		  		scale.minLon = parseFloat(attlist.getNamedItem("MINLONG").nodeValue);  
		  		scale.maxLon = parseFloat(attlist.getNamedItem("MAXLONG").nodeValue);
		  		scale.maxLat = parseFloat(attlist.getNamedItem("MAXLAT").nodeValue);
		  		scale._name = attlist.getNamedItem("LEVELCODE").nodeValue;
		  		if (attlist.getNamedItem("USERSCALING").nodeValue == "True") {
					scale._scaleValue = parseFloat(attlist.getNamedItem("USERSCALE").nodeValue);		  			
		  		}
		  		this.mapScales.push(scale);

	  		};
		};		
    };

	this.getMapTileUrl = function(col, row, mapScale) {		 
			var this_path = this.getTilePath(col, row);
			lvl = parseInt(mapScale._name) + 3;	
			if (lvl == 4) return img_path = this_path + 'data/SG-Getmap/sg' + row + '_' + col + '_1.gif';
			else return img_path = this_path + 'data/map/sg/'+lvl+'/sg'+row+'_'+col+'_'+lvl+'.gif';
    };

    this.getFirstScaleLevel = function(val) {
  	     if (this.mapScales[val] != undefined){  
  	     	return this.mapScales[val];
  	     };
    };
		
		// ismail
		// get proper hostname base on row and column, because we are using multiple hostname
		this.getTilePath = function(col, row)
		{
			var this_path = 'http://172.16.0.4/';
			var hostname = location.hostname;
			if (hostname.indexOf('streetdirectory') != -1)
			{
				//this_path = (row%2 == col%2) ? 'http://map1.streetdirectory.com/' : 'http://map2.streetdirectory.com/';
				if (hostname == 'beta.streetdirectory.com')
					this_path = 'http://beta.streetdirectory.com/';
				else
				{
					var server_no = 1 + (row+col)%4;
					this_path = 'http://map'+server_no+'.streetdirectory.com/';
				}
			}
			else if (hostname != 'localhost' && hostname != 'sdcom' && hostname != '172.16.0.4')
			{
				var server_no = 1 + (row+col)%4;
				this_path = 'http://map'+server_no+'.streetdirectory.com/';
			}
			return this_path;
		};
};

function MapScale(mapWidth, mapHeight, maxCol, maxRow, minLon, maxLon, minLat, maxLat,
    name_, desc, userScale, gridArray) {    
    this.mapWidth = mapWidth;
    this.mapHeight = mapHeight;
    this.maxCol = maxCol;
    this.maxRow = maxRow;
    this.minLon = minLon;
    this.maxLon = maxLon;
    this.minLat = minLat;
    this.maxLat = maxLat;
    this._name = name_;
    this.desc = desc;
    this.userScale = userScale;
    this._scaleValue = 0;

    this.scaleValue = function() {
    	if (this._scaleValue == 0) {
        	this._scaleValue = (this.maxLon - this.minLon) / (this.maxCol * this.mapWidth);
    	}
        return this._scaleValue;
    };
        
    this.pixelToUtm = function(x, y) {
        var _scaleValue = this.scaleValue();
        return new Vertex((this.minLon) + (x * _scaleValue), (this.maxLat) - (y * _scaleValue));
    }; 

    this.utmToPixel = function(vertX, vertY) {
        var result = new Point();
        var _scaleValue = this.scaleValue();                 
        result.x = Math.round((vertX - this.minLon) / _scaleValue);
        result.y = Math.round((this.maxLat - vertY) / _scaleValue);
        return result;
    };
    
    this.inflateVert = function(vert, x, y) {
        var ptPixel = this.utmToPixel(vert.x, vert.y);
        ptPixel = OffsetPoint(ptPixel, x, y);
        return this.pixelToUtm(ptPixel.x, ptPixel.y);
    };
    
    this.getDistance = function(vert0, vert1) {
    	if (isNaN(vert0.x) || isNaN(vert0.y)
    		|| isNaN(vert1.x) || isNaN(vert1.y)) {
    		return;
    	};
    	return Math.sqrt((vert0.x-vert1.x)*(vert0.x-vert1.x)
    		+(vert1.y-vert0.y)*(vert1.y-vert0.y));
    };

    this.getCenterVertex = function() {
        return this.pixelToUtm((this.maxCol * this.mapWidth) / 2, 
        	(this.maxRow * this.mapHeight) / 2);
    };
       
    this.getTopLeftPoint = function(vertX, vertY, displayWidth, displayHeight) {
        var pt = this.utmToPixel(vertX, vertY);
        pt = OffsetPoint(pt, -(displayWidth / 2), -(displayHeight / 2));
        return pt;
    };
};

function MapUtil(mapClient) {
	this.mapClient = mapClient;
	
	this.getCenterLevel = function(points) {
		var _x = new Array(), _y = new Array();
		var _min, _max, _main, _delta, _level, _scale, _resLevel, 
			_iconBounds;
		for (var b=0; b<points.length; b++) {
			if (points[b][0] != undefined) {				
				for (var c=0; c<points[b][0].length; c++) {
					if (points[b][0][c] != null 
						&& points[b][0][c].x != undefined 
						&& points[b][0][c].y != undefined) {
						_x.push(points[b][0][c].x);
						_y.push(points[b][0][c].y);
					}
				}			
			} else if (points[b] != undefined){
				if (points[b].x != undefined 
					&& points[b].y != undefined) {				
					_x.push(points[b].x);
					_y.push(points[b].y);
				}	
			}
		}
		
		_x.push(this.mapClient.centerVertex.x);
		_y.push(this.mapClient.centerVertex.y);		
		
		_min = new Point(this.findMin(_x), this.findMin(_y));
		_max = new Point(this.findMax(_x), this.findMax(_y));
		_iconBounds = new Rectangle(_min.x, _max.y, _max.x, _min.y);
		_main = new Point(parseInt((_min.x + _max.x)/2), parseInt((_min.y + _max.y)/2));

		var srcScales = this.mapClient.mapSource.mapScales;
		var prevDeltaScale = 10000;
		var ee = 0, cs = 0, currentScale = 0, deltaScale = 0, 
			iconTotalScale = 0, radian = null, mapBound = new Rectangle();
		for (var e=srcScales.length-1; e>=0; e--) {
			currentScale = this.mapClient.mapSource.mapScales[e];
			cs = currentScale.scaleValue();
			
			radian = new Point(this.mapClient.mapWidth / 2 * cs,
				this.mapClient.mapHeight / 2 * cs);
			mapBound.left = this.mapClient.centerVertex.x - radian.x;
			mapBound.right = this.mapClient.centerVertex.x + radian.x;
			mapBound.top = this.mapClient.centerVertex.y + radian.y;
			mapBound.bottom = this.mapClient.centerVertex.y - radian.y;
			
			if (_iconBounds.left > mapBound.left && _iconBounds.left < mapBound.right
				&& _iconBounds.right > mapBound.left && _iconBounds.right < mapBound.right
				&& _iconBounds.bottom > mapBound.bottom && _iconBounds.bottom < mapBound.top
				&& _iconBounds.top > mapBound.bottom && _iconBounds.top < mapBound.top				
			) {
				ee = e;
				break;
			}
		}
		_resLevel=ee;
		return { x : _main.x, y : _main.y, level : _resLevel };
	};	

	this.findMin = function(intA) {     
	     if ( intA.length == 0 ) { 
	         return 0;
	     }
	     if ( intA.length == 1 ) { 
	         return 1;
	     }
	     var o_intMin = intA[0];
	     for (var p_intI = 1; p_intI < intA.length; p_intI += 1) {
	         if ( intA[p_intI] < o_intMin ) {
	            o_intMin = intA[p_intI];
	         } 
	  	 } 
	  	 return parseInt(o_intMin);     
	};

	this.findMax = function(intA) {
	    for ( var i_intI = 0; i_intI < intA.length;i_intI += 1 ) {
	        intA[i_intI] = intA[i_intI] * -1;
	    };
	    var o_intMax = this.findMin(intA);
	    o_intMax = o_intMax * -1;
	    return parseInt(o_intMax);
	};
};

function MapScaleList(listSize) {
    this.listSize = listSize;
    this.listitems = new Array(listSize);
    
    this.getItem = function(idx){
        return listItems(idx);
    };
        
    this.setItem = function(idx, mapScale) {
        listItems[idx] = mapScale;
    };
};

function MapClient() {
    
    this.viewportInfo = new ViewportInfo();
    this.mapWidth = 0;
    this.mapHeight = 0;
    this.mapScale = new MapScale();
    this.centerVertex = new Vertex(0, 0);
    this.levelIndex = -1;
    this.mapName = 'Singapore';    
    this.mapSource = new MapSource();
	this.scale = null;
    
    this.setLevelIndex = function (lvl) {
    	if (this.mapSource.mapScales[lvl] != undefined) {
    		this.levelIndex = lvl;
    	};
    };
    
    this.setCenterVertex = function(vertex) {
    	this.centerVertex.x = vertex.x;
    	this.centerVertex.y = vertex.y; 
    };
    
	this.setMapSource = function(mapname, autoLevel) {
		this.mapName = mapname;  
			var _autoLevel = autoLevel;
  		  var _mapClient = this;
		  _mapClient.mapSource.name = _mapClient.mapName; 
		   _mapClient.mapSource.loadVar('<?xml version="1.0"?><MAPCONFIG><TITLE>Singapore</TITLE><YEAR>2009</YEAR><MAPCODE>sd</MAPCODE><MAPZONE>48</MAPZONE><ISSOUTH>0</ISSOUTH><CASSINI>-1</CASSINI><SCALES><SCALE WIDTH="500" HEIGHT="500" MAXROW="21" MAXCOL="18" MINLONG="-108737.68" MAXLONG="549042.41" MAXLAT="834122.85" USERSCALING="False" USERSCALE="0" LEVELNAME="1" LEVELCODE="1" DISABLED="False" ISTHUMBNAIL="False" /><SCALE WIDTH="256" HEIGHT="256" MAXROW="105" MAXCOL="85" MINLONG="-102604.7274" MAXLONG="480230.1328" MAXLAT="784378.2020" LEVELCODE="2" DISABLED="False" MODE="WGS"/><SCALE WIDTH="256" HEIGHT="256" MAXROW="14" MAXCOL="24" MINLONG="344689.2507" MAXLONG="399183.9097" MAXLAT=" 163677.5871" LEVELCODE="3" DISABLED="False" MODE="WGS"/><SCALE WIDTH="256" HEIGHT="256" MAXROW="19" MAXCOL="33" MINLONG="345295.6234" MAXLONG="398569.4080" MAXLAT="163127.4060" LEVELCODE="4" DISABLED="False" MODE="WGS"/><SCALE WIDTH="256" HEIGHT="256" MAXROW="32" MAXCOL="56" MINLONG="345342.104029" MAXLONG="398542.106215" MAXLAT="162993.174954" LEVELCODE="5" DISABLED="False" MODE="WGS"/><SCALE WIDTH="256" HEIGHT="256" MAXROW="64" MAXCOL="112" MINLONG="345342.104029" MAXLONG="398542.106215" MAXLAT="162993.174954" LEVELCODE="6" DISABLED="False" MODE="WGS"/><SCALE WIDTH="256" HEIGHT="256" MAXROW="128" MAXCOL="224" MINLONG="345342.104029" MAXLONG="398542.106215" MAXLAT="162993.174954" LEVELCODE="7" DISABLED="False" MODE="WGS"/></SCALES></MAPCONFIG>');
		   _mapClient.mapScale = _mapClient.mapSource.getFirstScaleLevel(_mapClient.levelIndex);
		   if (_mapClient.centerVertex.x == 0 && _mapClient.centerVertex.y == 0){
				_mapClient.centerVertex = _mapClient.mapScale.getCenterVertex();
		   };
		   if (_autoLevel && _mapClient.mapDraw != null) {
				var center = _mapClient.mapDraw.getCenterLevel(2);
				_mapClient.levelIndex = center.level;
				if (_mapClient.mapSource.mapScales[_mapClient.levelIndex] != undefined) {
					_mapClient.mapScale = _mapClient.mapSource.mapScales[_mapClient.levelIndex];
				}
		   }
		   _mapClient.drawMap();      
	};
	
    this.setMapSource2 = function(mapName, autoLevel) {
    	this.mapName = mapName;  	
    	this.mapConfig = this.baseUrl + 'param.php?cd=mc&s=' + escape(mapName);
    	var xmlHttp = getHttpObject();    	
    	var _mapClient = this;
    	var _autoLevel = autoLevel;
    	if (!xmlHttp){
            alert ('Your browser does not support AJAX!');
            return;
        };
        xmlHttp.onreadystatechange = function()
		    {		      
		        if(xmlHttp.readyState == 4)
		        {		            
		            if (xmlHttp.status==200)
		            {
		            	var xmlDom = xmlHttp.responseXML;
		                if (xmlDom == null) {
		                	return;		     
		                };
		               
		               _mapClient.mapSource.name = _mapClient.mapName; 
		               _mapClient.mapSource.loadFromXml(xmlDom);
		               _mapClient.mapScale = _mapClient.mapSource.getFirstScaleLevel(_mapClient.levelIndex);
		               if (_mapClient.centerVertex.x == 0 && _mapClient.centerVertex.y == 0){
		               		_mapClient.centerVertex = _mapClient.mapScale.getCenterVertex();
		               };
		               if (_autoLevel && _mapClient.mapDraw != null) {
		               		var center = _mapClient.mapDraw.getCenterLevel(2);
		               		_mapClient.levelIndex = center.level;
		               		if (_mapClient.mapSource.mapScales[_mapClient.levelIndex] != undefined) {
		               			_mapClient.mapScale = _mapClient.mapSource.mapScales[_mapClient.levelIndex];
		               		}
		               }
		               _mapClient.drawMap();               
		            };
		        };
		    };        
        xmlHttp.open('GET', this.mapConfig, true);
        xmlHttp.send(null);	
        
    };
        
    this.setContainerTopLeft = function(topleftPt, topLeftCell, bottomRightCell) {
    	this.mapContainer.bound.top = (topLeftCell.y - 1) * this.mapScale.mapHeight;
    	this.mapContainer.bound.left = (topLeftCell.x - 1) * this.mapScale.mapWidth;
    	this.mapContainer.bound.right = (bottomRightCell.x) * this.mapScale.mapWidth;  
    	this.mapContainer.bound.bottom = (bottomRightCell.y) * this.mapScale.mapHeight;
    	
    	this.mapContainer.rect.x = this.mapContainer.bound.left - topleftPt.x;
    	this.mapContainer.rect.y = this.mapContainer.bound.top - topleftPt.y;
    	this.mapContainer.style.left = this.mapContainer.rect.x+"px";
		this.mapContainer.style.top = this.mapContainer.rect.y+"px";
		this.mapContainer.style.width = ((bottomRightCell.x - topLeftCell.x + 1) * this.mapScale.mapWidth)+  "px"; 
		this.mapContainer.style.height = ((bottomRightCell.y - topLeftCell.y + 1) * this.mapScale.mapHeight)+  "px";
    };
    
    this.clearTilesContainer = function() {
    	var tileItems = this.mapContainer.Items; 
        for (i=0; i < tileItems.length; i++) {
        	this.tilesContainer.removeChild(tileItems[i].div);
        	tileItems[i].div = undefined;
			tileItems[i] = undefined;
        };	
        this.mapContainer.Items = [];
    };
    
    
    this.drawMap = function() {    	    

    	this.generateMap(this.getviewportInfo());   	
		if (this.mapDraw != undefined) {
			this.mapDraw.updatePanel();
		}
		this.onCompleted.call();
    };
    
    this.moveViewportPosition = function(offsetX, offsetY) {
      this.centerVertex = this.mapScale.inflateVert(this.centerVertex, -offsetX, -offsetY);
      this.mapContainer.rect.x += offsetX;
      this.mapContainer.rect.y += offsetY;
      this.mapContainer.style.left = this.mapContainer.rect.x + "px";
      this.mapContainer.style.top = this.mapContainer.rect.y + "px";
      this.updateInfo();
    };
    
    this.vertexToScreen = function(vertX, vertY) {
      if (this.mapScale == null) {
        return new Vertex(0,0);
      }
      var pt = this.mapScale.utmToPixel(vertX, vertY);
      var topLeft = this.mapScale.getTopLeftPoint(this.centerVertex.x,
        this.centerVertex.y, this.mapWidth, this.mapHeight);
      pt.x -= topLeft.x;
      pt.y -= topLeft.y;
      return pt;
    };
    
	this.screenToVertex = function(pos) {
		var pt = this.mapScale.inflateVert(this.centerVertex, 
			pos.x-this.mapWidth/2, pos.y-this.mapHeight/2);
		return pt;
	};
    
    this.getVertexTopLeft = function(x, y) {
    	var pt = this.mapScale.pixelToUtm(x, y);
    	var topLeft = this.mapScale.getTopLeftPoint(this.centerVertex.x, this.centerVertex.y, this.mapWidth, this.mapHeight);
    	pt.x -= topLeft.x;
    	pt.y -= topLeft.y;
    	return pt;
    };
    
    this.panMapByOffset = function(offsetX, offsetY) {   	 	
    	this.centerVertex = this.mapScale.inflateVert(this.centerVertex, -offsetX, -offsetY);
    	this.drawMap();
    	this.updateInfo();
    };
    
    this.zoomIn = function() {
    	var _chZoom = this.levelIndex + 1;
    	this.changeLevel(_chZoom);
    };
    
    this.changeLevel = function(level) {
      this.setLevelIndex(level);
      this.mapScale = this.mapSource.mapScales[this.levelIndex];
      /*this.scale.src = this.baseUrl + 'img/scale' + (this.levelIndex + 1) + '.gif';
      if (this.levelIndex == 0) {
        this.scale.style.width = '51px';
        this.scale.style.left = this.mapWidth - 51 + 'px';
      }
      else {
        this.scale.style.width = '65px';
        this.scale.style.left = this.mapWidth - 65 + 'px';
      }*/
      this.updateInfo();
      this.drawMap();
    };
    
    this.zoomOut = function() {
    	var _chZoom = this.levelIndex - 1;
      if (_chZoom >= 0) this.changeLevel(_chZoom);
    };
    
    this.generateMap = function(viewportInfo) {
    	if (this.mapScale == null 
    		|| this.mapScale.mapWidth == null) {
    		return;
    	};
		var vi = viewportInfo;		    	
        var topLeft = this.mapScale.getTopLeftPoint(
        	this.centerVertex.x, this.centerVertex.y, this.mapWidth, this.mapHeight);
        var colStart = Math.ceil(topLeft.x / this.mapScale.mapWidth);
        var rowStart = Math.ceil(topLeft.y / this.mapScale.mapHeight);
        var colEnd = Math.ceil((topLeft.x + this.mapWidth) /
            this.mapScale.mapWidth);
        var rowEnd = Math.ceil((topLeft.y + this.mapHeight) /
            this.mapScale.mapHeight);

        var r = new Rectangle(0, 0, 0, 0);
        
        var topLeftCell = new Point(colStart, rowStart);
        var bottomRightCell = new Point(colEnd, rowEnd);
        
        this.clearTilesContainer();
        this.setContainerTopLeft(topLeft, topLeftCell, bottomRightCell);
        for (iRow = rowStart; iRow <= rowEnd; iRow++)          
        {
            for (iCol = colStart; iCol <= colEnd; iCol++)
            {
				if (iRow < 0 || iCol < 0 || iCol > this.mapScale.maxCol 
					|| iRow > this.mapScale.maxRow)
                	continue;
                	            	
            	r.left = (iCol - colStart) * this.mapScale.mapWidth;
                r.top = (iRow - rowStart) * this.mapScale.mapHeight;
                r.Width = this.mapScale.mapWidth;
                r.Height = this.mapScale.mapHeight;
                                                             
                var divImage = new MDiv('', r.left + 'px', r.top + 'px',
                	this.mapScale.mapWidth + 'px', this.mapScale.mapHeight + 'px', 
                	"absolute");
                divImage.style.backgroundImage = "url(" + this.baseUrl + 'img/loading.gif' + ")";                
                var tile = new MapTile(iRow, iCol, new MImg(), divImage);
                var tileURL = this.mapSource.getMapTileUrl(iCol, iRow, this.mapScale);        		        		
                divImage.appendChild(tile.img);
        		this.tilesContainer.appendChild(divImage);
        		this.mapContainer.Items.push(tile);        		
        		tile.img.src = tileURL;
        		tile.img.style.width = this.mapScale.mapWidth+'px';
        		tile.img.style.height = this.mapScale.mapHeight+'px';
            tile.img.border = '0';
           };
        };
    };
    
    this.createDefaultMapSource = function(baseUrl) {    	
    	this.baseUrl = baseUrl;
    	this.mapSource = new MapSource('default', 'sq', 2000, '',
    		false, true, this.baseUrl, '');
    	this.mapSource.mapScales.push(new MapScale(5076, 2476, 1, 1, 1976, 57959, 0, 51191, '3', '3', 0, 0));
    	this.mapSource.mapScales.push(new MapScale(270, 372, 46, 17, 3072, 56897.75, 0, 51191, '4', '4', 0, 0));
    	this.mapSource.mapScales.push(new MapScale(540, 744, 46, 17, 3072, 56897.75, 0, 51191, '5', '5', 0, 0));
    	this.mapSource.mapScales.push(new MapScale(1080, 1488, 46, 17, 3072, 56897.75, 0, 51191, '6', '6', 0, 0));
    	
    	this.levelIndex = 4;
    	this.mapScale = this.mapSource.mapScales[this.levelIndex];
    	this.centerVertex.x = 44907;
    	this.centerVertex.y = 37804;    	
    };
    
    this.initWithDefaultMapSource = function(viewport_id, baseUrl) {
    	this.createDefaultMapSource(baseUrl);
    	this.init(viewport_id, baseUrl);    
    };
    
    this.init = function(mapApi) {
    	this.mapSource = new MapSource(mapApi.baseUrl);
    	this.mapDraw = mapApi.mapDraw;
   		this.viewport = mapApi.viewportLayer;
    	this.mapWidth = mapApi.granParentLayer.clientWidth == 0 ? parseInt(mapApi.granParentLayer.style.width) : mapApi.granParentLayer.clientWidth;
    	this.mapHeight = mapApi.granParentLayer.clientHeight == 0 ? parseInt(mapApi.granParentLayer.style.height) : mapApi.granParentLayer.clientHeight;
    	this.baseUrl = mapApi.baseUrl;
    	this.loadingImgUrl = this.baseUrl+'1.jpg';
    	
    	this.mapContainer = new MDiv('', "0px", "0px", 
    		"100%", "100%", "absolute", 0, ''); 
    	this.mapContainer.style.backgroundImage = "url(" + this.baseUrl + 'img/blue.gif' + ")";
		this.mapContainer.rect = {x: 0, y: 0};
		this.mapContainer.Items = [];
		this.mapContainer.bound = new Rectangle(0, 0, 0, 0);		
		    	
		this.tilesContainer = new MDiv('', "0px", "0px",
			'', '', "absolute", 0, ''); 
		this.mapContainer.appendChild(this.tilesContainer);
		this.viewport.appendChild(this.mapContainer);	
    };
    
    this.getviewportInfo = function() {
        var result = new ViewportInfo();
        result.width = this.mapWidth;
        result.height = this.mapHeight;
        result.centerVertex = this.centerVertex;
        return result;
    };
    
	this.openInfoWindowHtml = function(point, html, iconSize, option) {
		if (this.popup == null) {
      if (option == undefined) this.popup = new MapBubble(200, 100);
      else this.popup = new MapBubble(option.width, option.height);
      this.popup.enableStick(true);
			this.popup.init(this);
			this.viewport.appendChild(this.popup.obj);
		}
    else {
      this.viewport.removeChild(this.popup.obj);
      if (option == undefined) {
        this.popup.w = 200;
        this.popup.h = 100;
      }
      else {
        this.popup.w = option.width;
        this.popup.h = option.height;
      }
			this.popup.init(this);
			this.viewport.appendChild(this.popup.obj);
    }
		if (iconSize != undefined) {
			this.popup.iconSize = iconSize;
		}
		this.popup.setDisplay(2);
		this.popup.enableOpacity(false);
		this.popup.initContent(html, point);	
		this.popup.obj.style.display = "";	
	};
	
	this.updateInfo = function() {
		if (this.popup != undefined) {
			this.popup.updatePosition(true);
		}
	};
	
	this.updateInfoWindowHtml = function(point, html, iconSize) {
		if (this.popup != undefined) {
			if (iconSize != undefined) {
				this.popup.iconSize = iconSize;
			}			
			this.popup.setContent(html, point);
		} else {
			this.openInfoWindowHtml(point, html, iconSize);
		}
	};
	
	this.closeInfoWindow = function() {
		if (this.popup != undefined) {
			this.popup.obj.style.display = "none";
		};
	};  
    
    this.getScalePercentageCurrentLevelToHighLevel = function() {
        var lastScale  = mapSource.getLastLevel();
        if (lastScale == null) {
        	return 100;
        } else if (lastScale.totalWidth == 0) {
        	return 100;
        };
        return scale.totalWidth / lastScale.totalWidth;
    };
};

function MapDrawingController() {
	this.lines = new Array();
	this.icons = new Array();
	this.plots = new Array();
	this.color = "Black";
	this.dotColor = "Black";
	this.panelIcon = new MapIconController();
	this.panelLine = new MapLineController();
	this.panelDraw = new MapLineController();
	this.panelGeo = new MapGeofenceController();
	
	this.init = function (mapClient) {
		this.client = mapClient;
		this.panelIcon.init(mapClient);
		this.panelLine.init(mapClient);
		this.panelDraw.init(mapClient);
		this.panelDraw.liveMode = true;
		this.panelGeo.init(mapClient);
		this.panelDraw.panel.setLineWidth(2);
		this.panelDraw.setColor("red");		
		this.panelLine.setColor("blue");
		this.util = new MapUtil(mapClient);
	};
	
	this.panPanelByOffset = function(x, y) {
		this.panelIcon.panByOffset(x, y);
		this.panelLine.panByOffset(x, y);
		this.panelDraw.panByOffset(x, y);
		this.panelGeo.panByOffset(x, y);
	};
	
	this.stopDrawing = function() {		
		this.panelDraw.panel.endLine();
		this.getDistanceState();
		this.panelDraw.enableLiveDraw(false);
	};
	
	this.enableDot = function(values) {
		this.panelLine.dotMode = values;
	};
	
	this.clearDrawing = function() {
		this.panelDraw.deleteLines();
		this.panelDraw.panel.setPosX(0);
		this.panelDraw.panel.setPosY(0);
		this.panelDraw.panel.setSize(this.client.mapWidth, this.client.mapHeight);
		this.panelDraw.panel.setViewBox(0, 0, this.client.mapWidth, this.client.mapHeight);		
		
		this.getDistanceState();
		this.plots = new Array();		
	};

	this.enableOpacity = function(state) {
		if (state == true) {
			this.client.viewport.style.backgroundColor = "#FFFFFF";
			this.client.viewport.style.filter = "alpha(opacity=20)";
			this.client.viewport.style.MozOpacity = 2.0;
			this.client.viewport.style.opacity = 0.20;
		} else {
			this.client.viewport.style.backgroundColor = "";
			this.client.viewport.style.filter = "";
			this.client.viewport.style.MozOpacity = null;
			this.client.viewport.style.opacity = null;
		};
	};

	this.getCurrentPos = function(pos) {
		var _x = pos.x-this.client.mapWidth/2;
		var _y = pos.y-this.client.mapHeight/2;
		return {x : pos.x, y : pos.y, rx : _x, ry : _y};		
	};
	
	this.savePosition = function(pos) {
		var utm = this.client.mapScale.inflateVert(
			this.client.centerVertex, pos.rx, pos.ry);
		this.plots.push(utm);
	};
	
	this.addIcon = function(x, y, isCenter, showAllLevel) {
		if (isCenter == undefined) {
			isCenter = false;
		}
		return this.panelIcon.addIcon(x, y, isCenter, showAllLevel);
	};
  
  this.addMarker = function(marker) {
    return this.panelIcon.addMarker(marker);
  };
	
	this.addGeofence = function(x, y, r) {
		this.panelGeo.addGeofence(x, y, r);
	};
	
	this.addLine = function(point, color) {
		this.panelLine.addLine(point, color);
	};
	
	this.renderLine = function(point, color) {
		this.panelLine.render(point, color);
	};
	
	this.stopRenderLine = function() {
		this.panelLine.stopRender();
	};	
	
	this.addPoint = function(point, color) {
		this.panelLine.addPoint(point, color);
	};
	
	this.updatePanel = function () {
		this.panelIcon.updatePosition();
		this.panelLine.updatePosition();
		this.panelDraw.updatePosition();
		this.panelGeo.updatePosition();
		this.onCompleted.call();
	};
	
	this.setPosition = function(icon, x, y) {
		this.panelIcon.setPosition(icon, x, y);
	};
	
	this.getCenterLevel = function(mode) {
		if (mode == 2) {
			return this.util.getCenterLevel(this.panelIcon.icons);
		} else {
			return this.util.getCenterLevel(this.panelLine.points);
		}
	};
	
	this.draw = function(pos, buffer) {
		this.panelDraw.enableLiveDraw(true);
		var plot = this.getCurrentPos(pos);
		if (buffer == false) {
			this.savePosition(plot);
			this.panelDraw.points = new Array();
			this.panelDraw.addLine(this.plots);
			this.panelDraw.updatePosition();
			this.getDistanceState();
		} else {
			if (this.plots.length > 0) {			
				var tmp = this.client.vertexToScreen(this.plots[this.plots.length-1].x, 
					this.plots[this.plots.length-1].y);
				this.panelDraw.panel.clearShape();
				this.panelDraw.panel.startLine(tmp.x, tmp.y);
				this.panelDraw.panel.lineTo(plot.x, plot.y);
				this.panelDraw.panel.endLine();
				this.getDistanceState(plot);
			};
		};
	};
	
	this.getDistanceState = function(latestPos) {
		var dist = 0;
		for (var i=0,s=this.plots.length;i<s;i++) {
			if ((i+1) <= s-1) {
				dist += this.client.mapScale.getDistance(this.plots[i], 
					this.plots[i+1]);				
			};
		};
		if (latestPos != undefined) {
			var tmp = this.client.mapScale.inflateVert(
				this.client.centerVertex, latestPos.rx, latestPos.ry);
			dist += this.client.mapScale.getDistance(
				this.plots[this.plots.length-1], tmp);		
		};
		if (dist > 0) {
			if (this.divOutput != undefined || this.divOutput != null) {
				this.divOutput.innerHTML = "Distance&nbsp;:&nbsp;"+(dist/1000)+"&nbsp;km";
			} else {
				window.status = "Distance : "+(dist/1000)+" km";
			}					
		};
	};
	
	this.clear = function() {
		this.panelDraw.clear();
		this.panelIcon.clear();
		this.panelGeo.clear();
	};
	
	this.deleteAll = function() {
		this.panelDraw.deleteLines();
		this.panelLine.deleteLines();
		this.panelIcon.deleteIcons();		
		this.panelGeo.deleteGeos();
	};	
	
	this.deleteGeofences = function() {
		this.panelGeo.deleteGeos();
	};
	
	this.showStatusAt = function(div) {
		if (div == undefined || div == null) {
			return;
		}
		this.divOutput = div;
	};
};

function MapGeofenceController() {
	this.items = new Array();
	this.panel = null;
	this.mapClient = null;

	this.init = function(mapClient) {
		this.mapClient = mapClient;
		this.panel = new DrawingCanvas(mapClient.viewport);
		this.panel.setLineWidth("4");
		this.panel.container.style.zIndex = 7;
		this.panel.setLineColor("black");
		this.reset();
	};	
	
	this.clear = function() {
		this.reset();
		this.panel.clear();
		this.panel.setSize(this.mapClient.mapWidth, this.mapClient.mapHeight)
	};
	
	this.deleteGeos = function() {
		this.clear();
		this.items = new Array();		
	};

	this.reset = function() {
		this.panel.container.style.left = "0px";
		this.panel.container.style.top = "0px";
		this.panel.container.style.position = "absolute";		
	};	
	
	this.addGeofence = function(x, y, r) {
		this.items.push(new Array(x,y,r));
	};
	
	this.updatePosition = function() {
		this.clear();
		var fs = 11;
		switch (this.mapClient.levelIndex) {
			case 3:
				fs = 14; break;
			case 4:
				fs = 16; break;
			case 5:
				fs = 18; break;
		}
		//var fs = (this.mapClient.levelIndex + 1) * 5;
		for (var j=0, csum=this.items.length; j<csum; j++) {
			var pt = this.mapClient.vertexToScreen(this.items[j][0], this.items[j][1]);
			var r= Math.abs(this.items[j][2]/this.mapClient.mapScale.scaleValue());
			r = Math.round(r);			
			this.panel.createGeofence(parseInt(pt.x), parseInt(pt.y), r, this.items[j][2], fs);
		};
	};
	
	this.panByOffset = function(pX, pY) {
		var _x = parseInt(this.panel.container.style.left);
		var _y = parseInt(this.panel.container.style.top);
		if (!isNaN(_x) && !isNaN(_y)) {
		    this.panel.container.style.left = (_x + pX) + 'px';
		    this.panel.container.style.top = (_y + pY) + 'px';
		};
	};	
};

function MapLineController() {
	this.color = "blue";
	this.points = new Array();
	this.colors = new Array();
	this.dotMode = false;
	this.liveMode = false;
	this.panel = null;
	this.width = "4";	
	this.zIndex = 7;
	this.mapLevel = -1;
	this.mapClient = null;
	
	this.nSize = new Point(0,0);
	this.nPos = new Point(0,0);
	this.nTopLeft = new Vertex(0,0);
	this.liveDraw = false;
	this.running = true;
	this.simplify = new DPSimplifier();
	
	this.init = function(mapClient) {
		this.mapClient = mapClient;
//		this.mapLevel = mapClient.levelIndex;
		this.panel = new DrawingCanvas(mapClient.viewport);
		this.panel.setLineWidth(this.width);
		this.panel.container.style.zIndex = this.zIndex;
		this.reset();
	};
	
	this.enableLiveDraw = function(cond) {
		if (cond != undefined) {
			this.liveDraw = cond;
		}
	};
	
	this.setColor = function(color) {
		if (color != undefined) {
			this.color = color;
		}
	};
	
	this.deleteLines = function() {
		this.clear();
		this.points = new Array();
	};
	
	this.clear = function() {
		this.reset();
		this.panel.clear();
	};
	
	this.reset = function() {
		this.panel.container.style.left = "0px";
		this.panel.container.style.top = "0px";
		this.panel.container.style.position = "absolute";		
	};
	
	this.stopRender = function() {
		this.running = false;
		this.deleteLines();		
	};
	
	this.addLine = function(points, _color) {
		this.points.push(new Array(points, _color));
		//this.updatePosition();
	};
	
	this.inViewPort = function(point) {
	    var pt = this.mapClient.mapScale.utmToPixel(point.x, point.y);
	    var w0 = this.mapClient.mapWidth / 2;
	    var h0 = this.mapClient.mapHeight / 2;
	    if ((this.mapClient.mapWidth+w0 > pt.x && pt.x > -w0)
	    	&& (this.mapClient.mapHeight+h0 > pt.y && pt.y > -h0)
	    	&& !isNaN(pt.x) && !isNaN(pt.y)) {
	    	return true;
	    }
	    return false;
	};
	
	this.createArrow = function(pos0, pos1, color) {
	  	var headLength = 8;
	  	var delta = new Point(pos1.x - pos0.x, pos1.y - pos0.y);
	  	var sqrt = Math.sqrt(Math.pow(delta.x,2) + Math.pow(delta.y,2));  	
	  	var unitDelta = new Point(delta.x / sqrt, delta.y / sqrt);
	  	var base = new Point(pos1.x - (headLength * unitDelta.x), pos1.y - (headLength * unitDelta.y));
	  	var normalDelta = new Point(delta.y, -delta.x);
	  	var sqrtNormalDelta = Math.sqrt(Math.pow(normalDelta.x,2) + Math.pow(normalDelta.y,2));
	  	var unitNormalDelta = new Point(normalDelta.x / sqrtNormalDelta, normalDelta.y / sqrtNormalDelta);
	  	
	  	var pts2 = pos1;
	  	var pts1 = new Point(base.x + (headLength * unitNormalDelta.x), base.y + (headLength * unitNormalDelta.y));
	  	var pts3 = new Point(base.x - (headLength * unitNormalDelta.x), base.y - (headLength * unitNormalDelta.y)); 
		this.panel.createFullArrow(pts1, pts2, pts3, color);
	};
	
	this.draw = function(points) {
		this.nSize = new Vertex(0,0);
		this.nPos = new Vertex(0,0);
		var tolerance = 30;
		var pt = "", r =0, idx = 0, lastPos = new Vertex(0,0), i = 0, sum=points.length;
		this.simplify.distanceTolerance = this.mapClient.mapScale.scaleValue() / 2;		
		this.panel.clearFullArrow();
		while (this.running && i<sum) {
		//for (var i=0, sum=points.length; i<sum; i++) {			
			if (points[i][1] == undefined) {
				points[i][1] = this.color; 
			}
			this.panel.setLineColor(points[i][1]);
				
			//var x = this. //points[i][0]
			if (points[i][0] != undefined && points[i][0].length != undefined) {
				this.simplify.pts = points[i][0];
				var mpoints = this.liveDraw == true ? points[i][0] : this.simplify.simplify();
							
				for (var j=0, jsum=mpoints.length; j<jsum; j++) {
					if (mpoints[j].x == undefined 
						|| mpoints[j].y == undefined) {
						continue;
					}
					//if (this.inViewPort(this.points[i][0][j])) {
						pt = this.mapClient.vertexToScreen(mpoints[j].x, mpoints[j].y);
						if (!isNaN(pt.x) && !isNaN(pt.y)) {
							if (j == 0) {
								this.panel.startLine(pt.x, pt.y);
							} else if (lastPos.x != pt.x && lastPos.y != pt.y) {
								this.panel.lineTo(pt.x, pt.y);
								var delta = new Point(pt.x - lastPos.x, pt.y - lastPos.y);
								var hypothenuse = Math.sqrt(Math.pow(delta.x,2) + Math.pow(delta.y,2));
								if(hypothenuse >= tolerance) {
									this.createArrow(lastPos, pt, "red");
								}
							};							
							if (pt.x > this.nSize.x) this.nSize.x = pt.x;
							if (pt.y > this.nSize.y) this.nSize.y= pt.y;
							if (parseInt(pt.x) < this.nPos.x) this.nPos.x = pt.x;
							if (parseInt(pt.y) < this.nPos.y) this.nPos.y = pt.y;												
							lastPos = pt;
							//alert('a');
						}
					//}
				};								
				this.panel.endLine();
			};
			i++;			
		}
		
		if (this.liveDraw == false) 
		{
			/*if (!isNaN(this.nPos.x) && this.nPos.x < 0) {
				this.panel.setPosX(this.nPos.x);
			}
			if (!isNaN(this.nPos.y) && this.nPos.y < 0) {
				this.panel.setPosY(this.nPos.y);
			}*/
			this.nSize = OffsetPoint(this.nSize, -this.nPos.x, -this.nPos.y);
			this.nTopLeft = this.mapClient.screenToVertex(this.nPos);
			if (this.nSize.x > 0 && this.nSize.y > 0) {
				this.panel.setSize(this.nSize.x, this.nSize.y);
				this.panel.setViewBox(this.nPos.x, this.nPos.y, this.nSize.x, this.nSize.y);
			} else {
				this.panel.setSize(this.mapClient.mapWidth, this.mapClient.mapHeight);
			}			
		}
	};
	
	this.render = function(point, color) {
		var tmp = new Array(point, color);
		this.draw(new Array(tmp));
		this.points.push(tmp);
		this.mapLevel = this.mapClient.levelIndex;		
		//this.updatePosition();
		if (this.liveMode == false 
			&& this.nTopLeft.x != 0 && this.nTopLeft.y != 0) {
			this.reset();
			var pos = this.mapClient.vertexToScreen(this.nTopLeft.x, this.nTopLeft.y);
			if (!isNaN(pos.x)) this.panel.setPosX(pos.x);
			if (!isNaN(pos.y)) this.panel.setPosY(pos.y);
		}		
	};
	
	this.updatePosition = function() {		
		if (this.mapClient.levelIndex < 4) {
			this.panel._dotMode = false;
		} else {
			this.panel._dotMode = this.dotMode; 
		}	
	//	var diffLevel = false;
		if ((this.mapLevel != this.mapClient.levelIndex || this.liveDraw == true) 
			&& (this.mapClient.mapScale != null 
			&& this.points.length > 0)) {
			this.clear();
			this.draw(this.points);
			this.mapLevel = this.mapClient.levelIndex;
			diffLevel = true;
		}
		
		//window.status = this.nTopLeft.x + " : " + this.nTopLeft.y;
		if ((!this.liveDraw || (this.liveMode && !diffLevel)) 
			&& this.nTopLeft.x != 0 && this.nTopLeft.y != 0 && BrowserDetect.browser == 'Firefox') {
			this.reset();
			var pos = this.mapClient.vertexToScreen(this.nTopLeft.x, this.nTopLeft.y);
			if (!isNaN(pos.x)) this.panel.setPosX(pos.x);
			if (!isNaN(pos.y)) this.panel.setPosY(pos.y);
			/*
			if (this.nSize.x > 0 && this.nSize.y > 0) {			
				this.panel.setSize(this.nSize.x, this.nSize.y);
				this.panel.setViewBox(pos.x, pos.y, this.nSize.x, this.nSize.y);
			}
			*/		
		}
	};
	
	this.panByOffset = function(pX, pY) {
		var _x = parseInt(this.panel.container.style.left);
		var _y = parseInt(this.panel.container.style.top);
		if (!isNaN(_x) && !isNaN(_y)) {
		    this.panel.container.style.left = (_x + pX) + 'px';
		    this.panel.container.style.top = (_y + pY) + 'px';
		};
	};
};

function MapIconController() {
	this.icons = new Array();
	this.mapClient = null;
	this.zIndex = 9;
  this.markers = new Array();
	
	this.init = function(mapClient) {
		this.mapClient = mapClient;
	};
	
	this.addIcon = function(x, y, isCenter, showAllLevel) {		
		var ico = new MapIcon(x, y, this.zIndex, this.mapClient, isCenter, showAllLevel);
		this.icons.push(ico);
		//this.updatePosition();
		return ico;
	};
  
  this.addMarker = function(marker) {
    var ico = new MapIcon(marker.x, marker.y, this.zIndex, this.mapClient, false, true, marker.image, marker.obj, marker.size, marker.move);
		if (marker.po != null) ico.po = marker.po;
    this.icons.push(ico);
    return ico;
  };
  
	this.updatePosition = function() {
		if (this.icons.length > 0) {
			this.clear();
		};
		if ((this.mapClient.levelIndex > -1 && this.mapClient.mapDraw.panelLine.points.length > 0)
			|| this.mapClient.mapDraw.panelLine.points.length == 0) {
			for (var i=0, sum=this.icons.length; i<sum; i++) {
				this.icons[i].updatePosition();
				/*
				if (this.icons[i].updatePosition() == true) {
					this.mapClient.viewport.appendChild(this.icons[i].obj);
				};
				*/
			};
		};
	};
	
	this.setPosition = function (icon, x, y) {
		icon.x = x;
		icon.y = y;
		icon.updatePosition();
	};
	
	this.panByOffset = function (x, y) {
		for (var i=0, sum=this.icons.length; i<sum; i++) {
			this.icons[i].offsetPosition(x, y);	
		};
	};

	this.clear = function() {
		for (var i=0, sico=this.icons.length; i<sico; i++) {
			for (var j=0; j<this.mapClient.viewport.childNodes.length; j++) {
				if (this.icons[i].obj == this.mapClient.viewport.childNodes[j]) {
					this.mapClient.viewport.removeChild(this.icons[i].obj);
					break;	
				}			
			}
		}		
	};
	
	this.deleteIcons = function() {
		this.clear();
		this.icons = new Array();		
	};
};

function MapIcon(x, y, zIndex, mapClient, isCenter, hideLevel, image, obj, size, move) {
	this.x = x;
	this.y = y;
	this.move = move;
	this.popupContent = "";
	this.mapClient = mapClient;
  if (image == undefined) this.image = getBaseUrl() + "img/mappointer/star200.gif";
  else this.image = image;
  this.obj = obj;
  this.obj.mapIcon = this;        
  this.popup = null;
  this.isCenter = isCenter;
  this.hideLevel = hideLevel;
  this.gMarkerBound = new Rectangle(350, 250, this.mapClient.mapWidth-350, this.mapClient.mapHeight-250);
  this.isDisplayed = true;
  this.size = size;
	
	this.setUrl = function(url) {
    var tmp = document.createElement('img');
    tmp.src = url;
    var w = tmp.width;
    var h = tmp.height;
		this.obj.src = url;
		w = w % 2 == 0 ? w : w + 1;
		h = h % 2 == 0 ? h : h + 1;
		if (w > 0 && h > 0) {
			this.size = new Point(w, h);
    		this.obj.style.width = w + "px";
    		this.obj.style.height = h + "px";
		};		
	};
	
	this.setDisplay = function(cond) {
		this.isDisplayed = cond;
		this.updatePosition();
	};
	
	this.setPosition = function (x, y, updateCenterMap) {
		this.x = x;
		this.y = y;
		this.updatePosition(updateCenterMap);
	};	
		
	this.updatePosition = function(updateCenterMap) {
		if (this.hideLevel != undefined) {
			for (var j=0, d=this.hideLevel.length; j<d; j++) {
				if (this.mapClient.levelIndex == this.hideLevel[j]) {
					return;
					//this.isDisplayed = false;
				}
			}
		}
		var pos = new Point(0,0);
	    var pt = this.mapClient.vertexToScreen(this.x, this.y);
	    if ((this.mapClient.mapWidth > pt.x && pt.x > -10)
	    	&& (this.mapClient.mapHeight > pt.y && pt.y > -10)
	    	&& !isNaN(pt.x) && !isNaN(pt.y)) {
	    	if (this.isCenter) {
	    		pos.x = parseInt(this.obj.style.width)/2;
	    		pos.y = parseInt(this.obj.style.height)/2;
	    	} else {
					pos.x = parseInt(this.obj.style.width)/2 - 2;
					pos.y = parseInt(this.obj.style.height);
	    	}
				if (this.po == null)
				{
					this.obj.style.left = (pt.x - pos.x) + "px";
					this.obj.style.top  = (pt.y - pos.y) + "px";
				}
				else
				{
					this.obj.style.left = (pt.x - pos.x - this.po.x) + "px";
					this.obj.style.top  = (pt.y - pos.y - this.po.y)	 + "px";
				}
		    var _isExist = this.isExist();
			
		    if (!_isExist && this.isDisplayed) {
		    	this.mapClient.viewport.appendChild(this.obj);
		    } else if (_isExist && !this.isDisplayed && !this.move) {
		    	this.mapClient.viewport.removeChild(this.obj);
		    }
	    	return true;
	    };
	    if (updateCenterMap == true) {
	    	var x = this.gMarkerBound.right < pt.x ? -(pt.x - this.gMarkerBound.right) :
	    		this.gMarkerBound.left > pt.x ? -(pt.x - this.gMarkerBound.left) : 0;
	    	var y = this.gMarkerBound.top > pt.y ? -(pt.y - this.gMarkerBound.top) :
	    		this.gMarkerBound.bottom < pt.y ? -(pt.y - this.gMarkerBound.bottom) : 0;
	    	this.mapClient.panMapByOffset(x, y); 
	    }
	    
	    return false;
	};
	
	this.isExist = function() {
		var child = this.mapClient.viewport.childNodes;
		for (var j=0; j<child.length; j++) {
			if (this.obj == child[j]) {
				return true;
			}
		}	
		return false;	
	};
	
	this.offsetPosition = function(pX, pY) {
		var _x = parseFloat(this.obj.style.left);
		var _y = parseFloat(this.obj.style.top);
		if (!isNaN(_x) && !isNaN(_y)) {
		    this.obj.style.left = (_x + pX) + 'px';
		    this.obj.style.top = (_y + pY) + 'px';
		};
	};
	
	this.openInfoWindowHtml = function(html) {
		this.mapClient.openInfoWindowHtml(new Vertex(this.x, this.y), html, this.size);
	};
	
	this.updateInfoWindowHtml = function(html) {
		this.mapClient.updateInfoWindowHtml(new Vertex(this.x, this.y), html, this.size);
	};
	
	this.closeInfoWindow = function() {
		this.mapClient.closeInfoWindow();
	};
};


function MapBubble(w, h) {
	this.obj = null;
	this.content = null;
	this.mapClient = null;
	this.point = null;
	this.w = w; 
	this.h = h;	
	this.pos = 1;
	this.useStick = false;
	this.iconSize = new Point(17, 17);
	
	this.initContent = function(info, pt) {
		this.setContentHTML(info, pt);
		this.updatePosition(false);
	};
	
	this.setContent = function(info, pt) {
		this.setContentHTML(info, pt);
		this.updatePosition(true);
	};
	
	this.setContentHTML = function(info, pt) {
		this.point = pt;
		this.content.innerHTML = info;
		this.obj.style.display = "";
		this.obj.style.position = "absolute";		
	};
	
	this.setPosition = function(pt) {
		this.point = pt;
		this.updatePosition(false);
	};
	
	this.enableOpacity = function(cond) {
		if (cond == true) {
			this.obj.style.backgroundColor = "#FFFFFF";
			this.obj.style.filter = "alpha(opacity=75)";
			this.obj.style.MozOpacity = 7.5;
			this.obj.style.opacity = 0.75;
		} else {
			this.obj.style.backgroundColor = "";
			this.obj.style.filter = "";
			this.obj.style.MozOpacity = null;
			this.obj.style.opacity = null;
		};		
	};
	
	this.setDisplay = function(pos) {
		this.pos = pos;
	};
	
	this.enableStick = function(pos) {
		this.useStick = pos;
	};
	
	this.init = function(mapClient) {
		this.mapClient = mapClient;
		this.obj = new MDiv();
		this.obj.style.zIndex = 10;
		this.obj.style.width = this.w + 'px';
		this.obj.style.height = this.h + 'px';
		
		this.stick = new Point(34, 32);
		var sizeB = new Point(8, 8); 
		var topLeft = new Point(0, 0);
		var dwnRight = new Point(this.w-sizeB.x, this.h-sizeB.y);
		var tl = this.coreBnd(sizeB, topLeft, topLeft, "small_top_left.gif");
		var tr = this.coreBnd(sizeB, new Point(dwnRight.x, topLeft.y), topLeft, "small_top_right.gif");
		var bl = this.coreBnd(sizeB, new Point(topLeft.x, dwnRight.y), topLeft, "small_btm_left.gif");
		var br = this.coreBnd(sizeB, dwnRight, topLeft, "small_btm_right.gif");
		var c0 = this.coreBnd(this.stick, new Point(this.w/2.03 - this.stick.x/2.83, dwnRight.y), topLeft, "small_arr.gif");
		this.exBtn = this.coreBnd(new Point(14,13), new Point(dwnRight.x-13, 10), topLeft, "cl_grey.png");
    
		this.exBtn.style.cursor = "pointer";
		this.exBtn.o = this;
		this.exBtn.onclick = function() {
			if (this.o.obj.style.display == "") {
				this.o.obj.style.display = "none";
			} else {
				this.o.obj.style.display = "";
			}
		};
		
		var w_ = document.namespaces && document.namespaces.add ? 2 : 2;
		var h_ = document.namespaces && document.namespaces.add ? 25 : 24;
		var y_ = document.namespaces && document.namespaces.add ? 0 : 1;
		
    var tb = new MDiv();
    tb.style.cssText = "border-top: 1px solid rgb(171, 171, 171); " +
      "position: absolute; left: " + sizeB.x + "px; top: 0px; width: " + (this.w-sizeB.x*2) +"px;" +
        "height: " + sizeB.y + "px; background-color: white; font-size: 0px;";
    var mb = new MDiv();
    mb.style.cssText = "border-left: 1px solid rgb(171, 171, 171); " +
      "border-right: 1px solid rgb(171, 171, 171); " +
        "position: absolute; left: "+ topLeft.x +"px; top: " + topLeft.y+sizeB.y + "px; width: " 
        + (this.w-w_) + "px;" + "height: " + (dwnRight.y-sizeB.y) 
        + "px; background-color: white;";
    var bb = new MDiv();
    bb.style.cssText = "border-bottom: 1px solid rgb(171, 171, 171); " +
      "position: absolute; left: " + sizeB.x + "px; top: " + parseInt(dwnRight.y-y_)  + "px;" +
        "width: " + (this.w-sizeB.x*2) + "px; height: " + sizeB.y + "px; background-color: white; font-size: 0px;";
    this.content = new MDiv();
    this.content.style.cssText = "position: absolute; left: " + sizeB.x + "px; top: " + sizeB.y + "px; " +
      "width: " + (this.w-sizeB.x*2-14) + "px; height: " + (this.h-sizeB.y*2) + "px; z-index: 10;";
		
		this.obj.appendChild(tl); this.obj.appendChild(tr);
		this.obj.appendChild(bl); this.obj.appendChild(br);
		this.obj.appendChild(tb); this.obj.appendChild(mb); 
		this.obj.appendChild(bb); 
		this.obj.appendChild(this.exBtn);
		this.obj.appendChild(this.content);
		if (this.useStick) {
			this.obj.appendChild(c0);
		};	
	};
	this.coreBnd = function(size, posDiv, posImg, url) {
		var d = new MDiv('', posDiv.x + "px", posDiv.y + "px", 
			size.x + "px", size.y + "px", "absolute", 0, '', true); 
    var base_url = getBaseUrl();
		var i = new MImg('', 
			base_url + "dragmap/images/" + url, posImg.x + 'px',
			posImg.y + 'px', '', '', "absolute"); 
		i.border = '0';
		d.appendChild(i);
		return d;
	};	
	
	this.panByOffset = function(pX, pY) {
		var _x = parseInt(this.obj.style.left);
		var _y = parseInt(this.obj.style.top);
		if (!isNaN(_x) && !isNaN(_y)) {
		    this.obj.style.left = (_x + pX) + 'px';
		    this.obj.style.top = (_y + pY) + 'px';
		};
	};
	
	this.updatePosition = function(fromDrawer) {
		var diff = new Vertex(0,0), _ptx, _pty;
		var pt = this.mapClient.vertexToScreen(this.point.x, this.point.y);
		if (pt.x == null || pt.y == null) {
			return;
		};
		var left = pt;
		var right = left;
		var h = (this.useStick ? this.h + this.stick.y : this.h);
		_pty = new Point(this.w, h);
		switch(this.pos) {
			case 4:
				_ptx = new Point(-(this.w/2), -(h/2)+this.iconSize.y);
				break;			
			case 3:
				_ptx = new Point(-this.w-this.iconSize.x/2, -(h)+(h-this.iconSize.y));
				break;
			case 2:
        _pty = new Point(this.w, 0);
				_ptx = new Point(-(this.w/2) + 15, -(h)-this.iconSize.y/2);
				break;
			case 1:
			default:
				_ptx = new Point(this.iconSize.x/2, -(h)+(h-this.iconSize.y));
				break;
		};
		left = OffsetPoint(left, _ptx.x, _ptx.y);
		right = OffsetPoint(right, _pty.x, _pty.y);
		if (!isNaN(left.x)) this.obj.style.left = left.x + "px";
		if (!isNaN(left.y)) this.obj.style.top = left.y + "px";
		
		if (fromDrawer == false) {
		    if (this.mapClient.mapWidth < right.x) {
		    	diff.x = -(right.x - this.mapClient.mapWidth + 10);
		    };
			if (this.mapClient.mapHeight < right.y) {
				diff.y = -(right.y - this.mapClient.mapHeight - 10);
			};
			if (left.x < 25) {
				diff.x = Math.abs(left.x) + 25;
			};
			if (left.y < 10) {
				diff.y = Math.abs(left.y) + 20;
			};
			//this.mapClient.moveViewportPosition(diff.x, diff.y);
			this.mapClient.panMapByOffset(diff.x, diff.y);
			//this.panByOffset(diff.x, diff.y);
		};
	};
};

function MapThumbnail(w, h, viewportLayer) {
	this.width = w;
	this.height = h;
	this.baseUrl = "";
	this.mapApi = null;
	this.tmpSize = new Point(0, 0);
	
	this.init = function(w, h, mapApi) {
		this.width = w;
		this.height = h;		
		this.mapApi = mapApi;
		this.baseUrl = mapApi.baseUrl;
		this.wFac = w / 20;
		this.hFac = h / 20;
		
		this.thumbNailPanel = new MDiv();
		this.thumbNailPanel.style.cssText = "border-top: 1px solid " +
			"rgb(151, 151, 151); border-left: 1px solid " +
			"rgb(151, 151, 151); overflow: hidden; width: " + w + "px; " +
			"height: " + h + "px; background-color: white; z-index:11;" +
			"position: absolute; right: -1px; bottom: -1px;";
    if (document.namespaces && document.namespaces.add) {
      this.thumbNailPanel.style.cursor = "url('" + this.baseUrl + "img/openhand.cur'), default";			
    } else {
      this.thumbNailPanel.style.cursor = "-moz-grab";	
    };
		this.mapPanel = new MDiv();
		this.mapPanel.style.cssText = "position:absolute; left:3px; top:3px;" +
			"border-top:1px solid rgb(151, 151, 151); border-left:" +
			"1px solid rgb(151, 151, 151); z-index:1;";
		/*this.btnShow = new MImg();
		this.btnShow.style.cssText = "position: absolute; right: 0px; " +
			"bottom: 0px; cursor:pointer; z-index:11;";
		this.btnShow.src = this.baseUrl + "img/thumb_max.gif";
		this.btnShow.o = this;
		this.btnShow.onclick = function() {
			var me = this;
			if (this.o.tmpSize.x >= this.o.width 
				&& this.o.tmpSize.y >= this.o.height) {
				this.o.display(false);
			} else {
				this.o.display(true);
			};
		};*/		
		
		this.thumbNailControl = new MDiv();
		var map = new MImg();
		map.src = this.baseUrl + "img/thumbnail.gif";
		this.mapPanel.appendChild(map);
		this.thumbNailPanel.appendChild(this.mapPanel);
		this.thumbNailPanel.appendChild(this.thumbNailControl);
		mapApi.parentLayer.appendChild(this.thumbNailPanel);
    this.updateThumbNailControl();
		//mapApi.parentLayer.appendChild(this.btnShow);		
	};
		
	this.display = function(vars) {
		if (vars == true) {
			this.tmpSize.x += this.wFac; this.tmpSize.y += this.hFac;
		} else {
			this.tmpSize.x -= this.wFac; this.tmpSize.y -= this.hFac;
		};
		this.thumbNailPanel.style.width = this.tmpSize.x +'px';
		this.thumbNailPanel.style.height = this.tmpSize.y +'px';
		if ((this.tmpSize.x > 0 && this.tmpSize.y > 0 && vars == false) 
			|| (this.width+5 >= this.tmpSize.x 
				&& this.height+5 >= this.tmpSize.y && vars == true)) {
			var me = this;
			setTimeout(function() {
				me.display(vars);
			}, 5);
		} else {
			if (vars == true) {
				this.btnShow.src = this.baseUrl + 'img/thumb_min.gif';
			} else {
				this.btnShow.src = this.baseUrl + 'img/thumb_max.gif';
			};
		};
	};	
	
	this.updateThumbNailControl = function() {
		if (this.thumbNailPanel == null || this.mapApi.mapClient == undefined) {
			return;
		}		
		//var sc = this.mapApi.mapClient.mapSource.mapScales[2];
		var scale = new MapScale(this.width, this.height, 1, 1, 
			341963.83, 398341.80, 0, 162948.46);
		
		var pt = scale.utmToPixel(this.mapApi.mapClient.centerVertex.x, 
			this.mapApi.mapClient.centerVertex.y);

		var l = pt.x - 7.5, t = pt.y, w = 15, h = 15;
		this.thumbNailControl.style.cssText = "width: " + w + "px; " +
				"height: " + h + "px; left:" + l + "px; top: " + t + "px; " +

				"z-index:2; border-style: solid; border-color: rgb(136, 136, 255); " +
				"border-width: 2px; position: absolute; cursor: move; background-image:url(" + this.baseUrl + 'img/x.gif' + ")";
		this.thumbNailPanel._api = this.mapApi;
		this.thumbNailPanel._scale = scale;
		this.thumbNailPanel._parent = this;
		this.thumbNailPanel.onmousedown = this.onPanelMouseDown;		
		this.thumbNailPanel.onmousemove = this.onPanelMouseMove;
		this.thumbNailPanel.onmouseup = this.onPanelMouseClick;
		this.thumbNailPanel.onmouseout = this.onPanelMouseClick;		
	};
	
	this.onPanelMouseClick = function(e) {
		if (this.panelDrag == true) { 
			var pos = getCursorPos(e, this._parent.mapPanel);
			var p = this._scale.pixelToUtm(pos.x - 5 + 7.5, pos.y - 5);
			this._api.setCenterVertex(p);
			this._parent.updateThumbNailControl();
			this.panelDrag = false;
		}
	};
	
	this.onPanelMouseDown = function(e) {
		this.panelDrag = true;
	};
			
	this.onPanelMouseMove = function(e) {
		if (!this.panelDrag) {
			return;
		}
		var pos = getCursorPos(e, this._parent.mapPanel);
		this._parent.thumbNailControl.style.left = (pos.x - 5) + 'px';
		this._parent.thumbNailControl.style.top = (pos.y - 5) + 'px';
	};	
			
};

function MapApiController() {
	this.mapClient = new MapClient();
	this.mapDraw = new MapDrawingController();	
	this.mapThumb = new MapThumbnail();
	this.drawMode = false;
	this.dragging = true;
	this.autoLevel = false;
	
	function onMouseDblClick(e)	{
		if (this._p.drawMode == true){
			this._p.enableDrawCursor(false);
			this._p.setCursor(false);
			this._p.mapDraw.stopDrawing();
		};
		this._p.drawMode = false;
	};
	
	function onMouseDown(e)	{
		var pos = getCursorPos(e, this._p.granParentLayer);
		this.startX = pos.x;
		this.startY = pos.y;
		this.firstX = pos.x;
		this.firstY = pos.y;
		if (window.Event) {
			if (e.which == 2 || e.which == 3) {
				return;
			};
		} else if (event.button == 2 || event.button == 3) {
		    return;
		};
		this.dragging = this._p.dragging ? true : false;
		if (this.dragging == true) {
			this._p.setCursor(false);
		};
		if (this._p.drawMode == true) {
			this._p.enableDrawCursor(true);
			this._p.mapDraw.draw(pos, false);
			this.dragging = false;
		};
	};
	
	function onMouseMove(e)	{
		if (!this._p.drawMode && !this.dragging) {
			return;
		};
		var pos = getCursorPos(e, this._p.granParentLayer);
		var moveX = pos.x;
		var moveY = pos.y;
		if (this._p.drawMode == true) {
			this.dragging = false;
			this._p.enableDrawCursor(true);
			this._p.mapDraw.draw(pos, true);						
		};
		if (this.dragging == true) {			
			this._mapClient.moveViewportPosition(moveX-this.startX, moveY-this.startY);
			if (this._p.mapDraw != undefined) {
				this._p.mapDraw.panPanelByOffset(moveX-this.startX, moveY-this.startY);
			};			
			this.startX = pos.x;
			this.startY = pos.y;					
		};
	};
	
	function onMouseUp(e) {
		if (this.dragging == true) {			
			var pos = getCursorPos(e, this._p.granParentLayer);
			if (pos.x == this.firstX && pos.y == this.firstY) {
				this.dragging = false;
				return;
			};
			this._p.setCursor(true);
			this.dragging = false;
			moveStarPosition(this._mapClient,pos,this._p);
	  		this._mapClient.panMapByOffset(pos.x-this.startX, pos.y-this.startY);
			if(this._p.mapDraw!=undefined){
				this._p.mapDraw.panPanelByOffset(pos.x-this.startX, pos.y-this.startY);
			}	  			  					
	  		this._p.mapThumb.updateThumbNailControl();
						
		};
		this._p.revertContainer();
	};
	
	function onMapCompleted() {
		//window.status = "selesai";
	};
	
	function onDrawCompleted() {
		//alert("Draw COmpleted");
	};

	this.initController = function() {
		this.dragImgUrl = this.baseUrl + 'img/x.gif';
		this.dragArea = new MDiv('', '', '', "100%", "100%", "relative", 8, '');
		if (navigator.appVersion.indexOf('MSIE') != -1) this.dragArea.style.backgroundImage = "url(" +this.dragImgUrl + ")";
		this.dragArea._p = this;
		this.dragArea._mapClient = this.mapClient;
		this.dragArea.onmousedown = onMouseDown;		
		this.dragArea.onmousemove = onMouseMove;

		this.dragArea.onmouseup = onMouseUp;
		this.dragArea.onmouseout = onMouseUp;	
		this.dragArea.ondblclick = onMouseDblClick;
		this.viewportLayer.appendChild(this.dragArea);
		this.setCursor(true);
		//this.initLevelControl();
		//this.initZoomControl();
		this.loadingLayer = new MDiv('', '0px', '0px', '100%', '100%', 'absolute', 12, '');
		this.loadingLayer.style.backgroundImage = "url(" + this.baseUrl + 'img/blue.gif' + ")";
		this.loadingLayer.innerHTML = "Loading ...";
		this.loaderImg = new MImg('', this.baseUrl + "img/loading.gif", 
			(this.mapClient.mapWidth/2) - 50 + "px", 
			(this.mapClient.mapHeight/2) - 50 + "px", '', '', "absolute");
		this.loaderImg.style.display = "none";	
		this.parentLayer.appendChild(this.loaderImg);
		var logos = new MapLogo().init(this.mapClient, this);
		//this.parentLayer.appendChild();
		//this.parentLayer.appendChild(this.loadingLayer);		
	};
	
	this.revertContainer = function() {
		this.viewportLayer.style.height = "100%";
		this.parentLayer.style.height = "100%";
	};
	
	this.initContainer = function(parent_id) {
		this.granParentLayer = document.getElementById(parent_id);
		this.granParentLayer.setAttribute("onmousedown", "if (typeof event.preventDefault != 'undefined') {" +
				"event.preventDefault();}"); 
		if(!window.addEventListener){ 
			this.granParentLayer.attachEvent('onselectstart', function() {return false;});
		}
		this.parentLayer = new MDiv();
		this.viewportLayer = new MDiv('', "0px", "0px", "100%", "100%", "absolute", '', '', true);
		this.parentLayer.appendChild(this.viewportLayer);
		this.granParentLayer.appendChild(this.parentLayer);		
	};

	this.setMapSize = function(width, height) {		
		this.granParentLayer.style.width = width +"px";
		this.granParentLayer.style.height = height +"px";
		this.mapClient.mapWidth = width;
		this.mapClient.mapHeight = height;
		this.mapClient.drawMap();
	};
	
	this.setAutoLevel = function(value) {
		if (value == true || value == false) {
			this.autoLevel = value;
		}
	};
	
	this.setCursor = function(openx) {				
		if (openx == true) {
			if (document.namespaces && document.namespaces.add) {
				this.dragArea.style.cursor = "url('" + this.baseUrl + "img/openhand.cur'), default";			
			} else {
				this.dragArea.style.cursor = "-moz-grab";	
			};
		} else if (openx == false) {
			if (document.namespaces && document.namespaces.add) {
				this.dragArea.style.cursor = "url('" + this.baseUrl + "img/closehand.cur'), default";
			} else {
				this.dragArea.style.cursor = "-moz-grabbing";	
			};
		};
	};
	
	this.enableDrawCursor = function(openx) {
		if (openx == true) {
			this.dragArea.style.cursor = "move";
		} 
	};	
	
	this.setMapSource = function(mapName){
		this.mapClient.setMapSource(mapName, this.autoLevel);		
	};
	
	this.enableDragging = function(cond) {
		this.dragging = cond;
	};
	
	this.setCenterVertex = function(vertex) {
		if (vertex.x == 0 && vertex.y == 0) {
			return;
		}
		this.mapClient.setCenterVertex(vertex);
		this.mapClient.drawMap();
	};
	
	this.setLevelIndex = function(level) {
		this.mapClient.changeLevel(level);
		if (this.navigation != undefined 
			|| this.navigation != null) {
			this.navigation.getSelectedController(this.navigation.btnLevel, this.mapClient.levelIndex);
		}
	};
	
	this.addControl = function(control) {
		if (control == null || control == undefined
			|| control.navigation == undefined) {
			return;
		};
		control.navigation.init(this.mapClient, this);
		this.parentLayer.appendChild(control.getNavigation());
		this.navigation = control.navigation;
	};
	
	this.showThumbnail = function(cond) {
		if (cond) {
			this.mapThumb.init(180, 105, this);
		}
	};
	
	this.showLoadingImg = function(cond) {
		if (cond) {
			this.loaderImg.style.left = (this.mapClient.mapWidth/2) - 50 + "px";
			this.loaderImg.style.top = (this.mapClient.mapHeight/2) - 50 + "px";			
			this.loaderImg.style.display = "";
			this.mapDraw.enableOpacity(true);
		} else {
			this.loaderImg.style.display = "none";
			this.mapDraw.enableOpacity(false);
		}
	};	
	
	this.init = function(viewport_id, url) {		
		IeFix(url);		
		this.initContainer(viewport_id);
		this.baseUrl = url;
		this.mapClient.init(this, url);		
		this.mapDraw.init(this.mapClient);
		this.initController();
		this.mapClient.onCompleted = onMapCompleted;
		this.mapDraw.onCompleted = onDrawCompleted;
	};
	
  this.updateScaleImage = function() {
    if (this.mapClient.levelIndex > 6) return;
    this.mapClient.scale.src = this.baseUrl + "img/scale"+ (this.mapClient.levelIndex + 1) + ".gif";
  };
  
};

function TinyMapControl() {
	this.navigation = new MapNavigation();
	this.getNavigation = function() {
		var panel = new MDiv('', "0px", "40px",
			"50px", "80px", "absolute", 11);
		panel.appendChild(this.navigation.getZoomControl());
		return panel;
	};
};

function SmallMapControl() {
	this.navigation = new MapNavigation();
	this.getNavigation = function() {
		var panel = new MDiv('', "0px", "40px",
			"50px", "80px", "absolute", 11);
		panel.appendChild(this.navigation.getDirectionControl());
		panel.appendChild(this.navigation.getZoomControl());
		return panel;
	};
};

function MediumMapControl() {
	this.navigation = new MapNavigation();
	this.getNavigation = function() {
		var panel = new MDiv('', "0px", "40px",
			"50px", "100px", "absolute", 11);
		panel.appendChild(this.navigation.getDirectionControl());
		panel.appendChild(this.navigation.getLevelControl());
		return panel;
	};
};

function CompleteMapControl() {
	this.navigation = new MapNavigation();
	this.getNavigation = function() {
		var panel = new MDiv('', "0px", "40px",
			"50px", "150px", "absolute", 11);
		panel.appendChild(this.navigation.getDirectionControl());
		panel.appendChild(this.navigation.getZoomControl());
		panel.appendChild(this.navigation.getDrawControl());
		panel.appendChild(this.navigation.getLevelControl());
		return panel;
	};
};

function ZoomMapControl() {
  this.navigation = new MapNavigation();
  this.getNavigation = function() {
  	var panel = new MDiv('', "0px", "40px", "50px", "150px", "absolute", 11);
  	panel.appendChild(this.navigation.getSleekZoomControl());
  	return panel;
  };
};

function MapLogo() {
	this.init = function(mapClient, mapApi) {
		if (mapClient == null || mapApi == null) {
			return false;
		}
		var legendPanel = new MDiv('div_container', 0 + 'px', 0 + 'px', mapClient.mapWidth + 'px', mapClient.mapHeight+'px', 'absolute', 0);
		var logo = new MImg('', mapApi.baseUrl + "img/full_logo.gif", 
			"0px", "0px", '90px', '28px', "absolute");
		var scale = new MImg('', mapApi.baseUrl + 'img/scale' + (mapClient.levelIndex + 1) + '.gif', mapClient.mapWidth - 65 + 'px', 0 + 'px', 65 + 'px', 18 + 'px', 'absolute');
		var cpright = new MImg('', mapApi.baseUrl + "img/copyright.gif", 
			"0px", (mapClient.mapHeight - 12) + "px", '125px', '12px', "absolute");
		var north = new MImg('', mapApi.baseUrl + "img/north.gif", 
			(mapClient.mapWidth - 28) + "px", (mapClient.mapHeight - 16) + "px", '28px', '16px', "absolute");		
		
		mapClient.scale = scale;
		mapApi.parentLayer.appendChild(logo);
		//mapApi.parentLayer.appendChild(scale);
		mapApi.parentLayer.appendChild(cpright);
		mapApi.parentLayer.appendChild(north);
		if (GLOBALS['poweredby'] == undefined)
		{
			var poweredBy = new MDiv('', '2px', (mapClient.mapHeight - 27) + 'px', '185px', '16px', 'absolute', 0);
			poweredBy.style.fontFamily = 'arial';
			poweredBy.style.fontSize = '11px';
			poweredBy.style.fontWeight = 'bold';
			poweredBy.innerHTML = '<span style="color:#ff0000">Powered by</span> <span style="color:#008a54"><u><i>Streetdirectory.com</i></u></span>';
			mapApi.parentLayer.appendChild(poweredBy);
		}
	};
};


function MapNavigation() {
	this.mapClient = null;
	this.mapApi = null;
	
	this.init = function(mapClient, mapApi) {
		this.mapClient = mapClient;
		this.mapApi = mapApi;
	};
	
	this.createNavigationContainer = function(_left, _top, _w, _h, index, color) {
		return new MDiv('', _left, _top, _w, _h, "absolute", index, color);
	};
	
	this.checkValidity = function() {
		if (this.mapClient == null || this.mapApi == null) {
			return false;
		}
		return true;
	};
	
	this.createNavigationControl = function(url, left, topx, width, height, is_png)	{
		var arVersion = navigator.appVersion.split("MSIE");
		var version = parseFloat(arVersion[1]);
		
		if (is_png && (version >= 5.5) && (version < 7) && (document.body.filters)) 
		{
			var img = document.createElement('span');
			img.style.position = 'absolute';
			img.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'" + url + "\', sizingMethod='scale')";
			img.style.width = width + 'px';
			img.style.height = height + 'px';
			img.style.top = topx + 'px';
			img.style.left = left + 'px';
		}
		else
		{
			var img = new MImg('', url, left + "px", topx + "px",
				'', '', "absolute");
			img.border = '0';
			img.width = width;
			img.height = height;
		}
		img.style.cursor = "pointer";
		img._mapClient = this.mapClient;		
		img._mapApi = this.mapApi;
		img._p = this;
		return img;
	};
	
	this.getDirectionControl = function() {
		if (!this.checkValidity()) {
			return;
		}
        var moveX = this.mapClient.mapWidth / 2; 
        var moveY = this.mapClient.mapHeight / 2; 
        
        var directionPanel = new MDiv('', "0px", "0px", "50px", "70px", "relative", "11"); 
	    var img1 = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_up.gif", 16, 0, 17, 17);
	    img1.onclick = function() { this._mapClient.panMapByOffset(0, moveY); };
	    
	    var img2 = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_left.gif", 6, 22, 17, 17);
	    img2.onclick = function() { this._mapClient.panMapByOffset(moveX, 0); };
	    
	    var img3 = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_right.gif", 27, 22, 17, 17);

	    img3.onclick = function() { this._mapClient.panMapByOffset(-moveX, 0); };
	    
	    var img4 = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_btm.gif", 15, 44, 17, 17);
	    img4.onclick = function() { this._mapClient.panMapByOffset(0, -moveY); };

		directionPanel.appendChild(img1);
		directionPanel.appendChild(img2);
		directionPanel.appendChild(img3);
		directionPanel.appendChild(img4);
		return directionPanel;
	};
	
	this.getZoomControl = function() {	
		if (!this.checkValidity()) {
			return;
		}		    
		var zoomPanel = new MDiv('', "0px", "0px", "50px", "40px", "relative", "11");
	    var img5 = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_in.gif", 15, 0, 17, 17);
	    img5.onclick = function() {
	    	var newLevel = this._mapClient.levelIndex + 1;
	    	if ((this._p.btnLevel != undefined 
	    		&& this._p.btnLevel.length != undefined)
	    		&& newLevel > -1 && newLevel < 6) {
	    		this._p.getSelectedController(this._p.btnLevel, newLevel);	
	    	};
			
	    	this._mapClient.zoomIn();
	    };
	    
	    var img6 = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_out.gif", 15, 20, 17, 17);
	    img6.onclick = function() {
	    	var newLevel = this._mapClient.levelIndex - 1;
	    	if ((this._p.btnLevel != undefined 
	    		&& this._p.btnLevel.length != undefined)
	    		&& newLevel > -1 && newLevel < 6) {	    		
	    		this._p.getSelectedController(this._p.btnLevel, newLevel);	
	    	};
	    	this._mapClient.zoomOut();
	    };
        zoomPanel.appendChild(img5);
		zoomPanel.appendChild(img6);
		return zoomPanel;
	};
	
	this.getDrawControl = function() {
		if (!this.checkValidity()) {
			return;
		}		
		var drawPanel = new MDiv('', "0px", "0px", "50px", "20px", "relative", 11);		
	    var img7 = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_dist.gif", 15, 0);
	    img7.onclick = function() {
	    	if (this._mapApi.drawMode == false) {
	    		this._mapApi.mapDraw.clearDrawing(); 
	    	}
	    	this._mapApi.drawMode = !this._mapApi.drawMode;	    	
	    };
	    drawPanel.appendChild(img7);
	    return drawPanel;
	};
	
	this.getLevelControl = function() {
		if (!this.checkValidity()) {
			return;
		}		
		var levelPanel = new MDiv('', "0px", "0px", "50px", "120px", "relative", 11);
		btnLevel = new Array();
		
		btnLevel[0] = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_1.gif", 15, 0);
		btnLevel[1] = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_2.gif", 15, 22);
		btnLevel[2] = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_3.gif", 15, 44);
		btnLevel[3] = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_4.gif", 15, 66);
		btnLevel[4] = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_5.gif", 15, 88);
		btnLevel[5] = this.createNavigationControl(this.mapApi.baseUrl + "img/nav_6.gif", 15, 111);
		for (var i=0; i<btnLevel.length; i++) {
			levelPanel.appendChild(btnLevel[i]);			
			btnLevel[i].idx = i;
			btnLevel[i].my = this;
			btnLevel[i]._parent = btnLevel;
			btnLevel[i].onclick = function() {
				this._mapClient.changeLevel(this.idx);				
				this.my.getSelectedController(this._parent, this.idx);
			};
		};
		this.getSelectedController(btnLevel, this.mapClient.levelIndex);
		this.btnLevel = btnLevel;
		return levelPanel;
	};
	
	this.getSleekZoomControl = function()
	{
    if (!this.checkValidity()) {
      return;
    }
    
    // functions for this map control
    this.panel_onmousedown = function(e)
    {
    	this._mapApi.zooming = true;
    };
    
    this.panel_onmouseup = function(e)
    {
    	if (this._mapApi.zooming)
    	{
	      var lvl,lvl_y,pos = getCursorPos(e, this.parent);
				if (pos.y > 156) { lvl = 7; lvl_y = 169; }
	      else if (pos.y > 131) { lvl = 6; lvl_y = 144; }
	      else if (pos.y > 106) { lvl = 5; lvl_y = 118; }
	      else if (pos.y > 84) { lvl = 4; lvl_y = 95; }
	      else if (pos.y > 63) { lvl = 3; lvl_y = 73; }
	      else if (pos.y > 41) { lvl = 2; lvl_y = 53; }
	      else { lvl = 1; lvl_y = 30; }     
	      this._mapClient.changeLevel(lvl - 1);   
	      this._p.mover.style.top = lvl_y + 'px';
    	}
    	this._mapApi.zooming = false;
    };
    
		this.panel_onmousemove = function(e)
		{ 
		  if (this._mapApi.zooming)
		  { 
		    var pos = getCursorPos(e, this.parent);       
		    if (pos.y >= 25 && pos.y <= 170 )
		    {
		      this.style.cursor = 'pointer';
		      this._p.mover.style.top = (pos.y - 5) + 'px';      
		    }
		  }   
		  return true;
		}
		
		this.move_mover_to_level = function(curr_lvl)
		{
			var pos_lvl_y;     
			if (curr_lvl == 7) pos_lvl_y = 169;
      else if (curr_lvl == 6) pos_lvl_y = 144;
      else if (curr_lvl == 5) pos_lvl_y = 118;
      else if (curr_lvl == 4) pos_lvl_y = 95;
      else if (curr_lvl == 3) pos_lvl_y = 73;
      else if (curr_lvl == 2) pos_lvl_y = 53;
      else if (curr_lvl == 1) pos_lvl_y = 30;
      
      this.mover.style.top = pos_lvl_y + 'px';
		};
		// end of functions
		
    var curr_lvl,pos_lvl_y, moveX = 100;
    
    curr_lvl = this.mapClient.levelIndex + 1;
		if (curr_lvl == 7) pos_lvl_y = 169;
    else if (curr_lvl == 6) pos_lvl_y = 144;
    else if (curr_lvl == 5) pos_lvl_y = 118;
    else if (curr_lvl == 4) pos_lvl_y = 95;
    else if (curr_lvl == 3) pos_lvl_y = 73;
    else if (curr_lvl == 2) pos_lvl_y = 53;
    else if (curr_lvl == 1) pos_lvl_y = 30;
    
    var zoomPanel = new MDiv('', "0px", "0px", "50px", "40px", "relative", "11");
    var img1 = this.createNavigationControl(this.mapApi.baseUrl + "img/sleek_bar_id_03.png", 5, 0, 38, 206, true);
    var img2 = this.createNavigationControl(this.mapApi.baseUrl + "img/minus_normal.png", 17, 7, 16, 15, true);
    var img3 = this.createNavigationControl(this.mapApi.baseUrl + "img/plus_normal.png", 17, 183, 16, 15, true);
		
		var img4 = new MDiv('', '15px', pos_lvl_y + 'px', '18px', '13px', 'absolute', '');
		var arVersion = navigator.appVersion.split("MSIE");
		var version = parseFloat(arVersion[1]);
		
		if ((version >= 5.5) && (version < 7) && (document.body.filters)) 
		{
			img4.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'" + this.mapApi.baseUrl + "img/mover.png\', sizingMethod='scale')";
		}
		else
		{
			img4.style.background = 'url(' + this.mapApi.baseUrl + 'img/mover.png) no-repeat';
		}
    //var img4 = this.createNavigationControl(this.mapApi.baseUrl + "img/mover.png", 15, pos_lvl_y);
    img4._mapClient = this.mapClient;    
    img4._mapApi = this.mapApi;
    img4._p = this;
    
    // zoom out button
    img2.title = 'Zoom out';
    img2.style.cursor = 'pointer';
    img2.onclick = function() 
    {       
      var min_level = -1;
      if (this._mapClient.levelIndex - 1  > min_level)
      {
        this._mapClient.zoomOut();    
        this._p.move_mover_to_level(this._mapClient.levelIndex + 1);
      }
    }
    
    // zoom in button
    img3.title = 'Zoom in';
    img3.style.cursor = 'pointer';
    img3.onclick = function() 
    {                   
      var max_level = 6;
      if (this._mapClient.levelIndex + 1 <= max_level)
      {
        this._mapClient.zoomIn();
        this._p.move_mover_to_level(this._mapClient.levelIndex + 1);
      }
    }
    
    // mover button
    this.mover = img4;
    img4.id = 'mover';
    img4.parent = zoomPanel;
    img4.style.cursor = "pointer";
    img4.onmousedown = this.panel_onmousedown;
    img4.onmouseup = this.panel_onmouseup;
    
    // sleek bar
    img1.parent = zoomPanel;
    img1.style.cursor = 'pointer';
    img1.onmousedown = this.panel_onmousedown;
    img1.onmousemove = this.panel_onmousemove;
    img1.onmouseup = this.panel_onmouseup;
    
    zoomPanel.appendChild(img1);
    zoomPanel.appendChild(img2);
    zoomPanel.appendChild(img3);
    zoomPanel.appendChild(img4);
    return zoomPanel;
	};
	
	this.getSelectedController = function(controller, idx) {
		if (controller == undefined) {
			return false;
		}
		for (var i=0; i<controller.length; i++) {
			if (i == idx) {
				controller[i].style.border = "1px solid #000";
			} else {
				controller[i].style.border = "";
			};
		};
	};	
};
var VEvent = {
	addListener : function(object, method, refs) {
		var obj = object.obj == undefined ? object : object.obj;
		if(window.addEventListener){ 
			obj.addEventListener(method, refs, false);
		} else { 
			obj.attachEvent('on' + method, refs);
		}
	}
};

var BrowserDetect = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{
			string: navigator.userAgent,
			subString: "Chrome",
			identity: "Chrome"
		},
		{ 	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]

};
BrowserDetect.init();

function getBaseUrl()
{
  //var base_url = 'http://192.168.0.4/';
  var base_url = 'http://www.streetdirectory.com/';
  if (location.hostname == "localhost" || location.hostname == '172.16.0.4') base_url = "http://172.16.0.4/";
  else if(location.hostname == "beta.streetdirectory.com") base_url = "http://"+location.hostname+"/";
  return base_url;
}

function PlaceMarker(x, y) {
  this.x = x;
  this.y = y;
  this.image = getBaseUrl() + "/img/mappointer/star200.gif";
  this.html = null;
  this.move = false;
  this.mapClient = null;
  this.obj = new MImg('',
    this.image, x + 'px', y + 'px',
    "20px", "34px", 'absolute', 9); 
  this.obj.mapIcon = this;        
  var w = 20;
  var h = 34;
  w = w % 2 == 0 ? w : w + 1;
  h = h % 2 == 0 ? h : h + 1;
  if (w > 0 && h > 0) {
    this.size = new Point(w, h);
    this.obj.style.width = w + "px";
    this.obj.style.height = h + "px";
  };
  this.obj.style.cursor = "pointer";
  this.isDisplayed = true;
	this.po = null;	// pointer offset, an offset point where the icon should point to, counted from top left
  
  this.openInfoWindowHtml = function(html, option) {
    this.mapClient.openInfoWindowHtml(new Vertex(this.x, this.y), html, this.size, option);
  };
  
  this.setImage = function(image, width, height)
  {
		var is_png = false;
		if (image.indexOf('png') != -1) is_png = true;
		var arVersion = navigator.appVersion.split("MSIE");
		var version = parseFloat(arVersion[1]);
		if ((version >= 5.5) && (version < 7) && (document.body.filters) && is_png) 
		{
			this.obj = document.createElement('span');
			this.obj.style.cssText = "position: absolute; top: " + this.y + "px; left: " + this.x + "px; z-index: 9";
			this.obj.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'" + image + "\')";
		}
		else
		{
			this.obj = new MImg('', image, this.x + 'px', this.y + 'px', width + "px", height + "px", 'absolute', 9); 
		}
    var w = width;
    var h = height;
    if (w > 0 && h > 0) {
      this.size = new Point(w, h);
      this.obj.style.width = w + "px";
      this.obj.style.height = h + "px";
    };
    this.obj.style.cursor = "pointer";
  }
  
  this.moving = function (status)
  {
	  this.move = status;
  }
  
  this.attachEvent = function(method, f)
  {
    VEvent.addListener(this.obj, method, f);
  };
}

// ismail
// set pointer offset
PlaceMarker.prototype.setPointerOffset = function(p) {
	this.po = p;
};
