/********
** GeoMap
*/
function GeoMap(container,
    lat, lng, zoom,
    putLocalSearch,
    currentlyOnMapFoldable,
    setupRequestLocations,
    setupDblClickChoosesLocation,
    getCurrentLocationFromParentWindow,
    overlaySrc, overlayW, overlayH,
    filter_form, filter_form2) {

    if (GBrowserIsCompatible()) {
        this.pixelLocalCoef = 2912;
        this.container = getEl(container);
        this.marks = [];
        this.currentlyOnMapFoldable = getEl(currentlyOnMapFoldable);
        this.mapFeeder_reqs = new Array();
        this.cluster_panorama_count = [5, 10, 20, 30, 50];
        this.group_size = 8;

        if (!lat) this.lat = 0; else this.lat = lat;
        if (!lng) this.lng = 0; else this.lng = lng;
        if (!zoom) this.zoom = 3; else this.zoom = zoom;

        this.map = new GMap(this.container);

        this.loadHash();
        this.reCenter();
        this.setupMap();

        if (this.doMaxZoom) this.setMaxZoom();

        if (putLocalSearch) {
            var div = document.createElement("div");
            div.id = "fake";
            document.body.appendChild(div);

            this.gLocalSearch = new GlocalSearch();
            var this_ = this;
            this.gLocalSearch.setSearchCompleteCallback(null, function() {
                this_.on_search_complete();
            });
        };

        if (filter_form) this.calc_map_filters(filter_form, filter_form2);

        if (setupRequestLocations)  {
            this.setupRequestLocations();
        } else {
            var this_ = this;
            GEvent.addListener(this.map, "movestart", function() {
                this_.saveMapTypeState();
            });
        };

        if (setupDblClickChoosesLocation) {
            var t = this;
            GEvent.addListener(this.map, "dblclick", function(overlay, latlng) {
                if (typeof t.currentLocation == "undefined") {
                    getEl("btn_done").disabled = false;
                    t.currentLocation = new GMarker(latlng, {draggable: true});
                    t.map.addOverlay(t.currentLocation);
                } else {
                    t.currentLocation.setLatLng(latlng);
                };
            });
        };

        if (getCurrentLocationFromParentWindow) {
            if (overlaySrc) {
                this.overlayW = overlayW;
                this.overlayH = overlayH;
                var xy = get_window_parent().get_x_y(location.href);
                var latlng = this.normToMapCoords(xy[0], xy[1]);
                latlng = [latlng.lat(), latlng.lng(), xy[2]];
            } else {
                var latlng = get_window_parent().get_lat_lng(location.href);
            };

            if (latlng[0] != 0 || latlng[1] != 0) {
                getEl("btn_done").disabled = false;
                var loc = new GLatLng(latlng[0], latlng[1]);
                this.map.setCenter(loc, (zoom ? zoom : 10));
                if (empty(overlaySrc)) this.checkZoomLevel(zoom ? zoom : 10);

                this.currentLocation = new GMarker(loc, {draggable: true});
                this.map.addOverlay(this.currentLocation);
                this.fit();
            } else if (latlng[2] != "") {
                getEl("search_input").value = latlng[2];
                this.btn_search_click();
            } else {
                this.zoom = zoom = 0;
                this.reCenter();
            };
        };

        if (overlaySrc) {
            this.overlayW = overlayW;
            this.overlayH = overlayH;
            var opts = new GMapUIOptions(new GSize(500, 500));
            opts.maptypes.satellite = false;
            opts.maptypes.hybrid = false;
            opts.maptypes.physical = false;
            this.map.setUI(opts);
            this.imageOverlay(overlaySrc, overlayW, overlayH);
        } else {
            this.map.setUIToDefault();
        };

        this.map.disableDoubleClickZoom();
        return this;
    } else {
        return false;
    };
};

GeoMap.prototype.setMinMaxResolution = function(min, max) {
    var mapTypes = G_DEFAULT_MAP_TYPES.concat(G_PHYSICAL_MAP);
    for(var i = 0; i < mapTypes.length; i++){
        if (max) {
            mapTypes[i].getMaximumResolution = function (latlng) { return max; };
        };
        if (min) {
            mapTypes[i].getMinimumResolution = function (latlng) { return min; };
        };
    };
};

