(function($) {
	$.fn.YMapify = function(controls) {
    	return this.each(function() {
			var $this = $(this);
			var _this = this;
			var mapControls = $(controls);
			var mapId = this.id;
			
			
			var polyLines = [];
			var polyCurrent = -1; 
			var markers = {};
			var mapLastPoint = false;
			var mapState = 'newMarker';
			var mapPulse = false;
			var mapPulseCounter = 0;
			var mapLastMarker = false;
			
			var mapZoomLevels = {'street': 14, 'house': 16};
			
			
			this.SetLineStyle = function(lineId, color, width) {
				var s = new YMaps.Style();
				s.lineStyle = new YMaps.LineStyle();
				s.lineStyle.strokeColor = color;
				s.lineStyle.strokeWidth = width;
				YMaps.Styles.remove(mapId + '#' + lineId);
				YMaps.Styles.add(mapId + '#' + lineId, s);
			}
			
			
			
									
			var map = new YMaps.Map(this);
	        map.setCenter(new YMaps.GeoPoint(37.64, 55.76), 10);
	        
	        var typeControl = new YMaps.ToolBar();
			map.addControl(typeControl);
			typeControl = new YMaps.Zoom();
			map.addControl(typeControl);
			
			typeControl = new YMaps.TypeControl();
			map.addControl(typeControl);
								
			
			_this.SetLineStyle('line0', 'bf0000ff', 4); 
			
			var t = new YMaps.Template();
			t.text = '<div id="$[uniqueID|uniqueID]" style="border: 1px solid red; background-color: white; height: 6px; width: 6px; margin-left: -4px; margin-top: -4px;"></div>';
			YMaps.Templates.add("example#customPointIcon", t);
			
			var s = new YMaps.Style();
			s.iconStyle = new YMaps.IconStyle();
			s.iconStyle.setTemplate(t);
			YMaps.Styles.add(mapId + '#icon', s);
	
			
			this.SetData = function(data) {
				var lines = data.lines;

				// Сначала очистим все раннее старье, if any.
				for (var i=0; i < polyLines.length; ++i) {
					var pl = polyLines[i];
					var nodes = pl.nodes;
					for (p=0; p < nodes.length; ++p) {
						map.removeOverlay(nodes[p]);
					}
					
					map.removeOverlay(pl.line); 
				}
				polyLines = [];
				
				for (var i in markers) {
					map.removeOverlay(markers[i]);					
				}
				markers = {}; 
				
				
				if (data.map) {
					map.setCenter(new YMaps.GeoPoint(data.map.lng, data.map.lat), data.map.zoom);
				} else {
					map.setCenter(new YMaps.GeoPoint(37.64, 55.76), 10);
				}
				
				for (var i=0; i < lines.length; ++i) {
					var linePoints = [];
					var nodes = lines[i].nodes;
					
					for (p=0; p < nodes.length; ++p) {
						linePoints.push(new YMaps.GeoPoint(nodes[p].lng, nodes[p].lat, false));
					}
						
					polyLines[i] = {line: new YMaps.Polyline(linePoints), nodes: []};
					_this.SetLineStyle('line' + i, lines[i].style.color, lines[i].style.width); 
					polyLines[i].line.setOptions({style: mapId + '#line' + i});
					map.addOverlay(polyLines[i].line);
					
					for (p=0; p < nodes.length; ++p) {
						var pm = new YMaps.Placemark(new YMaps.GeoPoint(nodes[p].lng, nodes[p].lat, false), {style: mapId + '#icon', draggable: true, hasBalloon: false});
						YMaps.Events.observe(pm, pm.Events.Drag, _this.PlaceMarkDrag);
						YMaps.Events.observe(pm, pm.Events.Click, _this.PlaceMarkClick);
						pm.myIndex = p;
						pm.myPoly = i;
						
						map.addOverlay(pm);
						polyLines[i].nodes.push(pm);
					}
				}
				
				polyCurrent = lines.length - 1;
				
				
				var loadedMarkers = data.markers;
				
				for (var i=0; i < loadedMarkers.length; ++i) {
					var m = loadedMarkers[i];
					var pm = new YMaps.Placemark(new YMaps.GeoPoint(m.lng, m.lat), {draggable: true, hasBalloon: false}); 
					pm.setIconContent(m.text);
					map.addOverlay(pm);
					
					YMaps.Events.observe(pm, pm.Events.Click, _this.MapMarkerClick);										
					markers[pm.uniqueID] = pm;
				}
				
				mapState = false;
				_this.MapStateChange('newRoute');
				
			}
		
	
			this.GetData = function() {
				var data = {lines: [], markers: []};
				
				var centerPoint = map.getCenter();
				data.map = {lat: centerPoint.getLat(), lng: centerPoint.getLng(), zoom: map.getZoom()};
				
				for (i=0; i < polyLines.length; ++i) {
					var pl = polyLines[i];
					var newPl = {};
					var lineStyle = false;
					
					var polyOptions = polyLines[i].line.getOptions();
					if (polyOptions) {
						var currentStyleName = polyOptions.style;
						var currentStyle = YMaps.Styles.get(currentStyleName);
						if (currentStyle) {
							lineStyle = {color: currentStyle.lineStyle.strokeColor, width: currentStyle.lineStyle.strokeWidth};
						}
					}
					
					if (!lineStyle) {
						lineStyle = {color: 'bf0000ff', width: 4};
					}
					
					newPl.style = lineStyle;
					newPl.nodes = [];					
					for (n=0; n < pl.nodes.length; ++n) {
						var p = pl.nodes[n].getGeoPoint();
						newPl.nodes[n] = {lat: p.getLat(), lng: p.getLng()};
					}
					
					data.lines.push(newPl);
				}	
			
				for (var i in markers) {
					var pm = markers[i];
					var p = pm.getGeoPoint();
					data.markers.push({lat: p.getLat(), lng: p.getLng(), text: pm.getIconContent().innerHTML.replace('<br>', '\n')});
				}
				
			
				return data;
			}
			
	
			
	
	
			function ColorRGB2Hex(red, green, blue) {
				var d = (red << 16) + (green << 8) + blue;
				return ('000000' + d.toString(16)).slice(-6);
			}
			
			setInterval(function() {
				if (!mapPulse) return false;		
				mapPulse.css('background-color', '#' + ColorRGB2Hex(0, Math.floor(Math.abs(Math.sin(mapPulseCounter++ / 5) * 255)), 0)); 
					
			}, 50);
	
			
			this.PlaceMarkDrag = function(e) {
				polyLines[this.myPoly].line.splice(this.myIndex, 1, e.getGeoPoint());
			}
			
			this.PlaceMarkClick = function(e) {
				if (mapLastPoint) {
					$('#' + mapLastPoint.uniqueID).css({backgroundColor: 'white', border: '1px solid #bf0000'});
					if (mapLastPoint.uniqueID == this.uniqueID) {
						mapLastPoint = false;
						mapPulse = false;
						polyCurrent = this.myPoly;
						_this.MapStateChange('newRoute');
		
						return;
					}
				}
				
				_this.MapStateChange('continueRoute');
				
				mapLastPoint = this;					    		
				mapPulse = $('#' + this.uniqueID);
				mapPulse.css({backgroundColor: 'green', border: '1px solid white'});
				polyCurrent = this.myPoly;
				
				return false;
			}		
			
			
			this.MapMarkerText = function() {
				if (mapLastMarker) {
					mapLastMarker.setIconContent(this.value.replace('\n', '<br>'));
				}
			}
		
		
			this.MapMarkerClick = function(e) {
				mapLastMarker = this;
				_this.MapStateChange('changeMarker');
				mapControls.find('TEXTAREA.marker_text').val(this.getIconContent().innerHTML.replace('<br>', '\n')).focus();				
			}


			this.PolyChangeStyle = function() {
				var color = mapControls.find('SELECT.route_color').val();
				var width = mapControls.find('SELECT.route_width').val();
				
				var polyOptions = polyLines[polyCurrent].line.getOptions();
				if (polyOptions) {
					var currentStyleName = polyOptions.style;
					var currentStyle = YMaps.Styles.get(currentStyleName);
					if (currentStyle) {
						currentStyle.lineStyle.strokeColor = color;
						currentStyle.lineStyle.strokeWidth = width;
										
						YMaps.Styles.remove(currentStyleName);
						YMaps.Styles.add(currentStyleName, currentStyle);
		
						polyLines[polyCurrent].line.setOptions(polyOptions);
					} 		
				}
			}
			
			this.MapGeoSearchKeydown = function(e) {
				if (e.keyCode == 13) {
					_this.MapGeoSearch();
					e.stopPropagation();
					e.preventDefault();
					return false;
				}
			}
			
			this.MapGeoSearchKeyup = function(e) {	
				if (e.keyCode == 13) {
					e.stopPropagation();
					e.preventDefault();
					return false;
				}
			}
			
			this.MapGeoSearch = function() {	
				var text = mapControls.find('INPUT.map_search').val();
				if (text == '') {
					return false;
				}
			
				var geocoder = new YMaps.Geocoder(text);
				YMaps.Events.observe(geocoder, geocoder.Events.Load, function () {
				    if (this.length()) {
				        var firstResult = this.get(0);
				        map.addOverlay(firstResult);

				        if (mapZoomLevels[firstResult.kind] != undefined) {		        
				        	map.setCenter(firstResult.getGeoPoint(), mapZoomLevels[firstResult.kind]);
				        	
				        } else {		
				        	map.setZoom(10);
				        	map.panTo(firstResult.getGeoPoint());
				        }
				        
				        if (this.length() == 1) {
				        	_this.MapStateChange('newRoute');
				        	_this.MarkActLink('newRoute'); 
				        	
				        } else {
				        	var variantsStr = 'Мы перебросили вас к первому из найденных объектов. Ниже - другие варианты, отвечающие вашему запросу.';
				       		for (i = 1; i < this.length(); ++i) {
				       			var gr = this.get(i);
				       			variantsStr += '<br /><a href="#" class="ajax">' + gr.text + '</a>';
				       		}
				        	mapControls.find('P.map_search_results').html(variantsStr);
				        	_this.MarkActLink('newRoute'); 
				        }
				        
				    } else {
				    	mapControls.find('P.map_search_results').html('Поиск результатов не принес. Попробуйте уточнить запрос.');		        
				    }
				})
				
				return false;
			}
			
			this.MarkActLink = function(act) {
				mapControls.find('A.active[act]').removeClass('active');
				if (act) mapControls.find('A[act=' + act + ']').addClass('active');
			}
			
			
			this.MapStateChange = function(newState, processAnyway) {
				if (mapState == newState && !processAnyway) return;
				
				mapControls.find('DIV.map_route').hide();
				mapControls.find('DIV.map_geocoder').hide();
				mapControls.find('DIV.map_marker').hide();
				
				switch (newState) {
					case 'geoSearch': 
						mapControls.find('DIV.map_geocoder').show();
						mapControls.find('P.map_search_results').html('');
						if (polyLines.length) {
							mapControls.find('DIV.route_text_gotone').show();
						}
						_this.MarkActLink('geoSearch'); 
						
						break;
				
					case 'newMarker': 
						mapControls.find('DIV.map_marker').show();
						mapControls.find('DIV.marker_new').show();
						mapControls.find('DIV.marker_edit').hide();
						if (polyLines.length) {
							mapControls.find('DIV.route_text_gotone').show();
						}
						_this.MarkActLink('newMarker'); 
						
						break;
				
					case 'changeMarker': 
						mapControls.find('DIV.map_marker').show();
						mapControls.find('DIV.marker_new').hide();
						mapControls.find('DIV.marker_edit').show();
						
						if (polyLines.length) {
							mapControls.find('DIV.route_text_gotone').show();
						}
						
						_this.MarkActLink(false);
						
						break;
					
					case 'newRoute': 				
						mapControls.find('DIV.map_route').show();
						mapControls.find('DIV.route_text_new').show();
						mapControls.find('DIV.route_text_continue').hide();
						if (polyLines.length) {
							mapControls.find('DIV.route_text_gotone').show();
						}
						_this.MarkActLink('newRoute');
						
						break;
					
					case 'continueRoute':
						mapControls.find('DIV.map_route').show();
						mapControls.find('DIV.route_text_new').hide();
						mapControls.find('DIV.route_text_continue').show();
						
						if (polyLines.length > 1) {
							mapControls.find('DIV.route_text_gotone').show();
						}
						_this.MarkActLink(false);
						
						break;
				}
				
				mapState = newState;
			}
			
			
			
			this.MapClick = function(e) {
				if (mapState == 'newMarker') {
					var pm = new YMaps.Placemark(e.getGeoPoint(), {draggable: true, hasBalloon: false}); 	
					pm.setIconContent('');
					map.addOverlay(pm);
					mapLastMarker = pm;			
					_this.MapStateChange('changeMarker');
					YMaps.Events.observe(pm, pm.Events.Click, _this.MapMarkerClick);
					
					mapControls.find('TEXTAREA.marker_text').val('').focus();
					
					markers[pm.uniqueID] = pm;
		
				} else if (mapState == 'newRoute' || mapState == 'continueRoute') {
			
					if (mapLastPoint) {
						mapPulse = false;
						$('#' + mapLastPoint.uniqueID).css({backgroundColor: 'white', border: '1px solid #bf0000'});
					} else {
						polyCurrent++;
					}
													
					var pm = new YMaps.Placemark(e.getGeoPoint(), {style: mapId + '#icon', draggable: true, hasBalloon: false}); 
					
					YMaps.Events.observe(pm, pm.Events.Drag, _this.PlaceMarkDrag);
					YMaps.Events.observe(pm, pm.Events.Click, _this.PlaceMarkClick);
					map.addOverlay(pm);
							
					mapPulse = $('#' + pm.uniqueID);
					mapPulse.css({backgroundColor: 'green', border: '1px solid white'});
					
					if (polyLines[polyCurrent] == undefined) {							
						polyLines[polyCurrent] = {line: new YMaps.Polyline([e.getGeoPoint()])};
						polyLines[polyCurrent].line.setOptions({style: mapId + '#line' + polyCurrent});
						_this.PolyChangeStyle();
						
						map.addOverlay(polyLines[polyCurrent].line);
						pm.myIndex = 0;
						pm.myPoly = polyCurrent;
						
						polyLines[polyCurrent].nodes = [pm];
						_this.MapStateChange('continueRoute');
						
					} else {
						var pl = polyLines[polyCurrent];
						var newIndex = mapLastPoint.myIndex + 1; 
						if (mapLastPoint.myIndex == 0 && pl.line.getNumPoints() > 1) {
							newIndex = 0; 
						}
												
						pm.myIndex = newIndex;
						pm.myPoly = polyCurrent;
						pl.line.splice(pm.myIndex, 0, e.getGeoPoint());
						if (pm.myIndex == 1) {
							// map.addOverlay(polyLines[polyCurrent]);
						}
						
						// pl.nodes[pl.nodes.length] = pm;
						pl.nodes.splice(newIndex, 0, pm);						
						for (i=newIndex; i < pl.nodes.length; ++i) {
							pl.nodes[i].myIndex = i;
						}
					}
					
					mapLastPoint = pm;
				}
			}
			
			
			YMaps.Events.observe(map, map.Events.Click, this.MapClick);
			mapControls.find('SELECT.route_color, SELECT.route_width').change(this.PolyChangeStyle);
			mapControls.find('INPUT.map_search').keydown(this.MapGeoSearchKeydown).keyup(this.MapGeoSearchKeyup).keypress(this.MapGeoSearchKeyup);
			mapControls.find('INPUT.map_search_submit').click(this.MapGeoSearch);
			mapControls.find('TEXTAREA.marker_text').keyup(this.MapMarkerText);
			this.MapStateChange('newRoute');
			
			
			
			
			
			mapControls.find('A').live('click', function(e) {
				switch (this.getAttribute('act')) {
					case 'geoSearch': 
						_this.MapStateChange('geoSearch');
						mapControls.find('INPUT.map_search').focus();
						return false;
				
					case 'newMarker':
						_this.MapStateChange('newMarker');
						return false;
				
					case 'newRoute': 
						_this.MapStateChange('newRoute');
						if (mapLastPoint) {
							mapPulse = false;
							$('#' + mapLastPoint.uniqueID).css({backgroundColor: 'white', border: '1px solid #bf0000'});
							mapLastPoint = false;
						}
						return false;
						
					case 'deleteMarker': 
						if (mapLastMarker) {
							delete markers[mapLastMarker.uniqueID];
							map.removeOverlay(mapLastMarker); 
							mapLastMarker = false;
							_this.MapStateChange('newMarker');					
						}				
					
						return false;
					
					case 'deletePoint':
						if (mapLastPoint) {
							var pl = polyLines[mapLastPoint.myPoly];							
							
							if (pl.line.getNumPoints() == 1) { // Удаляем линию																
								
								var polyIndex = mapLastPoint.myPoly;
								
								map.removeOverlay(mapLastPoint);
								mapLastPoint = false;
								mapPulse = false;
								
								map.removeOverlay(pl.line);
								polyLines.splice(polyIndex, 1);
								for (var p = polyIndex; p < polyLines.length; ++p) {
									for (var n=0; n < polyLines[p].nodes.length; ++n) {
										polyLines[p].nodes[n].myPoly = p;
									}
								}
								
								_this.MapStateChange('newRoute');
								
							
							} else {							
								var removeIndex = mapLastPoint.myIndex;						
								pl.line.splice(removeIndex, 1);
								pl.nodes.splice(removeIndex, 1);
								for (i=removeIndex; i < pl.nodes.length; ++i) {
									pl.nodes[i].myIndex = i;
								}					
								
								map.removeOverlay(mapLastPoint);
								
								if (removeIndex > 0) {
									mapLastPoint = pl.nodes[removeIndex - 1];
									mapPulse = $('#' + mapLastPoint.uniqueID);
									mapPulse.css({backgroundColor: 'white', border: '1px solid white'});
									
								} else {
									if (pl.line.getNumPoints() > 0) {
										mapLastPoint = pl.nodes[0];
										mapPulse = $('#' + mapLastPoint.uniqueID);
										mapPulse.css({backgroundColor: 'white', border: '1px solid white'});
										
									} else {
										mapLastPoint = false;
										mapPulse = false;
									}
								}
							}
						}
						return false;
				
				}
				
				
				return false;
			});	
		});
	}

})(jQuery);




