/**
 * Google maps container
 * 
 * @author Brian Coit <brian@line.uk.com>
 */
var geoMap = {
	
	options: null,
	
	/* gmaps container */
	container: null,
	
	/** toggle control container */
	toggleContainer: null,
	
	/** google map object */
	map: {},
	
	/** array containing markers */
	arrMarkers: [],
	
	/** array containing info windows */
	arrInfoWindows: [],
	
	/** array containing map pin icon types */
	iconTypes: [],

	/**
	 * Gets icon attributes (image + shadow filenames)
	 * 
	 * @param string name Icon type
	 * @return object
	 */
	getIconAttributes: function(name)
	{
		// types:
		// HQ,
		// legacy-candidates
		// legacy-certified
		// network
		// partners/supporters
		// events

		var iconTypes = new Array();
		var dir = '/assets/site/images/map-icons/';
		var shadow_img = dir + 'shadow.png';

		iconTypes['oncourse-certified'] = {};
		iconTypes['oncourse-certified'].image = dir + 'geo-certified.png';
		iconTypes['oncourse-certified'].shadow = shadow_img;
    
		iconTypes['legacy-certified'] = {};
		iconTypes['legacy-certified'].image = dir + 'legacy-certified.png';
		iconTypes['legacy-certified'].shadow = shadow_img;

		iconTypes['partner'] = {};
		iconTypes['partner'].image = dir + 'partner.png';
		iconTypes['partner'].shadow = shadow_img;
    
		iconTypes['geosa'] = {};
		iconTypes['geosa'].image = dir + 'geosa.png';
		iconTypes['geosa'].shadow = shadow_img;
		
    iconTypes['hq'] = {};
		iconTypes['hq'].image = dir + 'geo-hq.png';
		iconTypes['hq'].shadow = shadow_img;
		
		iconTypes['legacy-candidates'] = {};
		iconTypes['legacy-candidates'].image = dir + 'legacy-candidates.png';
		iconTypes['legacy-candidates'].shadow = shadow_img;
    
		iconTypes['oncourse-candidates'] = {};
		iconTypes['oncourse-candidates'].image = dir + 'geo-oncourse.png';
		iconTypes['oncourse-candidates'].shadow = shadow_img;
    

		if(typeof(iconTypes[name]) != 'undefined')
		{
			return iconTypes[name];
		}

		// if we couldn't find a specified match, then return marker images with specified name
		iconTypes[name] = {};
		iconTypes[name].image = dir + name + '.png';
		iconTypes[name].shadow = shadow_img;

		return iconTypes[name];
	},

	/**
	 * Creates a custom marker
	 * 
	 * @param google.maps.LatLng point
	 * @param object options
	 * @return google.maps.Marker
	 */
	createCustomMarker: function(point, options)
	{
		options = $.extend({
			markerType: 'legacy-certified',
			addToMap: true
		},
		options);

		var iconType = geoMap.getIconAttributes(options.markerType);

		var image = new google.maps.MarkerImage(
		  iconType.image,
		  new google.maps.Size(31,37),
		  new google.maps.Point(0,0),
		  new google.maps.Point(16,37)
		);

		var shadow = new google.maps.MarkerImage(
		  iconType.shadow,
		  new google.maps.Size(28,18),
		  new google.maps.Point(0,0),
		  new google.maps.Point(15,8)
		);

		var shape = {
		  coord: [25,0,26,1,28,2,28,3,29,4,29,5,30,6,30,7,30,8,29,9,29,10,28,11,28,12,27,13,25,14,25,15,25,16,25,17,25,18,25,19,24,20,24,21,23,22,23,23,22,24,22,25,21,26,21,27,20,28,20,29,19,30,19,31,18,32,18,33,17,34,17,35,16,36,14,36,13,35,13,34,12,33,12,32,11,31,11,30,10,29,10,28,9,27,9,26,8,25,8,24,7,23,7,22,6,21,6,20,5,19,5,18,5,17,5,16,5,15,5,14,5,13,5,12,5,11,5,10,6,9,6,8,7,7,8,6,9,5,11,4,17,3,17,2,19,1,20,0,25,0],
		  type: 'poly'
		};

		options = $.extend({
			draggable: false,
			raiseOnDrag: false,
			icon: image,
			shadow: shadow,
			shape: shape,
			position: point
		},
		options);

		// add to map if specified in options
		if(options.addToMap)
		{
			options = $.extend({
				map: geoMap.map
			},
			options);
		}

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

		return marker;
	},
	
	/**
	 * Adds markers for a named marker type
	 * 
	 * @param string type Marker type to add
	 * @return int Number of affected items
	 */
	addMarkersForType: function(type)
	{
		if(typeof geoMap.arrMarkers[type] != 'undefined')
		{
			var arr = geoMap.arrMarkers[type];
			
			if(arr.length)
			{
				for(var i in arr)
				{
					arr[i].setMap(geoMap.map);
				}
				return ++i;
			}
		}
		return 0;
	},
	
	/**
	 * Removes markers of a specified type
	 * 
	 * @param str type Marker type to remove
	 * @return int Number of affected markers
	 */
	removeMarkersForType: function(type)
	{
		if(typeof geoMap.arrMarkers[type] != 'undefined')
		{
			var arr = geoMap.arrMarkers[type];
			
			if(arr.length)
			{
				for(var i in arr)
				{
					arr[i].setMap(null);
				}
				return ++i;
			}
		}
		
		return 0;
	},
	
	removeInfoWindowsForType: function(type)
	{
		if(typeof geoMap.arrInfoWindows[type] != 'undefined')
		{
			
			var arr = geoMap.arrInfoWindows[type];
			
			if(arr.length)
			{
				for(var i in arr)
				{
					arr[i].close();
				}
				return ++i;
			}
		}
		return 0;
	},
	
	/**
	 * Removes all markers from the map (but retains them in the registry)
	 * 
	 * @return integer Number of markers affected
	 */
	removeAllMarkers: function()
	{
		if(typeof geoMap.arrMarkers != 'undefined')
		{
			var arr = geoMap.arrMarkers;

			if(typeof arr === 'object')
			{
				for(var i in arr)
				{
					var tmp = arr[i];

					for(var j in tmp)
					{
						tmp[j].setMap(null);
					}
				}
				return ++j;
			}
		}
		return 0;
	},
	
	/**
	 * Set map type
	 * 
	 * @param string MapId string
	 * @return boolean
	 */
	setMapType: function(type)
	{
		if($.inArray(type, google.maps.MapTypeId))
		{
			return geoMap.map.setMapTypeId(type);
		}
		
		console.warn('Cannot set gmaps to maptype: ' + type.toString() + '. Type must exist within google.maps.MapTypeId object.');
		
		return false;
	},
	
	/**
	 * Initializes a map
	 * 
	 * @param object options Options object
	 * @return void
	 */
	init: function(options)
	{
		options = $.extend({
			container: 'map',
			lat: 55.85710562286997,
			lng: -4.242181777954102,
			url: '/map-data',
			mapOptions: {},
			visiblePinTypes: [],
			closeable: true
		},
		options);
		
		geoMap.options = options;
		
		var container = (options.container instanceof jQuery)
			? options.container.get(0)
			: document.getElementById(options.container);
			
		geoMap.container = $(container).wrap('<div id="mapContainerWrapper" />');
		
		var mapOptions = {
			zoom: 3,
			minZoom: 3,
//			maxZoom: 6,
			center: new google.maps.LatLng(options.lat, options.lng),
			mapTypeId: google.maps.MapTypeId.SATELLITE,
			mapTypeControl: 2, // 2 for nice dropdown
			mapTypeControlOptions: {
				style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
			},
			streetViewControl: false
		};
		
		mapOptions = $.extend(mapOptions, options.mapOptions);
		
		this.options = options;
		
		geoMap.map = new google.maps.Map(container, mapOptions);
		
		if(typeof options.onLoad == 'function')
		{
			options.onLoad(geoMap.container);
		}
		
		var totalNumPins = 0;
		var curLoaded = 0;
		
		$.getJSON(options.url, {}, function(data)
		{
			$.each(data.pins, function(type, grp)
			{
				totalNumPins+= data.pins[type].length;
				
				geoMap.arrMarkers[type] = new Array();
				geoMap.arrInfoWindows[type] = new Array();
				
				$.each(grp, function(i, item)
				{
					var marker = geoMap.createCustomMarker(new google.maps.LatLng(item.lat, item.lng), {markerType: type});

					// push marker into marker type registry
					geoMap.arrMarkers[type].push(marker);
					
					var infoBubble = new InfoBubble({
						map: geoMap.map,
						content: geoMap.getInfoWindowContent(item),
						padding: 0,
						borderRadius: 0,
						borderWidth: 0,
						shadowStyle: 3,
						minWidth: 294,
						maxWidth: 294,
						width: 294,
						height: 'auto',
						disableAutoPan: true
					});
					
					infoBubble.setArrowPosition(10);
					
					// push info window to type registry
					geoMap.arrInfoWindows[type].push(infoBubble);
					
					curLoaded++;
					
					// bind click event to show infowindow on click
					google.maps.event.addListener(marker, 'click', function()
					{
						geoMap.closeAllInfoWindows();
						infoBubble.open(geoMap.map, marker);
					});
				});
			});
			
			// hide the loader after we render the last pin
			if(curLoaded >= totalNumPins)
			{
				removeGoogleMapLoader();
			}
			
			geoMap.setupToggleContainer();
			geoMap.setupPinDefaultVisibility();

			// add close button to overlay
			if(geoMap.options.closeable)
			{
				var closeContainer = $('<div />').addClass('map-close')
					.prependTo(geoMap.container.parent().find('#map-toggle-container'));

				$('<a />')
					.attr('href', '#')
					.text('Close map')
					.click(function(e)
					{
						e.preventDefault();
						removeGoogleMap();
					})
					.appendTo(closeContainer);

				// set absolute position to match bottom of header
				geoMap.container.parent().css({
					top: $('#header').outerHeight() + 'px'
				});
			}
		});
	},
	
	getInfoWindowContent: function(item)
	{
		//var c = $('<div class="infobox-item"><div class="infobox-item-details"><h2 class="infobox-item-title">Name of legacy</h2><span class="infobox-item-text">Edinburgh, Scotland</span></div></div>');
		
		var fauxContainer = $('<div />');
		var rowContainer = $('<div class="infobox-row-container" />').appendTo(fauxContainer);
		
		if('rows' in item)
		{
			$.each(item.rows, function(idx, element)
			{
				var row = $('<div />')
					.addClass('infobox-row')
					.appendTo(rowContainer);
					
				// set 'last' class on last item
				if(element == item.rows[item.rows.length-1])
				{
					// only display when no infowindow footer
					if(typeof item.footer == 'undefined')
						row.addClass('infobox-row-last-item');
				}
					
				var rowInner = $('<div />')
					.addClass('infobox-row-inner')
					.appendTo(row);
					
				// add image
				if(typeof element.image != 'undefined')
				{
					var img = $('<img />')
						.attr('src', element.image)
						.attr('alt', element.title)
						.appendTo(rowInner);
						
					if(typeof element.image_width != 'undefined')
					{
						// original proposed size: 74px
						
						//margin 102 - 
						var diff = (Math.floor(element.image_width) - 74);
						var marginLeft = 102 + diff;
						rowInner.css({marginLeft: marginLeft});
						
						// original image -marginLeft -97px
						if(diff > 0)
						{
							img.css({
								marginLeft: -97 - diff
							});
						}
						else
						{
							img.css({
								marginLeft: -97 + diff
							});
						}
					}
				}
				
				if(typeof element.title != 'undefined')
				{
					var title = $('<h2 />')
						.addClass('infobox-row-title')
						.html(element.title)
						.appendTo(rowInner);
				}
				
				if(typeof element.text != 'undefined')
				{
					var p = $('<p />')
						.html(element.text)
						.appendTo(rowInner);
				}
				
				// add link + link text if applicable
				if(typeof element.link)
				{
					// wrap image
					if(typeof img != 'undefined')
						img.wrap('<a href="'+element.link+'" target="_blank"></a>');
					
					// wrap title
					if(typeof title != 'undefined')
						title.wrapInner('<a href="'+element.link+'" target="_blank"></a>');
					
          if (element.link_text)
            $('<a href="'+element.link+'" target="_blank">'+(element.link_text || element.link)+'</a>')
              .addClass('infobox-row-link')
              .appendTo(rowInner)
				}
			});
		}
		
		// set footer content
		if('footer' in item)
		{
			var footer = $('<div />')
				.addClass('infobox-footer')
				.appendTo(rowContainer);
			
			$.each(item.footer, function(idx, element)
			{
				if(typeof element.link != 'undefined' && element.link)
				{
					var tmpel = $('<a target="_blank" />')
						.attr('href', element.link)
						.html(element.link);
				}
				else
				{
					var tmpel = $('<span />');
				}
				
				tmpel.addClass('link-' + idx);
				
				if(idx+1 == item.footer.length)
				{
					tmpel.addClass('link-last');
				}
				
				if(typeof element.text != 'undefined')
				{
					tmpel.html(element.text);
				}
				
				tmpel.appendTo(footer);
			});
		}

		return fauxContainer.html();
	},
	
	/**
	 * Setups up the initial pin visibility from data supplied in
	 * JSON feed
	 * 
	 * @return void
	 */
	setupPinDefaultVisibility: function()
	{
		geoMap.removeAllMarkers();
		
		for(var j in this.options.visiblePinTypes)
		{
			for(var i in this.arrMarkers)
			{
				if(i == this.options.visiblePinTypes[j])
				{
					this.addMarkersForType(i);
				}
			}
		}
	},
	
	/**
	 * Clunky method to set up toggle control mappings
	 * 
	 * @return array
	 */
	getToggleNameMappings: function()
	{
		var namesArr = new Array();
		
		namesArr['GEO HQ'] = new Array();
		namesArr['GEO HQ'].push(new Array('hq', ''));
		
		namesArr['GEO OnCourse&trade;'] = new Array();
		namesArr['GEO OnCourse&trade;'].push(new Array('oncourse-candidates', 'Applicants'));
		namesArr['GEO OnCourse&trade;'].push(new Array('oncourse-certified', 'GEO Certified&trade;'));
		
		namesArr['Partners &amp; Supporters'] = new Array();
		namesArr['Partners &amp; Supporters'].push(new Array('partner', ''));
		
		namesArr['GEOSA Network'] = new Array();
		namesArr['GEOSA Network'].push(new Array('geosa', ''));
		
		return namesArr;
	},
	
	/**
	 * Gets all registered marker types
	 * 
	 * @return array
	 */
	getTypes: function()
	{
		var types = new Array();
		
		// push all the types into a types array
		for(var i in geoMap.arrMarkers)
		{
			types.push(i);
		}
		return types;
	},
	
	/**
	 * Sets up the toggle container
	 * 
	 * @return void
	 */
	setupToggleContainer: function()
	{
		// create the container, add groups based on a mapping array
		
		geoMap.addMarkerToggleContainer();
		
		var mappings = geoMap.getToggleNameMappings();
		var validTypes = geoMap.getTypes();
		
		for(var i in mappings)
		{
			var m = mappings[i];
			
			var r = new Array();
			
			for(var j in m)
			{
				var values = m[j];
				var type = values[0];
				var title = values[1];
				
				for(var k in validTypes)
				{
					if(validTypes[k] == type)
					{
						r.push({title: title, type: type});
					}
				}
			}
			
			if(r.length)
			{
				geoMap.addMarkerToggleGroup(i, r)
			}
		}
		
	},
	
	/**
	 * Closes all info windows
	 * 
	 * @return integer Number of affected info windows
	 */
	closeAllInfoWindows: function()
	{
		var types = geoMap.arrInfoWindows;
		var j = 0;

		for(var type in types)
		{
			var arr = types[type];

			for(var i in arr)
			{
				arr[i].close();
			}
			++j;
		}
		return j;
	},
	
	/**
	 * Adds the toggle control container element
	 * 
	 * @return void
	 */
	addMarkerToggleContainer: function()
	{
		var container = $('<div />')
			.attr('id', 'map-toggle-container');

		$('<dl><dt id="map-toggle-container-title">Legend</dt><dd id="map-toggle-container-content"></dd></dl>')
			.appendTo(container);

		$('#mapContainerWrapper')
			.append(container);
			
		var content = $('#map-toggle-container-content');
		
		var masterToggle = $('<div id="map-master-toggle" />').appendTo(content);
		
		var toggleShow = $('<a />').attr('href', '#')
			.addClass('show-all')
			.click(function(e)
			{
				e.preventDefault();
				
				content.find('input[type=checkbox]').prop('checked', true).change();
			})
			.text('Show all')
			.appendTo(masterToggle);

		var toggleHide = $('<a />').attr('href', '#')
			.addClass('hide-all')
			.click(function(e)
			{
				e.preventDefault();
				
				content.find('input[type=checkbox]').prop('checked', false).change();
			})
			.text('Hide all')
			.appendTo(masterToggle);
		
		
	},
	
	/**
	 * Adds a toggle group to the toggle container
	 * 
	 * @return void
	 */
	addMarkerToggleGroup: function(title, arr)
	{
		var el = $('<dl class="map-toggle-group"><dt><span class="toggle-icon"></span>' + title + '</dt><dd></dd></dl>');
		
		var toggler = el.find('> dt > span').addClass('toggle-open');
		
		var ul = $('<ul />').appendTo(el.find('dd'));

		for(var name in arr)
		{
			var li = $('<li />');
				
			var label = $('<label for="legend-' + arr[name].type + '" />')
				.appendTo(li);
				
			var imageHolder = $('<div />').addClass('marker-image').appendTo(label);
				
			var img = $('<img />')
				.attr('src', geoMap.getIconAttributes(arr[name].type).image)
				.attr('alt', arr[name].title)
				.appendTo(imageHolder);
				
			var type = arr[name].type;
				
			var checkbox = $('<input type="checkbox" />')
				.attr('id', 'legend-' + arr[name].type)
				.prependTo(label)
				.change(function()
				{
					var id = $(this).attr('id').replace('legend-', '');
					
					if(!$(this).is(':checked'))
					{
						geoMap.removeMarkersForType(id);
						geoMap.removeInfoWindowsForType(id);
					}
					else
					{
						geoMap.addMarkersForType(id);
					}
				});
			
			/**
			 * Check the radio if pins displayed on map
			 */
			if($.inArray(arr[name].type, this.options.visiblePinTypes) !== -1)
			{
				checkbox.prop('checked', true);
			}

			if(arr[name].title)
			{
				var span = $('<span />')
					.html(arr[name].title)
					.appendTo(label);
			}
			
			li.appendTo(ul);
		}

		el.appendTo('#map-toggle-container-content');
		
		/**
		 * collapsable
		 */
		toggler.click(function()
		{
			var content = $(this).parent().siblings('dd');
				
			if(content.is(':visible'))
			{
				toggler.parent().addClass('toggle-closed').removeClass('toggle-open');
				content.slideUp(200);
			}
			else
			{	
				toggler.parent().removeClass('toggle-closed').addClass('toggle-open');
				content.slideDown(200);
			}
		});
	}
};
	
	
	
	
	
