/**
 * @type {string}
 */
var trainNumber
/**
 * @type {string | null}
 */
var tripId = null
/**
 * @type {Date}
 */
var date
var groupIndex = null
/**
 * @type {string | null}
 */
var startId = null
/**
 * @type {string | null}
 */
var stopId = null

var yesterday = false
var showKm = false

var trainData = null
/**
 * @type {?Date}
 */
var lastSuccessfulFetch = null

var loadMap = false
/**
 * @type {any}
 */
var leafletMap = null
/**
 * @type {any[]}
 */
var mapLayers = []

/**
 * @param {DbTrip & DbArrDep} data
 * @param {?Date} fetchDate
 */
function onTrainData(data, fetchDate) {
	if (loadMap) {
		document.getElementById('load-map-button').remove()
	}

	if (window.localStorage) {
		localStorage.setItem('recent/view-train', JSON.stringify({
			trainNumber: data.line.fahrtNr,
			name: data.line.name,
			tripId: data.id,
			date: date ? date.toISOString() : undefined,
			$addDate: new Date().toISOString(),
		}))
	}
	var title = document.getElementById('title')
	title.textContent = ''
	var titleCategory = ''
	switch (data.line.product) {
		case 'bus':
			titleCategory = ''
			break
		case 'ferry':
			titleCategory = 'Ferry'
			break
		default:
			titleCategory = 'Train'
	}
	title.appendChild(document.createTextNode(titleCategory + ' '))
	var lineNameSpan = document.createElement('span')
	title.appendChild(lineNameSpan)
	lineNameSpan.textContent = data.line.name
	if (data.line.product) {
		if (data.line.productName === 'STB' && data.line.name.startsWith('STB U')) {
			data.line.product = 'subway'
		}
		if (data.line.adminCode === 'vvs020') {
			// Stuttgart Stadtbahn
			lineNameSpan.innerText = data.line.name.slice(4)
		} else if (data.line.adminCode === '800643') {
			// Stuttgart S-Bahn
			lineNameSpan.innerText = 'S' + data.line.name.slice(2)
		} else if (data.line.adminCode === 'kvv021') {
			// Karlsruhe Tram
			lineNameSpan.innerText = data.line.name.slice(4)
		}
		lineNameSpan.classList.add('product-' + data.line.product)
		lineNameSpan.classList.add('product-id-' + data.line.id)
		lineNameSpan.classList.add('product-adminCode-' + data.line.adminCode)
		if (data.line.operator) {
			lineNameSpan.classList.add('product-operator-' + data.line.operator.id)
		}
	}
	// trainIdSpan(data.line.productName, data.line.fahrtNr, title)
	// title.append(' ')
	title.append(` (${data.line.fahrtNr})`)

	document.getElementsByTagName('title')[0].textContent = `Train ${data.line.productName} ${data.line.fahrtNr} (${data.line.name})`

	if (data.line.operator) {
		document.getElementById('company').textContent = data.line.operator.name
	}
	var dateHref = document.createElement('a')
	var dateP = document.getElementById('date')
	while (dateP.childNodes.length > 0) {
		dateP.childNodes[0].remove()
	}
	dateP.appendChild(dateHref)
	dateHref.textContent = new Date(data.departure || data.plannedDeparture).toDateString()
	dateHref.href = '#'
	dateHref.classList.add('no-a-custom')
	dateHref.classList.add('items', 'no-a-custom')
	dateHref.addEventListener('click', function (e) {
		e.preventDefault()
		// Implement date switcher
		yesterday = !yesterday
		if (!yesterday) {
			history.back()
		}
		else {
			const yesterdayUrl = new URL(location.href)
			const newDate = new Date(date.getTime())
			newDate.setDate(newDate.getDate() - 1)
			yesterdayUrl.searchParams.set('date', newDate.toISOString())
			history.pushState('', '', yesterdayUrl)
		}
		refresh()
	})

	document.getElementById('loading').classList.add('hidden')

	/**
	 * @type {DbTrip & DbArrDep}
	 */
	var group = data
	document.getElementById('group-choice').classList.add('hidden')
	document.getElementById('train-info').classList.remove('hidden')
	document.getElementById('train-info').focus()

	document.getElementsByClassName('rsk')[0].textContent = 'Refresh'
	document.getElementsByClassName('csk')[0].textContent = ''

	document.getElementById('route-from').textContent = group.origin.name
	document.getElementById('route-to').textContent = group.destination.name

	if (group.status) {
		document.getElementById('status').classList.remove('hidden')

		var statusDelay = document.getElementById('status-delay')
		while (statusDelay.childNodes.length > 0) {
			statusDelay.childNodes[0].remove()
		}
		var delayString = ''
		var delayMinutes = group.status.delay
		if (delayMinutes === 0) {
			delayString = 'On time'
			statusDelay.appendChild(document.createTextNode(delayString))
		}
		else {
			var early = false
			if (delayMinutes < 0) {
				early = true
				delayMinutes = -delayMinutes
			}
			
			if (delayMinutes >= 60) {
				var hours = Math.floor(delayMinutes / 60)
				delayMinutes = delayMinutes % 60
				delayString += hours.toString()
				delayString += ' hour'
				if (hours > 1) {
					delayString += 's'
				}
			}
			if (delayMinutes > 0) {
				if (delayString.length > 0) {
					delayString += ' and '
				}
				delayString += delayMinutes.toString()
				delayString += ' minute'
				if (delayMinutes > 1) {
					delayString += 's'
				}
			}
			delayString += ' '
			statusDelay.appendChild(document.createTextNode(delayString))

			var kindSpan = document.createElement('span')
			statusDelay.appendChild(kindSpan)
			if (early) {
				kindSpan.textContent = 'early'
				kindSpan.classList.add('early')
			}
			else {
				kindSpan.textContent = 'late'
				kindSpan.classList.add('late')
			}
		}

		var statusLocation = document.getElementById('status-location')
		while (statusLocation.childNodes.length > 0) {
			statusLocation.childNodes[0].remove()
		}
		var stateString = ''
		if (group.status.state === 'arrival') {
			stateString += 'when arriving at '
		}
		else if (group.status.state === 'departure') {
			stateString += 'when departing from '
		}
		else if (group.status.state === 'passing') {
			stateString += 'while passing through '
		}
		statusLocation.appendChild(document.createTextNode(stateString))
		var stationSpan = document.createElement('span')
		statusLocation.appendChild(stationSpan)
		stationSpan.textContent = group.status.station
		stationSpan.classList.add('station')
	}
	else {
		document.getElementById('status').classList.add('hidden')
	}

	var stationsDiv = document.getElementById('stations')
	while (stationsDiv.childNodes.length > 0) {
		stationsDiv.childNodes[0].remove()
	}

	var separator = document.createElement('h4')
	stationsDiv.appendChild(separator)
	separator.textContent = 'Stations'

	var stationsList = document.createElement('ul')
	stationsDiv.appendChild(stationsList)

	/**
	 * @type {string[] | null}
	 */
	var journeyStations = null
	if (startId && stopId) {
		journeyStations = []
		var include = false
		for (var si = 0; si < group.stopovers.length; si++) {
			if (group.stopovers[si].stop.id === startId) {
				include = true
			}
			if (include) {
				journeyStations.push(group.stopovers[si].stop.id)
			}
			if (group.stopovers[si].stop.id === stopId) {
				break
			}
		}
	}

	group.stopovers.forEach(function (station) {
		var stationItem = document.createElement('li')
		stationsList.appendChild(stationItem)
		stationItem.classList.add('stationItem')
		if (station.cancelled && !station.arrival && !station.departure) {
			stationItem.classList.add('cancelled')
		}
		if (journeyStations && !journeyStations.includes(station.stop.id)) {
			stationItem.classList.add('not-in-journey')
		}

		var stationName = document.createElement('p')
		stationItem.appendChild(stationName)
		stationName.classList.add('pri', 'name')
		var stationNameHref = document.createElement('a')
		stationName.appendChild(stationNameHref)
		stationNameHref.textContent = station.stop.name
		stationNameHref.classList.add('items', 'no-a-custom')
		var stationUrl = new URL('/view-station.html', window.location.origin)
		stationUrl.searchParams.append('stationId', station.stop.id)
		stationUrl.searchParams.append('date', (station.arrival || station.departure))
		stationNameHref.href = stationUrl.toString()

		if (station.arrival) {
			var stationArrival = document.createElement('div')
			stationItem.appendChild(stationArrival)
			stationArrival.classList.add('arrival')

			var originalArr = document.createElement('p')
			stationArrival.appendChild(originalArr)
			var originalArrSpan = document.createElement('pre')
			originalArr.appendChild(originalArrSpan)
			var arrDate = new Date(station.plannedArrival)
			originalArrSpan.textContent = arrDate.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
			originalArr.classList.add('pri')
			if (station.arrivalDelay) {
				originalArr.classList.remove('pri')
				originalArr.classList.add('thi')
				originalArrSpan.classList.add('original')
				var delaySpanArr = document.createElement('span')
				originalArr.appendChild(delaySpanArr)
				delaySpanArr.textContent = `${station.arrivalDelay > 0 ? '+' : ''}${station.arrivalDelay / 60}`;
				delaySpanArr.classList.add(station.arrivalDelay > 0 ? 'late' : 'early')
				delaySpanArr.style.marginLeft = '4px'

				var actualArr = document.createElement('p')
				stationArrival.appendChild(actualArr)
				arrDate.setSeconds(arrDate.getSeconds() + station.arrivalDelay)
				actualArr.classList.add('pri', station.arrivalDelay > 0 ? 'late' : 'early')
				// if (!station.arrival.status.real) {
				// 	actualArr.classList.add('not-real')
				// }
				var actualArrPre = document.createElement('pre')
				actualArr.appendChild(actualArrPre)
                actualArrPre.textContent = arrDate.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
			}
		}

		if (station.departure) {
			var stationDeparture = document.createElement('div')
			stationItem.appendChild(stationDeparture)
			stationDeparture.classList.add('departure')

			var originalDep = document.createElement('p')
			stationDeparture.appendChild(originalDep)
			var depDate = new Date(station.plannedDeparture)
			var originalDepSpan = document.createElement('pre')
			originalDep.appendChild(originalDepSpan)
			originalDepSpan.textContent = depDate.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
			originalDep.classList.add('pri')
			if (station.departureDelay) {
				originalDep.classList.remove('pri')
				originalDep.classList.add('thi')
				originalDepSpan.classList.add('original')
				var delaySpanDep = document.createElement('span')
				originalDep.appendChild(delaySpanDep)
				delaySpanDep.textContent = `${station.departureDelay > 0 ? '+' : ''}${station.departureDelay / 60}`;
				delaySpanDep.classList.add(station.departureDelay > 0 ? 'late' : 'early')
				delaySpanDep.style.marginLeft = '4px'

				var actualDep = document.createElement('p')
				stationDeparture.appendChild(actualDep)
				depDate.setSeconds(depDate.getSeconds() + station.departureDelay)
				actualDep.classList.add('pri', station.departureDelay > 0 ? 'late' : 'early')
				// if (!station.departure.status.real) {
				// 	actualDep.classList.add('not-real')
				// }
				var actualDepPre = document.createElement('pre')
				actualDep.appendChild(actualDepPre)
                actualDepPre.textContent = depDate.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
			}
		}

		// var stationKm = document.createElement('p')
		// stationItem.appendChild(stationKm)
		// stationKm.textContent = `${station.km} km`
		// stationKm.classList.add('thi', 'km')
		// if (!showKm) {
		// 	stationKm.classList.add('hidden')
		// }

		if (station.arrivalPlatform || station.departurePlatform) {
			var stationPlatform = document.createElement('p')
			stationItem.appendChild(stationPlatform)
			stationPlatform.textContent = `platform ${station.departurePlatform || station.arrivalPlatform}`
			stationPlatform.classList.add('thi', 'platform')
			if (station.departurePlatform && station.departurePlatform !== station.plannedDeparturePlatform) {
				stationPlatform.classList.add('changed')
			}
		}

		var stationNotes = document.createElement('div')
		stationItem.appendChild(stationNotes)
		stationNotes.classList.add('notes')
		if (station.remarks) {
			station.remarks.forEach(function (remark) {
				var noteP = document.createElement('p')
				stationNotes.appendChild(noteP)
				noteP.classList.add('note', 'thi', `remark-${remark.type}`)
				noteP.textContent = remark.text
			})
		}
		if (journeyStations && station.stop.id === journeyStations[0]) {
			var boardNoteP = document.createElement('p')
			stationNotes.appendChild(boardNoteP)
			boardNoteP.classList.add('note', 'thi', 'remark-board')
			boardNoteP.textContent = 'Board here'
		}
		if (journeyStations && station.stop.id === journeyStations[journeyStations.length - 1]) {
			var boardNoteP = document.createElement('p')
			stationNotes.appendChild(boardNoteP)
			boardNoteP.classList.add('note', 'thi', 'remark-exit')
			boardNoteP.textContent = 'Exit here'
		}
		// if (station.notes && station.notes.length > 0) {

		// 	station.notes.forEach(function (note) {
		// 		var noteP = document.createElement('p')
		// 		stationNotes.appendChild(noteP)
		// 		noteP.classList.add('note', 'thi')

		// 		switch (note.kind) {
		// 			case 'departsAs': {
		// 				noteP.textContent = 'Train departs as '
		// 				trainIdSpan(note.rank, note.number, noteP)
		// 				break
		// 			}
		// 			case 'detachingWagons': {
		// 				noteP.textContent = `Detaching wagons to ${note.station}`
		// 				break
		// 			}
		// 			case 'receivingWagons': {
		// 				noteP.textContent = `Receiving wagons from ${note.station}`
		// 				break
		// 			}
		// 			case 'trainNumberChange': {
		// 				noteP.textContent = 'Train changes number to '
		// 				trainIdSpan(note.rank, note.number, noteP)
		// 				break
		// 			}
		// 		}
		// 	})
		// }
		
		if (station.cancelled && !station.arrival && !station.departure) {
			var noteP = document.createElement('p')
			stationNotes.appendChild(noteP)
			noteP.classList.add('note', 'thi')
			noteP.textContent = 'Stop is cancelled'
		} 
	})

	if (group.remarks && group.remarks.length > 0) {
		var remarksSeparator = document.createElement('h4')
		stationsDiv.appendChild(remarksSeparator)
		remarksSeparator.textContent = 'Remarks'

		var remarksList = document.createElement('ul')
		stationsDiv.appendChild(remarksList)
		remarksList.classList.add('remarks')
		
		group.remarks.forEach(function (remark) {
			var remarkItem = document.createElement('li')
			remarksList.append(remarkItem)
			remarkItem.classList.add('remarkItem', `remark-${remark.type}`)

			var remarkSummaryP = document.createElement('p')
			remarkItem.appendChild(remarkSummaryP)
			remarkSummaryP.classList.add('remark', 'pri')
			remarkSummaryP.textContent = remark.summary

			var remarkTextP = document.createElement('p')
			remarkItem.appendChild(remarkTextP)
			remarkTextP.classList.add('remark', 'sec')
			remarkTextP.textContent = remark.text
		})
	}

	var mapDiv = document.getElementById('map')
	if (group.polyline) {
		console.log(group.polyline)

		mapDiv.classList.remove('hidden')

		var actualMap = document.getElementById('actual-map')
		if (!actualMap) {
			actualMap = document.createElement('div')
			actualMap.id = 'actual-map'
			mapDiv.insertBefore(actualMap, null)
		}

		if (!leafletMap) {
			leafletMap = L.map('actual-map', {
				zoomSnap: 0.5,
				// zoomDelta: 0.5,
			}).setView([51.1657, 10.4515], 6)
			L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
				maxZoom: 19,
				attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
			}).addTo(leafletMap);
			L.tileLayer('https://{s}.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png', {
				attribution: ' Style: <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA 2.0</a> <a href="http://www.openrailwaymap.org/">OpenRailwayMap</a> and OpenStreetMap',
				minZoom: 2,
				maxZoom: 19,
				tileSize: 256
			}).addTo(leafletMap)
		}

		if (mapLayers) {
			mapLayers.forEach(function (layer) { layer.remove() })
			mapLayers = []
		}

		/**
		 * @type {[number, number][]}
		 */
		var lines = []
		/**
		 * @type {[number, number][] | null}
		 */
		var journeyLines = null
		include = false
		var stops = []
		var minLat = group.polyline.features[0].geometry.coordinates[1]
		var maxLat = minLat
		var minLng = group.polyline.features[0].geometry.coordinates[0]
		var maxLng = minLng
		for (var pi = 0; pi < group.polyline.features.length; pi++) {
			var feature = group.polyline.features[pi]
			var coord = feature.geometry.coordinates
			lines.push([coord[1], coord[0]])
			if (journeyStations && include !== -1) {
				if (feature.properties && feature.properties.id === journeyStations[0]) {
					minLat = maxLat = coord[1]
					minLng = maxLng = coord[0]
					include = true
				}
				if (include) {
					if (!journeyLines) journeyLines = []
					journeyLines.push([coord[1], coord[0]])
				}
				if (feature.properties && feature.properties.id === journeyStations[journeyStations.length - 1]) {
					include = -1
				}
			}
			if (feature.properties && feature.properties.type == 'stop') {
				stops.push({
					coord: [coord[1], coord[0]],
					id: feature.properties.id,
				})
			}

			if (!journeyStations || include === true) {
				if (minLat > coord[1]) {
					minLat = coord[1]
				}
				if (minLng > coord[0]) {
					minLng = coord[0]
				}
				if (maxLat < coord[1]) {
					maxLat = coord[1]
				}
				if (maxLng < coord[0]) {
					maxLng = coord[0]
				}
			}
		}

		mapLayers.push(L.polyline(lines, {
			color: !journeyLines ? '#6666ff' : '#9999dd',
			opacity: !journeyLines ? 1.0 : 0.8,
			weight: 4,
		}).addTo(leafletMap));
		if (journeyLines) {
			mapLayers.push(L.polyline(journeyLines, {
				color: '#6666ff',
				weight: 2,
			}).addTo(leafletMap));
		}

		for (var si = 0; si < stops.length; si++) {
			var stop = stops[si]
			mapLayers.push(L.circleMarker(stop.coord, {
				color: !journeyStations || journeyStations.includes(stop.id) ? '#ffff66' : '#dfdf66',
				radius: 5,
			}).addTo(leafletMap))
		}

		leafletMap.flyToBounds([[minLat, minLng], [maxLat, maxLng]], {
			duration: 0.2,
		})

		actualMap.scrollIntoView()
	}
	else if (loadMap) {
		mapDiv.classList.add('hidden')
	}

	lastSuccessfulFetch = fetchDate || new Date()
}

