{% extends 'internal/base.html' %}

{% set title = _("Live Map") %}
{% set sticky_banners = g.is_kiosk %}
{% set localized = true %}

{% block head %}
	{{- super() }}
	<style>
		#map-canvas, #map-canvas > div { border-radius: 0.25rem; }
	</style>
{% endblock head %}

{% block content %}
	<!--
	<div class="row">
		<div class="col text-center">
			<h2 class="text-center text-foli content-spaced-lg text-shadow">{{ _("Live Bus Traffic Nearby") }}</h2>
		</div>
	</div>
	-->

	<!-- Show next buses?? -->
	<div class="card box-shadow border-foli content-spaced-lg">
		<div class="list-group list-group-flush">
			<div class="list-group-item list-group-item-foli">
				<div class="row">
					<span class="col-8"><strong>{{ _("Line") }} / {{ _("Destination") }}</strong></span>
					<span class="col-2 text-center"><strong>{{ _("Time") }}</strong></span>
					<span class="col-2 text-center"><strong>{{ _("ETA") }}</strong></span>
				</div>
			</div>

			{% for bus in arrivals %}
			<div class="list-group-item list-group-item-action">
				<a class="row link-unstyled" href="#">
					<span class="col-8 text-foli">{{ util.line_name(bus) }}</span>
					<span class="col-2 text-center">{{ util.time_short(bus.time) }}</span>
					<span class="col-2 text-center text-success">{{ bus.time_relative | formatseconds }}</span>
				</a>
			</div>
			{% endfor %}
		</div>
	</div>

	<!-- draw the map -->
	<div class="card border-foli box-shadow">
		<div class="card-body p-0">
			
			<div class="embed-responsive embed-responsive-{% if not g.is_kiosk %}16by9{% else %}1by1{% endif %}">
				<!-- include the map in this div -->
				<div id="map-canvas"></div>
			</div>
		</div>
	</div>

{% endblock content %}

