/* Google maps plugin
------------------------------------------------------------------------------------------------ */

(function($) {
    $.fn.GoogleMaps = function(settings) {

        // Settings

        settings = $.extend({
            'backgroundColor'           : '#fff',                       // Background color of the map container
            'bound'                     : true,                         // If false center the first mapdata entry
            'boundTo'                   : 'MARKER',                     // value: MARKER | RESTRICTED
            'center'                    : false,                        // If bound is false then center map to this latlng
            'CustomStyle'               : false,                        // Custom map style. Experimental! Documentation: http://tinyurl.com/4mog4py
            'debug'                     : false,                        // DEBUG MODE
            'GroundOverlay'             : false,
            'icon'                      : false,                        // Default icon or individual icon from mapdata
            'icon_shadow'               : false,                        // Default iconshadow or individual iconshadow from mapdata
            'id'                        : false,
            'InfoWindow'                : {
                                            'maxWidth'  : 500,          // Infowindow max. width
                                            'hide'      : true
                                        },
            'mapdata'                   : false,                        // Locations data (address, latitude, longitude, etc.)
            'min_zoom'                  : 3,                            // min. zoom level
            'max_zoom'                  : 18,                           // max. zoom level
            'mapTypeControl'            : false,                        // values: true | false
            'mapTypeControlOptions'     : {
                                            'style'     : 'DEFAULT',    // values: DROPDOWN_MENU | HORIZONTAL_BAR | DEFAULT
                                            'position'  : 'LEFT'        // values: BOTTOM | BOTTOM_LEFT | BOTTOM_RIGHT | LEFT | RIGHT | TOP | TOP_LEFT | TOP_RIGHT
                                        },
            'mapTypeId'                 : 'ROADMAP',                    // values: HYBRID | ROADMAP | SATELLITE | TERRAIN
            'navigationControlOptions'  : {
                                            'style'     : 'DEFAULT',    // values: DEFAULT | ANDROID | SMALL | ZOOM_PAN
                                            'position'  : 'TOP_LEFT'    // values: BOTTOM | BOTTOM_LEFT | BOTTOM_RIGHT | LEFT | RIGHT | TOP | TOP_LEFT | TOP_RIGHT
                                        },
            'RestrictedArea'            : false,
            'zoom'                      : 17
        }, settings);

        return this.each(function() {

            var el          = this,
                geocoder    = new google.maps.Geocoder();

            if (!$(el).length || !settings.id || !settings.mapdata)
                return;

            // Show Map -> hide without javascript

            $(el).removeClass('hideme');

            // Set latitude and longitude in settings.mapdata and init the map

            $(settings.mapdata).each(function(index) {
                if (this.latitude && this.longitude) {
                    var latlng = new google.maps.LatLng(this.latitude, this.longitude);
                    settings.mapdata[index].latlng = latlng;
                }
                else if ((this.street && this.postal_code && this.locality && this.country)) {
                    var address     = this.street + ', ' +
                                      this.postal_code + ' ' + 
                                      this.locality + ' ' + 
                                      this.country;

                    geocoder.geocode({ 'address': address }, function(results, status) {
                        if (status == google.maps.GeocoderStatus.OK) {
                            var latlng = results[0].geometry.location;
                            settings.mapdata[index].latlng = latlng;
                            $.fn.GoogleMaps.init(el, settings);
                        }
                    });
                }
                $.fn.GoogleMaps.init(el, settings);
            });

        });
    }

    $.fn.GoogleMaps.init = function(el, settings){
        if(!settings.mapdata[settings.mapdata.length-1].latlng)
            return;

        // Map options

        var MapOptions = {
            'backgroundColor'           : settings.backgroundColor,
            'center'                    : settings.mapdata[0].latlng,
            'draggable'                 : true,
            'mapTypeId'                 : google.maps.MapTypeId[settings.mapTypeId],
            'mapTypeControl'            : settings.mapTypeControl,
            'mapTypeControlOptions'     : {
                                            'style'     : google.maps.MapTypeControlStyle[settings.mapTypeControlOptions.style],
                                            'position'  : google.maps.ControlPosition[settings.mapTypeControlOptions.position]
                                        },
            'navigationControl'         : true,
            'navigationControlOptions'  : {
                                            'style'     : google.maps.NavigationControlStyle[settings.navigationControlOptions.style],
                                            'position'  : google.maps.ControlPosition[settings.navigationControlOptions.position]
                                        },
            'scrollwheel'               : false,
            'zoom'                      : settings.zoom
        };

        // Infowindow options

        var InfoOptions = {
            'maxWidth'  : settings.InfoWindow.maxWidth
        };

        // Initialize map

        var map         = new google.maps.Map(document.getElementById($(el).attr('id')), MapOptions),
            infowindow  = new google.maps.InfoWindow(InfoOptions),
            bounds      = new google.maps.LatLngBounds();

        // Custom map style

        $.fn.GoogleMaps.CustomStyle(map, settings);

        // Ground overlay image

        $.fn.GoogleMaps.GroundOverlay(map, settings);

        // Restricted area

        $.fn.GoogleMaps.RestrictedArea(map, bounds, settings);

        // Look for locations at the same position

        var positions = new Object();

        $(settings.mapdata).each(function(i) {
            var coordinates = mapdata[i]['latitude'] + '/' + mapdata[i]['longitude'];

            if (!positions[coordinates]) {
                positions[coordinates] = {
                    lat       : mapdata[i]['latitude'],
                    long      : mapdata[i]['longitude'],
                    info      : '',
                    displayed : 0
                };
            }

            positions[coordinates]['info'] += mapdata[i]['infowindow']; // collect all infos of this location
        });

        var new_mapdata = new Array();

        $(settings.mapdata).each(function(i) { // run through mapdata again and only add one for each location

            var coordinates = mapdata[i]['latitude'] + '/' + mapdata[i]['longitude'];

            if (positions[coordinates]['displayed'] == 0) {  // if displayed == 0, then it hasn't been added yet, at it once now

                // overwrite old infowindow of this mapdata with the collected info of this location
                mapdata[i]['infowindow'] = mapdata[i]['infowindow_pre'] + positions[coordinates]['info'] + mapdata[i]['infowindow_post'];
                new_mapdata.push(mapdata[i]);
                positions[coordinates]['displayed'] = 1;
            }
        });

        settings.mapdata = new_mapdata;

        // Set markers

        $(settings.mapdata).each(function(index) {

            settings.mapdata[index].marker = $.fn.GoogleMaps.marker(this, map, infowindow, settings);

            if (settings.bound && settings.boundTo == 'MARKER') {
                bounds.extend(this.latlng);
            }
        });

        if (settings.mapdata.length > 1 && settings.bound && settings.boundTo == 'MARKER') {
            map.fitBounds(bounds);
        }
        
        if (settings.center) {
            var latlng = new google.maps.LatLng(settings.center.latitude, settings.center.longitude);
            map.setCenter(latlng);
        }

        // Close all infowindows on click to the map

        google.maps.event.addListener(map, 'click', function() {
            infowindow.close(map);
        });

        // Min. and max. zoomlevel

        $.fn.GoogleMaps.zoomlevel(map, settings);

        // Directions panel

        $.fn.GoogleMaps.directions(map, infowindow, settings);

        // Debug mode
        
        if (settings.debug) {
            google.maps.event.addListener(map, 'drag', function() {
                console.log('Center: ' + map.getCenter());
            });
        }

    }

    // Function: restricted area

    $.fn.GoogleMaps.RestrictedArea = function(map, bounds, settings) {
        if (!settings.RestrictedArea)
            return;

        var SW_LatLng   = new google.maps.LatLng(settings.RestrictedArea.SW_Latitude, settings.RestrictedArea.SW_Longitude),
            NE_LatLng   = new google.maps.LatLng(settings.RestrictedArea.NE_Latitude, settings.RestrictedArea.NE_Longitude);

        bounds.extend(SW_LatLng);
        bounds.extend(NE_LatLng);

        // Drag the map

        google.maps.event.addListener(map, 'idle', function() {

            var ViewportCenter  = this.getCenter();

            if (bounds.contains(ViewportCenter)) {
                if (settings.debug) {
                    console.log('Restricted area: true' + ', Viewport center: ' + ViewportCenter);
                }
                this.ViewportCenterTrue = ViewportCenter;
            }
            else {
                if (settings.debug) {
                    console.log('Restricted area: false' + ', Viewport center: ' + ViewportCenter);
                }
                this.setCenter(this.ViewportCenterTrue);
            }

        });

        // Fit bounds

        if (settings.bound && settings.boundTo == 'RESTRICTED') {
            map.fitBounds(bounds);
        }

        // Debug mode

        if (settings.debug){

            console.log('Restricted area: on');
            console.log('Viewport center: ' + map.getCenter());

            RestrictedArea = new google.maps.Rectangle({
                bounds          : bounds,
                fillOpalocality     : 0.2,
                strokeColor     : '#000',
                strokeOpalocality   : 0.8,
                strokeWeight    : 1
            });

            RestrictedArea.setMap(map);

        }
    }

    // Function: custom map style

    $.fn.GoogleMaps.CustomStyle = function(map, settings) {
        if (!settings.CustomStyle)
            return;

        // New custom map

        var CustomMapType = new google.maps.StyledMapType(settings.CustomStyle, {
            'map'   : map,
            'name'  : 'custom'
        });

        map.mapTypes.set('custom', CustomMapType);

        // Set custom map

        map.setMapTypeId('custom');

        // Debug mode
        
        if (settings.debug) {
            console.log('Custom style: on');
        }
    }

    // Function: ground overlay image

    $.fn.GoogleMaps.GroundOverlay = function(map, settings) {
        if (!settings.GroundOverlay)
            return;

        var SW_LatLng   = new google.maps.LatLng(settings.GroundOverlay.SW_Latitude, settings.GroundOverlay.SW_Longitude),
            NE_LatLng   = new google.maps.LatLng(settings.GroundOverlay.NE_Latitude, settings.GroundOverlay.NE_Longitude),
            MapBounds   = new google.maps.LatLngBounds(SW_LatLng, NE_LatLng),
            Overlay     = new google.maps.GroundOverlay(settings.GroundOverlay.Image, MapBounds);

        Overlay.setMap(map);
        
        // Debug mode
        
        if (settings.debug) {
            console.log('Ground overlay: on');
            console.log('Ground overlay image: ' + settings.GroundOverlay.Image);
            console.log('Ground overlay SW_LatLng: ' + SW_LatLng);
            console.log('Ground overlay NE_LatLng: ' + NE_LatLng);
        }
        
        // Return bounds
        
        return MapBounds;
    }

    // Function: set markers

    $.fn.GoogleMaps.marker = function(location, map, infowindow, settings) {

        if (!location.infowindow)
            return;

        // Set marker on map

        var marker = new google.maps.Marker({
            'clickable'     : settings.InfoWindow.hide ? false : true,
            'description'   : location.infowindow,
            'icon'          : settings.icon ? settings.icon : (location.icon ? location.icon : undefined),
            'map'           : map,
            'shadow'        : settings.icon_shadow ? settings.icon_shadow : (location.icon_shadow ? location.icon_shadow : undefined),
            'title'         : settings.debug ? location.locality + ' ' + location.latlng : location.locality,
            'position'      : location.latlng
        });

        // Open infowindow on click

        if (!settings.InfoWindow.hide && location.infowindow) {
            google.maps.event.addListener(marker, 'click', function(){
                infowindow.setContent(location.infowindow);
                infowindow.open(map, this);
            });
        }

        // Open infowindow if only on location

        if (settings.mapdata.length == 1) {
            google.maps.event.trigger(marker, 'click');
        }

        return marker;
    }

    // Function: directions panel

    $.fn.GoogleMaps.directions = function(map, infowindow, settings) {

        var direction   = '#direction_' + settings.id,
            panel       = '#panel_' + settings.id;

        if (!$(direction).length && !$(panel).length)
            return;

        // Show DIV -> hide without javascript

        $(direction).removeClass('hideme');

        // Initialize directions panel

        var directionsService   = new google.maps.DirectionsService(),
            directions          = new google.maps.DirectionsRenderer({
                                    'map'       : map,
                                    'panel'     : document.getElementById('panel_' + settings.id)
                                });


        $('form', direction).submit(function(){

            var saddr   = $('#saddr_' + settings.id).val(),
                daddr   = $('#daddr_' + settings.id).val();

            if (saddr.length) {

                $(panel).removeClass('hideme');

                // Print directions result

                $('.print a', panel).click(function() {
                    window.print();
                    return false;
                });

                // Directions result

                var destination    = settings.mapdata[daddr].latlng,
                    request        = {
                                        'origin'        : saddr,
                                        'destination'   : destination,
                                        'travelMode'    : google.maps.DirectionsTravelMode.DRIVING
                                    };

                directionsService.route(request, function(result, status) {

                    if (status == google.maps.DirectionsStatus.OK) {
                        directions.setDirections(result);

                        // Hide destination marker and close all open infowindows

                        settings.mapdata[daddr].marker.setVisible(false);
                        infowindow.close(map);

                    }

                });

            }
            else {
                $(panel).addClass('hideme');
            }

            return false;
        });

    }

    // Function: min/max zoomlevel

    $.fn.GoogleMaps.zoomlevel = function(map, settings) {

        if (settings.min_zoom > settings.max_zoom)
            return;

        google.maps.event.addListener(map, 'zoom_changed', function() {
            if (this.getZoom() < settings.min_zoom) {
                this.setZoom(settings.min_zoom);
            }
            if (this.getZoom() > settings.max_zoom) {
                this.setZoom(settings.max_zoom)
            };
            
            // Debug mode

            if (settings.debug) {
                console.log('Zoom: ' + this.getZoom());
            }
        });

    }

})(jQuery);