(function($) {
	$.fn.YMapShow = function(data) {
    	return this.each(function() {
			var $this = $(this);
			var _this = this;
			var mapId = this.id;
						
			this.SetLineStyle = function(lineId, color, width) {					
				var s = new YMaps.Style();
				s.lineStyle = new YMaps.LineStyle();
				s.lineStyle.strokeColor = color;
				s.lineStyle.strokeWidth = width;
				YMaps.Styles.remove(mapId + '#' + lineId);
				YMaps.Styles.add(mapId + '#' + lineId, s);
			}
									
			var map = new YMaps.Map(this);
			if (data.map) {
				map.setCenter(new YMaps.GeoPoint(data.map.lng, data.map.lat), data.map.zoom);
			} else {
				map.setCenter(new YMaps.GeoPoint(37.64, 55.76), 10);
			}
	        
	        var typeControl = new YMaps.ToolBar();
			map.addControl(typeControl);
			typeControl = new YMaps.Zoom();
			map.addControl(typeControl);
			typeControl = new YMaps.TypeControl();
			map.addControl(typeControl);

			var lines = data.lines;
						
			for (var i=0; i < lines.length; ++i) {
				var linePoints = [];
				var nodes = lines[i].nodes;
				
				for (p=0; p < nodes.length; ++p) {
					linePoints.push(new YMaps.GeoPoint(nodes[p].lng, nodes[p].lat, false));
				}
					
				var pl = new YMaps.Polyline(linePoints);
				_this.SetLineStyle('line' + i, lines[i].style.color, lines[i].style.width); 
				pl.setOptions({style: mapId + '#line' + i});
				map.addOverlay(pl);
			}
			
			var markers = data.markers;
			
			for (var i=0; i < markers.length; ++i) {
				var m = markers[i];
				var pm = new YMaps.Placemark(new YMaps.GeoPoint(m.lng, m.lat), {draggable: false, hasBalloon: false}); 
				pm.setIconContent(m.text.replace(/\n/g, '<br />'));
				map.addOverlay(pm);
			}
		});
	}
})(jQuery);