var refreshStopToken = null

/**
 * @typedef DbProducts
 * @property {boolean} nationalExpress
 * @property {boolean} national
 * @property {boolean} regionalExpress
 * @property {boolean} regional
 * @property {boolean} suburban
 * @property {boolean} bus
 * @property {boolean} ferry
 * @property {boolean} subway
 * @property {boolean} tram
 * @property {boolean} taxi
 */

/**
 * @typedef DbLocation
 * @property {'location'} type
 * @property {?string} id
 * @property {number} latitude
 * @property {number} longitude
 */

/**
 * @typedef DbLine
 * @property {'line'} type
 * @property {string} id
 * @property {string} fahrtNr
 * @property {string} name
 * @property {boolean} public
 * @property {string} adminCode
 * @property {string} productName
 * @property {string} mode
 * @property {string} product
 * @property {{type: 'operator', id: string, name: string}} operator
 * @property {string} additionalName
 */

/**
 * @typedef DbStop
 * @property {'stop'} type
 * @property {?string} id
 * @property {string} name
 * @property {DbLocation} location
 * @property {DbProducts} products
 */
	
/**
 * @typedef DbRemark
 * @property {string} type
 * @property {string} text
 * @property {string} code
 * @property {string} summary
 */

/**
 * @typedef DbArrDep
 * @property {string | null} arrival
 * @property {string | null} plannedArrival
 * @property {number | null} arrivalDelay
 * @property {string | null} arrivalPlatform
 * @property {string | null} plannedArrivalPlatform
 * @property {string | null} arrivalPrognosisType
 * @property {string | null} departure
 * @property {string | null} plannedDeparture
 * @property {number | null} departureDelay
 * @property {string | null} departurePlatform
 * @property {string | null} plannedDeparturePlatform
 * @property {string | null} departurePrognosisType
 */

