function xml_parse(xml) {
	let result;
	let path = [];
	let tag_begin;
	let text_begin;
	for (let i = 0; i < xml.length; i++) {
		let c = xml.charAt(i);
		if (!tag_begin && c == '<') {
			if (i > text_begin && path.length) {
				let value = xml.substring(text_begin, i);
				if (!/^\s*$/.test(value)) {
					path[path.length - 1].value = value;
				}
			}
			tag_begin = i + 1;
		} else if (tag_begin && c == '>') {
			let tag = xml.substring(tag_begin, i).trim();
			if (tag.startsWith('?') && tag.endsWith('?')) {
				/* Ignore directives. */
			} else  if (tag.startsWith('/')) {
				path.pop();
			} else {
				let parts = tag.split(' ');
				let attributes = {};
				for (let j = 1; j < parts.length; j++) {
					let eq = parts[j].indexOf('=');
					let value = parts[j].substring(eq + 1);
					if (value.startsWith('"') && value.endsWith('"')) {
						value = value.substring(1, value.length - 1);
					}
					attributes[parts[j].substring(0, eq)] = value;
				}
				let next = {name: parts[0], children: [], attributes: attributes};
				if (path.length) {
					path[path.length - 1].children.push(next);
				} else {
					result = next;
				}
				if (!tag.endsWith('/')) {
					path.push(next);
				}
			}
			tag_begin = undefined;
			text_begin = i + 1;
		}
	}
	return result;
}

function* xml_each(node, name) {
	for (let child of node.children) {
		if (child.name == name) {
			yield child;
		}
	}
}

export function gpx_parse(xml) {
	let result = {segments: []};
	let tree = xml_parse(xml);
	if (tree?.name == 'gpx') {
		for (let trk of xml_each(tree, 'trk')) {
			for (let trkseg of xml_each(trk, 'trkseg')) {
				let segment = [];
				for (let trkpt of xml_each(trkseg, 'trkpt')) {
					segment.push({lat: parseFloat(trkpt.attributes.lat), lon: parseFloat(trkpt.attributes.lon)});
				}
				result.segments.push(segment);
			}
		}
	}
	for (let metadata of xml_each(tree, 'metadata')) {
		for (let link of xml_each(metadata, 'link')) {
			result.link = link.attributes.href;
		}
		for (let time of xml_each(metadata, 'time')) {
			result.time = time.value;
		}
	}
	return result;
}