// jQuery Plugin to render StreetEats Embed map
// 2010-10-05 v0.995

(function($) {
	var settings = {
		mode: 'normal',
		lat:0,
		lng:0,
		zoom:17,
		vendor: null,
		city: null,
		server:"sevendor.com",
		schedule_div: '#schedule',
		panel_div: null,
		max_zoom: 15,
		infowindows: true,		
		onLoad: function(data){}
	};
	
	var map;
	var infowindow;
	var results = {};
	var markers = [];

	$.fn.StreetEatsMap = function(options, val){	
		if (typeof options == 'string'){
			if (options == 'city'){
				settings.city = val;
				init_map(this);
			}
			if (options == 'refresh'){
				init_map(this);
			}
			if (options == 'markers'){
				return(markers);
			}
		} else {
			$.extend(settings, options);
			debug('init: '+settings.mode);			
			return this.each(function (){
				init_map(this);
			});			
		}
	};
	
	function init_map(map_div) {
		request_url = buildURL();
		$.getJSON(request_url, function(data) {
			if (data){
				debug('got data');
				debug(data);
				results = data;
				if (markers.length>0){  // this is a refresh, remove existing markers
					for (var x=0; x<markers.length; x++) {
						markers[x].gmarker.setMap(null);
					}
				}
				markers = data.markers;
				for (var x=0; x<markers.length; x++){					
					if (settings.mode == 'adminmap'){
						markers[x].vendor_url = '/admin/users/sudo/'+markers[x].vendor_id;
					} else {
						markers[x].vendor_url = 'http://lovestreeteats.com/vendor/'+markers[x].url_name;
					}
				}
				updateMap(map_div);
				if (settings.vendor){
					updateSchedule(settings.schedule_div);	
				}
				if (settings.mode == 'bigmap' || settings.mode == 'adminmap'){
					updateTruckPanel(settings.panel_div);
				}
				$('#map_time').text(data.map_time); // the current time in the selected zone
			}
			//debug('callback data:'+data);
			settings.onLoad(data);	
			$('a.map-infowindowvendorinfo').live('mouseover',function(){
				$(this).css('background-position', '0 0');
			});
			$('a.map-infowindowvendorinfo').live('mouseout',function(){
				$(this).css('background-position', '-40px 0');
			});				
		});
	};
	
	function bindTruckPanel(panel_div){
		$(panel_div).delegate('a.trklnk','click',function(evt){
			//debug($(this));
			evt.preventDefault();
		});
	}
	
	// <div class="trk">
	//   <img name="truckname" src="http://www.lovestreeteats.com/wp-content/themes/StreeteatsHome/images/sample/testicon.png" width="61" height="61" border="0" alt="truckname" class="trkicn" />
	//     <div class="trkinfo">
	//       <h2 class="trkttl">Frites'n'Meats</h2>
	//       <p class="trkdesc">Bringing creme brulee to the people</p>
	//     </div> 
	//     <div class="trkdist">1.2 miles</div>
	//   <a href="#" class="trklnk"></a>
	// </div>
	function updateTruckPanel(panel_div){
		$(panel_div).html('');
		$(markers).each(function(i,marker){
			var div_id = 'truckrow-'+marker.id;
			var div = $('<div/>')
							.addClass('trk')
							.css('cursor','pointer')
							.attr('id',div_id);

			// icon
			var img = $('<img/>')
						.addClass('trkicn')
						.attr('src', marker.icon_web)
						.attr('alt', marker.company_name)
						.attr('width',61)
						.attr('height',61)
						.attr('border','0');
			div.append(img);

			// info				
			var info = $('<div/>').addClass('trkinfo');
			info.append($('<h2/>').addClass('trkttl').text(marker.company_name));
			info.append($('<p/>').addClass('trkdesc').text(marker.slogan));
			div.append(info);

			// distance
			// div.append($('<div/>').addClass('trkdst').html("&nbsp;"));
			
			// link
			var link = $('<a>')
				.addClass('trklnk')
				.attr('href',marker.vendor_url)
				.appendTo(div);
			
			// add it!
			$(panel_div).append(div);
			$('#truckrow-'+marker.id).data('marker',marker);			
			$('#truckrow-'+marker.id).click(function(evt){
				if (!$(evt.target).is('a')){
					// if they didn't click on the vendor link, go to the map marker
					var m = $(this).data('marker');
					//debug(evt);
					var bounds = new google.maps.LatLngBounds();
					var p = m.gmarker.position;
					bounds.extend(p);
					bounds.extend(new google.maps.LatLng(p.lat()+0.01, p.lng()+0.005));
					bounds.extend(new google.maps.LatLng(p.lat()-0.005, p.lng()-0.005));				
					map.setCenter(p);
					map.setZoom(settings.max_zoom);
					map.panTo(p);
					//debug('clicked '+$(this).data('marker').gmarker);										
				}
			});
			
		});
	} 
	
	function buildURL(){
		request_url = 'http://'+settings.server+'/api/embed_map';
		request_url += '?1=1';
		if (settings.vendor){
			debug(' vendor: '+settings.vendor);
			request_url += '&vendor='+settings.vendor;
		}
		if (settings.city){
			debug(' city: '+settings.city);
			request_url += '&city='+settings.city;			
		}
		return request_url += '&callback=?'
	}
	
	// here's where the schedule HTML gets generated
	function updateSchedule(schedule_div){
		$(results.schedule).each(function(i,group){
			var date_div = $('<div>').addClass('day').html(group.day);
			$(schedule_div).append(date_div);
			$(group.stops).each(function(i,stop){
				var truck_div = $('<div>').addClass('truck'+stop.truck_number);
				truck_div.append(
					$('<div>')
						.addClass('eventTime')
						.html(stop.start_time+' until '+stop.end_time)
				);
				truck_div.append(
					$('<div>')
						.addClass('eventLocation')
						.html(stop.address)
				);
				$(schedule_div).append(truck_div);
			});
			//debug(group);
		});
		$(schedule_div).append('<div class="listend"></div>');
	}
	
	// create google map, add markers and clicks
	function updateMap(map_div){
		var latlng = new google.maps.LatLng(settings.lat, settings.lng);
	    var myOptions = {
	        zoom: settings.zoom,
	        center: latlng,
			mapTypeControl: false,
			navigationControlOptions: {style: google.maps.NavigationControlStyle.DEFAULT},
			scrollwheel: false, // the scroll wheel conflicts with page scrolling	
	        mapTypeId: google.maps.MapTypeId.ROADMAP,
			zoom_changed: function(){
				if (map.getZoom() > settings.max_zoom){				
					map.setZoom(settings.max_zoom);
				}				
			}
	    };
		if (!map){
	    	map = new google.maps.Map(map_div, myOptions);			
		}
	    // infowindow = new google.maps.InfoWindow({maxWidth: 300});
		var bounds = new google.maps.LatLngBounds(); 

	    for (var x = 0; x < markers.length; x++) {
			//debug("marker "+x+": "+markers[x].lat+","+markers[x].lng);
			if (markers[x].event_type == 1){
		        var markerLoc = new google.maps.LatLng(markers[x].lat, markers[x].lng);
				var icon_url = markers[x].icon;
		        var gmarker = new google.maps.Marker({
		            position: markerLoc,
		            map: map,
					id: markers[x].truck_number,
					icon: icon_url,
		            title: markers[x].address
		        });
				if (settings.infowindows){
		        	attachMarkerEvent(gmarker, x);				
				}
				markers[x].gmarker = gmarker;
				bounds.extend(markerLoc);								
			}
	    }
	
		if (bounds.isEmpty()){
			debug(results.city);						
			var city = results.city.bounds;
			bounds.extend(new google.maps.LatLng(city.ne.lat, city.ne.lng));
			bounds.extend(new google.maps.LatLng(city.sw.lat, city.sw.lng));
		} else {
			// zoom out a little
			var ne = bounds.getNorthEast();
			var dist = ne.lat() - bounds.getSouthWest().lat();
			var newpt = new google.maps.LatLng(ne.lat() + dist/35, ne.lng());
			debug(newpt);
			bounds.extend(newpt);
		}
		// center and zoom
		map.fitBounds(bounds);
	}

	// here's where the infowindow HTML is generated
	function openInfowindow(gmarker, x){
		var content = $('<div>');
		
		var logo = $('<img>').css({
					'display': 'block',
					'border': 'none',
					'width': '36px',
					'height': '35px',
					'position': 'absolute',
					'top': '19px',
					'left': '18px',
					'z-index': '2'
				});
		logo.attr('src',markers[x].icon_web);
		logo.attr('height','35').attr('width','36');
		logo.attr('alt',markers[x].company_name);
		content.append(logo);
		
		var logo_link = $('<a>').attr('href',markers[x].vendor_url);
		logo_link.attr('class','map-infowindowvendorinfo');
		logo_link.css({
			'background': 'transparent url(http://maps.lovestreeteats.com/img/info-layer.png) -40px 0 no-repeat',
			'display': 'block',
			'overflow': 'hidden',
			'width':'36px',
			'height':'35px',
			'margin':'0',
			'padding':'0',
			'border':'none',
			'text-indent':'-999999px',
			'position':'absolute',
			'top':'19px',
			'left':'18px',
			'z-index':'3'	
		});
		logo_link.text('exit');
		content.append(logo_link);
		
		var h2 = $('<h2>').css({
					'font-family': "'Trebuchet MS','Lucida Grande',Verdana,Arial,Sans-Serif",
					'font-weight': 'bold',
					'font-size': '14px',
					'padding': '0',
					'margin': '0',
					'display': 'block',
					'width': '140px',
					'height': '30px',
					'line-height': '16px',
					'position': 'absolute',
					'top': '25px',
					'left': '60px',
					'z-index': '4'
				});
		h2.text(markers[x].company_name);
		content.append(h2);
		
		var p_slogan = $('<p>').css({					
					'font-family': "'Trebuchet MS','Lucida Grande',Verdana,Arial,Sans-Serif",
					'font-weight': 'normal',
					'font-size': '11px',
					'padding': '2px 0',
					'margin': '0',
					'display': 'block',
					'width': '185px',
					'height': '15px',
					'line-height': '13px',
					'position': 'absolute',
					'top': '58px',
					'left': '18px',
					'z-index': '5'
				});
		p_slogan.append($('<em>').text(markers[x].slogan));
		content.append(p_slogan);
		
		var p_schedule = $('<p>').css({
					'font-family': "'Trebuchet MS','Lucida Grande',Verdana,Arial,Sans-Serif",
					'font-weight': 'normal',
					'font-size': '11px',
					'padding': '0',
					'margin': '0',
					'display': 'block',
					'width': '185px',
					'height': '38px',
					'line-height': '13px',
					'position': 'absolute',
					'top': '80px',
					'left': '18px',
					'z-index': '6'					
				});
		p_schedule.append($('<strong>').text(markers[x].time_range));
		p_schedule.append(' '+markers[x].address);
		content.append(p_schedule);

		if (infowindow){
			infowindow.remove();
			infowindow = null;
		} 
		infowindow = new InfoBox({map: map, latlng: gmarker.getPosition(), content: content.html()});		
	}

	// attaches the click to the marker
	function attachMarkerEvent(gmarker, x) {	
	    google.maps.event.addListener(gmarker, 'click', function() {
			openInfowindow(gmarker, x);
	    });
	};

	function debug($obj) {
		if (window.console && window.console.log){
			window.console.log($obj);	
		}
	};

})(jQuery);



