function PositionPointer(map, config, cookies) {
	this.map = map;
	this.config = config;
	this.cookies = cookies;
	if (config.manual) this.initManual(config.manual);
	if (config.geolocation) this.initGeo(config.geolocation);

	var dp = config.defaultPosition;
	if (dp) this.movePositionMarker(new YMaps.GeoPoint(dp[0], dp[1]), false, config.balloonContent);
	
}
PositionPointer.polyFromArray = function (points) {
	for (var i = points.length; i--;) {
		points[i] = new YMaps.GeoPoint(points[i][0], points[i][1])
	}
	return new YMaps.Polygon(points);
};
PositionPointer.createMarker = function (point, im, draggable) {
	var s = new YMaps.Style();
	s.iconStyle = new YMaps.IconStyle();
	s.iconStyle.href   = im.href.imageUrl();
	s.iconStyle.size   = new YMaps.Point(im.size  [0], im.size  [1]);
	s.iconStyle.offset = new YMaps.Point(im.offset[0], im.offset[1]);
	if (im.balloon) s.balloonStyle = im.balloon;
	return new YMaps.Placemark(point, {
		draggable: draggable,
		style    : s,
		balloonOptions: {hasCloseButton: false, maxWidth:270}
	});
};

// создание нового круга с заданными параметрами
/*
PositionPointer.createAreaCircle = function(point, radius, stroke, fill){
    return new this.Circle(point, radius,{
                style : {
                    polygonStyle : {
                        outline : true,
                        strokeWidth : stroke,
                        strokeColor : "0000ff55",
                        fillColor : fill
                    }
                },
                interactive : YMaps.Interactivity.NONE
            });
};
*/
PositionPointer.savePosition = function (name, point, options) {
	if (typeof point.getGeoPoint == 'function') point = point.getGeoPoint();
	$.cookie(name, point.getX() + ' ' + point.getY(), options);
	return this;
};

// отрисовка кругов в зависимости от масштаба
/*
PositionPointer.drawReachArea = function (map, ic, oc){
	map.removeOverlay(ic);
	map.removeOverlay(oc);
	var zoom = map.getZoom();
	if (zoom <= 11){
		map.addOverlay(oc);
	}
	if (11 < zoom && zoom < 14){
		var icStyle = ic.getStyle();
		icStyle.polygonStyle.strokeWidth = 2;
		icStyle.polygonStyle.fillColor = "00000000";
		ic.setStyle(icStyle);
		map.addOverlay(oc);
		map.addOverlay(ic);
	}
	if (zoom >= 14){
		var icStyle = ic.getStyle();
		icStyle.polygonStyle.strokeWidth = 3;
		icStyle.polygonStyle.fillColor = "0000ff11";
		ic.setStyle(icStyle);
		map.addOverlay(ic);
	}
}
*/
// начальное позиционирование маркера геокодера
PositionPointer.moveGeoMarker = function (config, point, centering, msg, dragMsg) {
	var map = this.map;
	this.dragMsg = dragMsg;
	if (this.marker) {
		map.removeOverlay(this.marker);
	}
	var cfg = $.extend({}, config.image, { balloon: Marker.style.balloon });
	var pm = this.marker = PositionPointer.createMarker(point, cfg, config.draggable);
	YMaps.Events.observe(pm, pm.Events.DragEnd, function (el) {
		this.dragMsg && (this.marker.description = this.dragMsg);
		this.savePosition(pm.getGeoPoint());
	}, this);
	msg && (this.marker.description = msg);
	map.addOverlay(pm);
	// Смена центра карты
	if (centering) {
		centering === true ? map.panTo(point) :
			map.panTo(point, {
				callback: function () {
					map.setZoom(centering, { smooth: true });
				}
			});
	}
	this.savePosition(point);
	return this;
};

//перемещение позиции пользователя с кругами 
PositionPointer.movePositionMarker = function (config, point, centering, msg, dragMsg) {
	var map = this.map;
	this.dragMsg = dragMsg;
	if (this.marker) {
		map.removeOverlay(this.marker);
//		map.removeOverlay(this.innerCircle);
//		map.removeOverlay(this.outerCircle);
	}
	var cfg = $.extend({}, config.image, { balloon: Marker.style.balloon });
	var pm = this.marker = PositionPointer.createMarker(point, cfg, config.draggable);
/*	if (!this.innerCircle){
		this.innerCircle = PositionPointer.createAreaCircle(point, 1, 2, "00000000");
	}
	else{
		this.innerCircle.setCenter(point);
	}
	if (!this.outerCircle){
		this.outerCircle = PositionPointer.createAreaCircle(point, 3, 3, "0000ff11");
	}
	else{
		this.outerCircle.setCenter(point);
	}
	var ic = this.innerCircle, oc = this.outerCircle;
	YMaps.Events.observe(pm, pm.Events.DragStart, function (pos) {
		map.removeOverlay(ic);
		map.removeOverlay(oc);
	});
*/	
	YMaps.Events.observe(pm, pm.Events.DragEnd, function (el) {
		this.dragMsg && (this.marker.description = this.dragMsg);
//		ic.setCenter(pm.getGeoPoint());
//		oc.setCenter(pm.getGeoPoint());
//		PositionPointer.drawReachArea(map, ic, oc);
		this.savePosition(pm.getGeoPoint());
	}, this);
//	YMaps.Events.observe(map, map.Events.SmoothZoomEnd, function (map) {
//		PositionPointer.drawReachArea(map, ic, oc);
//	}, this);
	msg && (this.marker.description = msg);
	map.addOverlay(pm);
//	PositionPointer.drawReachArea(map, ic, oc);
	// Смена центра карты
	if (centering) {
		centering === true ? map.panTo(point) :
			map.panTo(point, {
				callback: function () {
					map.setZoom(centering, { smooth: true });
				}
			});
	}
	this.savePosition(point);
	return this;
};

