var gCollection, arrayPoints;
var controlFind = false;

function GeoObject(addressGeo, ballonContent, iconContent, options){
    this.getAddressGeo = function(){
        return addressGeo;
    }
    this.getBalloonContent = function(){
        return ballonContent;
    }

    this.getOptions = function(){
        return options;
    }

    this.getIconContent = function(){
        return iconContent;
    }
}
/**
 * Создает метку со всеми атрибутами
 */
function getPlacemark(point, geoObject){
    var placemark = new YMaps.Placemark(point, geoObject.getOptions());
    //    var placemark = new YMaps.Placemark(point, null);
    if (geoObject.getBalloonContent() != null){
        placemark.setBalloonContent(geoObject.getBalloonContent())
    }

    if (geoObject.getIconContent() != null){
        placemark.setIconContent(geoObject.getIconContent())
    }
    return placemark;
}

function addControl(map){
    // Добавление элементов управления
    map.addControl(new YMaps.TypeControl());
    map.addControl(new YMaps.Zoom());
    map.addControl(new YMaps.MiniMap(6));
    if (controlFind){
        map.addControl(new YMaps.SearchControl({
            resultsPerPage: 5,  // Количество объектов на странице
            useMapBounds: 1,     // Объекты, найденные в видимой области карты
            width: 300
        }));
    }
}
/**
 * используется в случае отображения одного адреса
 * Получается более корректно
 */
function showOneAddress(geoObject, map, control){
    var regexp = /\d+\.\d+,\d+\.\d+/;
    if (regexp.test(geoObject.getAddressGeo())){
        xy = geoObject.getAddressGeo().split(",")
        map.setCenter(new YMaps.GeoPoint(xy[0], xy[1]), 16);
        var placemark = getPlacemark(new YMaps.GeoPoint(xy[0], xy[1]) , geoObject);
        gCollection.add(placemark);
        map.addOverlay(placemark)

        YMaps.Events.observe(placemark, placemark.Events.Drag, function (obj) {
            showPoints(obj.getGeoPoint());
        });
        
    } else {
        // Запуск процесса геокодирования
        var geocoder = new YMaps.Geocoder(geoObject.getAddressGeo(), {
            results: 1,
            boundedBy: map.getBounds()
        });

        // Создание обработчика для успешного завершения геокодирования
        YMaps.Events.observe(geocoder, geocoder.Events.Load, function () {
            // Если объект был найден, то добавляем его на карту
            // и центрируем карту по области обзора найденного объекта
            if (this.length()) {
                var georesult = this.get(0);
                var placemark = getPlacemark(new YMaps.GeoPoint(georesult.getGeoPoint().getX(), georesult.getGeoPoint().getY()), geoObject);
                map.addOverlay(placemark);
                gCollection.add(placemark);
                map.setBounds(georesult.getBounds());

                YMaps.Events.observe(placemark, placemark.Events.Drag, function (obj) {
                    showPoints(obj.getGeoPoint());
                });

            } else {
                alert("Ничего не найдено")
            }
        });

        // Процесс геокодирования завершен неудачно
        YMaps.Events.observe(geocoder, geocoder.Events.Fault, function (geocoder, error) {
            alert("Произошла ошибка: " + error);
        })
    }
    if (control){
        addControl(map);
    }

}

