maphub = function() {
	return {
		init : function() {
			maphub.initMap();
			maphub.initViewToggle();
			maphub.initResultsAndPagination();
			maphub.initSearchForm();
		},
		
		initMap : function() {
			if (GBrowserIsCompatible()) {
				maphub.map = {};
				maphub.map.map = new GMap2(document.getElementById('map'));
				maphub.map.map.addControl(new GSmallMapControl());
				maphub.map.map.addControl(new GMapTypeControl());
				maphub.map.map.setCenter(new GLatLng(40.441590790335276, -80.01153945922852), 14);
				maphub.map.markerMgr = new MarkerManager(maphub.map.map, {trackMarkers:true});
				maphub.map.geocoder = new GClientGeocoder();
				
				maphub.map.mapIcon = new GIcon(G_DEFAULT_ICON);
				maphub.map.mapIcon.image = "images/blank.png";
				maphub.map.mapIcon.iconSize = new GSize(24,24);
				maphub.map.mapIcon.shadowSize = new GSize(37,34);
				maphub.map.mapIcon.iconAnchor = new GPoint(2,23);
				maphub.map.mapIcon.infoWindowAnchor = new GPoint(15, 6);
				
				// Define some categories manually
				
				var icons = {
					4113 : { 'name' : 'Trail Access', 'image' : 'http://bike.dev.deeplocal.com/im/trailhead.png', 'iconSize' : new GSize(30, 33) },
					4112 : { 'name' : 'Bike Shops', 'image' : 'http://bike.dev.deeplocal.com/im/bikeshop.png', 'iconSize' : new GSize(30, 33) },
					4115 : { 'name' : 'Landmarks', 'image' : 'http://bike.dev.deeplocal.com/im/businessdistrict.png', 'iconSize' : new GSize(30, 33) },
					4116 : { 'name' : 'Notes', 'image' : 'http://bike.dev.deeplocal.com/im/note.png', 'iconSize' : new GSize(30, 33) },
					4180 : { 'name' : 'Bridges', 'image' : 'http://bike.dev.deeplocal.com/im/bridge.png', 'iconSize' : new GSize(30, 33) },
					4114 : { 'name' : 'Bicycle Crashes', 'image' : 'http://bike.dev.deeplocal.com/im/mapIcons0005.png', 'iconSize' : new GSize(30, 33) }
				};
				
				maphub.map.icons = {};
				for (var id in icons) {
					if (typeof icons[id] != 'funciton') {
						maphub.map.icons[id] = new GIcon(G_DEFAULT_ICON);
						maphub.map.icons[id].image = icons[id].image;
						maphub.map.icons[id].iconSize = icons[id].iconSize;
						maphub.map.icons[id].shadowSize = new GSize(37,34);
						maphub.map.icons[id].iconAnchor = new GPoint(2,23);
						maphub.map.icons[id].infoWindowAnchor = new GPoint(15, 6);
					}
				}
			}
		},
		
		initCrashes : function() {
			maphub.catIds = [];
			var selected = $('#menu li.active');
			for (var i=0; i<selected.length; i++) {
				maphub.catIds[maphub.catIds.length] = selected[i].id.replace('category_', '');
			}
			
			maphub.getData();
		},
		
		initSearchForm : function() {
			$('#frmSearch input[name=searchInput]').data('title', $('#frmSearch input[name=searchInput]').attr('title')).val($('#frmSearch input[name=searchInput]').val() === '' ? $('#frmSearch input[name=searchInput]').attr('title') : $('#frmSearch input[name=searchInput]').val()).addClass('disabled').focus(function(e) {
				if ($(this).val() == $('#frmSearch input[name=searchInput]').attr('title')) {
					$(this).val('').removeClass('disabled');
				}
			}).blur(function(e) {
				if ($(this).val() === '') {
					$(this).val($('#frmSearch input[name=searchInput]').attr('title')).addClass('disabled');
				}
			});
			
			$('#frmSearch').submit(function(e) {
				e.preventDefault();
				if ($('#frmSearch input[name=searchInput]').val() === '' || $('#frmSearch input[name=searchInput]').val() == $('#frmSearch input[name=searchInput]').data('title')) {
					$('#frmSearch input[name=searchInput]').focus();
					return;
				}
				maphub.search = $('#frmSearch input[name=searchInput]').val();
				maphub.page = 0;
				maphub.getData();
			});
			
			// Init clearing of search
			
			$('#results .filter div:first p a').live('click', function(e) {
				if ($(e.target).hasClass('toggle')) {
					return;
				}
				e.preventDefault();
				maphub.search = null;
				$('#frmSearch input[name=searchInput]').val($('#frmSearch input[name=searchInput]').data('title')).addClass('disabled');
				maphub.page = 0;
				maphub.getData();
			});
		},
		
		initMenu : function() {
			for (var i=0; i<maphub.catIds.length; i++) {
				$('#category_' + maphub.catIds[i]).addClass('active');
			}
			for (i=0; i<maphub.kmlIds.length; i++) {
				$('#kml_' + maphub.kmlIds[i]).addClass('active');
			}

			$('#categories li a').click(maphub.processMenuClick);
			$('#kml li a').click(maphub.processKMLClick);
			
			if (maphub.catIds.length > 0) {
				maphub.getData();
			}
			
			if (maphub.kmlIds.length > 0) {
				maphub.processKMLClick();
			}
			
			// Neighborhood jump
			
			$('#neighborhoods').change(function(e) {
				var id = $(this).val().replace('neighborhood_', '') * 1;
				var neigh_data = maphub.neighborhoods[id];
				maphub.map.map.setCenter(new GLatLng(neigh_data[2], neigh_data[1]), 14);
				$(this).blur();
			});
		},

		initViewToggle : function() {
			$('#sub-content .toggler').click(maphub.toggleView);
		},
		
		toggleView : function() {
			if ($('#menu').css('opacity') < 1) {
			
				// Show menu

				$('#map').stop().animate({
					'opacity' : 0
				}, 250, function() {
					$('#map').removeClass('expanded');
				
					$('#sub-content').stop().animate({
						'width' : '722px'
					}, 250);
					$('#menu').stop().animate({
						'width' : '220px'
					}, 250, function() {
						$('#menu, #map').animate({
							'opacity' : 1
						}, 333);
						
						$('#sub-content .toggler').html('&laquo;');
						
						$('#results li table td.item').removeClass('item-extended');
					});
				});

			} else {
			
				// Hide menu

				$('#menu, #map').stop().animate({
					'opacity' : 0
				}, 333, function() {
					$('#menu').animate({
						'width' : '0px'
					}, 250);
					$('#sub-content').animate({
						'width' : '942px'
					}, 250, function() {
						$('#map').addClass('expanded');
						$('#map').stop().animate({
							'opacity' : 1
						}, 333);
						
						$('#sub-content .toggler').html('&raquo;');
						
						$('#results li table td.item').addClass('item-extended');
					});
				});

			}
		},
		
		processMenuClick : function(e) {
			if (e) {
				e.preventDefault();
				this.blur();
				
				if ($(this.parentNode).hasClass('disabled')) {
					return;
				}

				if ($(this.parentNode).hasClass('active')) {
					$(this.parentNode).removeClass('active');
				} else {
					$(this.parentNode).addClass('active');
				}
			}
			
			maphub.search = null;
			
			maphub.catIds = [];
			var selected = $('#categories li.active');
			for (var i=0; i<selected.length; i++) {
				maphub.catIds[maphub.catIds.length] = selected[i].id.replace('category_', '');
			}
			
			maphub.map.markerMgr.clearMarkers();
			
			maphub.page = 0;
			maphub.getData();
		},
		
		processKMLClick : function(e) {
			if (e) {
				e.preventDefault();
				this.blur();
				
				if ($(this.parentNode).hasClass('disabled')) {
					return;
				}

				if ($(this.parentNode).hasClass('active')) {
					$(this.parentNode).removeClass('active');
				} else {
					$(this.parentNode).addClass('active');
				}
			}
			
			maphub.kmlIds = [];
			
			// Get all the KML ids
			
			var selected = $('#kml li.active');
			for (var i=0; i<selected.length; i++) {
				maphub.kmlIds[maphub.kmlIds.length] = selected[i].id.replace('kml_', '') * 1;
			}
			
			// Clear the map
			
			maphub.map.map.clearOverlays();
			
			// Show KMLs on the map
			
			for (i=0; i<maphub.kmlIds.length; i++) {
				if (typeof(maphub.kmlData[maphub.kmlIds[i]]) != 'undefined') {
					
					// See if KML obj is already created
					
					if (typeof(maphub.kmlData[maphub.kmlIds[i]].obj) == 'undefined') {
						maphub.kmlData[maphub.kmlIds[i]].obj = new GGeoXml(maphub.baseUrl + '/kml/' + maphub.kmlData[maphub.kmlIds[i]].filename);
					}
					
					// Add to the map

					maphub.map.map.addOverlay(maphub.kmlData[maphub.kmlIds[i]].obj);
					
				}
			}
			
			// Refresh the map
			
			maphub.map.markerMgr.refresh();
			
			// Set hash
			
			maphub.setLocationHash();
		},

		initResultsAndPagination : function() {
			// Sort by
			$('#frmSortBy').change(function() {
				maphub.sort = $(this).val().split('-');
				maphub.page = 0;
				maphub.getData();
			});
			
			// Pagination
			$('#pagination2').click(function(e) {
				if (e.target.tagName != "A") {
					return;
				}
				
				e.preventDefault();
				
				if ($(e.target).hasClass('previous')) {
					maphub.page--;
				} else if ($(e.target).hasClass('next')) {
					maphub.page++;
				} else {
					maphub.page = $(e.target).text() - 1;
				}
				
				// Set hash

				maphub.setLocationHash();

				// Render
				
				maphub.render();
			});
			
			//Show all/Paginated
			$('#results .filter div:first p a.toggle').live('click', function(e) {
				e.preventDefault();
				
				if ($(this).text() == 'show all') {
					maphub.showAll = true;
				} else {
					maphub.showAll = false;
				}
				
				maphub.render();
				maphub.setLocationHash();
			});
		},
		
		getData : function() {
			// Set hash
			
			maphub.setLocationHash();
			
			var url = maphub.baseUrl + '/api/items.php';
			
			// Validation
			
			if (maphub.catIds.length === 0) {
				return false;
			}
			
			var params = {
				'c' : 'get',
				'cat' : maphub.catIds.join('|'),
				'sortBy' : maphub.sort[0],
				'sortDir' : maphub.sort[1]
			};
			
			if (maphub.search !== null && maphub.search !== '') {
				params.search = maphub.search;
			}
			
			// Hide/show divs
			
			$('#results').css('display', 'none');
			$('#loading').css('display', 'block');
			
			if (maphub.connObj) {
				maphub.connObj.abort();
			}
			
			maphub.connObj = $.getJSON(url, params, function(data) {
				maphub.data = data;
				maphub.render();
			});
		},
		
		render : function() {
		
			// Hide/show divs

			$('#loading').css('display', 'none');			
			$('#results').css('display', 'block');
		
			$('#results .results, #pagination2').empty();
			
			if (maphub.data.length === 0) {
				if (maphub.search) {
					$('#results .filter div:first p').html('No results found.<br/>Please, <a href="#">clear your search</a>.');
				} else {
					$('#results .filter div:first p').html('No results found.<br/>Please, revise your search.');
				}
				$('#results .filter div.second').css('display', 'none');
				return;
			}
			
			$('#results .filter div.second').css('display', 'block');
			$('#results .filter div:first p').html('<strong>' + maphub.data.length + ' ' + (maphub.data.length == 1 ? 'result' : 'results') + '</strong> found (<a class="toggle" href="#">' + (maphub.showAll === true ? 'show in pages' : 'show all') + '</a>):');
			
			maphub.renderPagination();
			
			var min, max;
			if (maphub.showAll === false) {
				min = maphub.page * 10;
				max = Math.min(min + 9, maphub.data.length - 1);
			} else {
				min = 0;
				max = maphub.data.length - 1;
			}
			
			maphub.map.markerMgr.clearMarkers();
			
			var bounds = new GLatLngBounds();
			var point, listItem, table;
			
			for (var i=min; i<=max; i++) {
				
				// Add to the list
				
				table = $('<table/>');
				table.append($('<tr/>').append(
					$('<td/>').addClass('num').html((i+1) + '.')
				).append(
					$('<td/>').addClass('category').html(maphub.getCategoryName(maphub.data[i].categoryId))
				).append(
					$('<td/>').addClass('item').html(maphub.data[i].name)
				).append(
					$('<td/>').addClass('date').html('added ' + maphub.getPrettyDate(maphub.data[i].created))
				));
				
				listItem = $('<li id="entity_' + maphub.data[i].id + '" />').addClass('clearfix').append(table);
				$('#results .results').append(listItem);
				
				// Add to the map

				point = maphub.addMapPoint(maphub.data[i], listItem);
				bounds.extend(point);
			}
			
			// Show the markers, re-center and zoom out enough to show them all

			maphub.map.markerMgr.refresh();
			maphub.map.map.setZoom(maphub.map.map.getBoundsZoomLevel(bounds));
			maphub.map.map.setCenter(bounds.getCenter());
		},
		
		addMapPoint : function(entity, placeBit) {
			var place = entity.place;
			var point = new GLatLng(place.latitude, place.longitude);
			var icon = maphub.map.mapIcon;
			if (typeof maphub.map.icons[entity.categoryId] != 'undefined') {
				icon = maphub.map.icons[entity.categoryId];
			}

			var marker = new GMarker(point, { title : place.name, icon : icon, draggable : false });
			
			GEvent.addListener(marker, "click", function() {
				marker.openInfoWindow(maphub.getInfoContent(entity));
				maphub.lastMarker = marker;
				placeBit.css('background', '#ccc').animate({ backgroundColor : '#f2f2f2' }, 1000);
			});
			
			placeBit.click(function(event) {
				// var el = event.target;
				// if (el.tagName != "LI") {
				// 	el = $(el).parents('li').get(0);
				// }
				
				marker.openInfoWindow(maphub.getInfoContent(entity));
				maphub.lastMarker = marker;
				
				$.scrollTo(0, 333);
			});
			
			maphub.map.markerMgr.addMarker(marker, 3);
			
			return point;
		},
		
		getAddress : function(place) {
			var add = "";
			
			if (typeof place.address1 != "undefined" && place.address1 !== "") {
				add = place.address1;
			}
			
			if (typeof place.address2 != "undefined" && place.address2 !== "") {
				add = add + ', ' + place.address2;
			}
			
			if (typeof place.city != "undefined" && place.city !== "") {
				add = add + ', ' + place.city;
			}
			
			if (typeof place.state != "undefined" && place.state !== "") {
				if (typeof place.city != "undefined" && place.city !== "") {
					add = add + ' ' + place.state;
				} else {
					add = add + ', ' + place.state;
				}
			}
			
			if (typeof place.zip != "undefined" && place.zip !== "") {
				add = add + ', ' + place.zip;
			}
			
			return add;
		},
		
		getInfoContent : function(entity) {
			var place = entity.place;
			var p = $('<p/>').attr({'class':'note'}).append('<a href="details.php?entId=' + entity.id + '&' + maphub.getURLVars() + '">Details</a> | ').append($('<a/>').attr({'href':'#'}).text('Zoom to me').click(function(event) {
				event.preventDefault();
				maphub.lastMarker.closeInfoWindow();
				var bounds = new GLatLngBounds();
				bounds.extend(maphub.lastMarker.getLatLng());
				maphub.map.map.setZoom(17);
				maphub.map.map.setCenter(bounds.getCenter());
			}));
			
			return $('<div/>').append(p).append('<p class="desc"><strong>' + entity.name + '</strong><br/><small>' + maphub.getShortDescription(entity.description) + '</small></p>').get(0);
		},
		
		getCategoryName : function(catId) {
			for (var i=0; i<maphub.categories.length; i++) {
				if (maphub.categories[i].id == catId) {
					return maphub.categories[i].name;
				}
			}
			
			return 'Unknown';
		},
		
		renderPagination : function() {
			
			if (maphub.showAll === true) {
				$('#pagination2').html('&nbsp;');
				return;
			}
			
			var parts = [];
			var totalPages = Math.ceil(maphub.data.length / 10);
			
			if (maphub.page === 0) {
				parts[parts.length] = '<span>Previous</span>';
			} else {
				parts[parts.length] = '<a href="#" class="previous">Previous</a>';
			}

			var i, pages = [];
			if (totalPages <= 6) { // Ex: 1, 2, 3, 4, 5
				for (i=1; i<=totalPages; i++) {
					pages[pages.length] = i;
				}
			} else if (totalPages > 6 && (maphub.page <= 2 || maphub.page >= (totalPages - 3))) { // Ex: 1, 2, 3, ... 70, 71, 72
				pages[pages.length] = 1;
				pages[pages.length] = 2;
				pages[pages.length] = 3;
				pages[pages.length] = "sep";
				pages[pages.length] = totalPages - 2;
				pages[pages.length] = totalPages - 1;
				pages[pages.length] = totalPages;
			} else { // Ex: 1, ... 13, 14, 15, ... 72
				pages[pages.length] = 1;
				pages[pages.length] = "sep";
				pages[pages.length] = maphub.page;
				pages[pages.length] = maphub.page + 1;
				pages[pages.length] = maphub.page + 2;
				pages[pages.length] = "sep";
				pages[pages.length] = totalPages;
			}

			for (i=0; i<pages.length; i++) {
				if (pages[i] == "sep") {
					parts[parts.length] = '<span>...</span>';
				} else {
					if (pages[i] - 1 == maphub.page) {
						parts[parts.length] = '<span>' + pages[i] + '</span>';
					} else {
						parts[parts.length] = '<a href="#">' + pages[i] + '</a>';
					}
				}
			}
			
			if (maphub.page == (totalPages - 1)) {
				parts[parts.length] = '<span>Next</span>';
			} else {
				parts[parts.length] = '<a href="#" class="next">Next</a>';
			}
			
			$('#pagination2').html(parts.join(''));
		},
		
		getURLVars : function() {
			var vars = [];
			vars[vars.length] = 'c=' + maphub.catIds.join(',');
			if (maphub.search !== null) {
				vars[vars.length] = 's=' + maphub.search;
			}
			vars[vars.length] = 'sb=' + maphub.sort.join(',');
			vars[vars.length] = 'p=' + (maphub.showAll === true ? 'all' : maphub.page);
			vars[vars.length] = 't=' + maphub.pageType;
			vars[vars.length] = 'k=' + maphub.kmlIds.join(',');
			return vars.join('&');
		},
		
		setLocationHash : function() {
			var vars = [];
			vars[vars.length] = 'c=' + maphub.catIds.join(',');
			if (maphub.search !== null) {
				vars[vars.length] = 's=' + maphub.search;
			}
			vars[vars.length] = 'sb=' + maphub.sort.join(',');
			vars[vars.length] = 'p=' + (maphub.showAll === true ? 'all' : maphub.page);
			vars[vars.length] = 'k=' + maphub.kmlIds.join(',');
			vars = vars.join(';');
			window.location.hash = vars;
		},
		
		loadHashData : function() {
			var hash = window.location.hash;
			if (hash[0] == '#') {
				hash = hash.substr(1, hash.length - 1);
			}
			hash = hash.split(';');
			
			var bits,key,val,o;
			for (var i=0; i<hash.length; i++) {
				bits = hash[i].split('=');
				key = bits[0];
				val = bits[1];
				
				switch (key) {
					case 'c':
						if (val === '') {
							break;
						}
						maphub.catIds = val.split(',');
						for (o=0; o<maphub.catIds.length; o++) {
							maphub.catIds[o] = maphub.catIds[o] * 1;
						}
						break;
					case 's':
						maphub.search = val;
						$('#frmSearch input[name=searchInput]').val(val);
						break;
					case 'sb':
						maphub.sort = val.split(',');
						$('#frmSortBy').val(maphub.sort.join('-'));
						break;
					case 'p':
						if (val == 'all') {
							maphub.page = 0;
							maphub.showAll = true;
						} else {
							maphub.page = val * 1;
						}
						break;
					case 'k':
						if (val === '') {
							break;
						}
						maphub.kmlIds = val.split(',');
						for (o=0; o<maphub.kmlIds.length; o++) {
							maphub.kmlIds[o] = maphub.kmlIds[o] * 1;
						}
						break;
				}
			}
			
			maphub.initMenu();
		},
		
		getPrettyDate : function(dbDate) {
			var date;
			try {
				date = new Date(dbDate);
			} catch(e) {
				return dbDate;
			}
			
			return (date.getMonth()+1) + '/' + date.getDate() + '/' + date.getFullYear();
		},
		
		getShortDescription : function(desc) {
			if (desc.length > 65) {
				return desc.substr(0, 62) + '...';
			}
			
			return desc;
		},
		
		// Vars
		
		baseUrl : null,
		map : null,
		catIds : [],
		categories : null,
		kmlIds : [],
		kmlData : null,
		connObj : null,
		data : [],
		page : 0,
		sort : ['created', 'desc'],
		search : null,
		pageType : 'index',
		showAll : false
	};
}();