GeoMap.prototype.reCenter = function() {
    this.map.setCenter(new GLatLng(this.lat, this.lng), this.zoom);
};

GeoMap.prototype.setupMap = function() {
    var mt = readCookie("_mt");
    if (!mt) {
        this.map.setMapType(G_HYBRID_MAP);
    } else if (mt == 1) {
        this.map.setMapType(G_NORMAL_MAP);
    } else if (mt == 2) {
        this.map.setMapType(G_SATELLITE_MAP);
    } else if (mt == 3) {
        this.map.setMapType(G_HYBRID_MAP);
    } else if (mt == 4) {
        this.map.setMapType(G_PHYSICAL_MAP);
    };

    this.setMinMaxResolution(2);

    this.map.disableDoubleClickZoom();
    var _this = this;
    GEvent.addListener(this.map, "zoomend", function(oldLevel, newLevel) {
        if (empty(_this.overlayW) && newLevel > oldLevel) _this.checkZoomLevel(newLevel);
    });

    this.allowedBounds = new GLatLngBounds(new GLatLng(-84, -180), new GLatLng(84, 180));
    this.setupBoundsLimit();
};

GeoMap.prototype.checkZoomLevel = function(zoom) {
    var latlng = this.map.getCenter();
    var _this = this;

    // this.map.getCurrentMapType().getMaxZoomAtLatLng(latlng, function(response) {
    G_SATELLITE_MAP.getMaxZoomAtLatLng(latlng, function(response) {
        if (response && response['status'] == G_GEO_SUCCESS) {
            var rzoom = response['zoom'];
            if (rzoom < zoom) _this.map.setZoom(rzoom);
        } else {
            //_this.map.setZoom(Math.min(zoom, 17));
        };
    });
};

GeoMap.prototype.setMaxZoom = function(latlng) {
    if (!latlng) var latlng = this.map.getCenter();
    var _this = this;

    // this.map.getCurrentMapType().getMaxZoomAtLatLng(latlng, function(response) {
    G_SATELLITE_MAP.getMaxZoomAtLatLng(latlng, function(response) {
        if (response && response['status'] == G_GEO_SUCCESS) {
            _this.map.setZoom(response['zoom']);
        } else {
            _this.map.setZoom(17);
        };
    });
};

GeoMap.prototype.setupBoundsLimit = function() {
    var t = this;
    GEvent.addListener(this.map, "moveend", function() {
        t.checkBounds();
    });
};

GeoMap.prototype.loadHash = function() {
    this.doMaxZoom = true;

    var plat = this.lat;
    var plng = this.lng;
    var pzoom = this.zoom;
    var hash = parseAnchorParams();
    if (hash && hash.length > 0) {
        for (var i = 0; i < hash.length; i++)
            if (hash[i][0] == "search") {
                var _this = this;
                setTimeout(function() {
                    getEl("search_input").value = decodeURIComponent(hash[i][1]);
                    _this.btn_search_click();
                }, 100);
                this.doMaxZoom = false;
                return;
            } else if (hash[i][0] == "lat") {
                plat = parseFloat(hash[i][1]);
            } else if (hash[i][0] == "lng") {
                plng = parseFloat(hash[i][1]);
            } else if (hash[i][0] == "zoom") {
                pzoom = parseFloat(hash[i][1]);
                this.doMaxZoom = false;
            };
    } else {
        this.doMaxZoom = false;
    };
    this.lat = plat;
    this.lng = plng;
    this.zoom = pzoom;
    this.doMaxZoom = this.doMaxZoom && (plat != 0 || plng != 0);
};