PositionPointer.prototype = {
	marker: null,
//	innerCircle: null, // внутренний круг
//	outerCircle: null, // внешний круг
	movePositionMarker: function(point, centering, msg, dragMsg) {
		return PositionPointer.movePositionMarker.call(this, this.config, point, centering, msg, dragMsg);
	},
	savePosition: function(point) {
		return PositionPointer.savePosition.call(this, this.cookies.position, point, this.cookies.options);
	},

	// manual
	manualButton: null,
	manualActive: false,
	changePositionButtonStatus: function () {
		var to = (this.manualActive = !this.manualActive);
		this.manualButton[to ? 'addClass' : 'removeClass']('set-location-active');
		this.$mouse[this.manualActive ? 'show' : 'hide']();
		return this;
	},
	initManual: function(manConfig) {
		var changeStatus = this.changePositionButtonStatus.bind(this, null);
		this.manualButton = $(manConfig.button).show().click(changeStatus);


		var $map  = $(this.map._element);
		var $cont = $map.find('.YMaps-common-object-layer');
		var activeImage = this.config.activeImage;
		var $mouse = this.$mouse = $('<img>', {
			src   : activeImage.href.imageUrl(),
			width : activeImage.size[0],
			height: activeImage.size[1],
			css: {
				zIndex: 150,
				position: 'absolute',
				display: 'none'
			}
		}).appendTo($cont);

		YMaps.Events.observe(this.map, this.map.Events.MouseMove, function(map, mapEvent) {
			var e = mapEvent.getLocalPixels(), pos = $cont.position();
			$mouse.css({
				left: e.x + activeImage.offset[0] - pos.left,
				top : e.y + activeImage.offset[1] - pos.top
			});
		}, this);

		YMaps.Events.observe(this.map, this.map.Events.Click, function(map, mapEvent) {
			if (this.manualActive) {
				changeStatus();
				this.movePositionMarker(mapEvent.getGeoPoint(), false, manConfig.balloonContent, this.config.balloonContent);
			}
		}, this);
		return this;
	},

	// geolocation
	geoButton: null,
	geoActive: false,
	limitsPoly: null,
	changeGeoButtonStatus: function (to) {
		if (to !== false && to !== true) to = (this.geoActive = !this.geoActive);
		this.geoButton[to ? 'addClass' : 'removeClass']('geolocation-active');
		return this;
	},
	initGeo: function(geocfg) {
		if (!navigator.geolocation) return this;
		if (geocfg.limits) this.limitsPoly = this.createLimitsPoly(geocfg.limits);
		this.geoButton = $(geocfg.button).show().click(function(){
			this.changeGeoButtonStatus();
			this.tryGetGeo(true);
		}.bind(this));
		// регистрация круга
//		YMaps.Utils.extend(PositionPointer.Circle, YMaps.Polygon);
		return this;
	},
	tryGetGeo: function() {
		var geoCfg = this.config.geolocation, uninit = this.changeGeoButtonStatus.bind(this, false);
		navigator.geolocation.getCurrentPosition(
			// Успешное завершение определения координат
			function (position) {
				uninit();
				var c = position.coords, point = new YMaps.GeoPoint(c.longitude, c.latitude);
				var accuracy = position.coords.accuracy;

				var limits = this.limitsPoly;

				if (limits && !limits.contains(point)) {
					geoCfg.onError('outOfLimits');
					return false;
				}
                
				if (accuracy > 5000) {
				    geoCfg.onError('lowAccuracy');
				}	

				this.movePositionMarker(point, geoCfg.centering, geoCfg.balloonContent, this.config.balloonContent);
			}.bind(this),
			// Вызывается, если во время определения координат произошли ошибки
			function (error) {
				geoCfg.onError([
					"unknownError", "permissionDenied",
					"positionUnavailable", "timeout"
				][error.code]);
				uninit();
			},
			geoCfg.options
		);
	},

	createLimitsPoly: function(points) {
		var workingPoly = PositionPointer.polyFromArray(points);

		var style = new YMaps.Style("default#greenPoint");
		style.polygonStyle = new YMaps.PolygonStyle();
		style.polygonStyle.fill = false;
		style.polygonStyle.outline = false;
		workingPoly.setStyle(style);
		this.map.addOverlay(workingPoly);

		return workingPoly;
	}
};

// объект круга - 360ти-угольник
/*
PositionPointer.Circle = function(center, radius, options) {
    var _this = this;
    options = YMaps.jQuery.extend({accuracy : 360 }, options);

    // Вызывает родительский конструктор
    YMaps.Polygon.call(this, [], options);

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

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

    // Вычисляет точки окружности
    this.updatePoints = function () {

        var map = yamaps.map;//this.getMap(),

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

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

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

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

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

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

        this.setPoints(points);
    }
    
};
 */