/// http://gmaps-samples-v3.googlecode.com/svn/trunk/infowindow_custom/infowindow-custom.html

/* An InfoBox is like an info window, but it displays
 * under the marker, opens quicker, and has flexible styling.
 * @param {GLatLng} latlng Point to place bar at
 * @param {Map} map The map on which to display this InfoBox.
 * @param {Object} opts Passes configuration options - content,
 *   offsetVertical, offsetHorizontal, className, height, width
 */
function InfoBox(opts) {
  google.maps.OverlayView.call(this);
  this.latlng_ = opts.latlng;
  this.map_ = opts.map;
  this.offsetVertical_ = -152;
  this.offsetHorizontal_ = -112;
  this.height_ = 119;
  this.width_ = 216;
  this.content_ = opts.content;

  var me = this;
  this.boundsChangedListener_ =
    google.maps.event.addListener(this.map_, "bounds_changed", function() {
      return me.panMap.apply(me);
    });

  // Once the properties of this OverlayView are initialized, set its map so
  // that we can display it.  This will trigger calls to panes_changed and
  // draw.
  this.setMap(this.map_);
}

/* InfoBox extends GOverlay class from the Google Maps API
 */
InfoBox.prototype = new google.maps.OverlayView();

/* Creates the DIV representing this InfoBox
 */
