/*
 *  GoogleMap API controller
 *  @author Daniel Honzik
 *  @version 0.2
 *  @site restaurace.cz 
 *
 *  customized options overwrites default ones
 *   
 *  $(selector).googlemap({
 *    lat: float, *default latitude is from google.ClientLocation or 50.087 when unavailable
 *    lng: float, *default longitude is from google.ClientLocation or 14.420 when unavailable
 *    zoom: int,
 *    streetView: boolean, *create paronama control to bypass markers in streetview
 *    mapNavigation: 'default', 'small', false,
 *    mapTypeControl: 'default', 'dropmenu', false,  
 *    mapChanged: function(){} *call custom function (500ms delay) on bounds change 
 *       with arguments: object from selector, controller functions, settings object
 *    complete: function(){} *call custom function 
 *      with arguments: object from selector, controller functions   
 *  });
 */ 
 
(function($, google){

  // shared items for all instances
  var geocoder = new google.maps.Geocoder(); 
  var infowindow = new google.maps.InfoWindow();
  var panorama;
  var suggested = {};
  
  // jquery fn
  $.fn.googlemap = function(options) {
    
    // no element has been found, interrupt before it gets fucked up
    if (this[0] === undefined) {
      return;
    }
    
    var $that = this;
    var timer = null;  
    var markers = [];
    
    // extend default settings
    var settings = $.extend({
      lat: (google.loader.ClientLocation) ? google.loader.ClientLocation.latitude : 50.087,        
      lng: (google.loader.ClientLocation) ? google.loader.ClientLocation.longitude : 14.420,        
      zoom: 14,
      northEast: {
        lat: null,
        lng: null
      },
      southWest: {
        lat: null,
        lng: null
      },
      mapNavigation: 'default',
      mapTypeControl: 'default',
      streetView: false
    }, options);
    
    // init google map
    var map = new google.maps.Map(this[0], {
        zoom: settings.zoom,      
        center: new google.maps.LatLng(settings.lat, settings.lng),
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        streetViewControl: (settings.streetViewControl === false) ? false : true,
        mapTypeControl: (settings.mapTypeControl === false) ? false : true,
        mapTypeControlOptions: (settings.mapTypeControl == 'dropmenu') ? {
            style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
            position: google.maps.ControlPosition.TOP_RIGHT 
          } : {
            style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
            position: google.maps.ControlPosition.TOP
          },
        navigationControl: (settings.mapNavigation === false) ? false : true,
        navigationControlOptions: (settings.mapNavigation == 'small') ? {
            style: google.maps.NavigationControlStyle.SMALL 
          } : {
            style: google.maps.NavigationControlStyle.DEFAULT,
            position: google.maps.ControlPosition.TOP_RIGHT
          }
    });
    
    // handle street view
    if (settings.streetView === true) {
      var panorama = new google.maps.StreetViewPanorama(map.getDiv(), {
        enableCloseButton: true,
        addressControl: true,
        navigationControl: true
      }); 

   		panorama.setVisible(false); 
      map.setStreetView(panorama);
    }

    // functions for local instance
    var controller = {
      // add new markers to the map, remove those are out of bounds
      updateMarkers: function(newMarkers) {
        var deleteMarker = true;

        for(var i = 0; i < markers.length; i++) {
          for(var j = 0; j < newMarkers.length; j++) {
            if (markers[i].position.b == newMarkers[j].lat &&
                markers[i].position.c == newMarkers[j].lng &&
                markers[i].title == newMarkers[j].title) {

              newMarkers.splice(j, 1);
              j--;
              deleteMarker = false;
            }
          }
          if (deleteMarker) {
            var m = markers.splice(i, 1);
            i--;
            m[0].setMap(null);
          } else {
            deleteMarker = true;
          }
        }

        while(m = newMarkers.pop()) {
          
          this.addMarker(m);
        }
      },
      // add one single marker and push it to array 
      addMarker: function(obj) {
        var icon = '/images/icons/restaurant.png';
        var zIndex = undefined;
        
        if (obj.level == 1) {
          icon = '/images/icons/p_restaurant.png';
          zIndex = 2000;
        } else if (obj.level == 2) {
          icon = '/images/icons/d_restaurant.png';
          zIndex = 3000;
        }
        
        var m = new google.maps.Marker({
          position: new google.maps.LatLng(obj.lat, obj.lng),
          map: map,
          title: obj.title,
          icon: icon,
          zIndex: zIndex
        });
        
        markers.push(m);

        if (obj.content !== undefined) {
          google.maps.event.addListener(m, 'click', function(){
            infowindow.setContent(obj.content);
            infowindow.open(map, m);
          });
        }
        
        if (obj.center === true) {
          settings.lat = obj.lat;
          settings.lng = obj.lng;
          this.refreshMap();
        }
      },
      // update map for new parameters
      updateMap: function() {
        google.maps.event.trigger(map, "bounds_changed");
      },
      // resize map and set center to set position
      refreshMap: function() {
        if (settings.streetView === true) {
          google.maps.event.trigger(panorama, "resize");
        }
        google.maps.event.trigger(map, "resize");
        map.setCenter(new google.maps.LatLng(settings.lat, settings.lng));
        map.setZoom(parseInt(settings.zoom));
      },
      // set new center position
      setCenter: function(lat, lng, zoom) {
        settings.lat = lat;
        settings.lng = lng;
        
        if (zoom != undefined) {
          settings.zoom = zoom;
        }
        
        this.refreshMap();
      },
      // remove all markers
      clearMarkers: function() {
        while(m = markers.pop()) {
          m.setMap(null);
        }
      },
      // call function with geocoder results
      geoSearch: function(q, fn) {
        geocoder.geocode( { 'address': q }, function(results, status) {
          fn.call(this, results);
        });
      }
    };
        
    // action afterLoad
    if (typeof settings.complete == 'function') {
      settings.complete.call($that, controller);
    }
    
    // listener map area click
    google.maps.event.addListener(map, 'click', function() {
      infowindow.close();
    });
    
    // listener bounds_chnaged
    if (typeof settings.mapChanged == 'function') {
      google.maps.event.addListener(map, 'bounds_changed', function() {
        var northEastCorner = map.getBounds().getNorthEast();
        var southWestCorner = map.getBounds().getSouthWest();
  
        settings.zoom = map.getZoom();
        settings.northEast.lat = northEastCorner.lat();
        settings.northEast.lng = northEastCorner.lng();
        settings.southWest.lat = southWestCorner.lat();
        settings.southWest.lng = southWestCorner.lng();
        
        // call function with 500ms delay, we don't wanna burn out
        (function(){
          clearTimeout(timer);
          timer = setTimeout(function() {
            settings.mapChanged.call($that, controller, settings); 
          }, 500);
        })();
      });
    }
    
  };
  
})(jQuery, google);