GeoMap.prototype.updateMapURL = function() {
    var map_center = this.map.getCenter();
    window.location.href = window.location.href.replace(/#(.+)/, "") + "#" +
        "lat=" + map_center.lat() +
        "&lng=" + map_center.lng() +
        "&zoom=" + this.map.getZoom();
};

GeoMap.prototype.addControl = function(ctrl) {
    this.map.addControl(ctrl);
};

GeoMap.prototype.saveMapTypeState = function() {
    var mt = this.map.getCurrentMapType();

    var c;
    if (mt == G_NORMAL_MAP) c = 1;
    if (mt == G_SATELLITE_MAP) c = 2;
    if (mt == G_HYBRID_MAP) c = 3;
    if (mt == G_PHYSICAL_MAP) c = 4;

    createCookie("_mt", c, 100);
};

GeoMap.prototype.setupRequestLocations = function() {
    var t = this;
    GEvent.addListener(this.map, "movestart", function() {
        clearTimeout(t.requestTimeout);
        t.saveMapTypeState();
    });
    GEvent.addListener(this.map, "moveend", function() {
        clearTimeout(t.requestTimeout);
        t.updateMapURL();
        t.requestLocations();
    });
    this.requestLocationsNow();
};

GeoMap.prototype.requestLocations = function() {
    this.requestTimeout = setTimeout("map.requestLocationsNow();", 500);
};

GeoMap.prototype.requestLocationsNow = function() {
    var bounds = this.map.getBounds();
    var south_west = bounds.getSouthWest();
    var north_east = bounds.getNorthEast();
    var long1 = south_west.lng();
    var long2 = north_east.lng();
    var url = aparg(tpl_feeder,
        (typeof this.map_filter_types_and_keywords == "undefined" ? "" : this.map_filter_types_and_keywords+"&") +
        "mode=geodata&fmt=json&limit=20&group_size=" + this.group_size +
        "&lat1=" + south_west.lat() +
        "&lat2=" + north_east.lat() +
        "&long1=" + long1 +
        "&long2=" + long2 +
        "&zoom=" + this.map.getZoom());
    var t = this;
    this.mapFeederQuery(url,
        function (response_text, response_flag, status_text) {
            t.clearMarks();
            if (response_text != "") {
                t.addMarks(eval(response_text));
                if (t.currentlyOnMapFoldable) {
                    loadFoldable(t.currentlyOnMapFoldable);
                };
            };
        }
    );
};

GeoMap.prototype.mapFeederQuery = function(url, callback) {
    if (!url || this.mapFeeder_reqs.url) return false;

    this.mapFeeder_reqs.url = url;
    this.mapFeeder_reqs.callback = callback;
    t = this;
    aQuery(url,
        function (response_text, response_flag, status_text) {
            t.mapFeeder_reqs.callback(response_text, response_flag, status_text);
            t.mapFeeder_reqs = new Array();
            execCallback(t.geodata_filters_on_complete);
            t.geodata_filters_on_complete = null;
        }
    );
};

GeoMap.prototype.calc_map_filters = function(filter_form, filter_form2) {
    // types=n1,n2,n3&keywords=n1,n2,n3
    var types = "";
    var keywords = "";
    for (var i = 0; i < filter_form.elements.length; i++) {
        var element = filter_form.elements[i];
        if (element.checked && element.name.indexOf("type_") == 0) {
            types = types + element.name.substr(5) + ",";
        };
        if (element.checked && element.name.indexOf("keyword_") == 0) {
            keywords = keywords + element.name.substr(8) + ",";
        };
    };

    if (filter_form2) {
        for (var i = 0; i < filter_form2.elements.length; i++) {
            var element = filter_form2.elements[i];
            if (element.checked && element.name.indexOf("type_") == 0) {
                types = types + element.name.substr(5) + ",";
            };
            if (element.checked && element.name.indexOf("keyword_") == 0) {
                keywords = keywords + element.name.substr(8) + ",";
            };
        };
    };

    if (types != "") {
        types = types.substr(0, types.length - 1);
    };
    if (keywords != "") {
        keywords = keywords.substr(0, keywords.length - 1);
    };

    var sort_field = "";
    if (filter_form['sort_field']) {
        sort_field = filter_form['sort_field'].value;
    } else {
        if (filter_form2 && filter_form2['sort_field']) sort_field = filter_form2['sort_field'].value;
    };

    var sort_order = "";
    if (filter_form['sort_order']) {
        sort_order = filter_form['sort_order'].value;
    } else {
        if (filter_form2 && filter_form2['sort_order']) sort_order = filter_form2['sort_order'].value;
    };

    this.map_filter_types_and_keywords =
        "types=" + types +
        "&keywords=" + keywords +
        "&sort_field=" + sort_field +
        "&sort_order=" + sort_order;

    this.map_filter_types_and_keywords_object = {
        "types" : types, "keywords" : keywords,
        "sort_field" : sort_field,
        "sort_order" : sort_order
    };
};

GeoMap.prototype.geodata_filters = function(filter_form, callback) {
    this.geodata_filters_on_complete = callback;
    if (filter_form.name && (filter_form.name == "map_filters_left") || (filter_form.name == "map_filters_right")) {
        this.calc_map_filters(document.map_filters_left, document.map_filters_right);
    } else {
        this.calc_map_filters(filter_form);
    };
    this.requestLocations();
    return false;
};

GeoMap.prototype.schedule_geodata_filters = function(filter_form, callback, timeout) {
    if (empty(timeout)) var timeout = 1000;
    if (!empty(this.schedule_geodata_filters_timeout)) clearTimeout(this.schedule_geodata_filters_timeout);
    var _this = this;
    this.schedule_geodata_filters_timeout = setTimeout(function() {
        _this.geodata_filters(filter_form, callback);
        _this.schedule_geodata_filters_timeout = null;
    }, timeout);
};

// Event handlers
GeoMap.prototype.beforeLoadMapFoldable = function(foldable) {
    var bounds = this.map.getBounds();
    var south_west = bounds.getSouthWest();
    var north_east = bounds.getNorthEast();

    foldable.feederParams.lat1 = south_west.lat();
    foldable.feederParams.lat2 = north_east.lat();
    foldable.feederParams.long1 = south_west.lng();
    foldable.feederParams.long2 = north_east.lng();
    foldable.feederParams.zoom = this.map.getZoom();

    for (var prop in this.map_filter_types_and_keywords_object) {
        foldable.feederParams[prop] = this.map_filter_types_and_keywords_object[prop];
    };
};

GeoMap.prototype.btn_search_click = function() {
    // t.gLocalSearch.setCenterPoint(new GLatLng(0, 0));
    this.gLocalSearch.setCenterPoint(this.map.getCenter());
    this.gLocalSearch.execute(getEl("search_input").value);
};

GeoMap.prototype.on_search_complete = function() {
    if (!this.gLocalSearch.results || this.gLocalSearch.results.length == 0) {
        var center = this.map.getCenter();
        if (center.lat() == 0 && center.lng() == 0) {
            this.map.setCenter(new GLatLng(0, 0), 2);
        };
        return;
    };

    var first = this.gLocalSearch.results[0];
    if (first) {
        this.map.setCenter(new GLatLng(parseFloat(first.lat), parseFloat(first.lng)), parseFloat(first.accuracy) + 8);
    };
};

GeoMap.prototype.btn_done_click = function() {
    if (this.overlayH) {
        var xy = this.mapToNormCoords(this.currentLocation.getLatLng());
        get_window_parent().set_x_y(location.href, xy.x, xy.y);
    } else {
        var latlng = this.currentLocation.getLatLng();
        get_window_parent().set_lat_lng(location.href, latlng.lat(), latlng.lng());
    };
    window_close();
};

GeoMap.prototype.btn_cancel_click = function() {
    window_close();
};



GeoMap.prototype.fit = function() {
    if (this.marks.length > 0) {
        var min_lat = 1000;
        var min_lng = 1000;
        var max_lat = -1000;
        var max_lng = -1000;
        for (var i=0; i < this.marks.length; i++) {
            var lat = this.marks[i].latlng.lat();
            var lng = this.marks[i].latlng.lng();
            if (lat < min_lat) min_lat = lat;
            if (lat > max_lat) max_lat = lat;
            if (lng < min_lng) min_lng = lng;
            if (lng > max_lng) max_lng = lng;
        };
        var bounds = new GLatLngBounds(new GLatLng(min_lat, min_lng), new GLatLng(max_lat, max_lng));
    } else {
        var bounds = this.map.getBounds();
    };

    this.map.setCenter(bounds.getCenter());
    this.map.setZoom(this.map.getBoundsZoomLevel(bounds));
};

GeoMap.prototype.centerAndZoomOnBounds = function(min_lat, min_lng, max_lat, max_lng) {
    var bounds = new GLatLngBounds(new GLatLng(min_lat, min_lng), new GLatLng(max_lat, max_lng));
    // make 10% bigger so all markers show completely
    var span = new GSize((bounds.maxX - bounds.minX) * 1.1, (bounds.maxY - bounds.minY)*1.1);
    var center = new GPoint(bounds.minX + span.width / 2., bounds.minY + span.height / 2.);

    var newZoom = this.map.spec.getLowestZoomLevel(center, span, this.map.viewSize);
    if (this.map.getZoomLevel() != newZoom) {
        this.map.centerAndZoom(center, newZoom);
    } else {
        this.map.recenterOrPanToLatLng(center);
    };
};

GeoMap.prototype.addMark = function(lat, lng, options) {
    var latlng = new GLatLng(lat, lng);
    var mark = new MarkerLight(latlng, options);
    this.marks.push(mark);
    this.map.addOverlay(mark);
};

GeoMap.prototype.checkBounds = function() {
    if (this.skipCheckBounds) return;

    var aberration = 0.2;

    var C = this.map.getCenter();
    var X = C.lng();
    var Y = C.lat();

    var currentBounds = this.map.getBounds();
    var cSpan = currentBounds.toSpan();
    var offsetX = cSpan.lng() / (2+aberration);
    var offsetY = cSpan.lat() / (2+aberration);

    var checkSW = new GLatLng(C.lat()-offsetY,C.lng()-offsetX);
    var checkNE = new GLatLng(C.lat()+offsetY,C.lng()+offsetX);

    if (this.allowedBounds.containsLatLng(checkSW) && this.allowedBounds.containsLatLng(checkNE)) return;

    var AmaxX = this.allowedBounds.getNorthEast().lng();
    var AmaxY = this.allowedBounds.getNorthEast().lat();
    var AminX = this.allowedBounds.getSouthWest().lng();
    var AminY = this.allowedBounds.getSouthWest().lat();

    if (X < (AminX+offsetX)) X = AminX + offsetX;
    if (X > (AmaxX-offsetX)) X = AmaxX - offsetX;
    if (Y < (AminY+offsetY)) Y = AminY + offsetY;
    if (Y > (AmaxY-offsetY)) Y = AmaxY - offsetY;

    this.skipCheckBounds = true;
    this.map.setCenter(new GLatLng(Y,X));
    this.skipCheckBounds = false;
};

GeoMap.prototype.setBounds = function(bounds, restrict) {
    if (empty(bounds)) bounds = this.map.getBounds();
    var center = bounds.getCenter();
    var zoom = this.map.getBoundsZoomLevel(bounds);
    var _this = this;

    // this.map.getCurrentMapType().getMaxZoomAtLatLng(center, function(response) {
    G_SATELLITE_MAP.getMaxZoomAtLatLng(center,
        function(response) {
            if (response && response['status'] == G_GEO_SUCCESS) {
                var rzoom = response['zoom'];
            } else {
                var rzoom = 17;
            };
            if (zoom >= rzoom) {
                zoom = rzoom;
                _this.map.setCenter(center, zoom);
                bounds = _this.map.getBounds();
            };
            _this.setMinMaxResolution(zoom, rzoom);
            if (restrict) _this.allowedBounds = bounds;
            _this.reCenter();
        }
    );
};

GeoMap.prototype.mapToNormCoords = function (latlng) {
    return {
        x: (100 * latlng.lng() * this.pixelLocalCoef) / this.overlayW + 50,
        y: 50 - (100 * latlng.lat() * this.pixelLocalCoef) / this.overlayH
    };
};

GeoMap.prototype.normToMapCoords = function (x, y) {
    var xx = x * this.overlayW / 100;
    var yy = y * this.overlayH / 100;
    return new GLatLng(
        (this.overlayH/2 - yy) / this.pixelLocalCoef,
        (-this.overlayW/2 + xx) / this.pixelLocalCoef
    );
};

GeoMap.prototype.imageOverlay = function(url, w, h) {
    var lat_delta = (h/2) / this.pixelLocalCoef;
    var lng_delta = (w/2) / this.pixelLocalCoef;

    this.overlayBounds = new GLatLngBounds(
        new GLatLng(-lat_delta, -lng_delta),
        new GLatLng(lat_delta, lng_delta)
    );

    this.map.addOverlay(new GGroundOverlay(url, this.overlayBounds));

    this.map.setCenter(new GLatLng(0, 0));
    this.map.setZoom(12);
    this.setMinMaxResolution(12, 14);

    this.allowedBounds = this.overlayBounds;
};

GeoMap.prototype.clearMarks = function() {
    if (this.marks) {
        this.map.clearOverlays();
        for (var i = 0; i < this.marks.len; i++) {
            this.marks[i].remove();
            this.marks[i] = null;
        };
        this.marks = null;
    };
};

GeoMap.prototype.addMarks = function(markers, marker_w, marker_h) {
    var cur_zooom = this.map.getZoom();
    this.marks = new Array();

    for (var i = 0; i < markers.length; i++) {
        if (this.overlayH) {
            var latlng = this.normToMapCoords(
                parseFloat(markers[i].coord_x),
                parseFloat(markers[i].coord_y)
            );
        } else {
            var latlng = new GLatLng(
                parseFloat(markers[i].geo_latitude),
                parseFloat(markers[i].geo_longitude)
            );
        };


        if (isNaN(latlng.lat()) || isNaN(latlng.lng())) {
            debug("warning! invalid coordinates for mark " + i);
            continue;
        };

        this.marks.push(new Object());
        var mc = this.marks.length - 1;

        if ((typeof markers[i].geo_count == "undefined") || (markers[i].geo_count == 1)) {
            if (cur_zooom > 3) {
                this.marks[mc] = new MarkerLight(latlng, {image: markers[i].mini, width: (empty(marker_w) ? 30 : marker_w), height: (empty(marker_h) ? 20 : marker_h)});
            } else {
                this.marks[mc] = new MarkerLight(latlng, {image: tpl_image_url + "/map/m0.png", width: 16, height: 16, border: false});
            };

            this.marks[mc].info_text =
                "<table class='tablebgcolor' border='0' cellpadding='2' cellspacing='0' width='250'><tr>" +
                "<td valign='top' width='108'><a href='"+markers[i].url+"'><img src='"+markers[i].sim+"' border='1' hspace='4' vspace='2'></a></td>" +
                "<td valign='top'><b>"+markers[i].geo_text + "</b><br><br>" +
                "Dimensions: "+markers[i].dimensions + "<br>" +
                "N "+markers[i].geo_latitude + "º<br>" +
                "E " + markers[i].geo_longitude + "º<br>" +
                "</td></tr></table>";
        } else {
            var hot = 0;
            while ((hot < 5) && (markers[i].geo_count >= this.cluster_panorama_count[hot])) {
                hot++;
            };
            this.marks[mc] = new MarkerLight(latlng, {image: tpl_image_url + "/map/m" + (hot + 1) + ".png", width: 16, height: 16, border: false});

            var thumbs = "";
            for (var j = 0; j < markers[i].geo_group_ids.length; j++) {
                thumbs = thumbs + "<div style='float: left; margin: 4px; width: 60px; height: 62px; font-size: 9px; overflow: hidden;'>" +
                    "<a href='" + markers[i].geo_group_ids[j].url + "'>" +
                    "<img style='width: 60px; height: 40px; border: 0;' src='" + markers[i].geo_group_ids[j].mini +
                    "' alt='" + markers[i].geo_group_ids[j].geo_text + "' title='" + markers[i].geo_group_ids[j].geo_text +
                    "'><br>" + markers[i].geo_group_ids[j].geo_text +
                    "</a></div>";
            };

            var diff = markers[i].geo_count - this.group_size;
            if (diff > 0)
                thumbs = thumbs + "<div style='clear:both;'>&nbsp;</div><i>" +
                    diff + " more location" + (diff == 1 ? " is" : "s are") +  " not shown. Try zooming in for closer look."

            this.marks[mc].info_text =
                "<table class='tablebgcolor' border='0' cellpadding='2' cellspacing='0' width='276'><tr>" +
                "<td valign='top' align='center'><b>"+markers[i].geo_count + " locations</b><br>near " +
                "N "+markers[i].geo_latitude + "º, " +
                "E " + markers[i].geo_longitude + "º<br><br>" +
                thumbs +
                "</td></tr></table>";
        };
        this.marks[mc].scrollTo = "item-" + markers[i].id;

        this.map.addOverlay(this.marks[mc]);
    };
};

GeoMap.prototype.addDraggablePins = function(markers, onDragEndCallback) {
    this.marks = new Array(markers.length);
    for (var i = 0; i < markers.length; i++) {
        if (this.overlayH) {
            var latlng = this.normToMapCoords(
                parseFloat(markers[i].coord_x),
                parseFloat(markers[i].coord_y)
            );
        } else {
            var latlng = new GLatLng(
                parseFloat(markers[i].geo_latitude),
                parseFloat(markers[i].geo_longitude)
            );
        };

        var marker = new GMarker(latlng, {draggable : true});
        GEvent.addListener(marker, "dragend", function() {
            onDragEndCallback(this);
        });

        marker.latlng = latlng;
        marker.geo_dest_id = markers[i].geo_dest_id;
        this.marks[i] = marker;
        this.map.addOverlay(marker);
    };
};


/***************
** GeoMapControl
**/
function GeoMapControl(templateDiv) {
    this.templateDiv = getEl(templateDiv);
};

GeoMapControl.prototype = new GControl();

GeoMapControl.prototype.initialize = function(map) {
    var container = document.createElement("div");
    container.innerHTML = this.templateDiv.innerHTML;

    map.getContainer().appendChild(container);
    return container;
};

GeoMapControl.prototype.getDefaultPosition = function() {
    return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(100, 7));
};