InfoBox.prototype.remove = function() {
  if (this.div_) {
    this.div_.parentNode.removeChild(this.div_);
    this.div_ = null;
  }
};

InfoBox.prototype.setloc = function(latlng){
	this.latlng_ = latlng;
};

/* Redraw the Bar based on the current projection and zoom level
 */
InfoBox.prototype.draw = function() {
  // Creates the element if it doesn't exist already.
  this.createElement();
  if (!this.div_) return;

  // Calculate the DIV coordinates of two opposite corners of our bounds to
  // get the size and position of our Bar
  var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
  if (!pixPosition) return;

  // Now position our DIV based on the DIV coordinates of our bounds
  this.div_.style.width = this.width_ + "px";
  this.div_.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
  this.div_.style.height = this.height_ + "px";
  this.div_.style.top = (pixPosition.y + this.offsetVertical_) + "px";
  this.div_.style.display = 'block';
};

/* Creates the DIV representing this InfoBox in the floatPane.  If the panes
 * object, retrieved by calling getPanes, is null, remove the element from the
 * DOM.  If the div exists, but its parent is not the floatPane, move the div
 * to the new pane.
 * Called from within draw.  Alternatively, this can be called specifically on
 * a panes_changed event.
 */
InfoBox.prototype.createElement = function() {
  var panes = this.getPanes();
  var div = this.div_;
  if (!div) {
    // This does not handle changing panes.  You can set the map to be null and
    // then reset the map to move the div.
    div = this.div_ = document.createElement("div");
    div.style.border = "0px none";
    div.style.position = "absolute";
    div.style.background = "url('http://maps.lovestreeteats.com/img/info-window.png')";
    div.style.width = this.width_ + "px";
    div.style.height = this.height_ + "px";
    var contentDiv = document.createElement("div");
    contentDiv.style.padding = "0 30px"
    contentDiv.innerHTML = this.content_;

    var topDiv = document.createElement("div");
    topDiv.style.textAlign = "right";
    var closeImg = document.createElement("img");
    closeImg.style.width = "32px";
    closeImg.style.height = "32px";
    closeImg.style.cursor = "pointer";
    closeImg.src = "http://maps.lovestreeteats.com/img/exit.png";
    topDiv.appendChild(closeImg);

    function removeInfoBox(ib) {
      return function() {
        ib.setMap(null);
      };
    }

    google.maps.event.addDomListener(closeImg, 'click', removeInfoBox(this));

    div.appendChild(topDiv);
    div.appendChild(contentDiv);
    div.style.display = 'none';
    panes.floatPane.appendChild(div);
    this.panMap();
  } else if (div.parentNode != panes.floatPane) {
    // The panes have changed.  Move the div.
    div.parentNode.removeChild(div);
    panes.floatPane.appendChild(div);
  } else {
    // The panes have not changed, so no need to create or move the div.
  }
}

