/**
 * @author	itspoma
 *
 */
(function($){
	if ( ! $) return;
	
	$.YMaps = function(options)
	{
		try
		{
			if ( true == jQuery.isFunction( YMaps.jQuery ) )
			{
				return new m_YMaps(options);
			}
		}
		catch(err) { }
		
		return null;
	};
	
	var m_YMaps = function(options)
	{
		this.map = null;
		this.map_location_now = null;
		this.map_placemark = null;
		this._polygon = null;
		
		this.settings = {
			div: "#map",				// блок, в котором будет лежать карта
			lat: 0,						// широта
			lng: 0,						// долгота
			zoom : 16,					// увеличение
			controls_type : true,       // кнопки схема\спутник\гибрид
			controls_toolbar : true,    // тулбар слеве-сверху
			controls_zoom : true,       // увеличение\уменьшение
			controls_scaleline : false // полоска справа-снизу
		};
		/*
		this.__defineGetter__("polygon",
			function()
			{
				if ( this._polygon == null )
				{
					this._polygon = new m_YMaps_Polygon({});
				}
				return this._polygon;
			}
		);
		*/
		$.extend(this.settings, options);
		
		this.init();
	};
	
	m_YMaps.prototype =
	{
		init : function()
		{
			this.map_location_now = YMaps.location;
			
			$s = this.settings;
			
			if ( $s.div == '' )
			{
				return;
			}
			
			this.settings.lat = this._check_var($s.lat, this.map_location_now.longitude);
			this.settings.lng = this._check_var($s.lng, this.map_location_now.latitude);
			
			this.map = new YMaps.Map(YMaps.jQuery($s.div)[0]);
			this.map.setCenter(new YMaps.GeoPoint($s.lat, $s.lng), $s.zoom);
			
			if ( $s.controls_type === true )
				this.map.addControl(new YMaps.TypeControl());
			if ( $s.controls_toolbar === true )
				this.map.addControl(new YMaps.ToolBar());
			if ( $s.controls_zoom === true )
				this.map.addControl(new YMaps.Zoom());
			if ( $s.controls_scaleline === true )
				this.map.addControl(new YMaps.ScaleLine());
		},
		
		/**
		 * добавление метки на карту
		 * @param string _name 	имя метки
		 * @param string _description описание метки
		 * @param float _lat широта
		 * @param float _lng долгота
		 * @param hash _options внутр. настройки метки
		 * @return YMaps.Placemark
		 */
		placemark_add : function(_name, _description, _lat, _lng, _options, _add_overlay)
		{
			_lat = this._check_var(_lat, this.settings.lat);
			_lng = this._check_var(_lng, this.settings.lng);
			
			if ( _options == undefined )
			{
				_options = {draggable: true};
			}
			this.map_placemark = new YMaps.Placemark(new YMaps.GeoPoint(_lat, _lng), _options);
			this.map_placemark.name = _name;
			this.map_placemark.description = _description;
			
			if ( _add_overlay !== false )
			{
				this.map.addOverlay(this.map_placemark);
			}
			
			return this.map_placemark;
		},
		
		/**
		 * удаление метки с карты
		 * @return bool
		 */
		placemark_remove : function()
		{
			if ( this.map_placemark == null ) { return false; }
			
			this.overlay_remove(this.map_placemark);
			this.map_placemark = null;
			
			return true;
		},
		
		/**
		 * открывает подсказку (балун)
		 * @param float _lat широта
		 * @param float _lng долгота
		 * @param string _text текст
		 */
		balloon_open : function(_lat, _lng, _text)
		{
			_lat = this._check_var(_lat, this.settings.lat);
			_lng = this._check_var(_lng, this.settings.lng);
		
			var _geoPoint = new YMaps.GeoPoint(_lat, _lng);
			
			this.map.openBalloon( _geoPoint, _text, {hasCloseButton: false} );
		},
		
		/**
		 * обновляет содержимое подсказки (балуна)
		 * @param string _content текст
		 * @return bool
		 */
		balloon_update : function( _content )
		{
			var ballon = this.map.getBalloon();
			if ( ballon == undefined ) { return false; }
			
			ballon.setContent( _content );
			
			return true;
		},
		
		/**
		 * закрывает (прятает) подсказку (балун)
		 */
		balloon_close : function()
		{
			this.map.closeBalloon();
		},
		
		/**
		 * добавляет новый обработчик события
		 * @param event _event событие
		 * @param function _function колбек (callback)
		 */
		observe_add : function(_event, _function)
		{
			YMaps.Events.observe(this.map, this._event(_event), 
				function (map, mEvent)
				{
					if ( mEvent !== undefined )
					{
						var _lat = mEvent.getGeoPoint().getX();
						var _lng = mEvent.getGeoPoint().getY();
						
						_function(_lat, _lng, map, mEvent);
						return;
					}
					
					_function(map);
				}
			);
		},
		
		/**
		 * геокодер координаты => местоположение (страна, улица, ..)
		 * @param float _lat широта
		 * @param float _lng долгота
		 * @param function _function колбек (callback)
		 */
		geocoder_c2v : function(_lat, _lng, _function)
		{
			_lat = this._check_var(_lat, this.settings.lat);
			_lng = this._check_var(_lng, this.settings.lng);
		
			var geocoder = new YMaps.Geocoder(new YMaps.GeoPoint(_lat, _lng), {results: 1});
			YMaps.Events.observe(geocoder, geocoder.Events.Load,
				function()
				{
					var _text = geocoder.get(0).text;
					_function(_text);
				}
			);
		},
		
		/**
		 * геокодер местоположение (страна, улица, .. координаты) => координаты
		 * @param string _value местоположение
		 * @param function _function колбек (callback)
		 */
		geocoder_v2c : function(_value, _function)
		{
			var geocoder = new YMaps.Geocoder(_value, {results: 1, boundedBy: this.map.getBounds()});
			YMaps.Events.observe(geocoder, geocoder.Events.Load,
				function()
				{
					var _result = null;
					if (this.length())
					{
						_result = this.get(0);
					}
					_function(_result);
				}
			);
		},
		
		/**
		 * добавляет новую метку (оверлей)
		 * @param overlay _overlay метка
		 * @return bool
		 */
		overlay_add : function(_overlay)
		{
			if ( _overlay == null ) { return false; }
			
			this.map.addOverlay(_overlay);
			
			return true;
		},
		
		/**
		 * удаляет метку (оверлей)
		 * @param overlay _overlay метка
		 * @return bool
		 */
		overlay_remove : function(_overlay)
		{
			if ( _overlay == null ) { return; false }
			
			if ( _overlay === 'all' || _overlay === 0 )
			{
				this.map.removeAllOverlays();
			}
			else
			{
				this.map.removeOverlay(_overlay);
			}
			return true;
		},
		
		/**
		 * устанавливает границы карты
		 * @param bounds _bounds границы
		 */
		set_bounds : function(_bounds)
		{
			this.map.setBounds(_bounds)
		},
		
		geo_collection : function()
		{
			return new YMaps.GeoObjectCollection();
		},
		
		/*
		geo_point : function(_lat, _lng)
		{
			var point = new YMaps.GeoPoint(_lat, _lng);
			return { lat: point.getLat(), lng: point.getLng() };
		},
		*/
		
		/**
		 * создает новый стиль
		 * @param hash _ico стиль метки
		 * @param hash _shadow стиль тени
		 */
		style : function(_ico, _shadow)
		{
			var _style = new YMaps.Style();
			
			_style.iconStyle = new YMaps.IconStyle();
			_style.iconStyle.href = _ico.link;
			_style.iconStyle.size = new YMaps.Point(_ico.w, _ico.h);
			if ( _ico.offset_w != undefined && _ico.offset_h != undefined )
			{
				_style.iconStyle.offset = new YMaps.Point(_ico.offset_w, _ico.offset_h);
			}
			
			if ( _shadow != undefined )
			{
				_style.shadow = new YMaps.IconShadowStyle();
				_style.iconStyle.shadow = new YMaps.IconShadowStyle();
				_style.iconStyle.shadow.href = _shadow.link;
				_style.iconStyle.shadow.size = new YMaps.Point(_shadow.w, _shadow.h);
				if ( _shadow.offset_w != undefined && _shadow.offset_h != undefined )
				{
					_style.iconStyle.shadow.offset = new YMaps.Point(_shadow.offset_w, _shadow.offset_h);
				}
			}
			
			return _style;
		},
		
		_map : function()
		{
			return this.map;
		},
		
		_check_var : function(_var, _default)
		{
			return _var == undefined ? _default : _var;
		},
		
		_event : function(_event)
		{
			switch ( _event ) {
				case 'map.click' : return this.map.Events.Click;
				case 'map.onZoomStart' : return this.map.Events.SmoothZoomStart;
				case 'map.onZoomEnd' : return this.map.Events.SmoothZoomEnd;
				case 'map.onTypeChange' : return this.map.Events.TypeChange;
				case 'map.onUpdate' : return this.map.Events.Update;
				case 'map.onDblClick' : return this.map.Events.DblClick;
				case 'map.onGragStart' : return this.map.Events.DragStart;
				case 'map.onGrag' : return this.map.Events.Drag;
				case 'map.onGragEnd' : return this.map.Events.DragEnd;
				default: return _event;
			}
		}
	};
	
	
	var m_YMaps_Polygon = function(options)
	{
		/*
		this.settings = {
			div: "#map",
		};
		
		$.extend(this.settings, options);
		*/
		this.init();
	};
	
	m_YMaps_Polygon.prototype =
	{
		init : function()
		{
			/*
			function extend (child, parent) {
				var c = function () {};
				c.prototype = parent.prototype;
				c.prototype.constructor = parent;
				return child.prototype = new c;
			};
			*/
			var c = function () {};
			c.prototype = YMaps.Polygon.prototype;
			c.prototype.constructor = YMaps.Polygon;
			this.Circle2.prototype = new c;
			
			//extend(this.Circle2, YMaps.Polygon);
		},
		
		/** 
		 * Оверлей "Круг"
		* center - географические координаты центра
		* radius - радиус круга в км
		* ptions.accuracy - количество граней многоугольника
		 */
		Circle2 : function(center, radius, options)
		{
			this.center = center;
			this.radius = radius;
			this.options = YMaps.jQuery.extend({accuracy : 360}, options);
			
			// Вызывает родительский конструктор
			YMaps.Polygon.call(this, [], this.options);

			// Вызывается при добавлении круга на карту
			this.onAddToMap = function (map, container) {
				this.map = map;
				this.calculatePoints();

				YMaps.Polygon.prototype.onAddToMap.call(this, map, container);
			}

			// Устанавливает новый центр и радиус
			this.setCenter = function (newCenter, newRadius) {
				if (this.map && (!this.center.equals(newCenter) || this.radius != newRadius)) {
					this.center = newCenter;
					this.radius = newRadius || this.radius;
					this.calculatePoints();
				}
			}

			// Вычисляет точки окружности
			this.calculatePoints = function () {
				// Откладываем геоточку от центра к северу на заданном расстоянии
				var northPoint = new YMaps.GeoPoint(
						this.center.getLng(), 
						this.center.getLat() + this.radius / 112.2
				),

				// Пиксельные координаты на последнем масштабе
				pixCenter = this.map.coordSystem.fromCoordPoint(this.center),

				// Радиус круга в пикселях
				pixRadius = pixCenter.getY() - this.map.coordSystem.fromCoordPoint(northPoint).getY(),

				// Вершины многоугол
				points = [],

				// Вспомогательные переменные
				twoPI = 2 * Math.PI,
				delta = twoPI / this.options.accuracy;

				for (var alpha = 0; alpha < twoPI; alpha += delta) {
					points.push(
						this.map.coordSystem.toCoordPoint(
							new YMaps.Point(
								Math.cos(alpha) * pixRadius + pixCenter.getX(), 
								Math.sin(alpha) * pixRadius + pixCenter.getY()
							)
						)
					) 
				}

			this.setPoints(points);
			}
		}		
	};
		
})(jQuery);
