/* Google Maps v3: http://code.google.com/apis/maps/documentation/v3 */

var geocoder;
var map;
var markers = [];

var latlongs = [];

var gmapListener;

function MapWindow(opts) {
	google.maps.OverlayView.call(this);
	this.marker_ = opts.marker;

	this.offsetVertical_ = 0;
	this.offsetHorizontal_ = 0;

	this.content_ = opts.content;

	var selfref = this;

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

	this.setMap(map);
}

function removeMapWindow(mw) {
	return function() {
		mw.div_.remove();
		mw.setMap(null);
	};
}

MapWindow.prototype = new google.maps.OverlayView();
MapWindow.prototype.remove = function() { if (this.div_) { this.div_.remove(); this.div_ = null; } };
MapWindow.prototype.draw = function() {
	this.createElement();
	if (!this.div_) { return; }

	var pixPosition = this.getProjection().fromLatLngToDivPixel(this.marker_.getPosition());
	if (!pixPosition) { return; }

	this.div_.css({top:pixPosition.y + this.offsetVertical_, left:pixPosition.x + this.offsetHorizontal_});
};

MapWindow.prototype.createElement = function() {
	var panes = this.getPanes();

	if ( !this.div_ ) {
		this.div_ = $('<div class="map-window">'+$('div#map-window-template div:first').html()+'</div>');

		var template = this.div_.find('div.content').empty();
		var related = this.div_.find('div.related a');

		if ( this.content_.title ) { 
			var search;

			if ( this.content_.search_terms )
			{
				search = '/search?keywords='+this.content_.search_terms+'&amp;display='+this.content_.title;
			} else {
				search = '/search?keywords=%22'+this.content_.title+'%22&amp;display='+this.content_.title;
			}

			if ( this.content_.group == 'funders' && this.content_.id )
			{
				template.append('<p class="headline"><a href="/directory/'+this.content_.group+'#directory-'+this.content_.id+'">'+this.content_.title+'</a></p>');
			} else {
				template.append('<p class="headline"><a href="'+search+'">'+this.content_.title+'</a></p>');
			}

			related.attr('href', search);
		} else {
			related.hide();
		}

		if ( this.content_.web ) { template.append('<p>w: <a href="'+this.content_.web+'">'+this.content_.web+'</a></p>'); }
		if ( this.content_.phone ) { template.append('<p>p: '+this.content_.phone+'</p>'); }
		if ( this.content_.email ) { template.append('<p>e: <a href="mailto:'+this.content_.email+'">'+this.content_.email+'</a></p>'); }

		if ( this.content_.summary ) { template.append('<p class="text">'+this.content_.summary+'</p>'); }

		google.maps.event.addDomListener(this.div_[0], 'mousedown', this.onClick_);
		google.maps.event.addDomListener(this.div_[0], 'dblclick', this.onClick_);
		google.maps.event.addDomListener(this.div_[0], 'DOMMouseScroll', this.onClick_);

		google.maps.event.addDomListener(this.div_.find('div.close')[0], 'click', removeMapWindow(this));

		$(panes.floatPane).append(this.div_);

		this.panMap();
	} else if ( this.div_.parent() != $(panes.floatPane) ) {
		this.div_.remove();
		$(panes.floatPane).append(this.div_);
	}
};

MapWindow.prototype.onClick_ = function(e) {
	if(navigator.userAgent.toLowerCase().indexOf('msie') != -1 && document.all) {
		window.event.cancelBubble = true;
		window.event.returnValue = false;
	} else {
		e.stopPropagation();
	}
};

MapWindow.prototype.panMap = function() {
	var bounds = map.getBounds();
	if (!bounds) { return; }

	var position = this.marker_.getPosition();

	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;

	var southWest = new google.maps.LatLng(Number(position.lat()) - this.div_.height()*degPixelY, Number(position.lng()));
	var northEast = new google.maps.LatLng(Number(position.lat()), Number(position.lng()) + this.div_.width()*degPixelX);

	var iwBounds = new google.maps.LatLngBounds(southWest,northEast);

	map.setCenter(iwBounds.getCenter());

	google.maps.event.removeListener(this.boundsChangedListener_);
	this.boundsChangedListener_ = null;
};