/**
 * @typedef DbTrip
 * @property {DbStop} origin
 * @property {DbStop} destination
 * @property {DbLine} line
 * @property {string} direction
 * @property {DbLocation} location
 * @property {({stop: DbStop, cancelled?: boolean, remarks?: DbRemark[]} & DbArrDep)[]} stopovers
 * @property {DbRemark[]} remarks
 * @property {string} id
 */

/**
 * @param {string | null} tripId
 * @returns {Promise}
 */
function onTripId(tripId) {
	if (tripId) {
		var reqUrl = new URL(`https://v6.db.transport.rest/trips/${encodeURIComponent(tripId)}`)
		reqUrl.searchParams.append('stopovers', 'true')
		reqUrl.searchParams.append('remarks', 'true')
		if (loadMap) {
			reqUrl.searchParams.append('polyline', 'true')
		}
		return fetch(
			reqUrl.toString(),
			{
				cache: 'no-store',
			},
		).then(function (response) {
			if (!response.ok) {
				// Check in 10 seconds if server returned error
				return Promise.reject('Response not okay')	
			}
			var cacheDate = response.headers.get('SW-Cached-At')
			return response.json().then(function (data) {
				data['$cacheDate'] = cacheDate
				return data
			})
		}).then(function (response) {
			if (!response) {
				return Promise.reject('No JSON response')
			}
			var cacheDate = response['$cacheDate']
			if (cacheDate) {
				cacheDate = new Date(cacheDate)
			}
			var success = !cacheDate
			trainData = response.trip
			onTrainData(response.trip, cacheDate)
			return success
		})
	} 
	else {
		return Promise.reject('No tripId found')
	}
}