function initMap(arrayGeoObjects, mapID, control){

    // Создание обработчика для события window.onLoad
    YMaps.jQuery(function () {
        // Создание экземпляра карты и его привязка к созданному контейнеру
        var map = new YMaps.Map(YMaps.jQuery("#" + mapID)[0]);

        // Создание коллекции меток
        gCollection = new YMaps.GeoObjectCollection();

        // Если передан один адрес, другой метод...
        if (arrayGeoObjects.length == 1){
            showOneAddress(arrayGeoObjects[0], map, control);
            return;
        }

        // Создание массива точек
        arrayPoints = new Array()

        // в адресах могут содержаться реальные адреса и точки
        // разбиваем данные на два массива (для геокодирования и непосредственной подстановки)
        var arrayAddress = new Array();
        var arrayPosition = new Array();
        var regexp = /\d+\.\d+,\d+\.\d+/;

        for (var i = 0; i < arrayGeoObjects.length; i++) {
            if (regexp.test(arrayGeoObjects[i].getAddressGeo())){
                arrayPosition.push(arrayGeoObjects[i])
            } else {
                arrayAddress.push(arrayGeoObjects[i])
            }
        }
        // Создаем метки по координатам
        if (arrayPosition.length != 0){
            for (var y = 0; y < arrayPosition.length; y++) {
                xy = arrayPosition[y].getAddressGeo().split(",")
                // добавляем точку в массив
                var point = new YMaps.GeoPoint(xy[0], xy[1])
                arrayPoints.push(point)
                // добаляем метку в коллекцию
                var placemark = getPlacemark(point, arrayPosition[y]);
                gCollection.add(placemark);
            }
        }

        if (arrayAddress.length != 0){
            // Создаем метки через геокодер
            var geocoder = new MultiplyGeocoder(arrayAddress);

            YMaps.Events.observe(geocoder, "Load", function () {
                var bounds = new YMaps.GeoCollectionBounds(arrayPoints)
                map.addOverlay(gCollection)
                map.setBounds(bounds)
            });
        } else {
            var bounds = new YMaps.GeoCollectionBounds(arrayPoints)
            map.addOverlay(gCollection)
            map.setBounds(bounds)
        }

        // Добавление элементов управления
        if (control){
            addControl(map);
        }
    });

    var ptp = extend(MultiplyGeocoder, YMaps.GeoObjectCollection);
}

// Реализует наследование прототипа без исполнения конструктора родителя
// Подробнее о наследовании: http://javascript.ru/tutorial/object/inheritance
function extend (child, parent) {
    var c = function () {};
    c.prototype = parent.prototype;
    c.prototype.constructor = parent;
    return child.prototype = new c;
}

// Множественный геокодер
// requests - массив адресов
function MultiplyGeocoder (arrayAddress) {

    points = new Array();

    // Вызов родительского конструктора
    YMaps.GeoObjectCollection.call(this);

    var _this = this,

    // Количество вызовов геокодера
    geocodeCallCount = 0,

    // Обработчики событий
    listeners = [];

    // Последовательно геокодируем все переданные адреса
    for (var i = 0, l = arrayAddress.length; i < l; i++) {
        geocode(arrayAddress[i]);
    }

    // Функция, отвечающая за геокодировании одного адреса
    function geocode (geoObject) {

        // Геокодируем
        var geocoder = new YMaps.Geocoder(geoObject.getAddressGeo());

        // Счетчик вызовов геокодирования увеличиваем
        geocodeCallCount++;

        // Сохраняем ссылки на обработчики событий
        listeners = listeners.concat(

            // Обработка событий Load и Fault
            YMaps.Events.observe(geocoder, [geocoder.Events.Load, geocoder.Events.Fault], function (geocoder) {
                if (geocoder.length()) {
                    var georesult = geocoder.get(0);
                    _this.add(georesult);
                    // добавляем точку в массив
                    var point = new YMaps.GeoPoint(georesult.getGeoPoint().getX(), georesult.getGeoPoint().getY())
                    arrayPoints.push(new YMaps.GeoPoint(point.getX(), point.getY()))
                    // добавляем метку в коллекцию
                    var placemark = getPlacemark(point, geoObject)
                    gCollection.add(placemark)
                }
                geocodeCallCount--;
                isFinish();
            })
            );
    }

    // Функция для проверки окончания процесса геокодирования
    function isFinish () {
        // Если все объекты сгеокодированы, то генерируем событие завершения
        if (!geocodeCallCount) {

            // Событие о завершении геокодирования
            YMaps.Events.notify(_this, "Load", _this);

            // Удаление обработчиков событий
            for (var i = 0, l = listeners.length; i < l; i++) {
                listeners[i].cleanup();
            }
        }
    }
}