{% block scripts %}
	{{- super() }}
	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.min.js"></script>
	<script src="https://maps.googleapis.com/maps/api/js?key={{ gmaps_key }}&amp;region={{ gmaps_region }}&amp;language={{ g.lang_code }}"></script>
	<!-- this is used to animate the movement of the buses on the map -->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/marker-animate-unobtrusive/0.2.8/vendor/markerAnimate.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/marker-animate-unobtrusive/0.2.8/SlidingMarker.min.js"></script>

	<script>
		var gmarkers, gmap = false;

		// focusedMarker is the title of the focused marker
		var focusedMarker = undefined;
		var focusedBus = undefined;
		var focusedShape = undefined;
		var focusedBusWindow = undefined;
		var apiEndpoint = "{{ url_for('apiLocatorService', version = 1, stopId = stop_info.stop_id, type = 'nearby', _external = True) }}";
		var trackingLoop = null;
		var currentMode = null;
		var busStop = {{ stop_info|tojson|safe }};
		var mapZoom = 16;

		var positionToGoogleLatLng = function(lat, lon) {
			return new google.maps.LatLng(lat, lon);
		};

		var drawMap = function(busStop, $canvas) {
			return new google.maps.Map($canvas.get(0), {
				center: positionToGoogleLatLng(busStop.stop_lat, busStop.stop_lon),
				zoom: mapZoom,
				gestureHandling: 'none',
				disableDefaultUI: true,
				clickableIcons: false,
				keyboardShortcuts: false,
				scaleControl: true,
				styles: [
					{
						featureType: 'transit.station.bus',
						stylers: [{ visibility: 'off' }]
					}
				]
			});
		};

		var drawBusStop = function(map, lat, lon, stopName, stopId) {
			return new google.maps.Marker({
				map: map,
				position: positionToGoogleLatLng(lat, lon),
				icon: {
					path: 'm 21.994938,16.091855 c 0,1.773648 -1.645131,3.224815 -3.655849,3.224815 H 12.931034 L 10.953347,21.953587 9.0770791,19.31667 H 3.7156949 c -2.0107168,0 -3.6558486,-1.451167 -3.6558486,-3.224815 V 3.1925996 c 0,-1.7736481 1.6451318,-3.22481421 3.6558486,-3.22481421 H 18.339089 c 2.010718,0 3.655849,1.45116611 3.655849,3.22481421 z',
					anchor: new google.maps.Point(11, 22),
					labelOrigin: new google.maps.Point(11, 10),
					strokeWeight: 1.5,
					strokeColor: '#ffffff',
					fillColor: '#00abed',
					fillOpacity: 1,
					scale: 1.5,
				},
				title: stopName,
				label: { text: stopId, color: '#ffffff', fontSize: '0.75rem' },
				zIndex: -1
			});
		};

		var drawBus = function(map, lat, lon, busName, id) {
			var marker = new SlidingMarker({
				map: map,
				position: positionToGoogleLatLng(lat, lon),
				icon: {
					path: google.maps.SymbolPath.CIRCLE,
					scale: 15,
					strokeWeight: 2,
					fillColor: '#f7aa00',
					fillOpacity: 0.8
				},
				title: id,
				label: busName,
				duration: 3000,
				easing: 'linear'
			});
			google.maps.event.addListener(marker, 'click', function() { markerClicked(marker) });
			return marker;
		};

		var stopTrackingLoop = function() {
			if (trackingLoop !== null) {
				clearInterval(trackingLoop);
				trackingLoop = null;
			}
		};

		// this function will determine what to draw on the map every 3 seconds
		var busTrackingLoop = function(mode, pollTime = 3000) {
			if (trackingLoop !== null) {
				console.log('redundant call to busTrackingLoop, already active!');
				return;
			}

			currentMode = mode;
			trackingLoop = setInterval(function () {
				if (currentMode === 'all') {
					drawAllBuses();
				} else if (currentMode === 'one') {
					drawOneBus();
				} else {
					console.log('mode set to unknown mode: ' + currentMode);
				}
			}, pollTime);
		};

		var markerClicked = function(marker) {
			if (focusedMarker !== undefined) {
				if (focusedMarker === marker.title) {
					console.log('stopped from double click');
					return;
				}
				if (focusedShape !== undefined) {
					focusedShape.setMap(null);
					focusedShape = undefined;
				}
			}

			focusedMarker = marker.title;
			initOneBusTracking();
		}

		var mapClicked = function() {
			if (focusedMarker !== undefined) {
				gmap.setZoom(mapZoom);
				gmap.panTo(positionToGoogleLatLng(busStop.stop_lat, busStop.stop_lon));

				initAllBusesTracking();
			}
		};

		// this function draws all the buses on the map for the first time
		var initAllBusesTracking = function() {
			stopTrackingLoop();

			if (focusedMarker !== undefined) {
				marker = gmarkers[focusedMarker]
				marker.setMap(null);
				focusedMarker = undefined;
				focusedBus = undefined;
				if (focusedShape !== undefined) {
					focusedShape.setMap(null);
					focusedShape = undefined;
				}
			}

			markers = {};
			$.getJSON(apiEndpoint,
				function (data) {
					console.log('found this many buses: ' + Object.keys(data).length);
					$.each( data, function( key, value ) {
						var tmpMarker = drawBus(gmap, value.latitude, value.longitude, value.publishedlinename, key);
						markers[key] = tmpMarker;
					});

					console.log('data: ', data);
					gmarkers = markers;

					busTrackingLoop("all");
				}
			);
		};

		var drawAllBuses = function() {
			$.getJSON(apiEndpoint,
				function (data) {
					// poor man's locking
					if (trackingLoop === null)
						return;

					// temporarily move all markers to a temp list
					// one by one all active markers will be moved back to the markers list
					// in the end all the markers in oldMarkers will be inactive (= need to remove those from the map)
					var oldMarkers = gmarkers;
					gmarkers = {};
					$.each( data, function( key, value ) {
						// get the marker for this vehicle
						var marker = oldMarkers[key];
						// if this is a new bus that wasn't there last refresh
						if (marker === undefined) {
							gmarkers[key] = drawBus(gmap, value.latitude, value.longitude, value.publishedlinename, key);
						} else {
							// getting here means that this marker is still active
							// => move the marker to the new list
							gmarkers[key] = oldMarkers[key];
							delete(oldMarkers[key]);
							marker.setPosition(positionToGoogleLatLng(value.latitude, value.longitude));
						}
					});

					// then in the end remove all the inactive markers from the map
					$.each( oldMarkers, function( key, value ) {
						if (value !== undefined) {
							value.setMap(null);
						}
					});
				}
			)
		};

		var initOneBusTracking = function() {
			stopTrackingLoop();

			// hide all the other markers but the clicked one
			console.log('gmarkers ', gmarkers);
			$.each(gmarkers, function (key, value) {
				if (key !== focusedMarker) {
					value.setMap(null);
				}
			});

			// get information about the focused bus
			var requestFocus = focusedMarker;
			$.getJSON(
				"{{ url_for('apiBusInfo', version = 1, _external = True) }}" + focusedMarker + '/true',
				function (data) {
					// poor man's locking (the A in Ajax is for Asynchronous :))
					if (requestFocus !== focusedMarker)
						return;

					focusedBus = data;
					console.log("found this bus info: ", focusedBus);

					// draw the shape
					var shapeCoordinates = [];
					$.each(focusedBus.shapes, function (key, value) {
						value.map( value => {
							shapeCoordinates.push(positionToGoogleLatLng(value[0], value[1]));
						});
					});

					focusedShape = new google.maps.Polyline({
						map: gmap,
						path: shapeCoordinates,
						strokeColor: "#FF0000",
						strokeOpacity: 1.0,
						strokeWeight: 2
					});
					updateInfoWindow();
				}
			);

			marker = gmarkers[focusedMarker];
			gmarkers = {};
			gmarkers[focusedMarker] = marker;

			gmap.panTo(marker.getPosition());
			gmap.setZoom(mapZoom + 1);

			busTrackingLoop("one");
		};

		var drawOneBus = function() {
			$.getJSON(
				"{{ url_for('apiBusInfo', version = 1, _external = True) }}" + focusedMarker + '/false',
				function (resultData) {
					// poor man's locking
					if (trackingLoop === null)
						return;

					// if the focused bus disappeared from the list, just go back to the 'all' mode
					if ($.isEmptyObject(resultData) || gmarkers[focusedMarker] === undefined) {
						console.log('lost track of the bus, going back to normal mode');
						mapClicked();
					} else {
						// getting here means that the bus is still active
						// => update its position
						marker = gmarkers[focusedMarker];
						focusedBus = resultData;

						updateInfoWindow();
						// get more information about the bus
						position = positionToGoogleLatLng(resultData.latitude, resultData.longitude);
						marker.setPosition(position);
						gmap.panTo(position);
					}
				}
			)
		};

		// creates or updates the info window for focused bus
		var updateInfoWindow = function() {
			// TODO is there a better way of doing this, this way is pretty ugly
			var infoWindowContent = `
			<h1>` + focusedBus.lineref + `</h1>
			Next Stop: ` + focusedBus.next_stoppointname + ` <br>
			Aimed Arrival: ` + focusedBus.next_aimedarrivaltime + ` <br>
			Expected Arrival: ` + focusedBus.next_expectedarrivaltime + ` <br>
			`;

			if (focusedBusWindow === undefined) {
				focusedBusWindow = new google.maps.InfoWindow({
					content: infoWindowContent
				});
				focusedBusWindow.open(gmap, gmarkers[focusedMarker]);
			} else {
				focusedBusWindow.setContent(infoWindowContent);
			}
		}

		$(document).ready(function() {
			console.log(busStop);

			console.log("hello world");

			// this draws an initial map that is zoomed and centered on the bus stop
			// this map is used then to start drawing buses dynamically on it
			gmap = drawMap(busStop, $('#map-canvas'));
			google.maps.event.addListener(gmap, 'click', function() { mapClicked() });

			drawBusStop(gmap, busStop.stop_lat, busStop.stop_lon, busStop.stop_name, busStop.stop_id);

			// start bus tracking loop
			initAllBusesTracking();

			// this may or may not violate Google Maps ToS (10.1.1, 9.4), but frankly not allowing users to break out
			// of the application on public displays is more important (and its not like we are removing attribution)
			google.maps.event.addListenerOnce(gmap, 'tilesloaded', function() { $('#map-canvas').disableExternalLinks(); })
		});
	</script>
{% endblock scripts %}