/*************
** MarkerLight
** possible opts {weight, color, height, width, text, and offset}
*/
function MarkerLight(latlng, opts) {
    this.latlng = latlng;

    if (!opts) opts = {};

    this.height_ = opts.height || 32;
    this.width_ = opts.width || 32;
    if (typeof opts.border != "undefined") this.border_ = opts.border;
    else this.border_ = true;
    this.image_ = opts.image;
    this.imageOver_ = opts.imageOver;
    this.clicked_ = 0;
};

MarkerLight.prototype = new GOverlay();

MarkerLight.prototype.initialize = function (map) {
    var me = this;

    var div = document.createElement("div");
    if (this.border_) div.style.border = "1px solid white";
    div.style.position = "absolute";
    div.style.paddingLeft = "0px";
    div.style.cursor = 'pointer';

    var img = document.createElement("img");
    img.src = me.image_;
    img.style.width = me.width_ + "px";
    img.style.height = me.height_ + "px";
    div.appendChild(img);

    GEvent.addDomListener(div, "click", function (event) {
        me.clicked_ = 1;
        var scrollToElement = getEl(me.scrollTo);
        if (scrollToElement) scrollToElement.parentNode.scrollTop = scrollToElement.offsetTop;
    });
    GEvent.addDomListener(div, "mouseover", function (event) {
        me.bringToFront_();
        if (me.info_text) hint(this, me.info_text);
    });
    GEvent.addDomListener(div, "mouseout", function (event) {
        me.sendBack_();
    });

    map.getPane(G_MAP_MARKER_PANE).appendChild(div);

    this.map_ = map;
    this.div_ = div;
};

