text: var jsGoogleCE = {
  	map: null,
  	arData: null,
  	obForm: null,
  	
  	currentView: '',
  	
  	bPositionFixed: true,
  	bAddPointMode: false,
  	bAddPolyMode: false,
  	
  	DblClickObserver: null,
  	
  	__arValidKeys: ['google_lat', 'google_lon', 'google_scale', 'PLACEMARKS', 'LON', 'LAT', 'TEXT'],
  	
  	__currentPolyLine: null,
  	__currentPolyLineObject: null,
  	
  	init: function() 
  	{
  		BX.loadCSS('/bitrix/components/bitrix/map.google.system/templates/.default/style.css');
  	
  		jsGoogleCE.map = GLOBAL_arMapObjects['system_view_edit'];
  		
  		jsGoogleCE.arData = arPositionData;
  		jsGoogleCE.obForm = document.forms['bx_popup_form_google_map'];
  		jsGoogleCE.obForm.onsubmit = jsGoogleCE.__saveChanges;
  		
  		
  		google.maps.event.addListener(jsGoogleCE.map, 'dragend', jsGoogleCE.__getPositionValues);
  		google.maps.event.addListener(jsGoogleCE.map, 'maptypeid_changed', jsGoogleCE.__getPositionValues);
  		
  		if (!jsGoogleCE.arData.google_lat || !jsGoogleCE.arData.google_lon || !jsGoogleCE.arData.google_scale)
  		{
  			var obPos = jsGoogleCE.map.getCenter();
  			jsGoogleCE.arData.google_lat = obPos.lat();
  			jsGoogleCE.arData.google_lon = obPos.lng();
  			jsGoogleCE.arData.google_scale = jsGoogleCE.map.getZoom();
  			jsGoogleCE.bPositionFixed = false;
  		}
  		else
  		{
  			jsGoogleCE.arData.google_scale = parseInt(jsGoogleCE.arData.google_scale);
  			jsGoogleCE.bPositionFixed = true;
  		}
  		
  		jsGoogleCE.setControlValue('google_lat', jsGoogleCE.arData.google_lat);
  		jsGoogleCE.setControlValue('google_lon', jsGoogleCE.arData.google_lon);
  		jsGoogleCE.setControlValue('google_scale', jsGoogleCE.arData.google_scale);
  
  		jsGoogleCE.currentView = BX.message('google_current_view');
  		
  		jsGoogleCE.setControlValue('google_view', BX.message('google_MAP_VIEW_' + jsGoogleCE.map.getMapTypeId().toUpperCase()));
  		
  		if (BX.browser.IsIE())
  		{
  			// unreally dirty hack....
  			var pm = new google.maps.Marker({
  				position: new google.maps.LatLng(90, 0),
  				map: jsGoogleCE.map
  			});
  		}
  		
  		if (jsGoogleCE.arData.PLACEMARKS && jsGoogleCE.arData.PLACEMARKS.length > 0)
  		{
  			for (var i = 0, len = jsGoogleCE.arData.PLACEMARKS.length; i < len; i++)
  			{
  				jsGoogleCE.addCustomPoint(jsGoogleCE.arData.PLACEMARKS[i], i);
  			}
  		}
  
  		BX('bx_restore_position').onclick = jsGoogleCE.restorePositionValues;
  		BX('bx_google_map_controls').style.visibility = 'visible';
  		BX('bx_google_map_address_search').style.visibility = 'visible';
  	},
  	
  	__getPositionValues: function()
  	{
  		if (jsGoogleCE.bPositionFixed)
  			return;
  	
  		var obPos = jsGoogleCE.map.getCenter();
  		jsGoogleCE.arData.google_lat = obPos.lat();
  		jsGoogleCE.arData.google_lon = obPos.lng();
  		jsGoogleCE.arData.google_scale = jsGoogleCE.map.getZoom();
  		
  		jsGoogleCE.setControlValue('google_lat', jsGoogleCE.arData.google_lat);
  		jsGoogleCE.setControlValue('google_lon', jsGoogleCE.arData.google_lon);
  		jsGoogleCE.setControlValue('google_scale', jsGoogleCE.arData.google_scale);
  		
  		jsGoogleCE.currentView = jsGoogleCE.map.getMapTypeId().toUpperCase();
  
  		jsGoogleCE.setControlValue('google_view', BX.message('google_MAP_VIEW_' + jsGoogleCE.currentView));
  	},
  	
  	restorePositionValues: function(e)
  	{
  		BX.PreventDefault(e);
  	
  		if (jsGoogleCE.currentView && google.maps.MapTypeId[jsGoogleCE.currentView])
  			jsGoogleCE.map.setMapTypeId(google.maps.MapTypeId[jsGoogleCE.currentView]);
  		
  		jsGoogleCE.map.setZoom(jsGoogleCE.arData.google_scale);
  		jsGoogleCE.map.panTo(new google.maps.LatLng(jsGoogleCE.arData.google_lat, jsGoogleCE.arData.google_lon));
  	},
  	
  	setFixedFlag: function(value)
  	{
  		jsGoogleCE.bPositionFixed = value;
  		if (!value)
  			jsGoogleCE.__getPositionValues();
  	},
  	
  	setControlValue: function(control, value)
  	{
  		var obControl = jsGoogleCE.obForm['bx_' + control];
  		if (null != obControl)
  			obControl.value = value;
  			
  		var obControlOut = BX('bx_' + control + '_value');
  		if (null != obControlOut)
  			obControlOut.innerHTML = value;
  	},
  	
  	__updatePointPosition: function()
  	{
  		if (null == this.BX_PLACEMARK_INDEX)
  			return;
  		
  		var obPoint = this.getPosition();
  		
  		jsGoogleCE.arData.PLACEMARKS[this.BX_PLACEMARK_INDEX].LON = obPoint.lng();
  		jsGoogleCE.arData.PLACEMARKS[this.BX_PLACEMARK_INDEX].LAT = obPoint.lat();
  	},
  	
  	addPoint: function()
  	{
  		//jsUtils.PreventDefault(e);
  	
  		if (jsGoogleCE.bAddPointMode)
  		{
  			jsGoogleCE.bAddPointMode = false;
  			jsGoogleCE.map.disableDoubleClickZoom = false;
  			BX('bx_google_addpoint_link').style.display = 'block';
  			BX('bx_google_addpoint_message').style.display = 'none';
  			
  			if (jsGoogleCE.DblClickObserver)
  				google.maps.event.removeListener(jsGoogleCE.DblClickObserver);
  		}
  		else
  		{
  			jsGoogleCE.bAddPointMode = true;
  			jsGoogleCE.map.disableDoubleClickZoom = true;
  			document.getElementById('bx_google_addpoint_link').style.display = 'none';
  			document.getElementById('bx_google_addpoint_message').style.display = 'block';
  			
  			jsGoogleCE.DblClickObserver = google.maps.event.addListener(jsGoogleCE.map, 'dblclick', jsGoogleCE.__addPoint);
  		}
  	},
  
  	__openBalloon: function(obPlacemark)
  	{
  		if (null == obPlacemark.infowin)
  		{
  			obPlacemark.infowin = new google.maps.InfoWindow({
  				content: ''
  			});
  		}
  		
  		obPlacemark.infowin.setContent('<textarea onblur="jsGoogleCE.__updatePointView(this, \'blur\')" onkeyup="jsGoogleCE.__updatePointView(this, \'keyup\')" id="BX_PLACEMARK_TEXT_' + obPlacemark.BX_PLACEMARK_INDEX + '">' + BX.util.htmlspecialchars(jsGoogleCE.arData.PLACEMARKS[obPlacemark.BX_PLACEMARK_INDEX].TEXT) + '</textarea>');
  		
  		obPlacemark.infowin.open(jsGoogleCE.map, obPlacemark);
  		
  		setTimeout(function() {
  			try {
  				BX('BX_PLACEMARK_TEXT_' + obPlacemark.BX_PLACEMARK_INDEX).focus();
  			} catch(e) {}
  		}, 500);
  	},
  	
  	__pointClick: function() 
  	{
  		jsGoogleCE.__openBalloon(this);
  	},
  	
  	__createPlaceMark: function(arPlacemark, index)
  	{
  		if (null == jsGoogleCE.arData.PLACEMARKS)
  			jsGoogleCE.arData.PLACEMARKS = [];
  		
  		if (null == index)
  		{
  			index = jsGoogleCE.arData.PLACEMARKS.length;
  			jsGoogleCE.arData.PLACEMARKS[index] = {
  				TEXT: arPlacemark.TEXT
  			};
  		}
  		
  		if (null != arPlacemark.POS)
  		{
  			jsGoogleCE.arData.PLACEMARKS[index].LON = arPlacemark.POS.lng();
  			jsGoogleCE.arData.PLACEMARKS[index].LAT = arPlacemark.POS.lat();
  		}
  		else
  		{
  			jsGoogleCE.arData.PLACEMARKS[index].LAT = arPlacemark.LAT;
  			jsGoogleCE.arData.PLACEMARKS[index].LON = arPlacemark.LON;
  		}
  
  		var obPointView = jsGoogleCE.__createPointView();
  		obPointView.id = 'BX_PLACEMARK_' + index;
  		
  		var obPoint = new google.maps.LatLng(jsGoogleCE.arData.PLACEMARKS[index].LAT, jsGoogleCE.arData.PLACEMARKS[index].LON);
  
  		var value_view = '';
  		if (arPlacemark.TEXT.length > 0)
  		{
  			var rnpos = arPlacemark.TEXT.indexOf("\n");
  			value_view = rnpos <= 0 ? arPlacemark.TEXT : arPlacemark.TEXT.substring(0, rnpos);
  			value_view = BX.util.htmlspecialchars(value_view);
  		}
  
  		obPointView.BXPlacemark = new google.maps.Marker({
  			position: obPoint,
  			map: jsGoogleCE.map,
  			draggable: true
  		});
  		
  		obPointView.BXPlacemark.BX_PLACEMARK_INDEX = index;
  		
  		obPointView.BXPlacemark.BXTEXT = '';
  		if (null != arPlacemark.TEXT && arPlacemark.TEXT.length > 0)
  			obPointView.BXPlacemark.BXTEXT = arPlacemark.TEXT.replace(/\n/g, '<br />');
  			
  		google.maps.event.addListener(obPointView.BXPlacemark, "click", jsGoogleCE.__pointClick);
  		google.maps.event.addListener(obPointView.BXPlacemark, "dragend", jsGoogleCE.__updatePointPosition);
  
  		jsGoogleCE.__updatePointViewText(obPointView, value_view ? value_view : BX.message('google_noname'));
  		
  		return obPointView.BXPlacemark;
  	},
  	
  	addCustomPoint: function(arPointInfo, index)
  	{
  		jsGoogleCE.__createPlaceMark({
  			TEXT: arPointInfo.TEXT,
  			LON: arPointInfo.LON,
  			LAT: arPointInfo.LAT
  		}, index);
  	},
  	
  	__addPoint: function(obPoint)
  	{
  		if (!jsGoogleCE.bAddPointMode)
  			return;
  		
  		jsGoogleCE.__openBalloon(jsGoogleCE.__createPlaceMark({
  			TEXT: '', POS: obPoint.latLng
  		}));
  	},
  	
  	__point_link_hover: function() {this.style.backgroundColor = "#E3E8F7"; this.firstChild.style.display = 'block';},
  	__point_link_hout: function() {this.style.backgroundColor = "#FFFFFF"; this.firstChild.style.display = 'none';},
  	
  	__createPointView: function()
  	{
  		var obView = BX('bx_google_points').appendChild(BX.create('LI', {
  			events: {
  				mouseover: jsGoogleCE.__point_link_hover,
  				mouseout: jsGoogleCE.__point_link_hout
  			},
  			children: [
  				BX.create('A', {
  					attrs: {
  						href: 'javascript: void(0)',
  						className: 'bx-google-delete'
  					},
  					events: {
  						click: jsGoogleCE.__deletePoint
  					},
  					style: {
  						display: 'none'
  					}
  				}),
  				BX.create('A', {
  					attributes: {
  						href: 'javascript: void(0)',
  						className: 'bx-google-point'
  					},
  					events: {
  						click: jsGoogleCE.__openPointBalloonFromView
  					},
  					html: BX.message('google_noname')
  				})
  			]
  		}));
  		
  		return obView;
  	},
  	
  	__deletePoint: function(e)
  	{
  		BX.PreventDefault(e);
  	
  		var obView = this.parentNode;
  		
  		jsGoogleCE.arData.PLACEMARKS[obView.BXPlacemark.BX_PLACEMARK_INDEX].DELETED = 1;
  		
  		if (obView.BXPlacemark.infowin)
  			obView.BXPlacemark.infowin = null;
  		obView.BXPlacemark.setMap(null);
  		
  		this.parentNode.parentNode.removeChild(this.parentNode);
  	},
  	
  	__updatePointViewText: function(obPointView, str)
  	{
  		obPointView.firstChild.nextSibling.innerHTML = str;
  	},
  	
  	__openPointBalloonFromView: function(e)
  	{
  		BX.PreventDefault(e);
  		jsGoogleCE.__openBalloon(this.parentNode.BXPlacemark);
  	},
  	
  	__updatePointView: function(obTextarea, type)
  	{
  		var value = obTextarea.value;
  		var index = obTextarea.id.substring(18)
  
  		jsGoogleCE.arData.PLACEMARKS[index].TEXT = value;
  		
  		var rnpos = value.indexOf("\n");
  
  		var value_view = '';
  		if (value.length > 0)
  			value_view = rnpos <= 0 ? value : value.substring(0, rnpos);
  
  		value_view = BX.util.htmlspecialchars(value_view);
  			
  		var obView = document.getElementById('BX_PLACEMARK_' + index);
  		
  		jsGoogleCE.__updatePointViewText(obView, value_view ? value_view : BX.message('google_noname'));
  		
  		if (type == 'blur')
  			obView.BXPlacemark.infowin.close();
  	},
  	
  	__checkValidKey: function(key)
  	{
  		if (Number(key) == key)
  			return true;
  	
  		for (var i = 0, len = jsGoogleCE.__arValidKeys.length; i < len; i++)
  		{
  			if (jsGoogleCE.__arValidKeys[i] == key)
  				return true;
  		}
  		
  		return false;
  	},
  	
  	__serialize: function(obj)
  	{
    		if (typeof(obj) == 'object')
    		{
      		var str = '', cnt = 0;
  		    for (var i in obj)
  		    {
  				if (jsGoogleCE.__checkValidKey(i))
  				{
  					++cnt;
  					str += jsGoogleCE.__serialize(i) + jsGoogleCE.__serialize(obj[i]);
  				}
  		    }
  		    
      		str = "a:" + cnt + ":{" + str + "}";
      		
      		return str;
  		}
  		else if (typeof(obj) == 'boolean')
  		{
  			return 'b:' + (obj ? 1 : 0) + ';';
  		}
  		else if (null == obj)
  		{
  			return 'N;'
  		}
  		else if (Number(obj) == obj && obj != '' && obj != ' ')
  		{
  			if (Math.floor(obj) == obj)
  				return 'i:' + obj + ';';
  			else
  				return 'd:' + obj + ';';
      	}
    		else if(typeof(obj) == 'string')
    		{
  			obj = obj.replace(/\r\n/g, "\n");
  			obj = obj.replace(/\n/g, "###RN###");
  
  			var offset = 0;
  			if (window._global_BX_UTF)
  			{
  				for (var q = 0, cnt = obj.length; q < cnt; q++)
  				{
  					if (obj.charCodeAt(q) > 127) offset++;
  				}
  			}
  			
    			return 's:' + (obj.length + offset) + ':"' + obj + '";';
  		}
  	},
  	
  	__saveChanges: function()
  	{
  		if (!jsGoogleCE.map) 
  			return false;
  			
  		jsGoogleCE.bAddPointMode = false;
  		
  		if (jsGoogleCE.arData['PLACEMARKS'])
  		{
  			var arNewPlacemarks = [];
  		
  			for(var i = 0, len = jsGoogleCE.arData.PLACEMARKS.length; i < len; i++)
  			{
  				if (null == jsGoogleCE.arData.PLACEMARKS[i].DELETED)
  					arNewPlacemarks[arNewPlacemarks.length] = jsGoogleCE.arData.PLACEMARKS[i];
  			}
  			
  			jsGoogleCE.arData.PLACEMARKS = arNewPlacemarks;
  		}
  	
  		window.jsGoogleCEOpener.saveData(jsGoogleCE.__serialize(jsGoogleCE.arData), jsGoogleCE.currentView);
  		return false;
  	}
  }
  
  var jsGoogleCESearch = {
  	bInited: false,
  
  	map: null,
  	geocoder: null,
  	obInput: null,
  	timerID: null,
  	timerDelay: 1000,
  	
  	arSearchResults: [],
  	
  	obOut: null,
  	
  	__init: function(input)
  	{
  		if (jsGoogleCESearch.bInited) return;
  		
  		jsGoogleCESearch.map = jsGoogleCE.map;
  		jsGoogleCESearch.obInput = input;
  		
  		input.form.onsubmit = function() {jsGoogleCESearch.doSearch(); return false;}
  		
  		input.onfocus = jsGoogleCESearch.showResults;
  		input.onblur = jsGoogleCESearch.hideResults;
  		
  		jsGoogleCESearch.bInited = true;
  	},
  	
  	setTypingStarted: function(input)
  	{
  		if (!jsGoogleCESearch.bInited)
  			jsGoogleCESearch.__init(input);
  
  		jsGoogleCESearch.hideResults();
  			
  		if (null != jsGoogleCESearch.timerID)
  			clearTimeout(jsGoogleCESearch.timerID);
  	
  		jsGoogleCESearch.timerID = setTimeout(jsGoogleCESearch.doSearch, jsGoogleCESearch.timerDelay);
  	},
  	
  	doSearch: function()
  	{
  		var value = jsUtils.trim(jsGoogleCESearch.obInput.value);
  		if (value.length > 1)
  		{
  			if (null == jsGoogleCESearch.geocoder)
  				jsGoogleCESearch.geocoder = new google.maps.Geocoder();
  			
  			jsGoogleCESearch.geocoder.geocode({
  				address: value, 
  				language: BX.message('LANGUAGE_ID')
  			}, jsGoogleCESearch.__searchResultsLoad);
  		}
  	},
  	
  	handleError: function()
  	{
  		alert(jsGoogleCE.jsMess.mess_error);
  	},
  	
  	__generateOutput: function()
  	{
  		var obPos = jsUtils.GetRealPos(jsGoogleCESearch.obInput);
  		
  		jsGoogleCESearch.obOut = document.body.appendChild(document.createElement('UL'));
  		jsGoogleCESearch.obOut.className = 'bx-google-address-search-results';
  		jsGoogleCESearch.obOut.style.top = (obPos.bottom + 2) + 'px';
  		jsGoogleCESearch.obOut.style.left = obPos.left + 'px';
  		jsGoogleCESearch.obOut.style.zIndex = parseInt(BX.WindowManager.Get().zIndex) + 200;
  	},
  
  	__searchResultsLoad: function(obResult, status)
  	{
  		var _this = jsGoogleCESearch;
  		
  		if (status != google.maps.GeocoderStatus.OK && status != google.maps.GeocoderStatus.ZERO_RESULTS)
  		{
  			_this.handleError({message: status});
  			return;
  		}
  		
  		if (!obResult)
  		{
  			_this.handleError();
  		}
  		else
  		{
  			if (null == _this.obOut)
  				_this.__generateOutput();
  			
  			_this.obOut.innerHTML = '';
  			_this.clearSearchResults();
  			
  			var len = 0;
  			if (status == google.maps.GeocoderStatus.OK)
  			{
  				len = obResult.length;
  				var obList = null;
  			}
  		
  			if (len > 0) 
  			{
  				for (var i = 0; i < len; i++)
  				{
  					_this.arSearchResults[i] = obResult[i].geometry.location;
  					
  					var lnk_text = '';
  					for (var j = 0; j < obResult[i].address_components.length; j++)
  					{
  						lnk_text += (lnk_text.length > 0 ? ', ' : '') + obResult[i].address_components[j].long_name;
  					}
  					
  					_this.obOut.appendChild(BX.create('LI', {
  						attrs: {className: i == 0 ? 'bx-google-first' : ''},
  						children: [
  							BX.create('A', {
  								attrs: {href: "javascript:void(0)"},
  								props: {BXSearchIndex: i},
  								events: {click: _this.__showSearchResult},
  								children: [
  									BX.create('SPAN', {
  										text: lnk_text
  									})
  								]
  							})
  						]
  					}));
  				}
  			} 
  			else 
  			{
  				_this.obOut.innerHTML = '<li class="bx-google-notfound">' + BX.message('google_nothing_found') + '</li>';
  			}
  			
  			_this.showResults();
  		}
  	},
  	
  	__showSearchResult: function(e)
  	{
  		if (null !== this.BXSearchIndex)
  		{
  			jsGoogleCESearch.map.panTo(jsGoogleCESearch.arSearchResults[this.BXSearchIndex]);
  		}
  		
  		return BX.PreventDefault(e);
  	},
  	
  	showResults: function()
  	{
  		if (null != jsGoogleCESearch.obOut)
  			jsGoogleCESearch.obOut.style.display = 'block';
  	},
  
  	hideResults: function()
  	{
  		if (null != jsGoogleCESearch.obOut)
  		{
  			setTimeout("jsGoogleCESearch.obOut.style.display = 'none'", 300);
  		}
  	},
  	
  	clearSearchResults: function()
  	{
  		for (var i = 0; i < jsGoogleCESearch.arSearchResults.length; i++)
  		{
  			delete jsGoogleCESearch.arSearchResults[i];
  		}
  
  		jsGoogleCESearch.arSearchResults = [];
  	},
  	
  	clear: function()
  	{
  		if (!jsGoogleCESearch.bInited)
  			return;
  			
  		jsGoogleCESearch.bInited = false;
  		if (null != jsGoogleCESearch.obOut)
  		{
  			jsGoogleCESearch.obOut.parentNode.removeChild(jsGoogleCESearch.obOut);
  			jsGoogleCESearch.obOut = null;
  		}
  		
  		jsGoogleCESearch.arSearchResults = [];
  		jsGoogleCESearch.map = null;
  		jsGoogleCESearch.geocoder = null;
  		jsGoogleCESearch.obInput = null;
  		jsGoogleCESearch.timerID = null;
  	}
  }
  
  