function map_create_marker()
{
	var group = markers.splice(0, 25);

	jQuery.each(group, function(){
		var data = this;

		var marker = new google.maps.Marker(data.options);

		if (typeof(data.record.url) !== 'undefined') {
			google.maps.event.addListener(marker, "click", function(e) { window.location = data.record.url; });
		} else {
			google.maps.event.addListener(marker, "click", function(e) {
				var infowindow = new MapWindow({marker:marker, content:data.record});
			});
		}
	});

	if ( markers.length )
	{
		setTimeout(map_create_marker, 250);
	} else {
		//console.timeEnd('markers');
	}
}

function map_populate()
{
	google.maps.event.removeListener(gmapListener); 

	//console.time('directory');

	jQuery.each(locations, function(){
		jQuery.each(this, function(){
			var record = this;

			// Determine correct icon

			var markericon = '/images/explore/map_icon.png';
			var markerZ = 20;

			switch (record.group)
			{
				case 'nonprofits':
					markericon = '/images/explore/icon_brown.png';
					markerZ = 15;
				break;
				case 'public':
					markericon = '/images/explore/icon_red.png';
					markerZ = 15;
				break;
			}

			// Prevent marker overlap by nudging coordinates

			if ( typeof(latlongs[record.latitude+':'+record.longitude]) === 'undefined' ) 
			{
				latlongs[record.latitude+':'+record.longitude] = 0;
			}

			if ( latlongs[record.latitude+':'+record.longitude] >= 1 )
			{
				var dupes = Number(latlongs[record.latitude+':'+record.longitude]);

				latlongs[record.latitude+':'+record.longitude]++;

				record.latitude = Number(record.latitude) + dupes * 0.0005;
				record.longitude = Number(record.longitude) + dupes * 0.0005;
			} else if ( latlongs[record.latitude+':'+record.longitude] === 0 ) {
				latlongs[record.latitude+':'+record.longitude] = 1;
			}

			// Add marker to queue

			markers.push({
				options:{
					position: new google.maps.LatLng(Number(record.latitude), Number(record.longitude)),
					map: map,
					title: record.title,
					icon: markericon,
					flat: true,
					zIndex: markerZ
				},
				record:record
			});
		});
	});

	//console.timeEnd('directory');

	//console.time('content');

	jQuery.each(pages, function(){
		var record = this;

		if ( record.latitude !== 0 && record.longitude !== 0 )
		{
			// Add marker to queue

			markers.push({
				options:{
					position: new google.maps.LatLng(Number(record.latitude), Number(record.longitude)),
					map: map,
					title: record.title,
					icon: '/images/explore/icon_gem_blue.png',
					flat: true,
					zIndex: 10
				},
				record:record
			});
		}
	});

	//console.timeEnd('content');

	//console.time('markers');

	map_create_marker();
}

function map_geocode()
{
	geocoder.geocode( { address: $(this).find('input').val()}, function(results, status) {
		if (status == google.maps.GeocoderStatus.OK && results.length) {
			if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
				map.fitBounds(results[0].geometry.viewport);
			}
		} else {
			alert("Geocode was unsuccessful due to: " + status);
		}
	});

	return false;
}

function map_init() {
	geocoder = new google.maps.Geocoder();

	var myOptions = {
		navigationControl: true,
		mapTypeControl: false,
		scaleControl: true,
		mapTypeId: google.maps.MapTypeId.TERRAIN
	};

	map = new google.maps.Map(document.getElementById("map-canvas"), myOptions);

	if (typeof(mapbounds) !== 'undefined') {
		map.fitBounds(mapbounds);
	} else {
		map.setCenter(new google.maps.LatLng(37.0625,-95.677068));
		map.set_zoom(4);
	}

	if (typeof(locations) !== 'undefined') { gmapListener = google.maps.event.addListener(map, 'tilesloaded', map_populate); }

	$('form.geolocate').submit(map_geocode);
	$('form.geolocate button').click(function(){
		$(this).closest('form').submit(); return false;
	});
}

$(function() {
	google.setOnLoadCallback(map_init);

	$('a.map-help').click(function(){
		$(this).closest('div#content').find('div#mapSearchOverlay').fadeIn('fast'); return false;
	});

	$('a.overlayClose').click(function(){
		$(this).closest('div.overlay').fadeOut('fast'); return false;
	});
});