function displayGoogleMap()
{
	if(window.gmapsLoaded)
		return false;
	
	window.gmapsLoaded = true;
	$('#main').hide();
	$('#footer').hide();

	var container = window['geoGoogleMapsContainer'] = $('<div />')
		.attr('id', 'mapContainer')
		.css({
			width: '100%',
			height: '860px'
		})
		.insertBefore('#footer');
		
//	if($('#mapContainerLoader').length)
//		return;
	
	var loaderContainer = container.clone()
		.attr('id', 'mapContainerLoader')
		.css({
			backgroundColor: '#fff',
			width: '100%',
			position: 'absolute',
			top: '0px',
			left: 0,
			paddingTop: '10px'
		})
		.insertBefore('#footer');

	$('#mapContainer').css({
		opacity: 0
	});
	
	//return;
	
	
	geoMap.init({
		container: container, 
		visiblePinTypes: [
			'partner', 
			'legacy-certified',
			'oncourse-certified',
			'geosa',
			'hq'
		],
		onLoad: function()
		{
			$('#mapContainerWrapper').css({
				width: '100%',
				position: 'absolute',
				top: '0px',
				left: 0,
				borderTop: '1px solid #fff'
			});
		},
		closeable: true
	});
	
	var mapCenter;

	google.maps.event.addListenerOnce(geoMap.map, 'tilesloaded', function()
	{
		mapCenter = geoMap.map.getCenter();
		
		var mapTypeControl = $('#mapContainer')
			.find('> div > div:last-child')
			.css({
				marginRight: '197px'
			})
			.attr('id', 'mapTypeControls');

		$(window).resize();
	});
	
	google.maps.event.addListener(geoMap.map, 'bounds_changed', function()
	{
		mapCenter = geoMap.map.getCenter();
	});
	
	$(window).resize(function()
	{
		var cHeight = $(window).height() - parseInt($('#mapContainerWrapper').css('padding-top')) - parseInt($('#mapContainer').css('border-top-width'));
		var toggleHeight = $('#map-toggle-container').height();
		
		if(cHeight < toggleHeight)
		{
			cHeight = toggleHeight;
		}
		
		container.height(cHeight);
		loaderContainer.height(cHeight);
		
		if(window.gmapsLoaded)
		{
			$('#backgroundContainer').height(cHeight);
		}
		
		if(mapCenter)
			geoMap.map.setCenter(mapCenter);
	})
	.resize();

	var originalHash = document.location.hash;
	document.location.hash = '#map';

	$(window).bind('hashchange', function(e)
	{
		if(originalHash != ('#' + e.fragment) && document.location.hash == originalHash)
		{
			removeGoogleMap();
		}
	});
}

function removeGoogleMapLoader()
{
	setTimeout(function() {
		$('#mapContainerLoader').fadeOut(500, function()
		{
			$(this).remove();

			$('body, html').animate({
				scrollTop: $('#header').outerHeight() + 'px'
			},
			300,
			function()
			{	
				$('#mapContainer').animate({
					opacity: 1
				}, 500, function()
				{
					$(window).resize();

					if(geoMap.options.closeable)
					{
						$(document).keyup(function(e)
						{
							if(e.keyCode == 27)
							{
								removeGoogleMap();
							}
						});
					}
				});
			});
		});
	}, 1000); // 1s delay to help account for GC
}

function removeGoogleMap()
{
	if(!window.gmapsLoaded)
		return false;

	$('#main').show();
	$('#footer').show();
	
	var container = $('#mapContainerWrapper');
	
	if(container.length)
	{
		container.remove();
	}
	window.gmapsLoaded = false;
}

$(document).ready(function()
{
	$('a.map-overlay-trigger').click(function(e)
	{
		e.preventDefault();
		displayGoogleMap();
	});
});
