(function($){
	$.MapToolType={zoomIn:0,zoomOut:1,back:2,next:3,pan:4,info:5,maxExtent:6,rule:7,edit:8,link:9}
	$.isLeftButton=function(event) { var result = true; if ($.browser.msie) { if (event.button != 1) { result = false; }} else if (event.button != 0) { result = false; } return result; }
	$.getPageOffset=function() { var offset = new Object(); if (window.pageYOffset) { offset.left = window.pageXOffset; offset.top = window.pageYOffset; } else if (document.documentElement) { offset.left = document.documentElement.scrollLeft; offset.top = document.documentElement.scrollTop; } return offset; }
	$.getStyle=function(el){if (el.currentStyle) return el.currentStyle; else return document.defaultView.getComputedStyle(el, null);}
	$.contains=function(node1, node2) { if (node1.contains) return node1.contains(node2); else return node1.compareDocumentPosition(node2) & Node.DOCUMENT_POSITION_CONTAINED_BY; }
	$.pixelToWorld=function(x, y, params, width, height) { var p = new Object(), t = (0.0254 / 96) * params.scale; p.x = Number(params.x) + Number((x - width / 2) * t); p.y = Number(params.y) - Number((y - height / 2) * t); return p; }
	$.worldToPixel=function(x, y, params, width, height) { var p = new Object(), t = (96 / 0.0254) / params.scale; p.x = parseInt((width / 2) + ((x - params.x) * t)); p.y = parseInt((height / 2) - ((y - params.y) * t)); return p; }
	$.distanceToPixel=function(d, params) {return parseInt(d*(96/0.0254)/params.scale);}
	$.getPosition=function(obj) {var offset=obj.offset(),pageOffset=$.getPageOffset(),s=$.getStyle(obj[0]);return {left:parseInt(offset.left-pageOffset.left+parseInt(s.borderLeftWidth)),top:parseInt(offset.top-pageOffset.top+parseInt(s.borderTopWidth))};}
	$.fn.extend({
		mapTool:function(options){
			if(this.length>1){this.each(function(){$(this).mapTool(options)});return this;}
			var e=true,p=false,hl=false,obj=$(this);
			var s={toolType:0,defURL:"",hlURL:"",pURL:"",dURL:"",pdURL:""};
			options?$.extend(s,options):null;
			obj.click(function(event){if(e)obj.trigger("toolClick",s.toolType);});
			obj.mousedown(function(event){if(e&&!p)obj.attr("src",s.pURL);});
			obj.mouseup(function(event){if(e&&!p)obj.attr("src",hl?s.hlURL:s.defURL);});
			obj.hover(function(){if(e&&!p)obj.attr("src",s.hlURL);hl=true;},function(){if(e&&!p)obj.attr("src",s.defURL);hl=false;});
			this.enable=function(state){ var url="";e=state;if(e)url=p?s.pURL:s.defURL;else url=p?s.pdURL:s.dURL;obj.attr("src",url);return this;}
			this.push=function(state){var url="";p=state;if(e)url=p?s.pURL:s.defURL;else url=p?s.pdURL:s.dURL;obj.attr("src",url);;return this;}
			this.getToolType=function(){return s.toolType;}
			return this;
		},
		mapControl: function(options) {
			if (this.length > 1) { this.each(function() { $(this).mapControl(options) }); return this; }
			var obj = $(this);
			var settings = {
				wrapperURL: "/MapControlAJAX/mapwrapper.asmx",
				scaleFactor: 2,
				autoResize: true,
				zoomExtentStyle: { "fill-opacity": 0.2, "fill": "blue", "stroke": "red", "stroke-width": 2 },
				waitToolTipText: "Получение информации...",
				waitToolTipImg: "images/addr_loading.gif",
				drawScaleBar: true,
				startTool:$.MapToolType.pan
			};
			options ? $.extend(settings, options) : null;
			//fields
			var isBusy = false, isToolTip = false, isMouseDown = false,isMouseMove = false, startX, startY, tools = [], currTool = null, backHistory = [], nextHistory = [], map = null, params = null;
			var urlCache = [];
			var ie = $.browser.msie;
			var width = obj.width();
			var height = obj.height();

			var layers = [];
			var wrapper = new WH();
			wrapper.MapWrapperURL  = settings.wrapperURL;
			wrapper.Host = document.domain;

			var rulePoints = [];

			//UI
			var canvas = null, currImg = null, nextImg = null, zoomExtent = null, toolTip = null;
			toolTip = $("<div></div>").hide().appendTo(document.body).addClass("toolTip");
			canvas = Raphael("mapContainer"); //this.get());
			obj.addClass("mapConteiner");
			if(ie){ currImg = $("<input type=\"image\" />").addClass("mapImg").hide().appendTo(obj).attr("src","");nextImg = $("<input type=\"image\" />").addClass("mapImg").hide().appendTo(obj).attr("src",""); $(canvas.childNodes[0]).css("z-index", 10); 
				zoomExtent = $("<div></div>").addClass("zoomExtent").hide().appendTo(obj);
			}

			var ruleToolTip = false;
			var ruleAllText = false;
			var ruleLastText = false;
			
			var moveRuleNode = false;
			var ruleStyles = [{ stroke: "#565656", "stroke-width": 8.0, "stroke-linecap": "round", opacity: 0.1 }, { stroke: "#565656", "stroke-width": 6.0, "stroke-linecap": "round", opacity: 0.25 }, { stroke: "white", "stroke-width": 2.0, "stroke-linecap": "round"}];//#0094FF
			var ruleNodeStyle = { fill: "white", stroke: "red", "stroke-width": 2, r: 3 };
			var ruleNodeHoverStyle = { fill: "white", stroke: "red", "stroke-width": 2, r: 5 };
			var ruleObj = [];

			//private methods
			var hoverRuleNode = function(node) { $(node.node).hover(function() { node.animate(ruleNodeHoverStyle, 100); }, function() { node.animate(ruleNodeStyle, 100); }); }
			var downRuleNode = function(node) { $(node.node).mousedown(function(event) { if (!event) event = window.event; if ($.isLeftButton(event)) moveRuleNode = node; });}
			var showRule = function(dx, dy) {
				dx = dx == undefined ? 0 : dx;
				dy = dy == undefined ? 0 : dy;
				hideRule();
				if (rulePoints.length > 0) {
					var c, p2, p1 = $.worldToPixel(rulePoints[0].x, rulePoints[0].y, params, width, height);
					p1.x = Number(p1.x) + Number(dx); p1.y = Number(p1.y) + Number(dy);
					c = canvas.circle(p1.x, p1.y, 2).attr(ruleNodeStyle).toFront();
					c.ruleNodeIndex = 0;
					hoverRuleNode(c);
					downRuleNode(c);
					ruleObj.push(c);
					for (i = 1; i < rulePoints.length; i++) {
						p2 = $.worldToPixel(rulePoints[i].x, rulePoints[i].y, params, width, height);
						p2.x = Number(p2.x) + Number(dx); p2.y = Number(p2.y) + Number(dy);
						$.each(ruleStyles, function() { ruleObj.push(canvas.path(this).moveTo(p1.x, p1.y).lineTo(p2.x, p2.y).toFront()); });
						ruleObj[ruleObj.length - 1 - ruleStyles.length].toFront();
						c = canvas.circle(p2.x, p2.y, 2).attr(ruleNodeStyle).toFront();
						c.ruleNodeIndex = i;
						hoverRuleNode(c);
						downRuleNode(c);
						ruleObj.push(c);
						p1 = p2;
					}
					if(rulePoints.length > 1) {
						var total = 0, curr = 0;
						for(i=1; i< rulePoints.length; i++) {
							total += Math.sqrt(Math.pow((rulePoints[i].x - rulePoints[i-1].x), 2) + Math.pow((rulePoints[i].y - rulePoints[i-1].y), 2));
						}
						curr = Math.sqrt(Math.pow((rulePoints[rulePoints.length - 1].x - rulePoints[rulePoints.length - 2].x), 2) + Math.pow((rulePoints[rulePoints.length - 1].y - rulePoints[rulePoints.length - 2].y), 2));
						var p = $.worldToPixel(rulePoints[rulePoints.length - 1].x, rulePoints[rulePoints.length - 1].y, params, width, height);
						var x = Number(p.x);
						var y = Number(p.y);
						offset = obj.offset();
						x += Number(offset.left); y += Number(offset.top);
						if(x >= offset.left && y >= offset.top && x <= offset.left + obj.width() && y <= offset.top + obj.height())
							showRuleToolTip(x, y, curr.toFixed(2), total.toFixed(2));
					}
				}
			}
			var hideRule = function() { $.each(ruleObj, function() { this.remove(); }); ruleObj = []; }
			//var moveRuleNode = function(x, y) {
				//var pIndex = moveRuleNode.ruleNodeIndex - ruleStyles.length;
				//var nIndex = moveRuleNode.ruleNodeIndex + ruleStyles.length;
				//rulePoints[moveRuleNode.ruleNodeIndex] = $.pixelToWorld(currX, currY, params, width, height);
				//if(pIndex >= 0) {
				//	var prev = $.worldToPixel(rulePoints[pIndex].x, rulePoints[pIndex].y, params, width, height);
				//	for(int i= pIndex + 1; i< moveRuleNode.ruleNodeIndex; i++) {
				
				//	}
				//}
			//}

			var enableTool = function(toolType, state) { $.each(tools, function() { if (this.getToolType() == toolType) this.enable(state); }) }
			var pushTool = function(toolType, state) { $.each(tools, function() { this.push(this.getToolType() == toolType); }); }
			var enableTools = function(state) { $.each(tools, function() { this.enable(state); }); enableTool($.MapToolType.back, backHistory.length > 0 && state); enableTool($.MapToolType.next, nextHistory.length > 0 && state); }
			var toolClick = function(event, toolType) { hideToolTip(); if (toolType == $.MapToolType.maxExtent) { maxExtent(); } else if (toolType == $.MapToolType.back) { back(); } else if (toolType == $.MapToolType.next) { next(); } else if (toolType == $.MapToolType.link) { showLink(); } else { currTool = toolType; pushTool(toolType, true); } }
			var busyOn = function(fireEvents) { isBusy = true; enableTools(false); hideRule(); if(fireEvents || fireEvents == undefined) obj.trigger("startLoading"); }
			var busyOff = function(fireEvents) { isBusy = false; enableTools(true); showRule(); if(fireEvents || fireEvents == undefined) obj.trigger("stopLoading"); }

			var endLoadingIE = function() { if(nextImg.attr("src") != "") { nextImg.css({left:"0px", top:"0px", width: width+"px", height: height+"px"}); nextImg.fadeIn(200, function() { currImg.stop(); currImg.hide(); currImg.attr("src", ""); var t = currImg; currImg = nextImg; nextImg = t; busyOff(); obj.trigger("paramsChanged", params); });}}
			var endLoading = function() { nextImg.animate({ "opacity": 1 }, 200, function() { if (currImg) { currImg.stop(); currImg.remove(); } currImg = nextImg;  currImg.attr({ "opacity": 1 }); busyOff(); obj.trigger("paramsChanged", params); }); }
			var refreshMap = function() { var url = wrapper.GMURL(settings.wrapperURL, params, layers); if(ie){nextImg.attr("src",url);} else { nextImg = canvas.image(url, 0, 0, width, height).attr({ "opacity": 0 }); if($.inArray(url, urlCache) != -1) endLoading(); else { $(nextImg.node).load(endLoading); urlCache.push(url); }}}
			var showMap = function() { params = wrapper.PMP(this.responseXML); params.drawScaleBar = settings.drawScaleBar; refreshMap(); }

			var saveBack = function() { nextHistory = []; backHistory.push(params); }
			var restoreBack = function() { nextHistory.push(params); if (backHistory.length > 0) { params = backHistory.pop(); params.width = width; params.height = height; } }
			var restoreNext = function() { backHistory.push(params); if (nextHistory.length > 0) { params = nextHistory.pop(); params.width = width; params.height = height; } }

			var showToolTip = function(x, y, content, extStyle, closeHandler, move) { if(isToolTip) toolTip.empty(); toolTip.append('<div class="toolTipBody '+(extStyle?extStyle:'')+'">'+content+'</div><a id="toolTipClose" href=""></a><div style="clear:both"></div>');$("#toolTipClose").click(function(){ if(closeHandler) closeHandler(); return false;});
			var p = {left: ((x + 10) + 'px'), top: ((y + 10) + 'px')}; 
			if(!isToolTip) { toolTip.css(p); toolTip.fadeIn("fast"); }
			else { if(move) toolTip.animate(p, "fast"); else toolTip.css(p); } isToolTip = true;} 
			var hideToolTip = function() { if(isToolTip) { toolTip.fadeOut("fast", function(){ toolTip.empty(); isToolTip = false;});}}
			var showWaitToolTip = function(x, y) { var c = '<img src="'+ settings.waitToolTipImg +'"/>'+settings.waitToolTipText; showToolTip(x, y, c, 'toolTipWait', function() { wrapper.Abort();busyOff(false);hideToolTip();}, true);}
			var showInfoToolTip = function() { var toolTipText = wrapper.PTT2(this.responseXML); if (!toolTipText) toolTipText = 'Нет информации'; busyOff(false); showToolTip(startX, startY, toolTipText, 'toolTipInfo', hideToolTip, true); }
			var showRuleToolTip = function(x, y, curr, total) { var c = "<ul><li>" + curr + "</li><li>" + total + "</li></ul>"; showToolTip(x, y, c, 'toolTipRule', function(){ rulePoints = [];hideRule();hideToolTip();});}

			var showMessage = function(title, message) {
				var c = '<h3>'+title+'</h3><div>'+message+'</div>';
				showToolTip(100, 100, c, 'toolTipDialog', hideToolTip, true);
			}

			//map methods
			var back = function() { restoreBack(); busyOn(false); refreshMap(); }
			var next = function() { restoreNext(); busyOn(false); refreshMap(); }
			var correctParams = function(x, y, width, height) { busyOn(); saveBack(); wrapper.GCMP(showMap, null, params, parseInt(x), parseInt(y), parseInt(width), parseInt(height)); }
			var zoomMap = function(x, y, new_width, new_height) { var h=Math.min(width/new_width,height/new_height),zx=(width)/2-(x+new_width/2)*h,zy=(height)/2-(y+new_height/2)*h,zw=width*h,zh=height*h;currImg.animate(ie?{left:zx+"px",top:zy+"px",width:zw+"px",height:zh+"px" }:{x:zx,y:zy,width:zw,height:zh}, 500);correctParams(x, y, new_width, new_height);}
			var zoomByPoint = function(x, y, scale) { var new_width = parseInt((scale * width) / params.scale), new_height = parseInt((scale * height) / params.scale); var new_x = parseInt(x - new_width / 2); var new_y = parseInt(y - new_height / 2); zoomMap(new_x, new_y, new_width, new_height); }
			var zoomInPoint = function(x, y) { var new_scale = params.scale / settings.scaleFactor; zoomByPoint(x, y, new_scale); }
			var zoomOutPoint = function(x, y) { var new_scale = params.scale * settings.scaleFactor; zoomByPoint(x, y, new_scale); }
			var maxExtent = function() { busyOn(); saveBack(); wrapper.GMEMP( showMap, null, map.id, width, height );}
			var infoByPoint = function(x, y) { busyOn(false); wrapper.GTT2(showInfoToolTip, null, params, parseInt(x), parseInt(y), layers); }
			var showLink = function() {
				var url = "http://" + document.domain + wrapper.GMURL(settings.wrapperURL, params, layers);
				showMessage("Ссылка на место", url);
				//var toolTipText = '<div class="stop"><span>Ост. «ул. Чайковского 40а»</span><h4>Автобусы</h4><ul><li>1,2,3,4,5</li></ul><h4>Троллейбусы</h4><ul><li>1,2,3,4,5</li></ul><h4>Трамваи</h4><ul><li>1,2,3,4,5</li></ul><h4>Маршрутки</h4><ul><li>1,2,3,4,5</li></ul></div>';
				//showToolTip(startX, startY, toolTipText, 'toolTipInfo', hideToolTip);
			}

			//public methods
			this.addTool = function(tool) { tools.push(tool); tool.bind("toolClick", toolClick); return this; }
			this.clearTools = function() { tools = new Array(); return this; }

			this.setMap = function(m) {
				if (!isBusy) {
					hideToolTip();
					busyOn();
					map = m;
					if (params != null) saveBack();
					else toolClick(null, settings.startTool);
					wrapper.GMEMP(showMap, null, map.id, width, height);
				}
				return this;
			}
			this.setScale = function(scale) {
				if (!isBusy) {
					hideToolTip();
					zoomByPoint(parseInt(width/2), parseInt(height/2),scale);
				}
				return this;
			}
			this.setCenter = function(x, y) {
				if (!isBusy) {
					hideToolTip();
					params.x = x;
					params.y = y;
					correctParams(0, 0, width, height);
				}
				return this;
			}
			this.setLayers = function(ids){if (isBusy) wrapper.Abort(); else { hideToolTip(); busyOn();} layers = ids; refreshMap();return this;}
			this.showAddress = function(streetName, addressName) { if (!isBusy) { hideToolTip(); busyOn(); saveBack(); wrapper.GMPYA(showMap, null, width, height, streetName, addressName); }return this;}
			this.showAddresser = function(type, id) { if (!isBusy) { hideToolTip(); busyOn(); saveBack(); wrapper.VSID(showMap, null, params, type, id);}return this;}
			this.refreshSize = function() { mapResize(); return this;}
			this.refresh = function() { refreshMap(); return this;}

			//map handlers
			var mapMouseDown = function(event) {
				if (isBusy) return; isMouseDown = $.isLeftButton(event); isMouseMove=false; var p=$.getPosition(obj); startX = parseInt(event.clientX - p.left); startY = parseInt(event.clientY - p.top);
				if (moveRuleNode) return;
				else if (currTool == $.MapToolType.zoomIn && isMouseDown) { 
					if(ie) zoomExtent.css("left", startX+"px").css("top", startY+"px").width(3).height(3).show();
					else zoomExtent = canvas.rect(startX, startY, 3, 3).attr(settings.zoomExtentStyle); 
				}
				else if (currTool == $.MapToolType.pan && isMouseDown) { obj.css("cursor", "move"); }
				return false;
			}
			var mapMouseMove = function(event) {
				var p=$.getPosition(obj), currX = event.clientX - p.left, currY = event.clientY - p.top;
				if (moveRuleNode) { rulePoints[moveRuleNode.ruleNodeIndex] = $.pixelToWorld(currX, currY, params, width, height); showRule(); }
				else if (currTool == $.MapToolType.zoomIn && isMouseDown) { 
					var rect_width = currX - startX; var rect_height = currY - startY; 
					if (rect_width < 0) ie?zoomExtent.css("left",currX+"px"):zoomExtent.attr({x:currX});
					if (rect_height < 0) ie?zoomExtent.css("top",currY+"px"):zoomExtent.attr({y:currY}); 
					if(ie){var s = $.getStyle(zoomExtent[0]);zoomExtent.width(Math.abs(rect_width-parseInt(s.borderLeftWidth)-parseInt(s.borderRightWidth))).height(Math.abs(rect_height-parseInt(s.borderTopWidth)-parseInt(s.borderBottomWidth)));}
					else zoomExtent.attr({width: Math.abs(rect_width), height: Math.abs(rect_height)});
				}
				else if (currTool == $.MapToolType.pan && isMouseDown) {var dx=currX-startX,dy=currY-startY;ie?currImg.css({left:dx+"px",top:dy+"px"}):currImg.attr({x:dx,y:dy});showRule(dx,dy); isMouseMove=true;}
				return false;
			}
			var mapMouseUp = function(event) {
				if (!isMouseDown) return; var new_x, new_y, rect_width, rect_height, p=$.getPosition(obj), currX = event.clientX - p.left, currY = event.clientY - p.top;
				if (moveRuleNode) { moveRuleNode = false; showRule(); }
				else if (currTool == $.MapToolType.zoomIn) { ie?zoomExtent.hide():zoomExtent.remove(); new_x = startX; new_y = startY; rect_width = currX - startX; rect_height = currY - startY; if (rect_width < 0) { rect_width *= -1; new_x -= rect_width; } if (rect_height < 0) { rect_height *= -1; new_y -= rect_height; } if (rect_width < 5 || rect_height < 5) zoomInPoint(new_x, new_y); else zoomMap(new_x, new_y, rect_width, rect_height); }
				else if (currTool == $.MapToolType.zoomOut) { zoomOutPoint(currX, currY); }
				else if (currTool == $.MapToolType.pan) { if(isMouseMove) {new_x = startX - currX;new_y = startY - currY;correctParams(new_x, new_y, width, height);} obj.css("cursor", "default");}
				else if (currTool == $.MapToolType.rule && !moveRuleNode) { rulePoints.push($.pixelToWorld(currX, currY, params, width, height)); showRule(); }
				else if (currTool == $.MapToolType.info) { var offset = $.getPageOffset(); startX = event.clientX + offset.left; startY = event.clientY + offset.top; showWaitToolTip(startX, startY); infoByPoint(currX, currY); }
				isMouseDown = false;
			}
			var mapMouseWeel = function(event) {
				if (isBusy) return false; hideToolTip();
				var delta = 0, p=$.getPosition(obj), currX = event.clientX - p.left, currY = event.clientY - p.top;
				if (event.wheelDelta) { delta = event.wheelDelta / 120; } else if (event.detail) { delta = -event.detail / 3; }
				if (delta < 0) zoomOutPoint(currX, currY); else zoomInPoint(currX, currY);
				return false;
			}
			var mapMouseOut=function(event){ if ($.contains(obj[0],event.relatedTarget)) return; if(!moveRuleNode) mapMouseUp(event);}
			var mapResize=function(event){if((width!=obj.width() || height != obj.height()) && params != null) { if(isBusy) wrapper.Abort(); width = obj.width(); height = obj.height(); params.width = width; params.height = height; correctParams(0, 0, width, height); }}
			var mapDblClick = function(event) {
				if (isBusy) return;
				if(currTool == $.MapToolType.pan) { var p=$.getPosition(obj), currX = event.clientX - p.left, currY = event.clientY - p.top; zoomInPoint(currX, currY);}
			}

			obj.mousedown(mapMouseDown);
			obj.mousemove(mapMouseMove);
			obj.mouseup(mapMouseUp);
			obj.mouseout(mapMouseOut);
			obj.dblclick(mapDblClick);
			//obj.bind("contextmenu",function(){return false;});
			obj.bind("DOMMouseScroll",mapMouseWeel);
			obj.bind("mousewheel",mapMouseWeel);
			obj.bind("drag",function(){return false;});
			if(ie) {nextImg.load(endLoadingIE);currImg.load(endLoadingIE);}
			if(settings.autoResize) $(window).bind("resize",mapResize);
			return this;
		},
		navigator: function(options) {
			if(this.length>1){this.each(function(){$(this).navigator(options)});return this;}
			var obj=$(this),settings={wrapperURL:"/MapControlAJAX/mapwrapper.asmx",maxOpacity:1,minOpacity:0.8,visibleAreaMinSize:6};options?$.extend(settings,options):null;
			//fields
			var isBusy=false,isMouseDown=false,isMouseOver=false,map=null,params=null,delayParams=null,width=obj.width(),height=obj.height();
			var wrapper=new WH();wrapper.MapWrapperURL=settings.wrapperURL;wrapper.Host=document.domain;
			//UI
			obj.addClass("navConteiner");
			var img=$("<input type=\"image\" />").addClass("mapImg").hide().appendTo(obj).attr("src",""),visibleArea=$("<div></div>").addClass("visibleArea").hide().appendTo(obj),hLine=$("<div></div>").addClass("hLine").hide().appendTo(obj),vLine=$("<div></div>").addClass("vLine").hide().appendTo(obj);
			//private methods
			var busyOn=function(){isBusy=true;obj.trigger("startLoading");}
			var busyOff=function(){isBusy=false;if(delayParams){setVArea(delayParams);delayParams=null;}obj.trigger("stopLoading");}
			var endLoading=function(){img.fadeIn(200,function(){busyOff();obj.trigger("paramsChanged",params);});}
			var refreshMap=function(){var url=wrapper.GMURL(settings.wrapperURL,params);img.attr("src",url);}
			var showMap=function(){params=wrapper.PMP(this.responseXML);params.drawScaleBar=false;refreshMap();}
			var goToMin=function(){obj.stop().animate({"opacity":settings.minOpacity},"fast");}
			var goToMax=function(){obj.stop().animate({"opacity":settings.maxOpacity},"fast");}
			var setVArea=function(mapParams){if(!isBusy){var h=params.scale*width/mapParams.width;h=mapParams.scale/h;var vWidth=parseInt(h*width);if(vWidth>width) vWidth=width;if(vWidth<settings.visibleAreaMinSize) vWidth=settings.visibleAreaMinSize;h=params.scale*height/mapParams.height;h=mapParams.scale/h;var vHeight=parseInt(h*height);if(vHeight>height) vHeight=height;if(vHeight<settings.visibleAreaMinSize) vHeight=settings.visibleAreaMinSize;visibleArea.css("left", parseInt(width/2+$.distanceToPixel(mapParams.x-params.x, params)-(vWidth/2))+"px").css("top", parseInt(height/2-$.distanceToPixel(mapParams.y-params.y, params)-(vHeight/2))+"px");var s=$.getStyle(visibleArea[0]);vHeight-=((parseInt(s.borderTopWidth)+parseInt(s.borderBottomWidth)));vWidth-=((parseInt(s.borderLeftWidth)+parseInt(s.borderRightWidth)));visibleArea.width(vWidth).height(vHeight).show();}else delayParams=mapParams;}
			//public methods
			this.setMap=function(m){if(!isBusy){busyOn();map=m;wrapper.GMEMP(showMap,null,map.id,width,height);}return this;}
			this.setVisibleArea = function(mapParams) {setVArea(mapParams);return this;}
			this.regMapControl=function(control){control.bind("paramsChanged",function(e,p){setVArea(p);});obj.bind("visibleAreaChanged",function(e,p){control.setCenter(p.x,p.y);});return this;}
			//map handlers
			var mapMouseDown = function(event) {if (isBusy) return; isMouseDown = $.isLeftButton(event);}
			var mapMouseMove = function(event) {var p=$.getPosition(obj),currX=event.clientX-p.left,currY=event.clientY-p.top;hLine.css("top",currY+"px");vLine.css("left",currX+"px");return false;}
			var mapMouseUp = function(event) {if (!isMouseDown) return; var p=$.getPosition(obj),currX=event.clientX-p.left,currY=event.clientY-p.top;var p = $.pixelToWorld(currX, currY, params, width, height);obj.trigger("visibleAreaChanged", p);isMouseDown = false;}
			var mapMouseOver = function(event){if(!isMouseOver){hLine.show();vLine.show();goToMax();isMouseOver=true;}}
			var mapMouseOut = function(event){if (!$.contains(obj[0], event.relatedTarget)){hLine.hide();vLine.hide();goToMin();isMouseOver=false;}}
			obj.mousedown(mapMouseDown);obj.mousemove(mapMouseMove);obj.mouseup(mapMouseUp);obj.mouseover(mapMouseOver);obj.mouseout(mapMouseOut);img.load(endLoading);goToMin();
			return this;
		},
		scaleBox: function(options) {
			if(this.length>1){this.each(function(){$(this).scaleBox(options)});return this;}
			var isDown=false,obj=$(this),s={downButton:""};options?$.extend(s,options):null;
			var list=$("<ul></ul>").appendTo(document.body).addClass("scaleBox").hide();
			var trim = function(str){return str.replace(" ","");}
			var format = function(number){var i,n=trim(number.toString()).split('').reverse().join(''),result=[],t;while(n.length>0){t=n.substr(0,3);n=n.substring(3);result.push(t.split('').reverse().join(''));}return result.reverse().join(' ');}
			obj.change(function(){if(!isDown){var s=parseInt(trim(obj.val()));obj.trigger("scaleChanged",s);}});
			obj.keydown(function(event){if(event.keyCode==13){var s=parseInt(trim(obj.val()));isDown=true;obj.trigger("scaleChanged",s);}else isDown=false;});
			if(s.downButton){$(s.downButton).click(function(){if(!isDown) {list.width(obj.width()+3).css({left:obj.offset().left+"px",top:obj.offset().top+obj.height()+3+"px"}).slideDown("fast");$(document.body).bind("click",hideList);isDown=true;}else hideList();return false;});}
			var hideList=function(event){list.slideUp("fast");$(document.body).unbind("click",hideList);isDown=false;return false;}
			var setScale=function(event){var s=parseInt(trim($(event.target).text()));obj.val(format(s));obj.trigger("scaleChanged",s);hideList();}
			this.setRange=function(max,min){list.empty();var v=min,r=[1000000, 500000, 250000, 100000, 50000, 25000, 15000, 10000, 5000, 2000, 1000]; $.each(r, function(){$("<li>"+format(this)+"</li>").click(setScale).appendTo(list);});return this;}
			this.regMapControl=function(control){control.bind("paramsChanged",function(e,p){obj.val(format(p.scale));});obj.bind("scaleChanged",function(e,s){control.setScale(s);});return this;}
			return this;
		},
		layersBox: function(options) {
			if(this.length>1){this.each(function(){$(this).scaleBox(options)});return this;}
			var isDown=false,obj=$(this),s={wrapperURL: "/MapControlAJAX/mapwrapper.asmx", aling: "rigth", minOpacity: 1, maxOpacity: 1, transparentImgURL:"/MapControlAJAX/images/legenda/e.gif"}, elems;options?$.extend(s,options):null;

			var wrapper = new WH();
			wrapper.MapWrapperURL  = s.wrapperURL;
			wrapper.Host = document.domain;

			var list=$("<ul></ul>").appendTo(document.body).addClass("layersBox").hide().hover(function(){ list.animate({opacity: s.maxOpacity}, "fast");}, function(){ list.animate({opacity: s.minOpacity}, "fast");});
			obj.click(function(){if(!isDown) {var p=obj.offset();if(s.aling=="left") list.css("left", p.left+"px");else list.css("right", $(document.body).width()-(p.left+obj.width()+7)+"px");list.css("top",p.top+obj.height()+6+"px").animate({opacity: s.minOpacity}, 0).slideDown("fast");$(document.body).bind("click",hideListHandler);isDown= true;}else hideList();return false;});
			var hideList=function(event){list.slideUp("fast");$(document.body).unbind("click",hideListHandler);isDown= false;obj.trigger("layersChanged");}
			var hideListHandler=function(event){if(!$.contains(list[0],event.target)) hideList();}

			var getRootState= function(elem) {var c1= $('input[mychecked="2"]', elem).length, c2=$('input[mychecked="0"]', elem).length, r="1";if(c1 == 0) r="0"; else if(c2 == 0) r="2";return r;}
			var setState = function(elem, state, p, c) {if(state == "0") {elem.removeClass("checked").removeClass("partChecked");elem.attr("mychecked", "0");}if(state == "1") {elem.removeClass("checked").addClass("partChecked");elem.attr("mychecked", "1");}else if(state == "2") {elem.removeClass("partChecked").addClass("checked");elem.attr("mychecked", "2");}if(c) { $.each($("ul", elem.parent()).find("input"), function(){setState($(this), state, false, true);});}var pul = elem.parent().parent().parent("li");if(pul.length && p) {setState(pul.find("input:first"), getRootState(pul), true, false);}}
			var fillList = function(elems, l ){$.each(elems, function(i,v){var t = this.childs.length?'<div class="minus"></div>':'<img src="'+this.legend+'"/>';var li = $('<li>'+t+'<input type="image" src="'+s.transparentImgURL+'" id="m_elem_'+this.code+'" mychecked="0" /><label>'+this.display+'</label></li>').appendTo(l);if(this.childs.length) fillList(this.childs, $('<ul></ul>').css("display", "block").appendTo(li));});}
			var endLoading=function(elems){elems = wrapper.PME(this.responseXML);list.empty(); fillList(elems, list);$("input",list).click(function(){var s=$(this).attr("mychecked")=="2"?"0":"2";setState($(this), s, true, true);});$("div.minus",list).click(function(){var ul=$(this).parent().find("ul:first");if($(this).hasClass("plus")) {ul.css("display", "block");$(this).removeClass("plus").addClass("minus");}else {ul.css("display", "none");$(this).removeClass("minus").addClass("plus");}});$("label",list).click(function(){var box=$(this).parent().find("input:first");box.click();});}
			var getLayers = function(){var l=[];$.each($('input[mychecked="2"]', list), function(){l.push($(this).attr("id").substring(7));});return l;}
			this.setMap=function(map){wrapper.GME(endLoading,null,map.id);return this;}
			this.regMapControl=function(control){obj.bind("layersChanged",function(e){control.setLayers(getLayers());});return this;}
			return this;
		}
	});
})(jQuery);
