function catalogMap(flats, center, mapOptions)
{
    var that = this;
    var markers = {};
    var eLabels = {};    
    var icon1, icon2, icon3, icon4, activeOverlay = null, hideOverlayTimer = null;
    var options = {emapId           : 'catalog_gmap',
                   zoom             : 14,
                   consoleId        : 'catalog_messages',
                   formId           : 'catalog_form',
                   searchUrl        : '/catalog/search/',
                   showAllId        : 'catalog_show_all',
                   checkboxes       : {classes: ['class_econom', 'class_standart', 'class_business', 'class_elite'],
                                       rooms  : ['rooms_1', 'rooms_2', 'rooms_3', 'rooms_4']},
                   inputId          : 'catalog_id_search',
                   domain           : document.domain,
                   overlayClass     : 'gmap_info_overlay',
                   hideOverlayDelay : 500};

    var icons = {'1' : {path     : '/templates/bezposrednika/images/gicon_1.png',
                        size     : [44,27],
                        anchor   : [22,27],
                        imageMap : [0,0, 43,0, 43,26, 0,26]},
                 '2' : {path     : '/templates/bezposrednika/images/gicon_2.png',
                        size     : [44,27],
                        anchor   : [22,27],
                        imageMap : [0,0, 43,0, 43,26, 0,26]},
                 '3' : {path     : '/templates/bezposrednika/images/gicon_3.png',
                        size     : [44,27],
                        anchor   : [22,27],
                        imageMap : [0,0, 43,0, 43,26, 0,26]},
                 '4' : {path     : '/templates/bezposrednika/images/gicon_4.png',
                        size     : [44,27],
                        anchor   : [22,27],
                        imageMap : [0,0, 43,0, 43,26, 0,26]}}

    this.setup = function()
    {
        setupMap();
        setupIcons();
        setupMarkers();
        setupEvents();
    }
    
    this.search = function()
    {
        hideActiveOverlay();
        
        var params = $('#' + options.formId).serializeArray();
        
        showLoading();
        $.post(options.searchUrl, params, searchResult, 'json');
    }
    
    this.showAll = function()
    {
        hideActiveOverlay();
        clearMessage();
        $.each(markers, function(key, value) {
            if (value.isHidden()) {
                value.show();
            }
        });
        
        setZoom(options.zoom);
        setMapCenter(center.x, center.y);
        checkAllCheckboxes(true);
        $('#' + options.inputId).attr('value', '');
        
        return false;
    }
    
    this.showMarkerInfoWindow = function(id)
    {
        if (typeof(eLabels[id]) != 'undefined') {
            showOverlay(id);
        }
    }
    
    this.closeActiveInfoWindow = function()
    {
        hideActiveOverlay();
    }
    
    this.setZoom = function(zoom)
    {        
        setZoom(zoom);
    }    
    
    function searchResult(data)
    {
        hideLoading();
        
        if (data.total == 0) {
            showMarkerOnlyIds([]);
            showError('Квартир с такими параметрами не найдено.');
            return;
        }
        
        switch (data.mode) {
            case 'id':
                setZoom(14);
                showMarkerOnlyIds([data.id]);
                var point = markers[data.id].getLatLng();
                setMapCenter(point.lng(), point.lat());
                that.showMarkerInfoWindow(data.id);
                break;
            case 'ids':
                setZoom(14);
                showMarkerOnlyIds(data.ids);                
                setMapCenter(data.center.x, data.center.y);
                showMessage('Найдено квартир: ' + data.total);                
                break;
        }
    }
    
    function showMarkerOnlyIds(ids)
    {
        $.each(markers, function(key, value) {
            if ($.inArray(key, ids) != -1) {
                if (value.isHidden()) {
                    value.show();
                }
            } else {                
                value.hide();
            }
        });
    }
    
    function checkAllCheckboxes(mode)
    {
        $.each(options.checkboxes, function(key, value) {
            for (var i=0; i<value.length; i++) {
                $('#' + value[i]).attr('checked', mode);
            }
        });
    }
    
    function setMapCenter(x, y)
    {
        $('#' + options.emapId).jmap('moveTo', {mapCenter:[y, x], centerMethod:'pan'});
    }
    
    function setZoom(zoom)
    {
        $('#' + options.emapId).jmap('setZoom', zoom);
    }
    
    function setupMarkers()
    {
        $.each(flats, function(key, value) {
            var curIcon = null;
            switch (value.flat_rooms_number) {
                case '1':
                    curIcon = icon1;
                    break;
                case '2':
                    curIcon = icon2;
                    break;
                case '3':
                    curIcon = icon3;
                    break;
                case '4':
                    curIcon = icon4;
                    break;
            }
            
            $('#' + options.emapId).jmap('addMarker',
                                         {pointLatLng : [value.flat_emap_y, value.flat_emap_x],
                                          pointIcon   : curIcon},
                                          function (marker) {
                                              markers[value.flat_id] = marker;
                                              GEvent.addListener(marker, "mouseover", function() {
                                                  showOverlay(value.flat_id);
                                              });
                                              
                                              GEvent.addListener(marker, "mouseout", function() {
                                                  startHideOverlayTimer();
                                              });
                                              
                                              GEvent.addListener(marker, "click", function() {
                                                  window.location = value.link;
                                                  return false;
                                              });                                              
                                          });

            var eLabel = new ELabel(new GLatLng(value.flat_emap_y, value.flat_emap_x), value.info_window, options.overlayClass, new GSize(-140, -9));
            eLabel.hide();
            eLabels[value.flat_id] = eLabel;
            
            $('#' + options.emapId).jmap('getGMap', function(GMap) {GMap.addOverlay(eLabel);});
            
            var div = $(eLabel.getDiv());            
            div.mouseover(function() {stopHideOverlayTimer()}).mouseout(function() {startHideOverlayTimer()});
            
            $('a.close_overlay', div).click(function() {hideActiveOverlay(); return false;});
        });        
    }    
    
    function showOverlay(id)
    {
        hideActiveOverlay();
        stopHideOverlayTimer();
        
        activeOverlay = id;
        eLabels[id].show();
    }
        
    function startHideOverlayTimer()
    {
        hideOverlayTimer = setTimeout(function() {hideActiveOverlay()}, options.hideOverlayDelay);
    }
    
    function hideActiveOverlay()
    {        
        if (null !== activeOverlay) {
            eLabels[activeOverlay].hide();
            activeOverlay = null;
        }        
    }
    
    function stopHideOverlayTimer()
    {
        if (hideOverlayTimer) {
            clearTimeout(hideOverlayTimer);
        }
    }
    
    function setupMap()
    {        
        var mapProps = {mapShowjMapIcon : false,
                        mapCenter       : [center.y, center.x],
                        mapZoom         : options.zoom};
     
        if (typeof(mapOptions) == 'object') {
            mapProps = $.extend(mapProps, mapOptions);
        }
        
        $('#' + options.emapId).jmap('init', mapProps);
    }
    
    function setupEvents()
    {
        $('#' + options.formId).submit(that.search);

        $('#' + options.showAllId).click(that.showAll);
    }
    
    function setupIcons()
    {
        icon1 = $.jmap.createIcon({iconImage  : 'http://' + options.domain + icons['1'].path,
                                   iconSize   : new GSize(icons['1'].size[0], icons['1'].size[1]),
                                   iconAnchor : new GPoint(icons['1'].anchor[0], icons['1'].anchor[1]),
                                   iconShadow : '',
                                   imageMap   : icons['1'].imageMap});

        icon2 = $.jmap.createIcon({iconImage  : 'http://' + options.domain + icons['2'].path,
                                   iconSize   : new GSize(icons['2'].size[0], icons['2'].size[1]),
                                   iconAnchor : new GPoint(icons['2'].anchor[0], icons['2'].anchor[1]),
                                   iconShadow : '',
                                   imageMap   : icons['2'].imageMap});

        icon3 = $.jmap.createIcon({iconImage  : 'http://' + options.domain + icons['3'].path,
                                   iconSize   : new GSize(icons['3'].size[0], icons['3'].size[1]),
                                   iconAnchor : new GPoint(icons['3'].anchor[0], icons['3'].anchor[1]),
                                   iconShadow : '',
                                   imageMap   : icons['3'].imageMap});
                                   
        icon4 = $.jmap.createIcon({iconImage  : 'http://' + options.domain + icons['4'].path,
                                   iconSize   : new GSize(icons['4'].size[0], icons['4'].size[1]),
                                   iconAnchor : new GPoint(icons['4'].anchor[0], icons['4'].anchor[1]),
                                   iconShadow : '',
                                   imageMap   : icons['4'].imageMap});
    }
    
    function showLoading()
    {
        showMessage('Загрузка...');
    }
    
    function hideLoading()
    {
        clearMessage();
    }
    
    function showMessage(message)
    {
        $('#' + options.consoleId).text(message);
    }
    
    function clearMessage()
    {
        $('#' + options.consoleId).empty();
    }
    
    function showError(error)
    {
        $('#' + options.consoleId).html('<span style="color:red;">' + error + '</span>');
    }
}