/**
 * Callback for when trips are found
 * @param {string} wantedTrainNumber
 * @param {{trips: (DbTrip & DbArrDep)[]}} data 
 * @param {?Date} fetchDate 
 */
function onTripsData(wantedTrainNumber, data, fetchDate) {
	data.trips.forEach(function (trip) {
		if (trip.line.fahrtNr == wantedTrainNumber || trip.line.name == wantedTrainNumber) {
			tripId = trip.id
			console.group('Found tripId by train number')
			console.log(`ID: ${trip.id}`)
			console.log(`Fahrt Nr: ${trip.line.fahrtNr}`)
			console.log(`Name: ${trip.line.name}`)
			console.log(`+Name: ${trip.line.additionalName}`)
			console.groupEnd()
		}
	})
	return onTripId(tripId)
}

/**
 * @returns {Promise<boolean>}
 */
function refresh() {
	function reschedule(timeout) {
		if (refreshStopToken != null) {
			clearTimeout(refreshStopToken)
		}
		refreshStopToken = setTimeout(function () { 
			refresh()
		}, timeout || 60000)
	}
	if (tripId) {
		return onTripId(tripId)
	}
	/**
	 * @type {Date}
	 */
	var reqDate = new Date(date.valueOf())
	if (yesterday) {
		reqDate.setDate(reqDate.getDate() - 1)
	}
	reqDate.setMinutes(0, 0, 0)
	var reqUrl = new URL(`https://v6.db.transport.rest/trips`)
	reqUrl.searchParams.append('query', trainNumber)
	if (loadMap) {
		reqUrl.searchParams.append('polyline', 'true')
	}
	reqUrl.searchParams.append('when', reqDate.toISOString())
	return fetch(
		reqUrl.toString(),
		{
			cache: 'no-store',
		},
	).then(function (response) {
		if (!response.ok) {
			// Check in 10 seconds if server returned error
			reschedule(10000)
			return
		}
		var cacheDate = response.headers.get('SW-Cached-At')
		return response.json().then(function (data) {
			data['$cacheDate'] = cacheDate
			return data
		})
	}).then(function (response) {
		if (!response) {
			return
		}
		var cacheDate = response['$cacheDate']
		if (cacheDate) {
			cacheDate = new Date(cacheDate)
		}
		var success = !cacheDate
		return onTripsData(trainNumber, response, cacheDate)
			.then(function () {
				// Check in 1 seconds if network error
				reschedule(success ? undefined : 1000)
				return success
			})
	}).catch(function (e) {
		// Check in 1 second if network error
		reschedule(1000)
		throw e
	})
}