MarkerLight.prototype.remove = function () {
    this.div_.parentNode.removeChild(this.div_);
};

MarkerLight.prototype.copy = function () {
    var opts = {};
    opts.color = this.color_;
    opts.height = this.height_;
    opts.width = this.width_;
    opts.image = this.image_;
    opts.imageOver = this.image_;
    return new MarkerLight(this.latlng, opts);
};

MarkerLight.prototype.redraw = function (force) {
    if (!force) return;

    var divPixel = this.map_.fromLatLngToDivPixel(this.latlng);

    this.div_.style.width = this.width_ + "px";
    this.div_.style.left = (divPixel.x - Math.round(this.width_ / 2)) + "px"
    this.div_.style.height = (this.height_) + "px";
    this.div_.style.top = (divPixel.y - Math.round(this.height_ / 2)) + "px";
};

MarkerLight.prototype.bringToFront_ = function () {
    var z = GOverlay.getZIndex(this.latlng.lat());
    this.div_.style.zIndex = 99;
};

MarkerLight.prototype.sendBack_ = function () {
    var z = GOverlay.getZIndex(this.latlng.lat());
    this.div_.style.zIndex = z;
};

MarkerLight.prototype.getPoint = function () {
    return this.latlng;
};

MarkerLight.prototype.setStyle = function (style) {
    for (s in style) {
        this.div_.style[s] = style[s];
    };
};

MarkerLight.prototype.setImage = function (image) {
    this.div_.style.background = 'url("' + image + '")';
};

MarkerLight.prototype.highlightBorder = function () {
    this.div_.style.border = "2px solid yellow";
};

MarkerLight.prototype.resetBorder = function () {
    this.div_.style.border = "1px solid white";
};
