;(function ( window, document, $, undefined ) {

	var map, service, list;
	var markers = [];
	var center = { lat: 45.523452, lng: -122.676207 };
	var infowindow = new google.maps.InfoWindow();

	// search terms to use for place type selections
	var types = {
		entertainment  : [ 'amusement_park', 'aquarium', 'art_gallery', 'bowling_alley', 'casino', 'gym', 'library', 'movie_theater', 'museum', 'night_club', 'zoo' ],
		government     : [ 'city_hall', 'courthouse', 'embassy', 'fire_station', 'local_government_office', 'police', 'post_office' ],
		hospital       : [ 'hospital', 'veterinary_care' ],
		restaurant     : [ 'bakery', 'bar', 'cafe', 'food', 'restaurant' ],
		school         : [ 'school', 'university' ],
		shopping       : [ 'bicycle_store', 'book_store', 'clothing_store', 'convenience_store', 'department_store', 'electronics_store', 'florist', 'furniture_store', 'grocery_or_supermarket', 'hardware_store', 'home_goods_store', 'jewelry_store', 'liquor_store', 'pet_store', 'shoe_store', 'shopping_mall', 'store' ],
		transportation : [ 'bus_station', 'subway_station', 'taxi_stand', 'train_station' ],
		venue          : [ 'ChIJvfIK2VKnlVQRp8nAsCikTaw', 'ChIJz39MDlOnlVQRAlGuv4fc780', 'ChIJ2SA5mB0KlVQRzsWcWLxhxP8' ]
	};

	// simple templates https://gist.github.com/segdeha/b73384e01c48c002c1bd
	function Template(str) {
		this.rgx = /{{([^{}]*)}}/g
		this.str = str || ''
	}

	Template.prototype.evaluate = function (vals) {
		vals = vals || {}
		function repr(str, match) {
			return 'string' === typeof vals[match] || 'number' === typeof vals[match] ? vals[match] : str
		}
		return this.str.replace(this.rgx, repr)
	}

	var tmpls = {
		infowindow : new Template('<div><strong>{{name}}</strong><br>{{addr}}<br>Mobility Rating: {{rating}}<br><a href="../venue/moda-center/?TIMESTAMP">Place Details</a></div>'),
		listitem : new Template('<li>{{name}}</li>')
	};

	function search(query) {
		if ('venue' === query) {
			// fudge the results by searching directly for a few IDs
			types.venue.forEach(function (id) {
				service.getDetails({
					placeId: id
				}, handleSearchResults);
			});
		}
		else {
			service.nearbySearch({
				location: center,
				radius: 1000,
				types: types[query]
			}, handleSearchResults);
		}
	}

	function handleSearchResults(results, status) {
		if (status === google.maps.places.PlacesServiceStatus.OK) {
			if (undefined === results.length) {
				results = [results];
			}
			for (var i = 0; i < results.length; i++) {
				createMarker(results[i]);
			}
			handleRatingChange();
		}
	}

	function generateRating(name) {
		// venues are special cases because they're being highlighted in the demo
		var rating;
		switch (name) {
			case 'Moda Center':
				rating = '★★★★';
			break;

			case 'Providence Park':
				rating = '★★★';
			break;

			case 'Veterans Memorial Coliseum':
				rating = '★★';
			break;

			default:
				rating = '★★★★'.slice(0, Math.floor(Math.random() * 4) + 1);
			break;
		}
		return rating;
	}

	function filterMapByRating(minrating) {
		for (var i = 0; i < markers.length; i += 1) {
			if (markers[i]._place._rating.length >= minrating) {
				markers[i].setMap(map);
			}
			else {
				markers[i].setMap(null);
			}
		}
		generateList();
	}

	function clearMarkers() {
		for (var i = 0; i < markers.length; i += 1) {
			markers[i].setMap(null);
		}
		markers = [];
	}

	function createMarker(place) {
		place._rating = generateRating(place.name);

		var marker = new google.maps.Marker({
			map: map,
			position: place.geometry.location
		});

		marker._place = place;

		google.maps.event.addListener(marker, 'click', function() {
			var html = tmpls.infowindow.evaluate({
				name : place.name,
				addr : place.formatted_address || place.vicinity,
				rating : place._rating
			});
			infowindow.setContent(html);
			infowindow.open(map, this);
		});

		markers.push(marker);
		generateList();
	}

	function clearList() {
		list.innerHTML = '';
	}

	function generateList() {
		var minrating = $('[name=rating]').val();
		clearList();
		for (var i = 0; i < markers.length; i += 1) {
			if (markers[i]._place._rating.length >= minrating) {
				addPlaceToList(markers[i]._place);
			}
		}
	}

	function addPlaceToList(place) {
		var html = tmpls.listitem.evaluate({
			name : place.name
		});
		list.insertAdjacentHTML('beforeend', html);
	}

	function handlePlaceTypeChange() {
		var query = $('[name=place-type]').val();
		clearMarkers();
		clearList();
		if ('' !== query) {
			search(query);
		}
	}

	function handleRatingChange() {
		var minrating = $('[name=rating]').val();
		filterMapByRating(minrating);
	}

	function addEventListeners() {
		$('[name=place-type]').change(handlePlaceTypeChange);
		$('[name=rating]').change(handleRatingChange);
	}

	function initMap() {
		list = document.getElementById('map-list');
		prompt = document.getElementById('map-list-prompt');
		map = new google.maps.Map(document.getElementById('map'), {
			zoom: 14,
			center: center
		});
		service = new google.maps.places.PlacesService(map);
		addEventListeners();
	}

	// create the map once the DOM is ready
	$(initMap);

}).call( this, this, this.document, jQuery );