/* Pan the map to fit the InfoBox.
 */
InfoBox.prototype.panMap = function() {
  // if we go beyond map, pan map
  var map = this.map_;
  var bounds = map.getBounds();
  if (!bounds) return;

  // The position of the infowindow
  var position = this.latlng_;

  // The dimension of the infowindow
  var iwWidth = this.width_;
  var iwHeight = this.height_;

  // The offset position of the infowindow
  var iwOffsetX = this.offsetHorizontal_;
  var iwOffsetY = this.offsetVertical_;

  // Padding on the infowindow
  var padX = 10;
  var padY = 10;

  // The degrees per pixel
  var mapDiv = map.getDiv();
  var mapWidth = mapDiv.offsetWidth;
  var mapHeight = mapDiv.offsetHeight;
  var boundsSpan = bounds.toSpan();
  var longSpan = boundsSpan.lng();
  var latSpan = boundsSpan.lat();
  var degPixelX = longSpan / mapWidth;
  var degPixelY = latSpan / mapHeight;

  // The bounds of the map
  var mapWestLng = bounds.getSouthWest().lng();
  var mapEastLng = bounds.getNorthEast().lng();
  var mapNorthLat = bounds.getNorthEast().lat();
  var mapSouthLat = bounds.getSouthWest().lat();

  // The bounds of the infowindow
  var iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
  var iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
  var iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
  var iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * degPixelY;

  // calculate center shift
  var shiftLng =
      (iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) +
      (iwEastLng > mapEastLng ? mapEastLng - iwEastLng : 0);
  var shiftLat =
      (iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) +
      (iwSouthLat < mapSouthLat ? mapSouthLat - iwSouthLat : 0);

  // The center of the map
  var center = map.getCenter();

  // The new map center
  var centerX = center.lng() - shiftLng;
  var centerY = center.lat() - shiftLat;

  // center the map to the new shifted center
  map.setCenter(new google.maps.LatLng(centerY, centerX));

  // Remove the listener after panning is complete.
  google.maps.event.removeListener(this.boundsChangedListener_);
  this.boundsChangedListener_ = null;
};