window.addEventListener('unload', function (e) {
	if (refreshStopToken != null) {
		clearTimeout(refreshStopToken)
	}
})

function rsk() {
	function changeRskText(newText) {
		document.querySelectorAll('.rsk').forEach(function (elem) {
			elem.textContent = newText
		})
	}

	changeRskText('Refreshing...')
	refresh().catch(function () { return false}).then(function (success) {
		if (!success) {
			changeRskText('Refreshing failed')
			setTimeout(function (_) {
				changeRskText('Refresh')
			}, 3000)
		}
		else {
			changeRskText('Refresh')
		}
	})
}

window.addEventListener('popstate', function (e) {
	if (yesterday) {
		yesterday = false
		trainData = null
	}
	else {
		groupIndex = null
	}
	if (trainData) {
		onTrainData(trainData)
	}
	else {
		refresh()
	}
})

window.addEventListener('load', function (e) {
	var sp = new URL(window.location.href).searchParams

	if (!sp.has('train') && !sp.has('tripId')) {
		window.history.back()
		this.setTimeout(function () {
			var url = new URL(window.location.href)
			url.pathname = 'train.html'
			window.location.href = url.toString()
		}, 100)
	}

	trainNumber = sp.get('train')
	date = sp.has('date') ? new Date(sp.get('date')) : new Date()
	groupIndex = sp.has('groupIndex') ? parseInt(sp.get('groupIndex')) : null
	tripId = sp.get('tripId')
	startId = sp.get('startId')
	stopId = sp.get('stopId')

	if (window.localStorage) {
		var oldRecent = localStorage.getItem('recent/view-train')
		if (oldRecent) {
			oldRecent = JSON.parse(oldRecent)
		}
		localStorage.setItem('recent/view-train', JSON.stringify({
			trainNumber: trainNumber,
			tripId: tripId,
			date: date.toISOString(),
			$addDate: new Date().toISOString(),
		}))
	}

	document.querySelectorAll('.rsk').forEach(function (rskElem) {
		rskElem.addEventListener('click', function (e) {
			rsk()
		})
	})

	if (navigator.canShare && navigator.canShare({ url: '' })) {
		document.getElementById('title').addEventListener('click', function () {
			navigator.share({ url: '' });
		})
	}

	var content = document.getElementsByClassName('content')[0]
	content.focus()
	content.addEventListener('keydown', function (e) {
		switch (e.key) {
			// case 'ArrowUp':
			// 	content.scrollBy(0, -50)
			// 	break
			// case 'ArrowDown':
			// 	content.scrollBy(0, 50)
			// 	break
			case 'SoftRight':
				rsk()
				break
			case '1':
				date.setDate(date.getDate() - 1)
				refresh()
				break
			case '3':
				date.setDate(date.getDate() + 1)
				refresh()
				break
			case '7':
				showKm = !showKm
				document.querySelectorAll('.km').forEach(function (kmItem) {
					if (showKm) {
						kmItem.classList.remove('hidden')
					}
					else {
						kmItem.classList.add('hidden')
					}
				})
				break
			default:
				console.log(e.key)
		}
	})

	document.getElementById('load-map-button').addEventListener('click', function (event) {
		event.preventDefault()
		event.target.textContent = 'Loading...'
		loadMap = true;
		refresh()
	})

	refresh()

	setInterval(function () {
		if (!lastSuccessfulFetch) {
			return
		}
		var millis = new Date() - lastSuccessfulFetch
		var secs = Math.floor(millis / 1000)
		
		var timeStr = ''
		if (secs / 3600 >= 1) {
			timeStr += `${Math.floor(secs / 3600)}h`
			secs = secs % 3600
		}
		if (secs / 60 >= 1) {
			timeStr += `${Math.floor(secs / 60)}m`
			secs = secs % 60
		}
		if (secs >= 1) {
			timeStr += `${Math.floor(secs)}s`
		}
		if (!timeStr) {
			document.querySelectorAll('.lsk').forEach(function (elem) {
				elem.textContent = 'Last refreshed now'
				elem.classList.add('last-refreshed')
			})
		}
		else {
			document.querySelectorAll('.lsk').forEach(function (elem) {
				elem.textContent = `Last refreshed ${timeStr} ago`
				elem.classList.add('last-refreshed')
			})
		}
	}, 500)

	// if (this.localStorage && !this.localStorage.getItem('info-yesterday')) {
	// 	this.alert("New feature: You can now view yesterday's train by selecting the date!")
	// 	this.localStorage.setItem('info-yesterday', 'true')
	// }
})