(function ($) {
    /* ======== ctor ======== */
    $.WebmapModule = {
        GetWebmap: function () {
            return _webmap;
        },
        GetWebmapSettings: function () {
            return _webmapSettings;
        },
        Init: function (webmapSettings) {
            _webmapSettings = WebmapSettings(webmapSettings);
//            if (_webmapSettings.useAlpmap)
//                createAlpMap(initCallback);
//            else
                createGoogleMap(initCallback);
        },
        Update: function (webmapSettings) {
            var _webmapSettings = WebmapSettings(webmapSettings);
            if (_webmap == null) {
                $.WebmapModule.Init(webmapSettings);
                return;
            }

            deleteOverlays();
            if (webmapSettings.skimarkers.length > 0) {
                //  _webmap.setZoom(20);
                _webmap.setCenter(_webmapSettings.Center());
                _webmap.setZoom(_webmapSettings.Zoom());
                //                _webmap.panToBounds(__bounds);
                //                _webmap.fitBounds(webmapSettings.Bounds());
                //                google.maps.event.addListenerOnce(_webmap, "idle", function () {
                //                      //http://boogleoogle.blogspot.com/2010/04/maximum-zoom-level-when-using-fitbounds.html
                //                    if (_webmap.getZoom() > 12) _webmap.setZoom(12);
                //                });
                putDataOnMap(_webmapSettings.skimarkers);
            }
        }
    };

    /* ======== fields ======== */
    var _webmapSettings;
    var _webmap;
    var markersArray = [];

    /* ======== private ======== */
    // http://code.google.com/apis/maps/documentation/javascript/overlays.html#RemovingOverlays
    // Removes the overlays from the map, but keeps them in the array
    function clearOverlays() {
        if (markersArray) {
            for (i in markersArray) {
                markersArray[i].setMap(null);
            }
        }
    }

    // Shows any overlays currently in the array
    function showOverlays() {
        if (markersArray) {
            for (i in markersArray) {
                markersArray[i].setMap(map);
            }
        }
    }

    // Deletes all markers in the array by removing references to them
    function deleteOverlays() {
        if (markersArray) {
            for (i in markersArray) {
                markersArray[i].setMap(null);
            }
            markersArray.length = 0;
        }
    }

    function putDataOnMap(items) {
        var image = new google.maps.MarkerImage(
                    '/imgtmp/map_icon.png',
                    new google.maps.Size(27, 29), // The size 
                    new google.maps.Point(0, 0), // The origin 
                    new google.maps.Point(13, 29)  // The anchor 
                );

        var imageHover = new google.maps.MarkerImage(
                    '/imgtmp/map_icon.png',
                    new google.maps.Size(27, 29), // The size 
                    new google.maps.Point(0, 29), // The origin 
                    new google.maps.Point(13, 29)  // The anchor 
                );

        for (var i = 0; i < items.length; i++) {
            var item = items[i];
            var position = new google.maps.LatLng(item.Latitude, item.Longitude);
            var marker = new MarkerWithLabel({
                //icon: '/imgtmp/map_icon.png',
                icon: image,
                position: position,
                map: _webmap,
                labelContent: item.Name,
                labelClass: "markerlabel",
                labelStyle: { opacity: 1 }
            });
            markersArray.push(marker);
            marker.setTitle("click to open");
            (function (marker, url) {
                zIndexBacking = 0;
                google.maps.event.addListener(marker, 'mouseover', function () {
                    //            window.themarker = marker;
                    zIndexBacking = marker.getZIndex(0);
                    marker.setZIndex(1000000);
                    marker.setIcon(imageHover);
                    marker.labelClass = 'markerlabelactive';
                    marker.label.setStyles();
                });
                google.maps.event.addListener(marker, 'mouseout', function () {
                    marker.setZIndex(zIndexBacking);
                    marker.setIcon(image);
                    marker.labelClass = 'markerlabel';
                    marker.label.setStyles();
                });
                google.maps.event.addListener(marker, 'click', function () {
                    window.location = url;
                });
            })(marker, item.Url);
        }
    }

    function initCallback() {
        if (typeof (bindUpdate) !== 'undefined')
            bindUpdate();

//        google.maps.event.addListener(_webmap, "center_changed", function () {
//        });

        if (typeof (_webmapSettings.skimarkers) == 'undefined') {
            //JsonController
            loadData();
        } else {
            putDataOnMap(_webmapSettings.skimarkers);
        }
        bindZoom();
        //        if (navigator.userAgent.indexOf("Firefox/6") != -1) {
        //            //document.getElementById("map_canvas").addEventListener('DOMMouseScroll', function (e) {
        ////            $('#map_canvas canvas').bind('DOMMouseScroll', function (e) {
        //            $('canvas').live('DOMMouseScroll', function (e) {
        //                e.stopPropagation();
        //                e.preventDefault();
        //                e.cancelBubble = false;
        //                return false;
        //            });
        ////            }, false);
        //        }
    };

    function createAlpMap(callback) {
        alp.gmap3(function (gm) {
            //var mapTypeIds = ['alpstein_map_winter', 'alpstein_map', 'alpstein_hybrid', gm.MapTypeId.SATELLITE, gm.MapTypeId.TERRAIN];
            var mapTypeIds = ['alpstein_map_winter'];

            var ff = /Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent);
            //scrollwheel: _webmapSettings.scrollwheel && (navigator.userAgent.indexOf("Firefox/6") == -1)
            //scrollwheel: (navigator.userAgent.indexOf("Firefox/6") == -1)
            //var fv = new Number(RegExp.$1) >= 6;
            //var ffgreaterequal6 = ff && fv;
            var scrollwheel = !ff;

            _webmap = new alp.gmap3.Map(document.getElementById("map_canvas"), {
                center: _webmapSettings.Center(),
                zoom: _webmapSettings.Zoom(),
                mapTypeId: mapTypeIds[0],
                mapTypeControlOptions: { mapTypeIds: mapTypeIds },
                scrollwheel: scrollwheel
            });

            if (_webmapSettings.skimarkers.length > 1 && _webmapSettings.webmapCenter == undefined)
                _webmap.fitBounds(_webmapSettings.Bounds());

            _webmap.set('panControl', false);
            _webmap.set('zoomControl', false);
            _webmap.set('streetViewControl', false);
            _webmap.set('mapTypeControl', false);
            callback();
        });
    }

    function createGoogleMap(callback) {
        var ff = /Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent);
        var scrollwheel = !ff;
        _webmap = new google.maps.Map(document.getElementById("map_canvas"), {
            center: _webmapSettings.Center(),
            zoom: _webmapSettings.Zoom(),
            mapTypeId: google.maps.MapTypeId.TERRAIN,
            scrollwheel: scrollwheel
        });

        if (_webmapSettings.skimarkers.length > 1 && _webmapSettings.webmapCenter == undefined)
            _webmap.fitBounds(_webmapSettings.Bounds());

        _webmap.set('panControl', false);
        _webmap.set('zoomControl', false);
        _webmap.set('streetViewControl', false);
        _webmap.set('mapTypeControl', false);
        callback();
    }

    function bindZoom() {
        $('#map-zoom').click(function () {
            if ($('#map-zoom').attr('data-state') == 'down') {
                $('#map-zoom').attr('data-state', 'up');
                _webmapSettings._webmapPixelWidth = 1008;
                toggleMap('#wrapper');
                $('#map').addClass('big');
            } else {
                $('#map-zoom').attr('data-state', 'down');
                $('#map').removeClass('big');
                _webmapSettings._webmapPixelWidth = 488;
                toggleMap('#map-holder');
            }
            //google.maps.event.trigger(_webmap, 'resize');
            //_webmap.setCenter(window.latlng);
        });
    }

    function toggleMap(target) {
        $('#map').slideUp('400', function () {
            $('#map').prependTo(target);

            $('#map').slideDown('400', function () {
                var _cc = _webmap.getCenter();
                google.maps.event.trigger(_webmap, 'resize');
                _webmap.setCenter(_cc);
                //                _webmap.setCenter(_webmapSettings.Center());
                //                _webmap.setCenter(new google.maps.LatLng(_webmapSettings.latitude, _webmapSettings.longitude));
                _webmap.set('panControl', !_webmap.get('panControl'));
                _webmap.set('zoomControl', !_webmap.get('zoomControl'));
                _webmap.set('streetViewControl', !_webmap.get('streetViewControl'));
                _webmap.set('mapTypeControl', !_webmap.get('mapTypeControl'));
            });

            $.smoothScroll({
                offset: -100,
                scrollTarget: '#map'
            });
        });
    }

    function loadData() {
        $.getJSON('/json', _webmapSettings.data, function (dataout) {
            if (typeof (dataout) == 'undefined' || dataout.length == 0) {
                return;
            }
            putDataOnMap(dataout.Items);
        });
    }

    /* ======== WebmapSettings ======== */
    function WebmapSettings(webmapSettings) {
        /* ======== Helpers ======== */
        function calcZoom(bounds, webmapPixelWidth) {
            //http://stackoverflow.com/questions/6048975/google-maps-v3-how-to-calculate-the-zoom-level-for-a-given-bounds/6055653#6055653
            var west = bounds.getSouthWest().lng();
            var east = bounds.getNorthEast().lng();
            var angle = east - west;
            if (angle < 0) {
                angle += 360;
            }
            var zoom = Math.floor(Math.log(webmapPixelWidth * 360 / angle / 256) / Math.LN2);
            if (zoom == Infinity)
                zoom = 10;
            return zoom;
        }

        function calcBoundsFromSkimarkers(skimarkers) {
            var bounds = new google.maps.LatLngBounds();
            for (var i = 0; i < skimarkers.length; i++) {
                var latLng = new google.maps.LatLng(skimarkers[i].Latitude, skimarkers[i].Longitude);
                bounds.extend(latLng);
            }
            return bounds;
        }

        //    function convertFromWebmapSettings(bounds) {
        //        return new google.maps.LatLngBounds(
        //            new google.maps.LatLng(bounds.sw.latitude, bounds.sw.longitude),
        //            new google.maps.LatLng(bounds.ne.latitude, bounds.ne.longitude)
        //                );
        //    }

        /* ======== ctor-ish ======== */
        var _webmapSettings = {
            _webmapPixelWidth: 488,
            Bounds: function () {
                return calcBoundsFromSkimarkers(this.skimarkers);
            },
            Center: function () {
                if (this.webmapCenter == undefined)
                    return this.Bounds().getCenter();
                else
                    return new google.maps.LatLng(this.webmapCenter.center.latitude, this.webmapCenter.center.longitude);
            },
            Zoom: function () {
                if (this.webmapCenter == undefined)
                    return calcZoom(this.Bounds(), this._webmapPixelWidth);
                else
                    return this.webmapCenter.zoom;
            }
        };
        _webmapSettings = $.extend(_webmapSettings, webmapSettings);
        return _webmapSettings;
    }

})(jQuery);

